home *** CD-ROM | disk | FTP | other *** search
- From: wht@n4hgf.atl.ga.us (Warren Tucker)
- Newsgroups: comp.sources.misc
- Subject: v42i111: ecu - ECU Asynchronous Communications v3.30, Part13/37
- Date: 23 May 1994 14:23:07 -0500
- Organization: Sterling Software
- Sender: kent@sparky.sterling.com
- Approved: kent@sparky.sterling.com
- Message-ID: <2rqvqr$dnh@sparky.sterling.com>
- X-Md4-Signature: 6868e46e2f0cfc48a3f804f382a33193
-
- Submitted-by: wht@n4hgf.atl.ga.us (Warren Tucker)
- Posting-number: Volume 42, Issue 111
- Archive-name: ecu/part13
- Environment: SCO,SCOXENIX,MOTOROLA,HP-UX,LINUX,NetBSD,SUNOS,SYSVR4,SOLARIS2
- Supersedes: ecu: Volume 32, Issue 36-75
-
- #! /bin/sh
- # This is a shell archive. Remove anything before this line, then feed it
- # into a shell via "sh file" or similar. To overwrite existing files,
- # type "sh file -c".
- # Contents: ecu330/fasi/RELEASENOTES ecu330/sea/ecusea.c
- # Wrapped by kent@sparky on Mon May 23 13:40:52 1994
- PATH=/bin:/usr/bin:/usr/ucb:/usr/local/bin:/usr/lbin:$PATH ; export PATH
- echo If this archive is complete, you will see the following message:
- echo ' "shar: End of archive 13 (of 37)."'
- if test -f 'ecu330/fasi/RELEASENOTES' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ecu330/fasi/RELEASENOTES'\"
- else
- echo shar: Extracting \"'ecu330/fasi/RELEASENOTES'\" \(23494 characters\)
- sed "s/^X//" >'ecu330/fasi/RELEASENOTES' <<'END_OF_FILE'
- XThis is the original RELEASENOTES from FAS 2.08 for reference only.
- XRead README.FASI. DO NOT CONTACT UWE DOERING REGARDING THIS HACKED VERSION
- X ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
- X
- X release 1.1a Sat Nov 11, 1989
- X
- X This is an unofficial release as I'm not the original author
- X of this async driver.
- X
- X Uwe Doering INET : gemini@geminix.in-berlin.de
- X Billstedter Pfad 17 b UUCP : ...!unido!fub!geminix.in-berlin.de!gemini
- X 1000 Berlin 20
- X Germany
- X
- X New Features:
- X
- X Added a third minor tty device number for every physical
- X port. See description preceding the asyopen function in
- X asy.c. Changed the behavior of ttyxx, too.
- X
- X Added output hardware handshake support for DSR. Now you
- X can do handshake with CTS, DSR or both. Input hardware
- X handshake is on if you use at least one of the output
- X handshake signals.
- X
- X More flexible support of additional interrupt registers
- X on mux boards. This is fully configurable now.
- X
- X Added support for the CREAD flag. If not set, receiver
- X interrupts are still serviced, but the received characters
- X are simply thrown away. This is not as elegant as disabeling
- X the interrupts themselves, but with the already existing
- X driver it was the easiest way, and the most new-bugs-preventing,
- X too.
- X
- X Added a lot of comments to the source so that the curious
- X user can understand why and how things are done.
- X
- X
- X Bug Fixes:
- X
- X The hang-up-on-last-close flag (HUPCL) was ignored. DTR
- X was asserted regardless of this flag.
- X
- X Made the detection of CTS and DCD more bullet-proof.
- X Especially because between a close and the next open of
- X a line, where interrupts are ignored, the software copys of
- X CTS and DCD must be set up propperly in the asyopen function
- X or the tty line would be blocked under certain circum-
- X stances. For similar reasons, there is also a setup in the
- X asyparam function.
- X
- X Rewrote the input character processing function to work
- X according to the TERMIO(7) man page.
- X
- X Changed the behavior of BREAK generation to let the
- X transmitter drain before TX is set to low.
- X
- X Changed line hangup procedure so that the closing
- X process returns immediately and doesn't sleep during
- X the hangup delay/time. Instead, if an other process tries
- X to open the line while hangup is still in progress, this
- X process will sleep until hangup is competed.
- X
- X With DOS Merge, on MicroPort V/386 3.0e the linker was
- X missing the function `init8250'. Reengineered this from
- X a disassembler listing of MicroPort's original driver and
- X modified it to work with the NS16550A 16-byte FIFO. This
- X funktion was added simply to be able to link the kernel.
- X DOS Merge's virtual COM ports are still unusable with this
- X release, though. To include this function, add a `-DMERGE'
- X to the CFLAGS line in your makefile.
- X
- X Made a lot of other corrections and enhancements in both
- X speed and functionallity. As a result of all my effords
- X I think this driver is slightly faster, more versatile
- X and much more stable than the original release.
- X
- X ------------------------------------------------------------
- X
- X release 1.1b Sat Nov 25, 1989
- X
- X New Features:
- X
- X Changed the minor device number scheme again.
- X There are now two main groups: The unblocked open
- X and the blocked open. Every group has four sub-modes
- X and an additional hardware handshake flag. All this
- X is coded in the higher four bits of the minor device
- X number. Because of this, the maximum of 32 ports was
- X reduced to 16 ports so that the port number fits into
- X the remaining lower four bits of the minor device number.
- X 32 dumb ports in a single machine would have been overkill
- X anyway. For more details refer to the description in the
- X README file.
- X
- X ------------------------------------------------------------
- X
- X release 2.00 Mon Nov 27, 1989
- X
- X As this release differs so much from the original version I got,
- X I now declare this as independant from the original author
- X Jim Murray. This allows me to introduce new release levels
- X without wondering whether they will collide with Jim's releases.
- X Of course many credits to Jim for writing this software in the
- X first place. Without his driver as a base I never would have
- X been able to do such kernel driver development.
- X
- X Bug Fixes:
- X
- X If there were glitches on the hardware handshake lines
- X and the DCD line a getty on this port would sometimes
- X hang and become an immortal process. I think this was
- X because the output buffer wasn't flushed properly
- X on carrier loss. I hope I fixed this now. We'll see.
- X
- X ------------------------------------------------------------
- X
- X release 2.01 Tue Nov 28, 1989
- X
- X Did some cleanup in the source code.
- X
- X I splitted the driver into two parts: The driver itself and
- X the file `space.c'.
- X `space.c' contains all data structures necessary to configure
- X the driver and is compiled at kernel link time. Therefore if you
- X change your serial card configuration you simply change `space.c'
- X directly in the link kit directory and relink the kernel. No
- X driver recompilation or installation is necessary for this.
- X But note that whenever you use `make install' your setup in
- X the link kit directory is overwritten by the original `space.c'
- X file. Therefore you should copy your new `space.c' back to
- X the source directory when you are finished with the configuration.
- X
- X Renamed the package to `FAS Final Async Solution'. The following
- X files have been renamed:
- X asy.c -> fas.c
- X asy.h -> fas.h
- X asy_conf-xxxxx -> space-xxxxx
- X
- X ISC 386/ix is supported now. There are separate makefiles
- X for uPort and ISC to cope with the differences in link kit
- X installation.
- X
- X Bug Fixes:
- X
- X `getty' still hung sometimes on a line with hardware
- X handshake. Tried to fix it this time.
- X
- X ------------------------------------------------------------
- X
- X release 2.02 Thu Nov 30, 1989
- X
- X Abandoned the distinction between space-xxxxx files with
- X and without hardware flow control because this is selected
- X by the minor device number now.
- X
- X Bug Fixes:
- X
- X Set the high and low water marks for hardware input flow
- X control to higher values than software flow control. This
- X gives precedence to software flow control if both methods
- X are used. These marks are self-adjusting and don't need to
- X be changed if some flavor of UNIX has a different buffer
- X size than the standard 256 characters. Before this change
- X concurrent use of both flow controls could cause trouble
- X with some high-speed modems. This is fixed now.
- X
- X A flush read or write buffer request now also clears the
- X receiver or transmitter FIFO, respectively. An ioctl
- X call with a TCSETA* command clears the FIFOs, too.
- X
- X ------------------------------------------------------------
- X
- X release 2.03 Fri Dec 01, 1989
- X
- X Wrote an installation guide. The driver should be quite
- X easy to install now.
- X
- X Added tty node configuration files for ISC.
- X
- X Hardware input flow control is bound now to the level of the
- X receiver ring buffer instead of the UNIX input buffer. This
- X has the advantage that buffer size and trigger levels are
- X defined in the driver and therefore can be varied as needed.
- X
- X New Features:
- X
- X Added a boot time status message that shows the init
- X state of each port. This tells you immediately what
- X ports are found and initted by the driver. Useful to
- X determine hardware configuration problems. Look at
- X the description in the README file. Thanks to
- X Kritt Gierlewsen (kritt@einoed.UUCP) for this proposal.
- X
- X ------------------------------------------------------------
- X
- X release 2.04 Thu Dec 07, 1989
- X
- X Did some cleanup in the source.
- X
- X Removed the FIFO clear from the ioctl function. We don't want
- X to do things there that aren't in the book.
- X
- X An ioctl call that switches off the CLOCAL flag will create
- X a SIGHUP signal if the carrier is actually missing at this
- X time.
- X
- X Every device is tested now quite thoroughly during initialization.
- X If the test fails the corresponding device keeps unconfigured.
- X
- X ------------------------------------------------------------
- X
- X release 2.05 Sat Jan 13, 1990
- X
- X This is the first public release of the FAS driver.
- X
- X Special thanks to the sysops of my test sites, Axel Fischer
- X (fischer@utower.UUCP) and Kritt Gierlewsen (kritt@einoed.UUCP).
- X
- X FAS is now an independant driver with its own driver name (`fas'),
- X major device number, link kit directory and other things necessary
- X for a driver. The original asy driver may or may not be linked
- X with the kernel. You only need it if you want to access some
- X serial devices via the virtual COM ports of the DOS emulator
- X (DosMerge or VP/ix) because the FAS driver doesn't have this
- X (really vendor dependant) feature.
- X
- X The default prefix for tty device node names is `ttyF' now.
- X This prevents mix-ups with the device names of the original
- X asy driver.
- X
- X Dropped the SYSV/AT support. I couldn't test the driver
- X for several release generations on uPort SYSV/AT, and because
- X there are not very much systems left with that flavor of UNIX
- X it doesn't make sense to try to maintain compatibility with it.
- X If someone really wants to use this driver on a 286 he has
- X to port it himself.
- X
- X Improved the transmitter FIFO fill procedure. Now it will try
- X harder to fill the FIFO as much as possible to cut down on
- X transmitter interrupts.
- X
- X Software input flow control (XON/XOFF) is controlled by the driver now.
- X It is bound to the level of the receiver ring buffer (as is hardware
- X flow control). As usual, it can be switched on and off by the
- X IXOFF flag in the termio(7) structure.
- X
- X Changed and speeded up the ring buffer -> unix buffer processing.
- X
- X For ISC, the getty lines for the inittab file are installed
- X by the makefile now.
- X
- X The conditional compilation of the function `init8250' (for
- X DosMerge) is now controlled by a define in `fas.h'. The compiler
- X switch `-DMERGE' is not used any more.
- X
- X Improved the documentation.
- X
- X The signals used for modem control and hardware flow control are
- X fully configurable in the `space.c' file now. Look at `fas.h' for
- X possible macros and combinations.
- X
- X There are some new modes for hardware flow control, for instance
- X HO_CTS_ON_DSR. This means that CTS is only looked at if DSR is on.
- X If DSR is off output is possible regardless of CTS. The underlying
- X assumption here is that we can expect proper handshake handling
- X only from devices that are in the ready state (indicated by DSR).
- X As a spin-off the problem with the hanging getty on lines with
- X turned-off terminals (mentioned in earlier releases) should be
- X gone if you use this new mode.
- X
- X If the XCLUDE-Flag is availabe (SYSV 3.2 because of Xenix
- X compatibility) exclusive open of a device is possible.
- X
- X The default size of the input ring buffer is now 5000 bytes.
- X This makes streaming input more likely even on loaded systems.
- X
- X Bug Fixes:
- X
- X The task state busy flag wasn't reset in some rare cases.
- X This could cause processes to become immortal while waiting
- X for the busy flag.
- X
- X Under some special conditions an ioctl call with a TCSETA?
- X command could corrupt the last character in the transmitter
- X shift register. This is fixed now.
- X
- X More fixing of the busy flag handling was necessary.
- X Co-ordinating several delayed tasks controlling this flag
- X is kind of tricky.
- X
- X After a TCSETA* ioctl command we disable the transmitter
- X for 2 sec (measured from the last transmitted character)
- X if the character format and/or speed has changed. This
- X gives the receiving side some time to do the same changes.
- X This is kind of experimental. There may be applications that
- X suffer from this delay. You may change the #define ADAPT_TIME
- X in `fas.h' to a smaller value.
- X
- X ------------------------------------------------------------
- X
- X release 2.06 Fri Mar 16, 1990
- X
- X This should have been patch #3 for release 2.05, but there are
- X so many changes now that I decided to make it a new release.
- X Therefor some of the changes are described in the 2.05 release
- X notes above but were never released to the public.
- X
- X New Features:
- X
- X There is a transmitter ring buffer now to make the output
- X less system load dependent. This really speeds things up
- X because the transmitter FIFO gets filled with more characters
- X at once. The buffer size depends on the actual baud rate to
- X prevent long output buffer drains at low speeds.
- X
- X There are also bigger input buffers to make FAS more competitive
- X against "intelligent" cards.
- X
- X Lots of speed improvements and many small changes.
- X
- X Bug Fixes:
- X
- X Fixed input/output buffer flush on carrier loss while close
- X is waiting for the output to drain.
- X
- X ------------------------------------------------------------
- X
- X release 2.07 Tue Sep 18, 1990
- X
- X This is a major redesign of the previous release. I put most of the
- X time consuming tasks in one function that is invoked asynchronously
- X by timeout calls. Inside this function most of the code runs at
- X a lower system priority level (spl5) than the interrupts. That
- X means that during character processing tty interrupts are allowed.
- X This is the main key to operation at 38400 bps on multiple ports
- X at the same time which is possible now with this release.
- X
- X New Features:
- X
- X FAS supports the VP/ix DOS emulator!
- X Now you can throw out the vendor's original driver even
- X if you like to have a serial mouse or modem access in DOS.
- X Read the paragraph about VP/ix in the README file.
- X
- X The Intel i82510 port chip is supported. It has separate
- X 4-character FIFOs for input and output. Although the
- X NS16550A is much better this chip is your second choice
- X if you can't get your hands on the National chips.
- X Thanks to Christian Seyb (cs@gold.UUCP) for sending me
- X patches and the necessary documentation for the Intel
- X chips.
- X
- X There is an init sequence in `space.c'. You can put any
- X number of address-data pairs in a null terminated array
- X to program your serial card or other hardware before
- X FAS makes the first access to the ports. AST 4-port cards,
- X for instance, have an additional port that needs to be
- X written to with a certain bit pattern to allow shared
- X interrupts. If you need to read a port to achieve the
- X setting or resetting of flags as a side effect, this
- X is possible, too.
- X
- X ESIX is officially supported now.
- X
- X SCO UNIX is officially supported, too. FAS needs to be
- X compiled with the command line flag `-DSCO'. The makefile
- X for SCO takes care of that. Thanks to Walter Mecky
- X (walter@mecky.systemware.de) and Frank Simon
- X (terra@sol.north.de) for helping me in making the necessary
- X changes for SCO UNIX.
- X
- X SCO Xenix 386 is also officially supported. FAS needs to be
- X compiled with the command line flag `-DXENIX'. The makefile
- X for SCO Xenix takes care of that. Thanks to Andreas
- X Steinmetzler (andreas@oil.UUCP) for doing the port.
- X
- X If you have the RTSFLOW and CTSFLOW termio(7) flags,
- X hardware handshake can be controlled by them.
- X Note that enabling handware flow control via the
- X minor device number overrides these flags. If you
- X like to use them you need to create tty device nodes
- X with minor device numbers in which the bit for hardware
- X handshake is set to 0. Look at the description in the
- X README file for more details.
- X Note also that if you choose to use RTSFLOW and CTSFLOW
- X all your programs that do initial access to tty devices
- X (getty, uucico, cu, SLIP dialup program etc.) need to know
- X about these flags or hardware handshake will not be used.
- X
- X The `O_EXCL' flag for the open(2) call is honored now.
- X This allowes exclusive access to an FAS device without
- X suffering from race conditions which could occure with
- X the termio(7) XCLUDE flag method.
- X
- X The `fas_test_device' function returns a digit now that
- X indicates at which phase the test exited due to an error.
- X This error digit is displayed in the boot message. Thanks
- X to Brian Beattie (beattie@visenix.UUCP) for sending me
- X the necessary patches.
- X
- X Bug Fixes:
- X
- X Automatic input FIFO flush after unblocking the getty
- X open by the carrier or the unblock signal. This makes sure
- X that there is no chance that there are characters in the
- X FIFO that were received before the open got unblocked.
- X
- X The sdevice entry for the AST 4-port card had a wrong
- X I/O address range (`s_fas-mux4'). This didn't affect FAS
- X but is checked by the kernel config program.
- X
- X The gcc (GNU cc) support was removed because gcc's object
- X file wants to link in some "helpful" functions that aren't
- X contained in the kernel. But anyway, FAS is tuned so carefully
- X and depends on the optimization behaviour of the AT&T
- X standard C compiler that gcc won't have any advantages.
- X
- X I changed the method with which the `fas_test_device' function
- X waits for certain events. The `delay' function was used
- X for that purpose but it turned out that with some flavors
- X of UNIX it is prohibited to use this function during the
- X xxinit phase of the boot process. Now a simple timeout loop
- X is used instead.
- X
- X Removed the ADAPT_TIME mechanismn introduced in release 2.05.
- X
- X The open() call now returns an `EBUSY' error number if the
- X device is already open and can't be opened in the desired
- X mode at this time.
- X
- X The handling of the RING signal needed fixing. Unlike the other
- X three modem status lines RING generates an interrupt only at
- X the trailing edge.
- X
- X No SIGHUP signal is sent any more if an ioctl call clears
- X the CLOCAL termio(7) flag while there is no carrier present.
- X SIGHUP is only sent if the actual DCD modem line drops.
- X
- X The files *-mux4 were renamed to *-ast4 because this type of
- X card was originally developed by AST (AST 4-port card).
- X
- X ------------------------------------------------------------
- X
- X release 2.08 Sun Jan 13, 1991
- X
- X New Features:
- X
- X Bell Tech/Intel UNIX 3.2 is supported.
- X
- X SCO Xenix 286 is also supported now. Thanks to Nickolay Saukh
- X (nms@saukh.rd.jvd.su) for providing the patches.
- X
- X The Bell Tech HUB-6 card can be used with FAS. Thanks to
- X Keith Walker (kew@cims2.UUCP) for the patches.
- X
- X For AT&T derived flavors of UNIX there is a line automatically
- X added to the kernel description file that makes the adding
- X and removing of FAS possible via the `kconfig' program. Thanks
- X to John Adams (johna@grumpy.boston.ma.us) for this idea.
- X
- X There is a mechanismn now that prevents excessive modem status
- X interrupts caused by crosstalking between wires or by a loose
- X cable.
- X
- X You can disable the FIFOs in a UART by "oring" the macro
- X `NO_FIFO' to the base port address of this device. This is
- X useful for mouse devices where you need immediate response
- X to the mouse movement.
- X
- X The meaning of the bit mapped part of the minor device
- X numbers has changed. Some rather useless functions were
- X removed in favor of more control over the hardware handshake
- X modes. Even systems where the SCO RTSFLOW/CTSFLOW termio(7)
- X flags are not available can now use half duplex hardware
- X flow control (selected via the minor device number).
- X
- X The assignment of RS232C lines to certain FAS functions
- X is even more flexible now. This allows to connect two
- X UNIX systems (with FAS) via a null modem cable, running
- X a getty at both ends. For more details, read the paragraph
- X about CABLING in the README file.
- X
- X A special handling of the NS16550A input FIFO was introduced.
- X This causes multiple receiver interrupts (on the same IRQ
- X line) to be synchronized so that only one interrupt is
- X necessary to process all receiving ports. This reduces the
- X interrupt handling overhead and therefor results in lower
- X CPU load for concurrent serial input at high speeds.
- X
- X The `fas_event' function processes all scheduled events
- X for all units with one single call. Previously, every unit
- X launched its own timeout() call if there was work to
- X do. This could lead to up to 16 timeouts at the same time,
- X resulting in some timeout handling overhead. This overhead
- X is minimized now.
- X
- X Bug Fixes:
- X
- X There were two bugs that could cause a port to lock up,
- X resulting in an immortal process.
- X
- X Almost any kernel sleep is killable now (at least with one or
- X two `kill -9'). Therefor, there should be no more immortal
- X processes. Even killing a process that is hanging in a
- X close-on-exit call is possible.
- X
- X The meaning of the RTSFLOW/CTSFLOW termio(7) flags was converted
- X to what SCO had in mind (half duplex flow control). This is for
- X compatibility reasons. Full duplex RTS/CTS hardware flow control
- X is still possible via the minor device number method. Thanks to
- X Dmitry V. Volodin (dvv@hq.demos.su) for providing me with the
- X necessary knowledge.
- X
- X If a process is already sleeping in a getty open it will only
- X unblock on DCD low->high. In particular, if in the meantime
- X the device was open for dialout and DCD is still present if
- X the getty open takes over again this won't unblock the getty
- X open any more.
- X
- X And there were, as usual, a number of other small bug fixes.
- END_OF_FILE
- if test 23494 -ne `wc -c <'ecu330/fasi/RELEASENOTES'`; then
- echo shar: \"'ecu330/fasi/RELEASENOTES'\" unpacked with wrong size!
- fi
- # end of 'ecu330/fasi/RELEASENOTES'
- fi
- if test -f 'ecu330/sea/ecusea.c' -a "${1}" != "-c" ; then
- echo shar: Will not clobber existing file \"'ecu330/sea/ecusea.c'\"
- else
- echo shar: Extracting \"'ecu330/sea/ecusea.c'\" \(37903 characters\)
- sed "s/^X//" >'ecu330/sea/ecusea.c' <<'END_OF_FILE'
- Xchar *version = "@(#)ecusea 3.30";
- X
- X/* #define TABLE_CRC16 */
- X
- X/*+-------------------------------------------------------------------------
- X ecusea.c - SEAlink - Sliding window file transfer protocol
- X
- X Defined functions:
- X Nap(msec)
- X arg_token(parsestr,termchars)
- X cancel_transaction(sig)
- X crc_update(c,crc)
- X fname_split(cmd,arg,arg_max_quan,narg_rtn)
- X fname_too_long(fname)
- X fname_truncated()
- X getspeed(atty)
- X lgetc_timeout(tenths)
- X main(argc,argv,envp)
- X rdchk(fd)
- X receive_block(buf)
- X receive_file()
- X send_comm_block(blk,blknum)
- X send_file(name)
- X send_file_block(fp,blknum)
- X set_sf_state(place,new_state)
- X set_utime_1980(filename,secs_since_1980)
- X sf_state_text(state)
- X wait_for_rcvr_response()
- X xmit_ack(blknum)
- X xmit_cancel()
- X xmit_nak(blknum)
- X
- Xecu adaptation by W. Tucker
- Xmodelled after MSDOS sealink.c, which carried the following proviso:
- X
- X MS-DOS Version 1.20, created on 08/05/87
- X at 17:51:40 (C) COPYRIGHT 1986,87 by
- X System Enhancement Associates; ALL RIGHTS
- X RESERVED By: Thom Henderson
- X
- X You are granted a license to use this
- X code in your programs, and to adapt it to
- X your particular situation and needs,
- X subject only to the following conditions:
- X 1) You must refer to it as the SEAlink
- X protocol, and you must give credit to
- X System Enhancement Associates. 2) If you
- X modify it in such a way that your version
- X cannot converse with the original code as
- X supplied by us, then you should refer to
- X it as "SEAlink derived", or as a
- X "variation of SEAlink", or words to that
- X effect. In short, we're not asking for
- X any money, but we'd like to get some
- X credit for our work.
- X
- X--------------------------------------------------------------------------*/
- X/*+:EDITS:*/
- X/*:05-04-1994-04:40-wht@n4hgf-ECU release 3.30 */
- X/*:04-01-1994-20:56-wht@n4hgf-pedantic what-compatible version */
- X/*:04-01-1994-20:46-wht@n4hgf-integrate rdchk here, eliminating srdchk.c */
- X/*:12-23-1992-00:19-wht@n4hgf-fix partially bracketed array in getspeed */
- X/*:09-10-1992-14:00-wht@n4hgf-ECU release 3.20 */
- X/*:08-22-1992-15:39-wht@n4hgf-ECU release 3.20 BETA */
- X/*:08-16-1992-03:08-wht@n4hgf-head off another POSIX plot */
- X/*:08-10-1992-04:01-wht@n4hgf-use init_Nap */
- X/*:07-20-1992-13:30-wht@n4hgf-put hzmsec in AGAIN ?? */
- X/*:07-17-1992-18:28-wht@n4hgf-remove Nap() and use common ../nap.o */
- X/*:05-11-1992-16:43-wht@gyro-fix WORKING_SELECT nap once and for all */
- X/*:05-08-1992-02:42-wht@n4hgf-select-based Nap was buggy */
- X/*:09-01-1991-14:22-wht@n4hgf2-on sun, use termios */
- X/*:08-30-1991-20:09-wht@n4hgf2-sun Nap was not returning a value */
- X/*:08-30-1991-02:34-jdeitch@jadpc.cts.com-fix no hzmsec */
- X/*:07-25-1991-12:59-wht@n4hgf-ECU release 3.10 */
- X/*:03-18-1991-22:49-wht@n4hgf-ISC 2.2 has struct timeval in sys/time.h */
- X/*:08-14-1990-20:40-wht@n4hgf-ecu3.00-flush old edit history */
- X
- X#include <stdio.h>
- X#include <string.h>
- X#include <ctype.h>
- X#include <signal.h>
- X#include <setjmp.h>
- X#include <fcntl.h>
- X#include <errno.h>
- X#include <sys/param.h>
- X#include <memory.h>
- X#include "../ecu_types.h"
- X#include "../ecu_stat.h"
- X#include "../ecu_time.h"
- X#include "../ecutermio.h"
- X
- X#ifdef CFG_SelectNap
- X#ifdef CFG_HasFdSet
- X#define SelBitmask struct fd_set
- X#else
- X#define SelBitmask int
- X#endif /* CFG_HasFdSet */
- X#endif /* CFG_SelectNap */
- X
- X/*
- X * for rdchk() below
- X */
- X#if defined(CFG_FionrdRdchk)
- X#undef ECHO
- X#undef NL0
- X#undef NL1
- X#undef TAB0
- X#undef TAB1
- X#undef TAB2
- X#undef XTABS
- X#undef CR0
- X#undef CR1
- X#undef CR2
- X#undef CR3
- X#undef FF0
- X#undef FF1
- X#undef BS0
- X#undef BS1
- X#undef TOSTOP
- X#undef FLUSHO
- X#undef PENDIN
- X#undef NOFLSH
- X#include <sys/ioctl.h>
- X#if defined (sun) && defined (SVR4)
- X#include <sys/filio.h>
- X#endif
- X#endif /* CFG_FionrdRdchk */
- X
- X/* Various system constants */
- X#define WINDOW 6 /* maximum size of window */
- X#define TIMEOUT 0x0FFF
- X#define OFFSET_1980 (time_t)315547200 /* time offset for 1970 <-> 1980 */
- X
- X/*
- X * The section of code that is compiled when NAKEOT is defined is in the
- X * original MS-DOS version 1.16 routine. Its purpose is to send a NAK when
- X * an EOT is received during receive_file(), apparently to confirm that this is
- X * indeed the end of file. However, in certain (apparently non - standard)
- X * versions of the protocol, it is possible that the program will report an
- X * error when in fact there isn't one. Comment this out at your discretion.
- X */
- X#define NAKEOT
- X
- X/* SEAlink block zero data structure */
- Xtypedef struct blk0
- X{
- X long length; /* length */
- X time_t secs_since_1980; /* creation/last mod in secs since 1/1/80 */
- X char filename[17]; /* file name */
- X char sender[15]; /* sending program */
- X char send_no_acks; /* true if rcvr need not ack */
- X char filler[87]; /* fill to 128 bytes */
- X}
- XBLK0;
- X
- X/* protocol characters */
- X#define SOH 0x01
- X#define EOT 0x04
- X#define ACK 0x06
- X#define NAK 0x15
- X#define CAN 0x18
- X
- X/* send_file state (sf_state) values */
- X#define SFS_GND 0 /* Ground state, ACK or NAK expected */
- X#define SFS_ACK 1 /* ACK received */
- X#define SFS_NAK 2 /* NAK received */
- X#define SFS_ACKW 3 /* ACK, block# received */
- X#define SFS_NAKW 4 /* NAK, block# received */
- X#define SFS_RGND 5 /* Returning to ground state */
- Xint sf_state;
- X
- Xint allow_slide = 1; /* sliding windows allowed */
- Xint crc_in_use; /* check type, 1 = CRC, 0 = checksum */
- Xchar *dfile = "/tmp/ecuSEA.log";
- Xint error_count = 0; /* total number of errors */
- Xint iofd = 0; /* file descriptor to use */
- Xint no_ack_mode = 1; /* true of ACKs not required */
- Xint rf_done = 0; /* receive file done */
- Xint sf_ackw_count; /* count of sliding ACKs seen */
- Xint sf_ackblk; /* number of last block ACKed */
- Xint sf_blknum; /* number of next block to send */
- Xint sf_lastnum; /* number of last block sent */
- Xint sf_nakquan; /* number of sequential NAKs */
- Xint sf_slide; /* true if sliding window */
- Xint sigint = 0; /* dummy for nap.c */
- X
- Xint sending_flag = -1; /* send == 1, receive == 0, bad usage == -1 */
- Xint log_packets = 0;
- Xlong rx_char_count = 0;
- Xlong tx_char_count = 0;
- Xint Filcnt = 0;
- Xint npaths = 0;
- Xchar curr_dir[256];
- Xchar s128[128];
- Xunsigned baud_rate;
- Xint exit_code;
- Xint sent_EOT = 0;
- X
- Xstruct termio tio;
- Xstruct termio tio0;
- X
- Xjmp_buf lgetc_timeout_jmpbuf;
- X
- X/* CRC16 routine; finish CRC calculation for compare */
- X
- X#ifdef TABLE_CRC16
- X
- X/* crctab calculated by Mark G. Mendel,Network Systems Corporation */
- Xunsigned short crctab[256] =
- X{
- X 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7,
- X 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef,
- X 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6,
- X 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de,
- X 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485,
- X 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d,
- X 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4,
- X 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc,
- X 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823,
- X 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b,
- X 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12,
- X 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a,
- X 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41,
- X 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49,
- X 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70,
- X 0xFF9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78,
- X 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f,
- X 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067,
- X 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e,
- X 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256,
- X 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d,
- X 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405,
- X 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c,
- X 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634,
- X 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab,
- X 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3,
- X 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a,
- X 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92,
- X 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9,
- X 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1,
- X 0xef1f, 0xFF3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8,
- X 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0
- X};
- X
- X/*+-------------------------------------------------------------------------
- X updcrc macro derived from article Copyright (C) 1986 Stephen Satchell.
- X NOTE: First argument must be in range 0 to 255.
- X Second argument is referenced twice.
- X Programmers may incorporate any or all code into their programs, giving
- X proper credit within the source. Publication of the source routines is
- X permitted so long as proper credit is given to Stephen Satchell,
- X Satchell Evaluations and Chuck Forsberg, Omen Technology.
- X--------------------------------------------------------------------------*/
- X#define crc_update(ch,crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ ch)
- X
- X#else /* calculated crc */
- X
- X/*+-------------------------------------------------------------------------
- X crc_update(c,crc)
- X--------------------------------------------------------------------------*/
- Xunsigned short
- Xcrc_update(c, crc)
- Xregister c;
- Xregister unsigned crc;
- X{
- X register count;
- X
- X for (count = 8; --count >= 0;)
- X {
- X if (crc & 0x8000)
- X {
- X crc <<= 1;
- X crc += (((c <<= 1) & 0400) != 0);
- X crc ^= 0x1021;
- X }
- X else
- X {
- X crc <<= 1;
- X crc += (((c <<= 1) & 0400) != 0);
- X }
- X }
- X return (crc);
- X} /* end of crc_update */
- X#endif /* crc calc selection */
- X
- X/*+-------------------------------------------------------------------------
- X rdchk(f)
- X--------------------------------------------------------------------------*/
- X#if defined(CFG_FionrdRdchk)
- Xint
- Xrdchk(fd)
- Xint fd;
- X{
- X int waiting = 0;
- X
- X ioctl(fd, FIONREAD, &waiting);
- X return (!!waiting);
- X
- X} /* end of rdchk */
- X#endif /* CFG_FionrdRdchk */
- X
- X/*+-----------------------------------------------------------------------
- X arg_token(parsestr,termchars)
- X
- XGet next token from string parsestr ((char *)0 on 2nd, 3rd, etc.
- Xcalls), where tokens are nonempty strings separated by runs of chars
- Xfrom termchars. Writes nulls into parsestr to end tokens.
- Xtermchars need not remain constant from call to call.
- X
- XTreats multiple occurrences of a termchar as one delimiter (does not
- Xallow null fields).
- X------------------------------------------------------------------------*/
- X#if defined(M_UNIX)
- Xstatic char *arg_token_static = (char *)0;
- Xchar *
- Xarg_token(parsestr, termchars)
- Xchar *parsestr;
- Xchar *termchars;
- X{
- X register char *parseptr;
- X char *token;
- X
- X if (parsestr == (char *)0 && arg_token_static == (char *)0)
- X return ((char *)0);
- X
- X if (parsestr)
- X parseptr = parsestr;
- X else
- X parseptr = arg_token_static;
- X
- X while (*parseptr)
- X {
- X if (!strchr(termchars, *parseptr))
- X break;
- X parseptr++;
- X }
- X
- X if (!*parseptr)
- X {
- X arg_token_static = (char *)0;
- X return ((char *)0);
- X }
- X
- X token = parseptr;
- X if (*token == '\'')
- X {
- X token++;
- X parseptr++;
- X while (*parseptr)
- X {
- X if (*parseptr == '\'')
- X {
- X arg_token_static = parseptr + 1;
- X *parseptr = 0;
- X return (token);
- X }
- X parseptr++;
- X }
- X arg_token_static = (char *)0;
- X return (token);
- X }
- X while (*parseptr)
- X {
- X if (strchr(termchars, *parseptr))
- X {
- X *parseptr = 0;
- X arg_token_static = parseptr + 1;
- X while (*arg_token_static)
- X {
- X if (!strchr(termchars, *arg_token_static))
- X break;
- X arg_token_static++;
- X }
- X return (token);
- X }
- X parseptr++;
- X }
- X arg_token_static = (char *)0;
- X return (token);
- X} /* end of arg_token */
- X#endif
- X
- X/*+-------------------------------------------------------------------------
- X fname_split(cmd,arg,arg_max_quan,&narg)
- X--------------------------------------------------------------------------*/
- X#if defined(M_UNIX)
- Xvoid
- Xfname_split(cmd, arg, arg_max_quan, narg_rtn)
- Xchar *cmd;
- Xchar **arg;
- Xint arg_max_quan;
- Xint *narg_rtn;
- X{
- X register itmp;
- X register narg;
- X
- X for (itmp = 0; itmp < arg_max_quan; itmp++)
- X arg[itmp] = (char *)0;
- X arg[0] = arg_token(cmd, "/");
- X
- X for (narg = 1; narg < arg_max_quan; ++narg)
- X {
- X if ((arg[narg] = arg_token((char *)0, "/")) == (char *)0)
- X break;
- X }
- X
- X *narg_rtn = narg;
- X
- X} /* end of fname_split */
- X#endif
- X
- X#if defined(M_UNIX)
- X#define MAX_COMPONENT_LEN 14
- X#define MAX_PATH_COMPONENTS 16
- Xstatic char trunc_fname[257];
- Xstatic char *trunc_components[MAX_PATH_COMPONENTS];
- Xstatic int trunc_components_quan;
- Xstatic int trunc_absolute_path;
- X
- X#endif
- X
- X/*+-------------------------------------------------------------------------
- X fname_too_long(fname) - check for any pathname component too long
- X--------------------------------------------------------------------------*/
- X#if defined(M_UNIX)
- Xint
- Xfname_too_long(fname)
- Xregister char *fname;
- X{
- X register int itmp;
- X register char **cpptr;
- X
- X if (trunc_absolute_path = (*fname == '/'))
- X fname++;
- X strncpy(trunc_fname, fname, sizeof(trunc_fname) - 1);
- X fname_split(trunc_fname, trunc_components,
- X MAX_PATH_COMPONENTS, &trunc_components_quan);
- X itmp = trunc_components_quan;
- X cpptr = trunc_components;
- X while (itmp--)
- X {
- X if (strlen(*cpptr) > MAX_COMPONENT_LEN)
- X return (1);
- X cpptr++;
- X }
- X return (0);
- X} /* end of fname_too_long */
- X#endif
- X
- X/*+-------------------------------------------------------------------------
- X fname_truncated() - build truncated path last checked by fname_too_long
- X--------------------------------------------------------------------------*/
- X#if defined(M_UNIX)
- Xchar *
- Xfname_truncated()
- X{
- X register int icomp;
- X char new_fname[257];
- X register char *cptr = new_fname;
- X
- X if (trunc_absolute_path)
- X {
- X *cptr = '/';
- X *(cptr + 1) = 0;
- X }
- X else
- X *cptr = 0;
- X for (icomp = 0; icomp < trunc_components_quan; icomp++)
- X {
- X if (strlen(trunc_components[icomp]) > MAX_COMPONENT_LEN)
- X *(trunc_components[icomp] + MAX_COMPONENT_LEN) = 0;
- X strcat(cptr, trunc_components[icomp]);
- X if (icomp < trunc_components_quan - 1)
- X strcat(cptr, "/");
- X }
- X strcpy(trunc_fname, cptr);
- X return (trunc_fname);
- X
- X} /* end of fname_truncated */
- X#endif
- X
- X/*+-------------------------------------------------------------------------
- X xmit_cancel()
- X--------------------------------------------------------------------------*/
- Xvoid
- Xxmit_cancel()
- X{
- X char *cancel_msg = "\030\030\030\030\030\030\030\030\b\b\b\b\b\b\b\b";
- X
- X ecuflush(iofd, TCOFLUSH);
- X write(iofd, cancel_msg, 16);
- X tx_char_count += 16;
- X report_str("CANCELling transfer", 1);
- X report_last_txhdr("CAN", 0);
- X
- X} /* end of xmit_cancel */
- X
- X/*+-------------------------------------------------------------------------
- X xmit_ack(blknum)
- X--------------------------------------------------------------------------*/
- Xvoid
- Xxmit_ack(blknum)
- Xregister int blknum; /* block number */
- X{
- X char s16[16];
- X
- X sprintf(s16, "ACK %3d", blknum);
- X report_last_txhdr(s16, 0);
- X
- X s16[0] = ACK;
- X s16[1] = blknum; /* block number */
- X s16[2] = blknum ^ 0xFF; /* block number check */
- X write(iofd, s16, 3);
- X tx_char_count += 3;
- X} /* end of xmit_ack */
- X
- X/*+-------------------------------------------------------------------------
- X xmit_nak(blknum)
- X--------------------------------------------------------------------------*/
- Xvoid
- Xxmit_nak(blknum)
- Xregister int blknum; /* block number */
- X{
- X char s16[16];
- X
- X sprintf(s16, "NAK %d", blknum);
- X report_last_txhdr(s16, 1);
- X
- X if (crc_in_use)
- X s16[0] = 'C';
- X else
- X s16[0] = NAK;
- X
- X s16[1] = blknum; /* block number */
- X s16[2] = blknum ^ 0xFF; /* block number check */
- X write(iofd, s16, 3);
- X tx_char_count += 3;
- X
- X} /* end of xmit_nak */
- X
- X/*+-------------------------------------------------------------------------
- X lgetc_timeout(tenths)
- X
- X reads one character from line unless timeout in tenths passes
- X with no receipt.
- X--------------------------------------------------------------------------*/
- Xunsigned int
- Xlgetc_timeout(tenths)
- Xint tenths;
- X{
- X unsigned char rdchar;
- X
- X if (tenths < 0) /* prevent sadness */
- X tenths = 0;
- X
- X if (!tenths)
- X {
- X if (!rdchk(iofd))
- X return (TIMEOUT);
- X else
- X {
- X read(iofd, &rdchar, 1);
- X rx_char_count++;
- X return ((unsigned int)rdchar);
- X }
- X }
- X
- X if (tenths < 6)
- X tenths = 6;
- X
- X#if defined(CFG_SelectNap)
- X
- X {
- X struct timeval tval;
- X
- X#ifdef CFG_HasFdSet
- X struct fd_set fdset;
- X
- X FD_ZERO(&fdset);
- X FD_SET(iofd, &fdset);
- X#else
- X int fdmask;
- X
- X fdmask = 1 << iofd;
- X#endif
- X
- X tval.tv_sec = tenths / 10L;
- X tval.tv_usec = (tenths % 10L) * 100000L;
- X if ((select(iofd + 1,
- X#ifdef CFG_HasFdSet
- X &fdset,
- X#else
- X &fdmask,
- X#endif
- X (SelBitmask *) 0, (SelBitmask *) 0, &tval) < 0) ||
- X (!rdchk(iofd)) || (read(iofd, &rdchar, 1) < 0))
- X {
- X report_last_rxhdr("TIMEOUT", 0);
- X return (TIMEOUT);
- X }
- X rx_char_count++;
- X return ((unsigned int)rdchar);
- X }
- X
- X#else
- X
- X {
- X int seconds;
- X unsigned long msec = tenths * 100;
- X unsigned long interval = msec / 10;
- X long Nap();
- X
- X if (interval < 20)
- X interval = 20;
- X else if (interval > 1000)
- X interval = 1000;
- X
- X while (msec)
- X {
- X msec -= Nap(20L);
- X if (rdchk(iofd))
- X {
- X read(iofd, &rdchar, 1);
- X rx_char_count++;
- X return ((unsigned int)rdchar);
- X }
- X }
- X report_last_rxhdr("TIMEOUT", 0);
- X return (TIMEOUT);
- X }
- X
- X#endif
- X
- X /*
- X * for safety, though should get unreachable code warning
- X */
- X _exit(TIMEOUT); /* should get unreachable code warning */
- X
- X} /* end of lgetc_timeout */
- X
- X/*+-------------------------------------------------------------------------
- X sf_state_text(state)
- X--------------------------------------------------------------------------*/
- Xchar *
- Xsf_state_text(state)
- Xregister state;
- X{
- X char unrecog[16];
- X
- X switch (state)
- X {
- X case SFS_GND:
- X return ("GND");
- X case SFS_ACK:
- X return ("ACK");
- X case SFS_NAK:
- X return ("NAK");
- X case SFS_ACKW:
- X return ("ACKW");
- X case SFS_NAKW:
- X return ("NAKW");
- X case SFS_RGND:
- X return ("RGND");
- X default:
- X sprintf(unrecog, "SFS_%d", state);
- X return (unrecog);
- X }
- X
- X} /* end of sf_state_text */
- X
- X/*+-------------------------------------------------------------------------
- X set_sf_state(place,new_state)
- X--------------------------------------------------------------------------*/
- Xvoid
- Xset_sf_state(place, new_state)
- Xint place;
- Xint new_state;
- X{
- X if (log_packets)
- X {
- X sprintf(s128, "state from %s to %s (%d)",
- X sf_state_text(sf_state), sf_state_text(new_state), place);
- X report_str(s128, 0);
- X }
- X sf_state = new_state;
- X} /* end of set_sf_state */
- X
- X/*+-------------------------------------------------------------------------
- X wait_for_rcvr_response() - check for ACK or NAK
- X sets 'sf_state' to SFS_... value depending on response from file rcvr
- X returns 1 if TIMEOUT at state other than ground, else 0
- X--------------------------------------------------------------------------*/
- Xint
- Xwait_for_rcvr_response()
- X{
- X int c; /* one byte of data */
- X static int rawblk = 0; /* raw block number */
- X
- X while ((c = lgetc_timeout((sf_state == SFS_GND) ? 0 : 6)) != TIMEOUT)
- X {
- X if (c == CAN)
- X { /* CANcel received? */
- X if ((c = lgetc_timeout(20)) == CAN)
- X {
- X sf_nakquan = 11;
- X report_last_rxhdr("CAN", 0); /* error counted at cancel
- X * time */
- X }
- X break;
- X }
- X if (sf_state == SFS_ACKW || sf_state == SFS_NAKW) /* windowed */
- X {
- X sf_slide = 0; /* assume this will fail */
- X /* see if we believe the number */
- X if (rawblk == (c ^ 0xFF))
- X {
- X rawblk = sf_blknum - ((sf_blknum - rawblk) & 0xFF);
- X if ((rawblk >= 0) && (rawblk <= sf_blknum) &&
- X (rawblk > (sf_blknum - 128)))
- X { /* we have sliding window! */
- X if (sf_state == SFS_ACKW)
- X {
- X sf_ackblk = (sf_ackblk > rawblk) ? sf_ackblk : rawblk;
- X sf_slide = 1;
- X if (no_ack_mode && (++sf_ackw_count > 10))
- X {
- X no_ack_mode = 0;
- X report_str("Overdrive disengaged", 0);
- X }
- X }
- X else
- X {
- X sf_blknum = (rawblk < 0) ? 0 : rawblk;
- X sf_slide = (sf_nakquan < 4);
- X }
- X sprintf(s128, "%s %5d",
- X (sf_state == SFS_ACKW) ? "ACKW" : "NAKW", rawblk);
- X report_last_rxhdr(s128, (sf_state != SFS_ACKW) && rawblk);
- X }
- X }
- X set_sf_state(1, SFS_RGND); /* return to ground state */
- X }
- X
- X if (sf_state == SFS_ACK || sf_state == SFS_NAK)
- X {
- X rawblk = c;
- X if (sf_state == SFS_ACK)
- X set_sf_state(2, SFS_ACKW);
- X else
- X set_sf_state(3, SFS_NAKW);
- X }
- X
- X if (!sf_slide || sf_state == SFS_GND)
- X {
- X if (c == ACK)
- X {
- X if (!sf_slide)
- X {
- X sprintf(s128, "ACK %3d", sf_ackblk);
- X report_last_rxhdr(s128, 0);
- X sf_ackblk++;
- X }
- X set_sf_state(4, SFS_ACK);
- X sf_nakquan = 0;
- X }
- X else if (c == 'C' || c == NAK)
- X {
- X /* if method not determined yet */
- X if (crc_in_use > 1) /* then do what rcvr wants */
- X {
- X crc_in_use = (c == 'C');
- X report_protocol_crc_type(crc_in_use ? "/CRC16" : "/CHK");
- X }
- X ecuflush(iofd, TCOFLUSH);
- X if (!sf_slide)
- X {
- X sf_blknum = sf_ackblk + 1;
- X sprintf(s128, "NAK %3d", sf_blknum);
- X report_last_rxhdr(s128, (!!sf_blknum));
- X }
- X set_sf_state(5, SFS_NAK);
- X sf_nakquan++;
- X if (sf_lastnum)
- X error_count++;
- X }
- X }
- X
- X if (sf_state == SFS_RGND)
- X set_sf_state(6, SFS_GND);
- X }
- X return ((sf_state != SFS_GND) && (c == TIMEOUT));
- X} /* end of wait_for_rcvr_response */
- X
- X/*+-------------------------------------------------------------------------
- X send_comm_block(blk,blknum) - format and transmit block
- X--------------------------------------------------------------------------*/
- Xint
- Xsend_comm_block(blk, blknum)
- Xchar *blk; /* data to be shipped */
- Xint blknum; /* number of block */
- X{
- X register unsigned short rUINT16 = 0;
- X register int itmp;
- X unsigned char chksum;
- X char *cptr = blk;
- X char s3[3];
- X
- X s3[0] = SOH; /* block header */
- X s3[1] = blknum; /* block number */
- X s3[2] = blknum ^ 0xFF; /* block number check value */
- X
- X/* calculate the crc or checksum */
- X itmp = 128;
- X if (crc_in_use)
- X {
- X while (itmp--)
- X {
- X rUINT16 = crc_update(*cptr, rUINT16);
- X cptr++;
- X }
- X rUINT16 = crc_update(0, rUINT16);
- X rUINT16 = crc_update(0, rUINT16);
- X }
- X else
- X {
- X while (itmp--)
- X rUINT16 += *cptr++;
- X }
- X
- X/* write the block */
- X
- X write(iofd, s3, 3); /* the header */
- X write(iofd, blk, 128); /* the block */
- X if (crc_in_use) /* the crc or checksum */
- X {
- X s3[0] = rUINT16 >> 8;
- X s3[1] = rUINT16 & 0xFF;
- X write(iofd, s3, 2);
- X tx_char_count += 133;
- X }
- X else
- X {
- X chksum = rUINT16;
- X write(iofd, &chksum, 1);
- X tx_char_count += 132;
- X }
- X
- X return (1);
- X} /* end of send_comm_block */
- X
- X/*+-------------------------------------------------------------------------
- X send_file_block(fp,blknum) - read a block from file and send it
- X--------------------------------------------------------------------------*/
- Xvoid
- Xsend_file_block(fp, blknum)
- XFILE *fp;
- Xint blknum;
- X{
- X long fileaddr;
- X char buf[128];
- X
- X fileaddr = (long)(blknum - 1) * 128L;
- X if (blknum != sf_lastnum + 1)
- X fseek(fp, fileaddr, 0); /* move where to */
- X sf_lastnum = blknum;
- X report_txpos(fileaddr);
- X
- X memset(buf, 0x1A, sizeof(buf)); /* fill buffer with control Zs */
- X fread(buf, 1, sizeof(buf), fp); /* read in some data */
- X send_comm_block(buf, blknum); /* pump it out to the receiver */
- X} /* end of send_file_block */
- X
- X/*+-------------------------------------------------------------------------
- X send_file(name) - transmit a file
- X--------------------------------------------------------------------------*/
- Xint
- Xsend_file(name)
- Xchar *name;
- X{
- X register int endblk; /* block number of EOT */
- X FILE *fp = (FILE *) 0; /* file to send */
- X struct stat fst;
- X BLK0 blk0;
- X char *basename; /* base filename */
- X char eot = EOT;
- X
- X Filcnt++;
- X if (name && *name) /* if sending a file */
- X {
- X if ((fp = fopen(name, "r")) == NULL)
- X {
- X sprintf(s128, "Cannot open %s", name);
- X report_str(s128, 1);
- X exit_code = 253;
- X return (0);
- X }
- X
- X memset((char *)&blk0, 0, sizeof(blk0)); /* clear out data block */
- X
- X stat(name, &fst); /* get file statistics */
- X blk0.length = (long)fst.st_size;
- X
- X /* cnvt time from 1970 base to 1980 */
- X if ((blk0.secs_since_1980 = fst.st_mtime - OFFSET_1980) < 0L)
- X blk0.secs_since_1980 = 0;
- X
- X if ((basename = strrchr(name, '/')) == NULL) /* find basename */
- X strcpy(blk0.filename, name);
- X else
- X {
- X basename++;
- X strcpy(blk0.filename, basename);
- X }
- X
- X strcat(blk0.sender, version + 4);
- X blk0.send_no_acks = no_ack_mode;
- X
- X endblk = (int)((blk0.length + 127L) / 128L) + 1;
- X report_file_send_open(name, &fst);
- X }
- X else
- X {
- X endblk = 0; /* fake for no file */
- X report_str("sending EOT indication", -1);
- X report_txpos(blk0.length);
- X }
- X
- X sf_blknum = 1; /* set starting state */
- X sf_ackblk = -1;
- X sf_state = SFS_GND;
- X sf_lastnum = 0;
- X sf_slide = 0;
- X sf_nakquan = 0;
- X error_count = 0;
- X sf_ackw_count = 0;
- X crc_in_use = 2; /* undetermined */
- X
- X while (sf_ackblk < endblk) /* while not all there yet */
- X {
- X sent_EOT = 0;
- X if (sf_blknum <= sf_ackblk + ((sf_slide && allow_slide) ? WINDOW : 1))
- X {
- X if (sf_blknum < endblk)
- X {
- X if (sf_blknum > 0)
- X {
- X sprintf(s128, "sending block %d", sf_blknum);
- X report_last_txhdr(s128, 0);
- X send_file_block(fp, sf_blknum);
- X }
- X else
- X {
- X sprintf(s128, "sending filename", sf_blknum);
- X report_last_txhdr(s128, 0);
- X send_comm_block((char *)&blk0, 0);
- X report_txpos(0L);
- X }
- X if (no_ack_mode && sf_slide && allow_slide)
- X sf_ackblk = sf_blknum;
- X }
- X else if (sf_blknum == endblk)
- X {
- X report_last_txhdr("EOT", 0);
- X write(iofd, &eot, 1);
- X sent_EOT = 1;
- X Nap(500L);
- X tx_char_count++;
- X }
- X sf_blknum++;
- X }
- X
- X if (wait_for_rcvr_response() && sent_EOT)
- X {
- X report_str("Receiver did not ACK our EOT", -1);
- X break;
- X }
- X
- X if (sf_nakquan > 10)
- X goto CANCEL_TRANSFER;
- X }
- X
- X if (endblk) /* if sending file, not EOT */
- X fclose(fp);
- X return (1); /* exit with good status */
- X
- X CANCEL_TRANSFER:
- X if (endblk) /* if sending file, not EOT */
- X fclose(fp);
- X xmit_cancel();
- X return (0); /* exit with bad status */
- X} /* end of send_file */
- X
- X/*+-------------------------------------------------------------------------
- X set_utime_1980(filename,secs_since_1980)
- X--------------------------------------------------------------------------*/
- Xvoid
- Xset_utime_1980(filename, secs_since_1980)
- Xchar *filename; /* file to set stamp on */
- Xlong secs_since_1980;
- X{
- X time_t times[2];
- X time_t time();
- X
- X times[0] = time((long *)0); /* accessed */
- X times[1] = secs_since_1980 + OFFSET_1980; /* modified (convert time) */
- X utime(filename, times);
- X} /* end of set_utime_1980 */
- X
- X/*+-------------------------------------------------------------------------
- X receive_block(buf) - get block from line
- Xreturn 0 if good chk/CRC, 1 if bad
- X--------------------------------------------------------------------------*/
- Xint
- Xreceive_block(buf)
- Xchar *buf; /* data buffer */
- X{
- X register unsigned int rdchar;
- X register unsigned short rUINT16 = 0; /* calculated CRC or check
- X * value */
- X int itmp;
- X int timeout = no_ack_mode ? 200 : 5; /* short block timeout */
- X unsigned short rcvd_crc; /* received CRC or check value */
- X
- X itmp = 128;
- X while (itmp--)
- X {
- X if ((rdchar = lgetc_timeout(timeout)) == TIMEOUT)
- X return (1);
- X if (crc_in_use)
- X rUINT16 = crc_update(rdchar, rUINT16);
- X else
- X rUINT16 += rdchar;
- X *buf++ = rdchar;
- X }
- X
- X if (crc_in_use)
- X {
- X rUINT16 = crc_update(0, rUINT16);
- X rUINT16 = crc_update(0, rUINT16);
- X rdchar = lgetc_timeout(timeout);
- X rcvd_crc = (rdchar << 8) | lgetc_timeout(timeout);
- X }
- X else
- X {
- X rUINT16 &= 0xFF;
- X rcvd_crc = lgetc_timeout(timeout) & 0xFF;
- X }
- X
- X if (rUINT16 != rcvd_crc)
- X {
- X sprintf(s128, "bad %s calc=%04x rcvd=%04x",
- X crc_in_use ? "CRC" : "checksum", rcvd_crc, rUINT16);
- X report_str(s128, -1);
- X }
- X return (rUINT16 != rcvd_crc);
- X} /* end of receive_block */
- X
- X/*+-------------------------------------------------------------------------
- X receive_file()
- X--------------------------------------------------------------------------*/
- Xchar *
- Xreceive_file()
- X{
- X int rdchar; /* received character */
- X int tries; /* retry counter */
- X int blknum; /* desired block number */
- X int inblk; /* this block number */
- X FILE *fp;
- X char buf[128]; /* data buffer */
- X char tmpname[100]; /* name of temporary file */
- X static char outname[100];/* name of final file */
- X BLK0 blk0; /* file header data storage */
- X int endblk; /* block number of EOT, if known */
- X long left = 0; /* bytes left to output */
- X int itmp; /* index */
- X int cnvrt; /* flag -- convert filename? */
- X char *onp; /* use to convert filename to l / rdchar */
- X long ftell();
- X
- X *outname = '\0'; /* get name from transmitter */
- X cnvrt = 1; /* convert to local is necessary */
- X sprintf(tmpname, "./SEA%05d.tmp", getpid()); /* use a unique temp
- X * filename */
- X
- X if (!(fp = fopen(tmpname, "w")))
- X { /* open temporary file */
- X sprintf(s128, "Cannot create temp file %s\n", tmpname);
- X report_str(s128, 0);
- X xmit_cancel();
- X return (NULL);
- X }
- X
- X blknum = 0;
- X tries = -10; /* kludge for first time around */
- X crc_in_use = 1; /* try for CRC error checking */
- X error_count = 0; /* no errors yet */
- X endblk = 0; /* we don't know the size yet */
- X no_ack_mode = 0; /* we don't know about this yet */
- X memset((char *)&blk0, 0, sizeof(blk0)); /* or much of anything else */
- X report_protocol_crc_type("/CRC16");
- X
- X SEND_NAK: /* we got a bad block */
- X if (blknum > 1)
- X {
- X error_count++;
- X report_str("bad block", 1);
- X }
- X if (++tries > 10)
- X goto CANCEL_TRANSFER;
- X if (tries == 0) /* if CRC isn't going */
- X {
- X crc_in_use = 0; /* then give checksum a try */
- X report_protocol_crc_type("/CHK");
- X }
- X
- X xmit_nak(blknum); /* send the NAK */
- X if (no_ack_mode && error_count > 20)
- X { /* if no_ack_mode mode isn't working */
- X no_ack_mode = 0; /* then shut it off */
- X report_str("Overdrive disengaged", 0);
- X }
- X
- X RECEIVE_NEXT_BLOCK: /* start of "get a block" */
- X report_rxpos(ftell(fp));
- X while ((rdchar = lgetc_timeout(30)) != TIMEOUT)
- X {
- X if (rdchar == CAN)
- X {
- X if ((rdchar = lgetc_timeout(30)) == CAN)
- X {
- X xmit_cancel();
- X return (NULL);
- X }
- X break;
- X }
- X if (rdchar == EOT)
- X {
- X if (!endblk || endblk == blknum)
- X goto RECEIVE_EOT_SEEN;
- X }
- X else if (rdchar == SOH)
- X {
- X if ((inblk = lgetc_timeout(5)) == TIMEOUT)
- X goto SEND_NAK;
- X if (lgetc_timeout(5) == (inblk ^ 0xFF))
- X {
- X sprintf(s128, "receiving %d", inblk);
- X report_last_rxhdr(s128, 0);
- X goto GOT_START_OF_BLOCK; /* we found a start */
- X }
- X }
- X }
- X goto SEND_NAK;
- X
- X GOT_START_OF_BLOCK: /* start of block detected */
- X rdchar = blknum & 0xFF;
- X if (inblk == 0 && blknum <= 1)
- X { /* if this is the header */
- X if (receive_block((char *)&blk0))
- X goto SEND_NAK; /* bad header block */
- X else
- X {
- X xmit_ack(inblk); /* ack the header */
- X
- X#if defined(M_UNIX)
- X if (fname_too_long(blk0.filename))
- X {
- X strcpy(s128, "truncated: ");
- X strncat(s128, blk0.filename, sizeof(s128) - 12);
- X report_str(s128, -1);
- X strcpy(outname, fname_truncated());
- X }
- X else
- X#endif
- X strcpy(outname, blk0.filename);
- X report_file_rcv_started(outname, blk0.length,
- X blk0.secs_since_1980 + OFFSET_1980);
- X if (left = blk0.length) /* length to transfer */
- X endblk = (int)((left + 127L) / 128L) + 1;
- X if (no_ack_mode != blk0.send_no_acks)
- X {
- X sprintf(s128, "Overdrive %sengaged",
- X (blk0.send_no_acks) ? "" : "dis");
- X report_str(s128, 0);
- X }
- X no_ack_mode = blk0.send_no_acks;
- X blknum = 1; /* now we want first data block */
- X goto RECEIVE_NEXT_BLOCK;
- X }
- X }
- X
- X if (inblk == rdchar)
- X { /* if this is the one we want */
- X if (!receive_block(buf))
- X { /* else if we get it okay */
- X if (!no_ack_mode)/* if we're sending ACKs */
- X xmit_ack(inblk); /* then ACK the data */
- X for (itmp = 0; itmp < 128; itmp++)
- X {
- X if (endblk)
- X { /* limit file size if known */
- X if (!left)
- X break;
- X left--;
- X }
- X if (fputc(buf[itmp], fp) == EOF)
- X {
- X report_str("FILE WRITE ERROR", 0);
- X goto CANCEL_TRANSFER;
- X }
- X }
- X tries = 0; /* reset try count */
- X blknum++; /* we want the next block */
- X goto RECEIVE_NEXT_BLOCK;
- X }
- X goto SEND_NAK; /* ask for a resend */
- X }
- X
- X if (inblk < rdchar || inblk > rdchar + 100)
- X { /* if resending what we have */
- X receive_block(buf); /* ignore it */
- X xmit_ack(inblk); /* but ack it */
- X }
- X goto RECEIVE_NEXT_BLOCK; /* else if running ahead */
- X
- X RECEIVE_EOT_SEEN:
- X#ifdef NAKEOT
- X xmit_nak(blknum); /* NAK the EOT, make sure */
- X if (lgetc_timeout(20) != EOT) /* we're all done */
- X goto SEND_NAK;
- X#endif /* NAKEOT */
- X xmit_ack(blknum); /* ACK it and clean up */
- X report_last_rxhdr("EOT", 0);
- X if (blknum > 1)
- X { /* if we really got anything */
- X fclose(fp);
- X unlink(outname); /* rename temp to proper name */
- X for (onp = outname; cnvrt && *onp; onp++)
- X /* find out if there's lower- */
- X if (islower(*onp)) /* case letters filename */
- X cnvrt = 0; /* there are, don't convert */
- X if (cnvrt) /* if there aren't, make all */
- X for (onp = outname; *onp; onp++) /* into uppercase */
- X *onp = tolower(*onp);
- X if (link(tmpname, outname) == 0)
- X unlink(tmpname);
- X if (blk0.secs_since_1980) /* set stamp, if known */
- X set_utime_1980(outname, blk0.secs_since_1980);
- X return (outname);
- X }
- X else
- X { /* else no real file */
- X fclose(fp);
- X unlink(tmpname); /* discard empty file */
- X report_str("end of transfer", 0);
- X rf_done = 1;
- X return (NULL);
- X }
- X
- X CANCEL_TRANSFER:
- X fclose(fp);
- X xmit_cancel();
- X rf_done = 2;
- X return (NULL);
- X} /* end of receive_file */
- X
- X/*+-------------------------------------------------------------------------
- X cancel_transaction(sig)
- X--------------------------------------------------------------------------*/
- XSIGTYPE
- Xcancel_transaction(sig)
- Xint sig;
- X{
- X xmit_cancel();
- X sprintf(s128, "signal %d ... exiting", sig);
- X report_str(s128, 1);
- X/*
- X report_rx_ind(0);
- X report_tx_ind(0);
- X*/
- X report_uninit();
- X if (sig == SIGQUIT)
- X abort();
- X exit(128 + sig);
- X} /* end of cancel_transaction */
- X
- X/*+-------------------------------------------------------------------------
- X getspeed(code)
- X--------------------------------------------------------------------------*/
- Xstruct B_to_baud
- X{
- X unsigned baud;
- X int B_code;
- X};
- Xunsigned
- Xgetspeed(atty)
- Xstruct termio *atty;
- X{
- X register itmp;
- X int code = ecugetspeed(atty);
- X static struct B_to_baud speeds[] =
- X {
- X {50, B50},
- X {75, B75},
- X {110, B110},
- X {300, B300},
- X {600, B600},
- X {1200, B1200},
- X {2400, B2400},
- X {4800, B4800},
- X {9600, B9600},
- X {19200, EXTA},
- X {38400, EXTB},
- X {0, 0}
- X };
- X
- X for (itmp = 0; speeds[itmp].baud; itmp++)
- X if (speeds[itmp].B_code == code)
- X return (speeds[itmp].baud);
- X return (38400); /* Assume fifo if ioctl failed */
- X} /* end of getspeed */
- X
- X/*+-------------------------------------------------------------------------
- X main(argc,argv,envp)
- X--------------------------------------------------------------------------*/
- Xmain(argc, argv, envp)
- Xint argc;
- Xchar **argv;
- Xchar **envp;
- X{
- X int ipaths;
- X int ok = 0;
- X
- X#define MAX_PATHS 512
- X char *paths[MAX_PATHS];
- X char **ppaths = paths;
- X char *cptr;
- X char **gargv = argv;
- X int gargc = argc;
- X
- X exit_code = 254;
- X while (--argc)
- X {
- X cptr = *++argv;
- X if (*cptr == '-')
- X {
- X cptr++;
- X switch (*cptr++)
- X {
- X case ',':
- X log_packets = 1;
- X break;
- X case '/':
- X if (--argc < 1)
- X exit(255);
- X strcpy(curr_dir, *++argv);
- X break;
- X case '.':
- X if (--argc < 1)
- X exit(255);
- X iofd = atoi(*++argv);
- X break;
- X case 'r':
- X sending_flag = 0;
- X break;
- X case 's':
- X sending_flag = 1;
- X }
- X }
- X else if (argc > 0)
- X {
- X if (npaths < MAX_PATHS)
- X {
- X *ppaths++ = cptr;
- X npaths++;
- X }
- X else
- X {
- X printf("too many filenames to send\n");
- X exit(255);
- X }
- X }
- X }
- X
- X if (sending_flag == -1)
- X {
- X printf("no -r or -s\n");
- X exit(255);
- X }
- X
- X if ((npaths < 1) && sending_flag)
- X exit(253);
- X
- X if (npaths && !sending_flag)
- X exit(255);
- X
- X if (log_packets)
- X {
- X char log_packets_name[64];
- X FILE *ftmp;
- X int iargv;
- X
- X sprintf(log_packets_name, "/tmp/sea%05d.plog", getpid());
- X unlink(log_packets_name);
- X ftmp = fopen(log_packets_name, "w");
- X fclose(ftmp);
- X log_packets = open(log_packets_name, O_WRONLY, 0644);
- X if (log_packets < 0)
- X log_packets = 0;
- X else
- X {
- X write(log_packets, "exec: ", 6);
- X for (iargv = 0; iargv < gargc; iargv++)
- X {
- X write(log_packets, gargv[iargv], strlen(gargv[iargv]));
- X write(log_packets, " ", 1);
- X }
- X write(log_packets, "\n", 1);
- X }
- X }
- X
- X report_init(version + 4);
- X report_top_line("System Enhancement Associates");
- X signal(SIGHUP, cancel_transaction);
- X signal(SIGQUIT, cancel_transaction);
- X signal(SIGINT, cancel_transaction);
- X signal(SIGTERM, cancel_transaction);
- X#if defined(SIGSTOP)
- X
- X /*
- X * call Roto-Rooter on POSIX plots
- X */
- X signal(SIGSTOP, SIG_IGN);
- X signal(SIGTSTP, SIG_IGN);
- X signal(SIGCONT, SIG_IGN);
- X signal(SIGTTIN, SIG_IGN);
- X signal(SIGTTOU, SIG_IGN);
- X#endif
- X
- X ecugetattr(iofd, &tio0);
- X tio = tio0;
- X
- X tio.c_oflag = 0;
- X tio.c_cflag &= ~PARENB;
- X tio.c_cflag &= ~CSIZE;
- X tio.c_cflag |= CS8;
- X
- X /*
- X * learn tick rate for various timers
- X */
- X init_Nap();
- X
- X baud_rate = getspeed(&tio);
- X ecusetattr(iofd, TCSETA, &tio);
- X report_line(baud_rate, "RAW");
- X
- X switch (sending_flag)
- X {
- X case 0: /* receive files */
- X while (receive_file() != NULL)
- X Nap(1000L);
- X ok = (rf_done == 1);
- X break;
- X
- X case 1: /* send files */
- X ipaths = 0;
- X while (ipaths < npaths)
- X {
- X if (!(ok = send_file(paths[ipaths])))
- X break;
- X Nap(1000L);
- X ipaths++;
- X }
- X if (ok) /* no errors, send end marker */
- X send_file("");
- X report_str("end of transfer", 0);
- X break;
- X }
- X
- X ecusetattr(iofd, TCSETA, &tio0);
- X report_line(baud_rate, "NORMAL");
- X report_uninit();
- X exit(ok ? 0 : exit_code);/* and return error status */
- X
- X} /* end of main */
- END_OF_FILE
- if test 37903 -ne `wc -c <'ecu330/sea/ecusea.c'`; then
- echo shar: \"'ecu330/sea/ecusea.c'\" unpacked with wrong size!
- fi
- # end of 'ecu330/sea/ecusea.c'
- fi
- echo shar: End of archive 13 \(of 37\).
- cp /dev/null ark13isdone
- MISSING=""
- for I in 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 ; do
- if test ! -f ark${I}isdone ; then
- MISSING="${MISSING} ${I}"
- fi
- done
- if test "${MISSING}" = "" ; then
- echo You have unpacked all 37 archives.
- rm -f ark[1-9]isdone ark[1-9][0-9]isdone
- else
- echo You still must unpack the following archives:
- echo " " ${MISSING}
- fi
- exit 0
- exit 0 # Just in case...
-