|
|
1.1 root 1: # This is a shell archive.
2: # Remove everything above and including the cut line.
3: # Then run the rest of the file through sh.
4: -----cut here-----cut here-----cut here-----cut here-----
5: #!/bin/sh
6: # shar: Shell Archiver
7: # Run the following text with /bin/sh to create:
8: # rb.1
9: # rb.c
10: # rbsb.c
11: # sb.1
12: # sb.c
13: # undos.1
14: # undos.c
15: # This archive created: Fri Jan 10 12:33:41 1986
16: cat << \SHAR_EOF > rb.1
17: '\" Revision Level
18: '\" Last Delta 12-16-85
19: .TH RB 1 OMEN
20: .SH NAME
21: rb \- YMODEM batch file receive
22: .SH SYNOPSIS
23: .B rb
24: [
25: .B \-bquv
26: ]
27: .PP
28: .B rb
29: [
30: .B \-bcquv
31: ]
32: .B file
33: .PP
34: .B [-][v]rbCOMMAND
35: .SH DESCRIPTION
36: .B Rb
37: receives 0 or more files in batch mode.
38: Iff
39: .B file
40: is speficied,
41: a single file is received in XMODEM single file mode.
42:
43: Normally, the file contents are converted to
44: .SM Unix
45: conventions by stripping carriage returns and all characters
46: beginning with Control Z (CP/M end of file).
47: If the raw pathname ends in
48: ".A",
49: ".ARC",
50: ".CCC",
51: ".CL",
52: ".CMD",
53: ".COM",
54: ".CRL",
55: ".DAT",
56: ".DIR",
57: ".EXE",
58: ".O",
59: ".OBJ",
60: ".OVL",
61: ".PAG",
62: ".REL",
63: ".SAV",
64: ".SUB",
65: ".SWP",
66: ".SYS",
67: ".TAR",
68: ".UTL",
69: ".a",
70: ".o",
71: ".tar",
72: or if the first sector contains
73: data that suggest a binary file
74: (parity bits or characters in the range 000 to 006 before the first ^Z),
75: or if the file mode is transmitted and the 0100000 bit is set,
76: that file will be received in binary mode anyway.
77:
78: Otherwise,
79: if the raw pathname ends in .MSG, or .TXT, any existing file will
80: be appended to rather than replaced.
81:
82: Normally, each file name is converted to lower case
83: unless it contains one or more lower case letters.
84:
85: Rb works with either standard 128 byte sectors or
86: 1024 byte sectors
87: (YAM
88: .B k
89: option).
90: The user should determine experimentally
91: the conditions under which use of 1k blocks
92: actually improves throughput without causing
93: problems.
94:
95: If extended file information (file length, etc.)
96: is received,
97: the file length controls the number of bytes written to
98: the output dataset,
99: and the modify time and file mode
100: (iff non zero)
101: are set accordingly.
102:
103: If no extended file information is received,
104: slashes in the pathname are changed to underscore,
105: and any trailing period in the pathname is eliminated.
106:
107: If rb is invoked with stdout and stderr to different datasets,
108: Verbose is set to 2, causing frame by frame progress reports
109: to stderr.
110: This may be disabled with the
111: .B q
112: option.
113:
114: If the SHELL environment variable includes
115: .I "rsh"
116: or
117: .I "rksh"
118: (restricted shell),
119: rb will not accept pathnames containing referenced to absolute paths
120: or to a parent directory, will not receive to an existing file, and
121: removes any files received in error.
122:
123: .PP
124: The meanings of the available options are:
125: .PP
126: .PD 0
127: .TP
128: .B b
129: transfer all files in binary
130: (tell it like it is)
131: mode.
132: This option disables any append mode special processing.
133: .TP
134: .B c
135: Request 16 bit cyclic redundancy check
136: (8 bit checksum default).
137: .TP
138: .B q
139: Quiet suppresses verbosity.
140: .TP
141: .B v
142: .IR Verbose
143: causes a list of file
144: names to be appended to
145: /tmp/rblog .
146: More v's generate more output.
147: .TP
148: .B u
149: Retain upper case letters in file names unconditionally.
150: .PD
151: .SH EXAMPLES
152: (
153: .SM Unix
154: command)
155: .RS
156: $rb
157: .br
158: rb: ready C
159: .br
160: .RE
161: (Pro-YAM command)
162: .RS
163: <F1>
164: .br
165: >>>c: sbt *.h *.c
166: .br
167: .RE
168: .SH SEE ALSO
169: YMODEM.DOC,
170: IMP(CP/M),
171: ncu(1),
172: Professional-YAM manual,
173: sb(omen),
174: usq(omen),
175: undos(omen)
176:
177: Compile time options for various operating systems are described in the
178: program source file.
179: .SH NOTES
180: If rb is invoked as
181: .B rbCOMMAND
182: (with an optional leading \- as generated by login(1)),
183: rb will pipe each received file to ``COMMAND filename''
184: (filename is the name of the transmitted file)
185: with the file contents as standard input.
186: A typical usage for this form is rbrmail which calls rmail
187: to post mail.
188: On some
189: .SM Unix
190: systems, the login directory must contain
191: COMMAND as login sets SHELL=rsh which disallows absolute
192: pathnames.
193: If invoked with a leading ``v'' rb will report progress to LOGFILE.
194: The following entry works for
195: .SM Unix
196: 3.0.
197: rbrmail::5:1::/bin:/usr/local/rbrmail
198: .PP
199: The following (in a shell script)
200: may be used to fetch file(s) from a remote computer connected to /dev/tty7
201: once sb has been started on the remote.
202: rb -v >/dev/tty7 </dev/tty7
203: .SH BUGS
204: Pathnames are restricted to 127 characters.
205:
206: In XMODEM single file mode, the pathname given on the command line
207: is still processed as described above.
208:
209: The CR/LF to NL translation merely deletes CR\'s;
210: undos(omen) performs a more intelligent translation.
211: .SH "VMS VERSION"
212: Some of the #includes with file names enclosed with angle brackets <>
213: may need to have the angle brackets removed, or vice versa.
214:
215: The VMS version does not set binary mode according to the incoming
216: file type.
217: Non binary file processing consists of stripping all characters beginning
218: with CPMEOF (^Z).
219:
220: The VMS version does not set the file time.
221:
222: VMS occaisonally loses incoming characters, resulting in retries
223: and degradation of throughput.
224:
225: There may be unknown interactions between the VMS C standard i/o
226: package and RMS.
227:
228: The VMS version does not support invocation as
229: .B rbCOMMAND .
230: SHAR_EOF
231: cat << \SHAR_EOF > rb.c
232: #define VERSION "2.17 12-07-85"
233: #define PUBDIR "/usr/spool/uucppublic"
234:
235: /*% cc -DUSG -DNFGVMIN -O -K % -o rb
236: *
237: * rb.c By Chuck Forsberg
238: *
239: * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
240: * cc -O -DV7 rb.c -o rb Unix V7, BSD 2.8 - 4.2
241: * cc -O -DUSG rb.c -o rb USG (3.0) Unix
242: * cc -o rb.c Regulus
243: * (Don't try this on Unix, you'll clobber the source!)
244: * Unix is a trademark of Western Electric Company
245: *
246: * Regulus conventions 1-10-83 CAF
247: *
248: * Some systems (Venix, Coherent, Regulus) do not support tty raw mode
249: * read(2) the same way as Unix. ONEREAD must be defined to force one
250: * character reads for these systems. Added 7-01-84 CAF
251: *
252: * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF
253: *
254: * NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN]
255: * doesn't seem to work (even though it compiles without error!).
256: *
257: * A program for Unix which can receive
258: * files from computers running YAM or MODEM.
259: * rb uses Unix System III buffered input to reduce CPU time.
260: * If no filename is given, YAM batch mode is assumed.
261: *
262: * Iff the program is invoked by rbCOMMAND, output is piped to
263: * "COMMAND filename"
264: *
265: * Supports the CRC option or regular checksum.
266: * Received pathnames containing no lowercase letters will be changed to lower
267: * case unless -u option is given.
268: *
269: * Unless the -b (binary) option is given, \r is discarded and
270: * ^Z (which is also discarded) acts as end of file.
271: *
272: * Any slashes in the pathname are changed to underscore.
273: * If the raw pathname ends in .MSG or .TXT, any existing file will
274: * be appended to rather than replaced. Trailing periods are eliminated.
275: *
276: * If the raw pathname ends in any of the extensions in Extensions,
277: * or .?Q* (squeezed file), or if the first sector contains binary-like
278: * data (parity bits or characters in the range 0 to 6 before ^Z is seen),
279: * or if the transmitted file mode has the 0100000 but set,
280: * that file will be received in binary mode anyway.
281: *
282: *
283: * A log of activities is appended to LOGFILE with the -v option
284: * If stdout and stderr refer to different devices, progress is displayed to
285: * stderr.
286: *
287: * rb is derived from yam2.c and sb.c
288: */
289: #define LOGFILE "/tmp/rblog"
290:
291: #include <stdio.h>
292: #include <signal.h>
293: #include <setjmp.h>
294: #include <ctype.h>
295: FILE *popen();
296:
297: #define OK 0
298: #define FALSE 0
299: #define TRUE 1
300: #define ERROR (-1)
301:
302: #define HOWMANY 133
303: #include "rbsb.c" /* most of the system dependent stuff here */
304:
305: char *substr();
306: FILE *fout;
307:
308: char *Extensions[] = {
309: ".A",
310: ".ARC",
311: ".CCC",
312: ".CL",
313: ".CMD",
314: ".COM",
315: ".CRL",
316: ".DAT",
317: ".DIR",
318: ".EXE",
319: ".O",
320: ".OBJ",
321: ".OVL",
322: ".PAG",
323: ".REL",
324: ".SAV",
325: ".SUB",
326: ".SWP",
327: ".SYS",
328: ".TAR",
329: ".UTL",
330: ".a",
331: ".o",
332: ".tar",
333: ""
334: };
335:
336: /* Ward Christensen / CP/M parameters - Don't change these! */
337: #define ENQ 005
338: #define CAN ('X'&037)
339: #define XOFF ('s'&037)
340: #define XON ('q'&037)
341: #define SOH 1
342: #define STX 2
343: #define EOT 4
344: #define ACK 6
345: #define NAK 025
346: #define CPMEOF 032
347: #define WANTCRC 0103 /* send C not NAK to get crc not checksum */
348: #define TIMEOUT (-2)
349: #define ERRORMAX 5
350: #define RETRYMAX 5
351: #define WCEOT (-10)
352: #define SECSIZ 128 /* cp/m's Magic Number record size */
353: #define PATHLEN 257 /* ready for 4.2 bsd ? */
354: #define KSIZE 1024 /* record size with k option */
355: #define UNIXFILE 0x8000 /* happens to the the S_IFREG file mask bit for stat */
356:
357: int Lastrx;
358: int Crcflg;
359: int Firstsec;
360: int Eofseen; /* indicates cpm eof (^Z) has been received */
361: int totblocks; /* total number of blocks received */
362: int errors;
363: int Restricted=0; /* restricted; no /.. or ../ in filenames */
364:
365: #define DEFBYTL 2000000000L /* default rx file size */
366: long Bytesleft; /* number of bytes of incoming file left */
367: long Modtime; /* Unix style mod time for incoming file */
368: short Filemode; /* Unix style mode for incoming file */
369: char Pathname[PATHLEN];
370: char *Progname; /* the name by which we were called */
371:
372: int Batch=0;
373: int Wcsmask=0377;
374: int Topipe=0;
375: int MakeLCPathname=TRUE; /* make received pathname lower case */
376: int Verbose=0;
377: int Quiet=0; /* overrides logic that would otherwise set verbose */
378: int Rxbinary=FALSE; /* receive all files in bin mode */
379: int Thisbinary; /* current file is to be received in bin mode */
380: int Blklen; /* record length of received packets */
381: char secbuf[KSIZE];
382: char linbuf[KSIZE];
383: int Lleft=0; /* number of characters in linbuf */
384:
385: jmp_buf tohere; /* For the interrupt on RX timeout */
386:
387: unsigned short updcrc();
388:
389: alrm()
390: {
391: longjmp(tohere, -1);
392: }
393:
394: /* called by signal interrupt or terminate to clean things up */
395: bibi(n)
396: {
397: canit(); mode(0);
398: fprintf(stderr, "sb: caught signal %d; exiting", n);
399: exit(128+n);
400: }
401:
402: main(argc, argv)
403: char *argv[];
404: {
405: register char *cp;
406: register npats;
407: char *virgin, **patts;
408: char *getenv();
409: int exitcode;
410:
411: setbuf(stderr, NULL);
412: if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh")))
413: Restricted=TRUE;
414:
415: chkinvok(virgin=argv[0]); /* if called as [-]rbCOMMAND set flag */
416: npats = 0;
417: while (--argc) {
418: cp = *++argv;
419: if (*cp == '-') {
420: while( *++cp) {
421: switch(*cp) {
422: case '1':
423: iofd = 1; break;
424: case '7':
425: Wcsmask = 0177;
426: case 'b':
427: Rxbinary=TRUE; break;
428: case 'k':
429: case 'c':
430: Crcflg=TRUE; break;
431: case 'q':
432: Quiet=TRUE; Verbose=0; break;
433: case 'u':
434: MakeLCPathname=FALSE; break;
435: case 'v':
436: ++Verbose; break;
437: default:
438: usage();
439: }
440: }
441: }
442: else if ( !npats && argc>0) {
443: if (argv[0][0]) {
444: npats=argc;
445: patts=argv;
446: }
447: }
448: }
449: if (npats > 1)
450: usage();
451: if (Verbose) {
452: if (freopen(LOGFILE, "a", stderr)==NULL) {
453: printf("Can't open log file %s\n",LOGFILE);
454: exit(0200);
455: }
456: setbuf(stderr, NULL);
457: fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
458: }
459: if (fromcu() && !Quiet) {
460: if (Verbose == 0)
461: Verbose = 2;
462: }
463: mode(1);
464: if (signal(SIGINT, bibi) == SIG_IGN) {
465: signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
466: }
467: else {
468: signal(SIGINT, bibi); signal(SIGKILL, bibi);
469: }
470: if (wcreceive(npats, patts)==ERROR) {
471: exitcode=0200;
472: canit();
473: }
474: mode(0);
475: if (exitcode != 0) /* bellow again with all thy might. */
476: canit();
477: #ifdef REGULUS
478: else
479: printf("\6\6\6\6\6\n"); /* Regulus doesn't wait ... */
480: #endif
481: exit(exitcode);
482: }
483:
484:
485: usage()
486: {
487: fprintf(stderr,"%s %s by Chuck Forsberg\n", Progname, VERSION);
488: fprintf(stderr,"Usage: rb [-17buv]\n\tor rb [-1bcuv] file\n");
489: exit(1);
490: }
491:
492: wcreceive(argc, argp)
493: char **argp;
494: {
495: if (Batch || argc==0) {
496: Crcflg=(Wcsmask==0377);
497: fprintf(stderr, "rb: ready ");
498: for (;;) {
499: totblocks=0;
500: if (wcrxpn(secbuf)== ERROR)
501: goto fubar;
502: if (secbuf[0]==0)
503: return OK;
504: if (procheader(secbuf) == ERROR)
505: goto fubar;
506: if (wcrx()==ERROR)
507: goto fubar;
508: }
509: } else {
510: totblocks=0; Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
511:
512: strcpy(Pathname, *argp);
513: checkpath(Pathname);
514: fprintf(stderr, "\nrb: ready to receive %s ", Pathname);
515: if ((fout=fopen(Pathname, "w")) == NULL)
516: return ERROR;
517: if (wcrx()==ERROR)
518: goto fubar;
519: }
520: return OK;
521: fubar:
522: canit();
523: if (Topipe && fout) {
524: pclose(fout); return ERROR;
525: }
526: if (fout)
527: fclose(fout);
528: if (Restricted) {
529: unlink(Pathname);
530: fprintf(stderr, "\r\nrb: %s removed.\r\n", Pathname);
531: }
532: return ERROR;
533: }
534:
535:
536: /*
537: * Fetch a pathname from the other end as a C ctyle ASCIZ string.
538: * Length is indeterminate as long as less than Blklen
539: * a null string represents no more files
540: */
541: wcrxpn(rpn)
542: char *rpn; /* receive a pathname */
543: {
544: register c;
545:
546: #ifdef NFGVMIN
547: readline(1);
548: #else
549: purgeline();
550: #endif
551:
552: et_tu:
553: Firstsec=TRUE;
554: sendline(Crcflg?WANTCRC:NAK);
555: while ((c = wcgetsec(rpn, 100)) != 0) {
556: log( "Pathname fetch returned %d\n", c);
557: if (c == WCEOT) {
558: sendline(ACK); readline(1); goto et_tu;
559: }
560: return ERROR;
561: }
562: sendline(ACK);
563: return OK;
564: }
565:
566: /*
567: * Adapted from CMODEM13.C, written by
568: * Jack M. Wierda and Roderick W. Hart
569: */
570:
571: wcrx()
572: {
573: register int sectnum, sectcurr;
574: register char sendchar;
575: register char *p;
576: int cblklen; /* bytes to dump this block */
577: time_t timep[2];
578:
579: Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
580: sendchar=Crcflg?WANTCRC:NAK;
581:
582: for (;;) {
583: sendline(sendchar); /* send it now, we're ready! */
584: sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
585: report(sectcurr);
586: if (sectcurr==(sectnum+1 &Wcsmask)) {
587:
588: if (sectnum==0 && !Thisbinary)
589: for (p=secbuf,sectcurr=Blklen;
590: *p != 032 && --sectcurr>=0; ++p)
591: if (*p < 07 || (*p & 0200)) {
592: Thisbinary++;
593: if (Verbose)
594: fprintf(stderr, "Changed to BIN\n");
595: break;
596: }
597: sectnum++;
598: cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
599: if (putsec(secbuf, cblklen)==ERROR)
600: return ERROR;
601: if ((Bytesleft-=cblklen) < 0)
602: Bytesleft = 0;
603: sendchar=ACK;
604: }
605: else if (sectcurr==(sectnum&Wcsmask)) {
606: log( "Received dup Sector\n");
607: sendchar=ACK;
608: }
609: else if (sectcurr==WCEOT) {
610: if (Topipe) {
611: if (pclose(fout)!=ERROR) {
612: sendline(ACK);
613: return OK;
614: }
615: canit(); return ERROR;
616: }
617: if (fclose(fout)==ERROR) {
618: canit();
619: fprintf(stderr, "file close ERROR\n");
620: return ERROR;
621: }
622: if (Modtime) {
623: timep[0] = time(NULL);
624: timep[1] = Modtime;
625: utime(Pathname, timep);
626: }
627: if (Filemode)
628: chmod(Pathname, (07777 & Filemode));
629: sendline(ACK);
630: return OK;
631: }
632: else if (sectcurr==ERROR)
633: return ERROR;
634: else {
635: log( "Sync Error\n");
636: return ERROR;
637: }
638: }
639: }
640:
641: /*
642: * wcgetsec fetches a Ward Christensen type sector.
643: * Returns sector number encountered or ERROR if valid sector not received,
644: * or CAN CAN received
645: * or WCEOT if eot sector
646: * time is timeout for first char, set to 4 seconds thereafter
647: ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
648: * (Caller must do that when he is good and ready to get next sector)
649: */
650:
651: wcgetsec(rxbuf, maxtime)
652: char *rxbuf;
653: int maxtime;
654: {
655: register checksum, wcj, firstch;
656: register unsigned short oldcrc;
657: register char *p;
658: int sectcurr;
659:
660: for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
661:
662: if ((firstch=readline(maxtime))==STX) {
663: Blklen=KSIZE; goto get2;
664: }
665: if (firstch==SOH) {
666: Blklen=SECSIZ;
667: get2:
668: sectcurr=readline(1);
669: if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) {
670: oldcrc=checksum=0;
671: for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
672: if ((firstch=readline(1)) < 0)
673: goto bilge;
674: oldcrc=updcrc(firstch, oldcrc);
675: checksum += (*p++ = firstch);
676: }
677: if ((firstch=readline(1)) < 0)
678: goto bilge;
679: if (Crcflg) {
680: oldcrc=updcrc(firstch, oldcrc);
681: if ((firstch=readline(1)) < 0)
682: goto bilge;
683: oldcrc=updcrc(firstch, oldcrc);
684: if (oldcrc)
685: log("CRC=0%o\n", oldcrc);
686: else {
687: Firstsec=FALSE;
688: return sectcurr;
689: }
690: }
691: else if (((checksum-firstch)&Wcsmask)==0) {
692: Firstsec=FALSE;
693: return sectcurr;
694: }
695: else
696: log( "Checksum Error\n");
697: }
698: else
699: log("Sector number garbled 0%o 0%o\n",
700: sectcurr, oldcrc);
701: }
702: /* make sure eot really is eot and not just mixmash */
703: #ifdef NFGVMIN
704: else if (firstch==EOT && readline(1)==TIMEOUT)
705: return WCEOT;
706: #else
707: else if (firstch==EOT && Lleft==0)
708: return WCEOT;
709: #endif
710: else if (firstch==CAN) {
711: if (Lastrx==CAN) {
712: log( "Sender CANcelled\n");
713: return ERROR;
714: } else {
715: Lastrx=CAN;
716: continue;
717: }
718: }
719: else if (firstch==TIMEOUT) {
720: if (Firstsec)
721: goto humbug;
722: bilge:
723: log( "Timeout\n");
724: }
725: else
726: log( "Got 0%o sector header\n", firstch);
727:
728: humbug:
729: Lastrx=0;
730: while(readline(1)!=TIMEOUT)
731: ;
732: if (Firstsec)
733: sendline(Crcflg?WANTCRC:NAK);
734: else {
735: maxtime=40; sendline(NAK);
736: }
737: }
738: /* try to stop the bubble machine. */
739: canit();
740: return ERROR;
741: }
742:
743: /*
744: * This version of readline is reasoably well suited for
745: * reading many characters.
746: * (except, currently, for the Regulus version!)
747: *
748: * timeout is in tenths of seconds
749: */
750: readline(timeout)
751: int timeout;
752: {
753: register n;
754: static char *cdq; /* pointer for removing chars from linbuf */
755:
756: if (--Lleft >= 0) {
757: if (Verbose > 8) {
758: fprintf(stderr, "%02x ", *cdq&0377);
759: }
760: return (*cdq++ & Wcsmask);
761: }
762: n = timeout/10;
763: if (n < 2)
764: n = 3;
765: if (Verbose > 3)
766: fprintf(stderr, "Calling read: n=%d ", n);
767: if (setjmp(tohere)) {
768: #ifdef TIOCFLUSH
769: /* ioctl(iofd, TIOCFLUSH, 0); */
770: #endif
771: Lleft = 0;
772: if (Verbose>1)
773: fprintf(stderr, "Readline:TIMEOUT\n");
774: return TIMEOUT;
775: }
776: signal(SIGALRM, alrm); alarm(n);
777: #ifdef ONEREAD
778: /* Sorry, Regulus and some others don't work right in raw mode! */
779: Lleft=read(iofd, cdq=linbuf, 1);
780: #else
781: Lleft=read(iofd, cdq=linbuf, KSIZE);
782: #endif
783: alarm(0);
784: if (Verbose > 3) {
785: fprintf(stderr, "Read returned %d bytes\n", Lleft);
786: }
787: if (Lleft < 1)
788: return TIMEOUT;
789: --Lleft;
790: if (Verbose > 8) {
791: fprintf(stderr, "%02x ", *cdq&0377);
792: }
793: return (*cdq++ & Wcsmask);
794: }
795:
796:
797:
798:
799: purgeline()
800: {
801: Lleft = 0;
802: #ifdef USG
803: ioctl(iofd, TCFLSH, 0);
804: #else
805: lseek(iofd, 0L, 2);
806: #endif
807: }
808:
809: /* update CRC */
810: unsigned short
811: updcrc(c, crc)
812: register c;
813: register unsigned crc;
814: {
815: register count;
816:
817: for (count=8; --count>=0;) {
818: if (crc & 0x8000) {
819: crc <<= 1;
820: crc += (((c<<=1) & 0400) != 0);
821: crc ^= 0x1021;
822: }
823: else {
824: crc <<= 1;
825: crc += (((c<<=1) & 0400) != 0);
826: }
827: }
828: return crc;
829: }
830:
831: /*
832: * process incoming header
833: */
834: procheader(name)
835: char *name;
836: {
837: register char *openmode, *p, **pp;
838:
839: /* set default parameters */
840: openmode = "w"; Thisbinary=Rxbinary;
841: Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
842:
843: p = name + 1 + strlen(name);
844: if (*p) { /* file coming from Unix or DOS system */
845: sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
846: if (Filemode & UNIXFILE)
847: ++Thisbinary;
848: if (Verbose) {
849: fprintf(stderr, "Incoming: %s %ld %lo %o\n",
850: name, Bytesleft, Modtime, Filemode);
851: }
852: }
853: else { /* File coming from CP/M system */
854: for (p=name; *p; ++p) /* change / to _ */
855: if ( *p == '/')
856: *p = '_';
857:
858: if ( *--p == '.') /* zap trailing period */
859: *p = 0;
860: }
861:
862: /* scan for extensions that signify a binary file */
863: if (p=substr(name, "."))
864: for (pp=Extensions; **pp; ++pp)
865: if (strcmp(p, *pp)==0) {
866: Thisbinary=TRUE; break;
867: }
868:
869: /* scan for files which should be appended */
870: if ( !Thisbinary
871: && (substr(name, ".TXT")
872: || substr(name, ".txt")
873: || substr(name, ".MSG")))
874: openmode = "a";
875: if (MakeLCPathname && !IsAnyLower(name))
876: uncaps(name);
877: if (Topipe) {
878: sprintf(Pathname, "%s %s", Progname+2, name);
879: if (Verbose)
880: fprintf(stderr, "Topipe: %s %s\n",
881: Pathname, Thisbinary?"BIN":"ASCII");
882: if ((fout=popen(Pathname, "w")) == NULL)
883: return ERROR;
884: } else {
885: strcpy(Pathname, name);
886: if (Verbose) {
887: fprintf(stderr, "Receiving %s %s %s\n",
888: name, Thisbinary?"BIN":"ASCII", openmode);
889: }
890: checkpath(name);
891: if ((fout=fopen(name, openmode)) == NULL)
892: return ERROR;
893: }
894: return OK;
895: }
896:
897: /* make string s lower case */
898: uncaps(s)
899: register char *s;
900: {
901: for ( ; *s; ++s)
902: if (isupper(*s))
903: *s = tolower(*s);
904: }
905:
906:
907: /*
908: * IsAnyLower returns TRUE if string s has lower case letters.
909: */
910: IsAnyLower(s)
911: register char *s;
912: {
913: for ( ; *s; ++s)
914: if (islower(*s))
915: return TRUE;
916: return FALSE;
917: }
918: /*
919: * putsec writes the n characters of buf to receive file fout.
920: * If not in binary mode, carriage returns, and all characters
921: * starting with CPMEOF are discarded.
922: */
923: putsec(buf, n)
924: char *buf;
925: register n;
926: {
927: register char *p;
928:
929: ++totblocks;
930: if (Thisbinary)
931: {
932: for (p=buf; --n>=0; )
933: putc( *p++, fout);
934: }
935: else {
936: if (Eofseen)
937: return OK;
938: for (p=buf; --n>=0; ++p ) {
939: if ( *p == '\r')
940: continue;
941: if (*p == CPMEOF) {
942: Eofseen=TRUE; return OK;
943: }
944: putc(*p ,fout);
945: }
946: }
947: return OK;
948: }
949: sendline(c)
950: {
951: char d;
952:
953: d = c;
954: if (Verbose>2)
955: fprintf(stderr, "Sendline: %x\n", c);
956: write(1, &d, 1);
957: Lleft=0; /* Do read next time ... */
958: }
959:
960:
961: /*
962: * substr(string, token) searches for token in string s
963: * returns pointer to token within string if found, NULL otherwise
964: */
965: char *
966: substr(s, t)
967: register char *s,*t;
968: {
969: register char *ss,*tt;
970: /* search for first char of token */
971: for (ss=s; *s; s++)
972: if (*s == *t)
973: /* compare token with substring */
974: for (ss=s,tt=t; ;) {
975: if (*tt == 0)
976: return s;
977: if (*ss++ != *tt++)
978: break;
979: }
980: return NULL;
981: }
982:
983: /*VARARGS1*/
984: log(s,p,u)
985: char *s, *p, *u;
986: {
987: if (!Verbose)
988: return;
989: fprintf(stderr, "error %d: ", errors);
990: fprintf(stderr, s, p, u);
991: }
992:
993: /* send 10 CAN's to try to get the other end to shut up */
994: canit()
995: {
996: register n;
997: for (n=10; --n>=0; )
998: sendline(CAN);
999: }
1000:
1001: #ifdef REGULUS
1002: /*
1003: * copies count bytes from s to d
1004: * (No structure assignment in Regulus C compiler)
1005: */
1006:
1007: movmem(s, d, count)
1008: register char *s, *d;
1009: register count;
1010: {
1011: while (--count >= 0)
1012: *d++ = *s++;
1013: }
1014: #endif
1015:
1016: /*
1017: * return 1 iff stdout and stderr are different devices
1018: * indicating this program operating with a modem on a
1019: * different line
1020: */
1021: fromcu()
1022: {
1023: struct stat a, b;
1024: fstat(1, &a); fstat(2, &b);
1025: return (a.st_rdev != b.st_rdev);
1026: }
1027:
1028: report(sct)
1029: int sct;
1030: {
1031: if (Verbose>1)
1032: fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
1033: }
1034:
1035: /*
1036: * if called as [-][dir/../]vrbCOMMAND set Verbose to 1
1037: * if called as [-][dir/../]rbCOMMAND set the pipe flag
1038: */
1039: chkinvok(s)
1040: char *s;
1041: {
1042: register char *p;
1043:
1044: p = s;
1045: while (*p == '-')
1046: s = ++p;
1047: while (*p)
1048: if (*p++ == '/')
1049: s = p;
1050: if (*s == 'v') {
1051: Verbose=1; ++s;
1052: }
1053: Progname = s;
1054: if (s[2] && s[0]=='r' && s[1]=='b')
1055: Topipe=TRUE;
1056: }
1057:
1058: checkpath(name)
1059: char *name;
1060: {
1061: if (Restricted) {
1062: if (fopen(name, "r") != NULL) {
1063: canit();
1064: fprintf(stderr, "\r\nrb: %s exists\n", name);
1065: bibi();
1066: }
1067: /* restrict pathnames to current tree or uucppublic */
1068: if ( substr(name, "../")
1069: || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
1070: canit();
1071: fprintf(stderr,"\r\nrb:\tSecurity Violation\r\n");
1072: bibi();
1073: }
1074: }
1075: }
1076:
1077: SHAR_EOF
1078: cat << \SHAR_EOF > rbsb.c
1079: /* -rev 09-13-85
1080: * mode function and most of the rest of the system dependent
1081: * stuff for rb.c and sb.c This file is #included so the includer
1082: * can set parameters such as HOWMANY.
1083: */
1084:
1085: #ifdef USG
1086: #include <sys/types.h>
1087: #include <sys/stat.h>
1088: #include <termio.h>
1089: #include <sys/ioctl.h>
1090: #define OS "USG"
1091: #endif
1092:
1093: #ifdef V7
1094: #include <sys/types.h>
1095: #include <sys/stat.h>
1096: #include <sgtty.h>
1097: #define OS "V7"
1098: #endif
1099:
1100: #ifndef OS
1101: #include <termio.h>
1102: #include <sys/ioctl.h>
1103: #include <stat.h>
1104: #define REGULUS
1105: #define ONEREAD
1106: #define OS "REGULUS"
1107: #define void int
1108: #define time_t long
1109: #endif
1110:
1111:
1112: #ifdef ICANON
1113: struct termio oldtty, tty;
1114: #else
1115: struct sgttyb oldtty, tty;
1116: struct tchars oldtch, tch;
1117: #endif
1118:
1119: int iofd = 0; /* File descriptor for ioctls & reads */
1120:
1121: /*
1122: * mode(n)
1123: * 2: set a cbreak, XON/XOFF control mode if using Pro-YAM's -g option
1124: * 1: save old tty stat, set raw mode
1125: * 0: restore original tty mode
1126: */
1127: mode(n)
1128: {
1129: static did0 = FALSE;
1130:
1131: switch(n) {
1132: #ifdef USG
1133: case 2: /* Cbreak mode used by sb when -g detected */
1134: if(!did0)
1135: (void) ioctl(iofd, TCGETA, &oldtty);
1136: tty = oldtty;
1137:
1138: tty.c_iflag = BRKINT|IXON;
1139:
1140: tty.c_oflag = 0; /* Transparent output */
1141:
1142: tty.c_cflag &= ~PARENB; /* Disable parity */
1143: tty.c_cflag |= CS8; /* Set character size = 8 */
1144:
1145: #ifdef XCLUDE
1146: tty.c_lflag = XCLUDE | ISIG;
1147: #else
1148: tty.c_lflag = ISIG;
1149: #endif
1150:
1151: tty.c_cc[VINTR] = 030; /* Interrupt on CANCEL */
1152: tty.c_cc[VMIN] = 1;
1153:
1154: (void) ioctl(iofd, TCSETAW, &tty);
1155: did0 = TRUE;
1156: return OK;
1157: case 1:
1158: if(!did0)
1159: (void) ioctl(iofd, TCGETA, &oldtty);
1160: tty = oldtty;
1161:
1162: tty.c_iflag = IGNBRK;
1163:
1164: /* No echo, crlf mapping, INTR, QUIT, delays, no erase/kill */
1165: tty.c_lflag &= ~(ECHO | ICANON | ISIG);
1166: #ifdef XCLUDE
1167: tty.c_lflag |= XCLUDE;
1168: #endif
1169:
1170: tty.c_oflag = 0; /* Transparent output */
1171:
1172: tty.c_cflag &= ~PARENB; /* Leave baud rate alone, disable parity */
1173: tty.c_cflag |= CS8; /* Set character size = 8 */
1174: tty.c_cc[VMIN] = HOWMANY; /* Satisfy reads when this many chars in */
1175: tty.c_cc[VTIME] = 1; /* ... or in this many tenths of seconds */
1176: (void) ioctl(iofd, TCSETAW, &tty);
1177: did0 = TRUE;
1178: return OK;
1179: #endif
1180: #ifdef V7
1181: case 2:
1182: if(!did0) {
1183: ioctl(iofd, TIOCEXCL, 0);
1184: ioctl(iofd, TIOCGETP, &oldtty);
1185: ioctl(iofd, TIOCGETC, &oldtch);
1186: }
1187: tty = oldtty;
1188: tch = oldtch;
1189: tch.t_intrc = 030;
1190: tty.sg_flags |= CBREAK;
1191: tty.sg_flags &= ~ECHO;
1192: ioctl(iofd, TIOCSETP, &tty);
1193: ioctl(iofd, TIOCSETC, &tch);
1194: did0 = TRUE;
1195: return OK;
1196: case 1:
1197: if(!did0) {
1198: ioctl(iofd, TIOCEXCL, 0);
1199: ioctl(iofd, TIOCGETP, &oldtty);
1200: ioctl(iofd, TIOCGETC, &oldtch);
1201: }
1202: tty = oldtty;
1203: tty.sg_flags |= RAW;
1204: tty.sg_flags &= ~ECHO;
1205: ioctl(iofd, TIOCSETP, &tty);
1206: did0 = TRUE;
1207: return OK;
1208: #endif
1209: #ifdef REGULUS
1210: case 2:
1211: return ERROR;
1212: case 1:
1213: if(!did0) {
1214: ioctl(iofd, TCGETA, &oldtty);
1215: }
1216: tty = oldtty;
1217:
1218: tty.c_lflag = 0;
1219: tty.c_iflag = IGNBRK;
1220: tty.c_oflag = 0; /* Transparent output */
1221:
1222: tty.c_cflag &= ~PARENB; /* Leave baud rate alone, disable parity */
1223: tty.c_cflag |= CS8; /* Set character size = 8 */
1224: tty.c_cc[VMIN] = HOWMANY; /* Satisfy reads when this many chars in */
1225: tty.c_cc[VTIME] = 1; /* ... or in this many tenths of seconds */
1226: ioctl(iofd, TCSETA, &tty);
1227: did0 = TRUE;
1228: return OK;
1229: #endif
1230: #ifdef REGULUS10
1231: if(!did0) {
1232: ioctl(iofd, TIOCGETP, &oldtty);
1233: }
1234: /* Sorry, No structure assignment in Regulus C */
1235: movmem( (char *)&oldtty, (char *)&tty, sizeof(tty));
1236: tty.sg_flags |= (EIGHTBIT|RAW);
1237: tty.sg_flags &= ~ECHO;
1238: tty.sg_ledit &= ~LEDIT;
1239: ioctl(iofd, TIOCSETP, &tty);
1240: did0 = TRUE;
1241: return OK;
1242: #endif
1243: case 0:
1244: if(!did0)
1245: return ERROR;
1246: #ifdef USG
1247: (void) ioctl(iofd, TCSBRK, 1); /* Wait for output to drain */
1248: (void) ioctl(iofd, TCFLSH, 1); /* Flush input queue */
1249: (void) ioctl(iofd, TCSETAW, &oldtty); /* Restore original modes */
1250: (void) ioctl(iofd, TCXONC,1); /* Restart output */
1251: #endif
1252: #ifdef V7
1253: ioctl(iofd, TIOCSETP, &oldtty);
1254: ioctl(iofd, TIOCSETC, &oldtch);
1255: ioctl(iofd, TIOCNXCL, 0);
1256: #endif
1257: #ifdef REGULUS
1258: ioctl(iofd, TCSETAW, &oldtty); /* Restore original modes */
1259: #endif
1260: #ifdef REGULUS10
1261: ioctl(iofd, TIOCSETP, &oldtty);
1262: #endif
1263: return OK;
1264: default:
1265: return ERROR;
1266: }
1267: }
1268:
1269: SHAR_EOF
1270: cat << \SHAR_EOF > sb.1
1271: '\" Revision Level
1272: '\" Last Delta 12-07-85
1273: .TH SB 1 OMEN
1274: .SH NAME
1275: sb \- send files in batch mode
1276: .SH SYNOPSIS
1277: .B sb
1278: [
1279: .B \-1dfkquv
1280: ]
1281: .B file ...
1282: .br
1283: .B "sb -X"
1284: [
1285: .B \-1kquv
1286: ]
1287: .B file
1288: .SH DESCRIPTION
1289: .B Sb
1290: sends one or more files with YMODEM batch protocol.
1291: Normally, only the file name part of the pathname is transmitted.
1292: On
1293: .SM Unix
1294: systems, additional information about the file is transmitted.
1295: If the receiving program uses this information,
1296: the transmitted file length controls the exact number of bytes written to
1297: the output dataset,
1298: and the modify time and file mode
1299: are set accordingly.
1300:
1301: With the
1302: .B -X
1303: flag,
1304: .B sb
1305: sends a single file using XMODEM protocol.
1306: The received file name must be supplied by the user.
1307:
1308: If sb is invoked with stdout and stderr to different datasets,
1309: Verbose is set to 2, causing frame by frame progress reports
1310: to stderr.
1311: This may be disabled with the
1312: .B q
1313: option.
1314:
1315: Iff sb is invoked with $SHELL set and iff that variable contains the
1316: string
1317: .I "rsh"
1318: or
1319: .I "rksh"
1320: (restricted shell), sb operates in restricted mode.
1321: Restricted mode restricts pathnames to the current directory and
1322: PUBDIR (conventionally, /usr/spool/uucppublic) and/or subdirectories
1323: thereof.
1324:
1325: Sb supports YMODEM
1326: .B g
1327: mode by switching to "cbreak" tty mode with XON/XOFF folow control
1328: and the interrupt character set to CAN.
1329: The YMODEM
1330: .B g
1331: mode
1332: (Pro-YAM
1333: .B g
1334: option)
1335: increases throughput over error free channels
1336: (direct connection, X.PC, etc.)
1337: by not acknowledging each transmitted sector.
1338: .PP
1339: The meanings of the available options are:
1340: .PP
1341: .PD 0
1342: .TP
1343: .B 1
1344: Use file descriptor 1 for ioctls and reads.
1345: By default, file descriptor 0 is used.
1346: .TP
1347: .B X
1348: (XMODEM protocol)
1349: Send a single file without the filename packet.
1350: .TP
1351: .B d
1352: Change all instances of "." to "/" in the transmitted pathname.
1353: Thus, C.omenB0000 (which is unacceptable to MSDOS or CP/M)
1354: is transmitted as C/omenB0000.
1355: If the resultant filename has more than 8 characters in the stem,
1356: a "." in inserted to allow a total of eleven.
1357: .TP
1358: .B f
1359: Send Full pathnname.
1360: Normally directory prefices are stripped from the transmitted
1361: filename.
1362: .TP
1363: .B k
1364: Send files using 1024 byte blocks
1365: rather than the default 128 byte blocks.
1366: The user should determine experimentally
1367: the conditions under which use of 1k blocks
1368: actually improves throughput without causing
1369: problems.
1370: .TP
1371: .B q
1372: Quiet suppresses verbosity.
1373: .TP
1374: .B u
1375: Unlink the file after successful transmission.
1376: .TP
1377: .B v
1378: .IR Verbose
1379: causes a list of file
1380: names to be appended to
1381: /tmp/sblog .
1382: More v's generate more output.
1383: .PD
1384: .SH EXAMPLES
1385: (Unix command)
1386: .RS
1387: sb -k *.c
1388: .br
1389: .RE
1390: (Pro-YAM command)
1391: .RS
1392: <F3>
1393: .br
1394: .RE
1395: (8-bit YAM Commands)
1396: .br
1397: .RS
1398: ^E
1399: .br
1400: >>>c: rt -y
1401: .br
1402: .RE
1403: .SH SEE ALSO
1404: rb(omen),
1405: YMODEM.DOC,
1406: Professional-YAM manual,
1407: IMP(CP/M),
1408: ncu(1),
1409: sq(omen),
1410: todos(omen),
1411: tocpm(omen),
1412: tomac(omen)
1413:
1414: Compile time options for various operating systems are described in the
1415: program source file.
1416: .SH BUGS
1417: On VMS,
1418: some of the #includes with file names enclosed with angle brackets <>
1419: may need to have the angle brackets removed, or vice versa.
1420:
1421: The VMS version does not transmit the file date.
1422:
1423: The VMS version does not recognize Pro-YAM\'s
1424: .B g
1425: option (YMODEM-g protocol).
1426:
1427: The VMS version calculates the file length by counting the bytes therin.
1428:
1429: When VMS is lightly loaded, the response time may be too quick for MODEM7
1430: unless the MODEM7
1431: .B "q"
1432: modifier is used.
1433:
1434: There may be unknown interactions between the VMS C standard i/o
1435: package and RMS.
1436: SHAR_EOF
1437: cat << \SHAR_EOF > sb.c
1438: #define VERSION "sb 2.24 01-04-86"
1439: #define PUBDIR "/usr/spool/uucppublic"
1440:
1441: /*% cc -K -O -DUSG sb.c -o sb
1442:
1443: * sb.c By Chuck Forsberg
1444: *
1445: * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
1446: * cc -O -DV7 sb.c -o sb Unix version 7, 2.8 - 4.3 BSD
1447: * cc -O -DUSG sb.c -o sb USG (3.0) Unix
1448: * ******* Some systems (Venix, Coherent, Regulus) do not *******
1449: * ******* support tty raw mode read(2) identically to *******
1450: * ******* Unix. ONEREAD must be defined to force one *******
1451: * ******* character reads for these systems. *******
1452: *
1453: * A small program for Unix which can send 1 or more
1454: * files in Batch mode to computers running YAM. (Use "rb" in YAM.)
1455: * Supports the CRC option or regular checksum.
1456: * Exit status is 0 for all transfers completed successfully,
1457: * 1 for 1 or more unreadable files or'd with 200 for incomplete file xfer.
1458: *
1459: * accepts -k option for 1kb record length.
1460: *
1461: * sb is derived from yam2.c
1462: * Uses buffered i/o to reduce the CPU time compared to UMODEM.
1463: */
1464:
1465: #define LOGFILE "/tmp/sblog"
1466:
1467: #include <stdio.h>
1468: #include <signal.h>
1469: #include <setjmp.h>
1470: #include <ctype.h>
1471:
1472: #define PATHLEN 256
1473: #define OK 0
1474: #define FALSE 0
1475: #define TRUE 1
1476: #define ERROR (-1)
1477:
1478: #define HOWMANY 2
1479: #include "rbsb.c" /* most of the system dependent stuff here */
1480:
1481: FILE *in;
1482:
1483: /* Ward Christensen / CP/M parameters - Don't change these! */
1484: #define ENQ 005
1485: #define CAN ('X'&037)
1486: #define XOFF ('s'&037)
1487: #define XON ('q'&037)
1488: #define SOH 1
1489: #define STX 2
1490: #define EOT 4
1491: #define ACK 6
1492: #define NAK 025
1493: #define CPMEOF 032
1494: #define WANTCRC 0103 /* send C not NAK to get crc not checksum */
1495: #define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */
1496: #define TIMEOUT (-2)
1497: #define RETRYMAX 10
1498: #define SECSIZ 128 /* cp/m's Magic Number record size */
1499: #define KSIZE 1024
1500:
1501: char Lastrx;
1502: char Crcflg;
1503: int Wcsmask=0377;
1504: int Verbose=0;
1505: int Modem=0; /* MODEM - don't send pathnames */
1506: int Restricted=0; /* restricted; no /.. or ../ in filenames */
1507: int Quiet=0; /* overrides logic that would otherwise set verbose */
1508: int Fullname=0; /* transmit full pathname */
1509: int Unlinkafter=0; /* Unlink file after it is sent */
1510: int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */
1511: int firstsec;
1512: int errcnt=0; /* number of files unreadable */
1513: int blklen=SECSIZ; /* length of transmitted records */
1514: int Optiong; /* Let it rip no wait for sector ACK's */
1515: int Noeofseen;
1516: int Totsecs; /* total number of sectors this file */
1517: char txbuf[KSIZE];
1518: int Filcnt=0; /* count of number of files opened */
1519:
1520: jmp_buf tohere; /* For the interrupt on RX timeout */
1521:
1522: unsigned updcrc();
1523: char *substr(), *getenv();
1524:
1525: /* called by signal interrupt or terminate to clean things up */
1526: bibi(n)
1527: {
1528: canit(); fflush(stdout); mode(0);
1529: fprintf(stderr, "sb: caught signal %d; exiting\n", n);
1530: if (n == SIGQUIT)
1531: abort();
1532: exit(128+n);
1533: }
1534:
1535: #ifdef REGULUS
1536: sendline(c)
1537: {
1538: static char d[2];
1539:
1540: d[0] = c&Wcsmask;
1541: write(1, d, 1);
1542: }
1543: #else
1544: #define sendline(c) putchar(c & Wcsmask)
1545: #endif
1546:
1547: main(argc, argv)
1548: char *argv[];
1549: {
1550: register char *cp;
1551: register npats;
1552: int agcnt; char **agcv;
1553: char **patts;
1554: int exitcode;
1555: #ifndef REGULUS
1556: static char xXbuf[BUFSIZ];
1557: #endif
1558:
1559: if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh")))
1560: Restricted=TRUE;
1561:
1562: npats=0;
1563: if (argc<2)
1564: usage();
1565: #ifndef REGULUS
1566: setbuf(stdout, xXbuf);
1567: #endif
1568: while (--argc) {
1569: cp = *++argv;
1570: if (*cp++ == '-' && *cp) {
1571: while ( *cp) {
1572: switch(*cp++) {
1573: case '1':
1574: iofd = 1; break;
1575: case '7':
1576: Wcsmask=0177; break;
1577: case 'd':
1578: ++Dottoslash;
1579: /* **** FALL THROUGH TO **** */
1580: case 'f':
1581: Fullname=TRUE; break;
1582: case 'k':
1583: blklen=KSIZE; break;
1584: case 'q':
1585: Quiet=TRUE; Verbose=0; break;
1586: case 'u':
1587: ++Unlinkafter; break;
1588: case 'v':
1589: ++Verbose; break;
1590: case 'X':
1591: ++Modem; break;
1592: default:
1593: usage();
1594: }
1595: }
1596: }
1597: else if ( !npats && argc>0) {
1598: if (argv[0][0]) {
1599: npats=argc;
1600: patts=argv;
1601: if ( !strcmp(*patts, "-"))
1602: iofd = 1;
1603: }
1604: }
1605: }
1606: if (npats < 1)
1607: usage();
1608: if (Verbose) {
1609: if (freopen(LOGFILE, "a", stderr)==NULL) {
1610: printf("Can't open log file %s\n",LOGFILE);
1611: exit(0200);
1612: }
1613: setbuf(stderr, NULL);
1614: }
1615: if (fromcu() && !Quiet) {
1616: if (Verbose == 0)
1617: Verbose = 2;
1618: }
1619: if (Verbose != 1) {
1620: fprintf(stderr, "sb: %d file%s requested:\r\n",
1621: npats, npats>1?"s":"");
1622: for ( agcnt=npats, agcv=patts; --agcnt>=0; ) {
1623: fprintf(stderr, "%s ", *agcv++);
1624: }
1625: }
1626:
1627: mode(1);
1628: if (signal(SIGINT, bibi) == SIG_IGN) {
1629: signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
1630: }
1631: else {
1632: signal(SIGINT, bibi); signal(SIGKILL, bibi);
1633: signal(SIGQUIT, bibi);
1634: }
1635:
1636: if (wcsend(npats, patts)==ERROR) {
1637: exitcode=0200;
1638: canit();
1639: }
1640: fflush(stdout);
1641: mode(0);
1642: exit((errcnt != 0) | exitcode);
1643: }
1644:
1645: wcsend(argc, argp)
1646: char *argp[];
1647: {
1648: register n;
1649:
1650: Crcflg=FALSE;
1651: firstsec=TRUE;
1652: for (n=0; n<argc; ++n) {
1653: Totsecs = 0;
1654: if (wcs(argp[n])==ERROR)
1655: goto fubar;
1656: }
1657: Totsecs = 0;
1658: if (Filcnt==0) { /* bitch if we couldn't open ANY files */
1659: fprintf(stderr,"\r\nCan't open any requested files.\n");
1660: return ERROR;
1661: }
1662: else if (wctxpn("")==ERROR)
1663: goto fubar;
1664: return OK;
1665: fubar:
1666: canit(); return ERROR;
1667: }
1668:
1669: wcs(oname)
1670: char *oname;
1671: {
1672: register c;
1673: register char *p;
1674: struct stat f;
1675: char name[PATHLEN];
1676:
1677: strcpy(name, oname);
1678:
1679: if (Restricted) {
1680: /* restrict pathnames to current tree or uucppublic */
1681: if ( substr(name, "../")
1682: || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
1683: canit();
1684: fprintf(stderr,"\r\nsb:\tSecurity Violation\r\n");
1685: return ERROR;
1686: }
1687: }
1688:
1689: if ( !strcmp(oname, "-")) {
1690: sprintf(name, "s%d.sb", getpid());
1691: in = stdin;
1692: }
1693: else if ((in=fopen(oname, "r"))==NULL) {
1694: ++errcnt;
1695: return OK; /* pass over it, there may be others */
1696: }
1697: ++Noeofseen;
1698: /* Check for directory or block special files */
1699: #ifndef REGULUS /* This doesn't seem to work on Regulus */
1700: fstat(fileno(in), &f);
1701: c = f.st_mode & S_IFMT;
1702: if (c == S_IFDIR || c == S_IFBLK) {
1703: fclose(in);
1704: return OK;
1705: }
1706: #endif
1707: ++Filcnt;
1708: if (wctxpn(name)== ERROR)
1709: return ERROR;
1710: if (wctx()==ERROR)
1711: return ERROR;
1712: if (Unlinkafter)
1713: unlink(oname);
1714: return 0;
1715: }
1716:
1717: /*
1718: * generate and transmit pathname block consisting of
1719: * pathname (null terminated),
1720: * file length, mode time and file mode in octal
1721: * as provided by the Unix fstat call.
1722: * N.B.: modifies the passed name, may extend it!
1723: */
1724: wctxpn(name)
1725: char *name;
1726: {
1727: register firstch;
1728: register char *p, *q;
1729: char name2[PATHLEN];
1730: struct stat f;
1731:
1732: if (Modem)
1733: return OK;
1734: logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>");
1735: if (getnak())
1736: return ERROR;
1737:
1738: q = (char *) 0;
1739: if (Dottoslash) { /* change . to . */
1740: for (p=name; *p; ++p) {
1741: if (*p == '/')
1742: q = p;
1743: else if (*p == '.')
1744: *(q=p) = '/';
1745: }
1746: if (q && strlen(++q) > 8) { /* If name>8 chars */
1747: q += 8; /* make it .ext */
1748: strcpy(name2, q); /* save excess of name */
1749: *q = '.';
1750: strcpy(++q, name2); /* add it back */
1751: }
1752: }
1753:
1754: for (p=name, q=txbuf ; *p; )
1755: if ((*q++ = *p++) == '/' && !Fullname)
1756: q = txbuf;
1757: *q++ = 0;
1758: p=q;
1759: while (q < (txbuf + KSIZE))
1760: *q++ = 0;
1761: if (in == stdin)
1762: strcpy(p, "1999999999");
1763: #ifndef REGULUS /* This doesn't seem to work on Regulus */
1764: else if (*name && fstat(fileno(in), &f)!= -1)
1765: sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode);
1766: #endif
1767: /* force 1k blocks if name won't fit in 128 byte block */
1768: if (txbuf[125])
1769: blklen=KSIZE;
1770: else { /* A little goodie for IMP/KMD */
1771: txbuf[127] = f.st_size >>7;
1772: txbuf[126] = f.st_size >>15;
1773: }
1774: if (wcputsec(txbuf, 0, SECSIZ)==ERROR)
1775: return ERROR;
1776: return OK;
1777: }
1778:
1779: getnak()
1780: {
1781: register firstch;
1782:
1783: Lastrx = 0;
1784: for (;;) {
1785: switch (firstch = readock(800,2)) {
1786: case TIMEOUT:
1787: logent("Timeout on pathname\n");
1788: return TRUE;
1789: case WANTG:
1790: mode(2); /* Set cbreak, XON/XOFF, etc. */
1791: Optiong = TRUE;
1792: blklen=KSIZE;
1793: case WANTCRC:
1794: Crcflg = TRUE;
1795: case NAK:
1796: return FALSE;
1797: case CAN:
1798: if (Lastrx == CAN)
1799: return TRUE;
1800: default:
1801: break;
1802: }
1803: Lastrx = firstch;
1804: }
1805: }
1806:
1807:
1808: wctx()
1809: {
1810: register int sectnum, attempts, firstch;
1811:
1812: firstsec=TRUE;
1813:
1814: while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC
1815: && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN)
1816: ;
1817: if (firstch==CAN) {
1818: logent("Receiver CANcelled\n");
1819: return ERROR;
1820: }
1821: if (firstch==WANTCRC)
1822: Crcflg=TRUE;
1823: if (firstch==WANTG)
1824: Crcflg=TRUE;
1825: sectnum=1;
1826: while (filbuf(txbuf, blklen)) {
1827: if (wcputsec(txbuf, sectnum, blklen)==ERROR) {
1828: return ERROR;
1829: } else
1830: sectnum++;
1831: }
1832: if (Verbose>1)
1833: fprintf(stderr, " Closing ");
1834: fclose(in);
1835: attempts=0;
1836: do {
1837: logent(" EOT ");
1838: purgeline();
1839: sendline(EOT);
1840: fflush(stdout);
1841: ++attempts;
1842: }
1843: while ((firstch=(readock(100, 2)) != ACK) && attempts < RETRYMAX);
1844: if (attempts == RETRYMAX) {
1845: logent("No ACK on EOT\n");
1846: return ERROR;
1847: }
1848: else
1849: return OK;
1850: }
1851:
1852: wcputsec(buf, sectnum, cseclen)
1853: char *buf;
1854: int sectnum;
1855: int cseclen; /* data length of this sector to send */
1856: {
1857: register checksum, wcj;
1858: register char *cp;
1859: unsigned oldcrc;
1860: int firstch;
1861: int attempts;
1862:
1863: firstch=0; /* part of logic to detect CAN CAN */
1864:
1865: if (Verbose>1)
1866: fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 );
1867: for (attempts=0; attempts <= RETRYMAX; attempts++) {
1868: Lastrx= firstch;
1869: sendline(cseclen==KSIZE?STX:SOH);
1870: sendline(sectnum);
1871: sendline(-sectnum -1);
1872: oldcrc=checksum=0;
1873: for (wcj=cseclen,cp=buf; --wcj>=0; ) {
1874: sendline(*cp);
1875: oldcrc=updcrc(*cp, oldcrc);
1876: checksum += *cp++;
1877: }
1878: if (Crcflg) {
1879: oldcrc=updcrc(0,updcrc(0,oldcrc));
1880: sendline((int)oldcrc>>8);
1881: sendline((int)oldcrc);
1882: }
1883: else
1884: sendline(checksum);
1885:
1886: if (Optiong) {
1887: firstsec = FALSE; return OK;
1888: }
1889: firstch = readock(400, (Noeofseen&§num) ? 2:1);
1890: gotnak:
1891: switch (firstch) {
1892: case CAN:
1893: if(Lastrx == CAN) {
1894: cancan:
1895: logent("Cancelled\n"); return ERROR;
1896: }
1897: break;
1898: case TIMEOUT:
1899: logent("Timeout on sector ACK\n"); continue;
1900: case WANTCRC:
1901: if (firstsec)
1902: Crcflg = TRUE;
1903: case NAK:
1904: logent("NAK on sector\n"); continue;
1905: case ACK:
1906: firstsec=FALSE;
1907: Totsecs += (cseclen>>7);
1908: return OK;
1909: case ERROR:
1910: logent("Got burst for sector ACK\n"); break;
1911: default:
1912: logent("Got %02x for sector ACK\n", firstch); break;
1913: }
1914: for (;;) {
1915: Lastrx = firstch;
1916: if ((firstch = readock(400, 2)) == TIMEOUT)
1917: break;
1918: if (firstch == NAK || firstch == WANTCRC)
1919: goto gotnak;
1920: if (firstch == CAN && Lastrx == CAN)
1921: goto cancan;
1922: }
1923: }
1924: logent("Retry Count Exceeded\n");
1925: return ERROR;
1926: }
1927:
1928:
1929: /* fill buf with count chars padding with ^Z for CPM */
1930: filbuf(buf, count)
1931: register char *buf;
1932: {
1933: register c, m;
1934: static lfseen=0;
1935:
1936: m=count;
1937: while ((c=getc(in))!=EOF) {
1938: *buf++ =c;
1939: if (--m == 0)
1940: break;
1941: }
1942: if (m==count)
1943: return (Noeofseen=0);
1944: else
1945: while (--m>=0)
1946: *buf++ = CPMEOF;
1947: return count;
1948: }
1949:
1950:
1951: alrm()
1952: {
1953: longjmp(tohere, -1);
1954: }
1955:
1956:
1957: /*
1958: * readock(timeout, count) reads character(s) from file descriptor 0
1959: * (1 <= count <= 3)
1960: * it attempts to read count characters. If it gets more than one,
1961: * it is an error unless all are CAN
1962: * (otherwise, only normal response is ACK, CAN, or C)
1963: * Only looks for one if Optiong, which signifies cbreak, not raw input
1964: *
1965: * timeout is in tenths of seconds
1966: */
1967: readock(timeout, count)
1968: {
1969: register int c;
1970: static char byt[5];
1971:
1972: if (Optiong)
1973: count = 1; /* Special hack for cbreak */
1974:
1975: fflush(stdout);
1976: if (setjmp(tohere)) {
1977: logent("TIMEOUT\n");
1978: return TIMEOUT;
1979: }
1980: c = timeout/10;
1981: if (c<2)
1982: c=2;
1983: if (Verbose>3) {
1984: fprintf(stderr, "Timeout=%d Calling alarm(%d) ", timeout, c);
1985: byt[1] = 0;
1986: }
1987: signal(SIGALRM, alrm); alarm(c);
1988: #ifdef ONEREAD
1989: c=read(iofd, byt, 1); /* regulus raw read is unique */
1990: #else
1991: c=read(iofd, byt, count);
1992: #endif
1993: alarm(0);
1994: if (Verbose>5)
1995: fprintf(stderr, "ret cnt=%d %x %x\n", c, byt[0], byt[1]);
1996: if (c<1)
1997: return TIMEOUT;
1998: if (c==1)
1999: return (byt[0]&0377);
2000: else
2001: while (c)
2002: if (byt[--c] != CAN)
2003: return ERROR;
2004: return CAN;
2005: }
2006:
2007: purgeline()
2008: {
2009: #ifdef USG
2010: ioctl(iofd, TCFLSH, 0);
2011: #else
2012: lseek(iofd, 0L, 2);
2013: #endif
2014: }
2015:
2016: /* update CRC */
2017: unsigned updcrc(c, crc)
2018: register c;
2019: register unsigned crc;
2020: {
2021: register count;
2022:
2023: for (count=8; --count>=0;) {
2024: if (crc & 0x8000) {
2025: crc <<= 1;
2026: crc += (((c<<=1) & 0400) != 0);
2027: crc ^= 0x1021;
2028: }
2029: else {
2030: crc <<= 1;
2031: crc += (((c<<=1) & 0400) != 0);
2032: }
2033: }
2034: return crc;
2035: }
2036:
2037: /* send 10 CAN's to try to get the other end to shut up */
2038: canit()
2039: {
2040: register n;
2041: for (n=10; --n>=0; )
2042: sendline(CAN);
2043: }
2044:
2045: #ifdef REGULUS
2046: /*
2047: * copies count bytes from s to d
2048: * (No structure assignment in Regulus C compiler)
2049: */
2050: movmem(s, d, count)
2051: register char *s, *d;
2052: register count;
2053: {
2054: while (--count >= 0)
2055: *d++ = *s++;
2056: }
2057: #endif
2058:
2059: /*VARARGS1*/
2060: logent(a, b, c)
2061: char *a, *b, *c;
2062: {
2063: if(Verbose)
2064: fprintf(stderr, a, b, c);
2065: }
2066:
2067: /*
2068: * return 1 iff stdout and stderr are different devices
2069: * indicating this program operating with a modem on a
2070: * different line
2071: */
2072: fromcu()
2073: {
2074: struct stat a, b;
2075: fstat(1, &a); fstat(2, &b);
2076: return (a.st_rdev != b.st_rdev);
2077: }
2078:
2079: /*
2080: * substr(string, token) searches for token in string s
2081: * returns pointer to token within string if found, NULL otherwise
2082: */
2083: char *
2084: substr(s, t)
2085: register char *s,*t;
2086: {
2087: register char *ss,*tt;
2088: /* search for first char of token */
2089: for (ss=s; *s; s++)
2090: if (*s == *t)
2091: /* compare token with substring */
2092: for (ss=s,tt=t; ;) {
2093: if (*tt == 0)
2094: return s;
2095: if (*ss++ != *tt++)
2096: break;
2097: }
2098: return NULL;
2099: }
2100:
2101: usage()
2102: {
2103: fprintf(stderr,"%s by Chuck Forsberg\n", VERSION);
2104: fprintf(stderr,"Usage: sb [-17dfkquvX] [-] file ...\n");
2105: fprintf(stderr," 1 Use stdout for all modem i/o\n");
2106: fprintf(stderr," 7 Use 7 bits only\n");
2107: fprintf(stderr," d Change '.' to '/' in pathnames\n");
2108: fprintf(stderr," f Send full pathname\n");
2109: fprintf(stderr," k Send 1024 byte packets\n");
2110: fprintf(stderr," q Quiet (no progress reports)\n");
2111: fprintf(stderr," u Unlink file after transmission\n");
2112: fprintf(stderr," v Verbose - give more information\n");
2113: fprintf(stderr," X XMODEM protocol - send no pathnames\n");
2114: fprintf(stderr,"- as pathname sends standard input, filename=sPID.sb, requires -1 flag\n");
2115: exit(1);
2116: }
2117: SHAR_EOF
2118: cat << \SHAR_EOF > undos.1
2119: .TH UNDOS 1 OMEN
2120: .SH NAME
2121: undos,tounix,todos,tocpm,tomac,unmac \- Change file format for target operating system
2122: .SH SYNOPSIS
2123: .B undos
2124: [
2125: .B -s
2126: ]
2127: file ...
2128: .br
2129: .B tounix
2130: [
2131: .B -s
2132: ]
2133: file ...
2134: .br
2135: .B todos
2136: [
2137: .B -s
2138: ]
2139: file ...
2140: .br
2141: .B tocpm
2142: [
2143: .B -s
2144: ]
2145: file ...
2146: .br
2147: .B unmac
2148: [
2149: .B -s
2150: ]
2151: file ...
2152: .br
2153: .B tomac
2154: [
2155: .B -s
2156: ]
2157: file ...
2158: .SH DESCRIPTION
2159: .B Undos
2160: and
2161: .B tounix
2162: convert DOS or CP/M format source files to Unix format by deleting
2163: carriage returns preceding linefeeds and eliminating characters
2164: starting with CPMEOF (^Z).
2165: .PP
2166: .B Todos
2167: converts Unix format source files to DOS format by adding a carriage return
2168: (if not already present) before each linefeed,
2169: and eliminates characters
2170: starting with CPMEOF (^Z).
2171: .B Tocpm
2172: additionally appends CPMEOF (^Z) characters to the resulting file
2173: to make the file length a multiple of the 128 byte CP/M record length.
2174:
2175: Any combination of
2176: .B undos, todos,
2177: or
2178: .B tocpm
2179: (without flags)
2180: may be applied to a proper ASCII
2181: file without destroying information.
2182: Lone carriage returns used to force overprinting are not translated
2183: to CR/LF pairs.
2184:
2185: .B Unmac
2186: converts files with lines terminated only by carriage return
2187: to Unix format.
2188: .B Unmac
2189: should only be used to translate files whose lines are terminated
2190: by lone carriage returns.
2191:
2192: .B Tomac
2193: converts Unix format files to Macintosh format
2194: (lines terminated by carriage return only).
2195:
2196: The optional flag
2197: .B -s
2198: Strips the parity bit on all characters
2199: and discards all resulting characters with values less than 7.
2200:
2201: The access and modification times of the modified files are set
2202: to those of the original files.
2203: .SH DIAGNOSTICS
2204: Refuses to translate files in which "binary" characters (less than 7
2205: or greater than 127) are seen before CPMEOF.
2206: Refuses to translate files
2207: with ultra long lines.
2208: Refuses to translate special files.
2209: .SH NOTES
2210: Should be executed with the current directory in the same filesystem
2211: as the target files for minimum disk i/o.
2212: .SH BUGS
2213: Does not detect short files without linefeeds.
2214: .B Unmac
2215: and
2216: .B tomac
2217: cannot handle files with CR-only overprinting.
2218: (Files whose lines end with CR only violate the ASCII code!).
2219: .SH SEE ALSO
2220: lar(1), yam(1), sq(1), usq(1), rb(omen), sb(omen)
2221: SHAR_EOF
2222: cat << \SHAR_EOF > undos.c
2223: /*% cc -O -K % -o undos
2224: *
2225: * Undos - change DOS format files to Unix, etc.
2226: */
2227: char ID[] =
2228: "Undos Rev 12-07-85 (C)Copyright Omen Technology Inc All Rights Reserved\n";
2229: /*
2230: * This program and documentation may be copied, used, or modified
2231: * by Professional-YAM and POWERCOMM licensees provided these notices are
2232: * not removed. Others may use this program for non-profit purposes only.
2233: */
2234:
2235: #include <stdio.h>
2236: #include <sys/types.h>
2237: #include <sys/stat.h>
2238:
2239: #define LL 1024
2240: #define SUB 032
2241:
2242: char Lbuf[LL];
2243: char *Progname;
2244: int Todos = 0;
2245: int Tocpm = 0;
2246: int Tomac = 0;
2247: int Unmac = 0;
2248: int Strip = 0;
2249:
2250: main(argc, argv)
2251: char **argv;
2252: {
2253: Progname = *argv;
2254: if (! strcmp(Progname, "tocpm"))
2255: Todos = Tocpm = 1;
2256: if (! strcmp(Progname, "todos"))
2257: Todos = 1;
2258: if (! strcmp(Progname, "unmac"))
2259: Unmac = 1;
2260: if (! strcmp(Progname, "tomac"))
2261: Tomac = 1;
2262:
2263: if (! strcmp(argv[1], "-s")) {
2264: ++Strip; --argc; ++argv;
2265: }
2266:
2267:
2268: if (argc<2 || *argv[1]== '-')
2269: usage();
2270: while (--argc >= 1)
2271: chngfmt(*++argv);
2272: exit(0);
2273: }
2274: usage()
2275: {
2276: fprintf(stderr, ID);
2277: fprintf(stderr, "Usage: {undos|tounix|todos|tocpm|unmac} [-s] file ...\n");
2278: fprintf(stderr, " -s Strip parity bit, ignore bytes < 007\n");
2279: exit(1);
2280: }
2281:
2282:
2283: chngfmt(name)
2284: char *name;
2285: {
2286: register c;
2287: register char *p;
2288: register n;
2289: register long fpos;
2290: struct stat st;
2291: FILE *fin, *fout;
2292: int linno = 0;
2293: long ftell();
2294: char *mktemp();
2295: char outnam[64];
2296:
2297: if (stat(name, &st)) {
2298: xperror(name); return;
2299: }
2300: if ((st.st_mode & S_IFMT) != S_IFREG) {
2301: fprintf(stderr, "%s: %s is not a regular file\n", Progname, name);
2302: return;
2303: }
2304: if ((fin = fopen(name, "r")) == NULL) {
2305: xperror(name); return;
2306: }
2307: strcpy(outnam, "undosXXXXXX");
2308: mktemp(outnam);
2309: if ((fout = fopen(outnam, "w")) == NULL) {
2310: xperror(outnam); exit(1);
2311: }
2312:
2313: for (;;) {
2314: ++linno;
2315: for (p=Lbuf, n=LL; --n>0; ) {
2316: ignore:
2317: if ((c = getc(fin)) == EOF)
2318: break;
2319: if ( !c)
2320: goto ignore;
2321: if (c < '\7' || (c & 0200)) {
2322: if (Strip) {
2323: if ((c &= 0177) < 7)
2324: goto ignore;
2325: } else
2326: goto thisbin;
2327: }
2328: if (c == SUB)
2329: break;
2330: if (c == '\r' && Unmac)
2331: c = '\n';
2332: *p++ = c;
2333: if (c == '\n')
2334: break;
2335: }
2336: *p = '\0';
2337:
2338: if (n == 0) {
2339: thisbin:
2340: if (n) {
2341: fprintf(stderr, "%s: %s is a binary file", Progname, name);
2342: fprintf(stderr, " line=%d char =%2X\n", linno, c);
2343: } else
2344: fprintf(stderr, "%s: %s has no linefeeds: try unmac?\n", Progname, name);
2345: fclose(fout);
2346: unlink(outnam);
2347: return;
2348: }
2349:
2350: if (Todos) {
2351: if (*--p == '\n' && p[-1] != '\r') {
2352: *p++ = '\r'; *p++ = '\n'; *p = 0;
2353: }
2354: } else if (Tomac) {
2355: if (*--p == '\n') {
2356: if (p[-1] == '\r')
2357: --p;
2358: *p++ = '\r'; *p = 0;
2359: }
2360: } else {
2361: if (*--p == '\n' && *--p == '\r') {
2362: *p++ = '\n'; *p = 0;
2363: }
2364: }
2365: if (fputs(Lbuf, fout) == EOF) {
2366: xperror(outnam); exit(1);
2367: }
2368: switch (c) {
2369: case EOF:
2370: if (ferror(fin)) {
2371: xperror(name); exit(0200);
2372: }
2373: case SUB:
2374: if (Tocpm) {
2375: fpos = ftell(fout);
2376: do {
2377: putc(SUB, fout);
2378: } while (++fpos & 127);
2379: }
2380: fclose(fout); fclose(fin);
2381: if (st.st_nlink > 1)
2382: sprintf(Lbuf, "cp %s %s", outnam, name);
2383: else
2384: sprintf(Lbuf, "mv %s %s", outnam, name);
2385: system(Lbuf);
2386: utime(name, (struct utimbuf *) &st.st_atime);
2387: if (st.st_nlink > 1)
2388: unlink(outnam);
2389: return;
2390: }
2391: }
2392: }
2393:
2394: xperror(s)
2395: char *s;
2396: {
2397: register char *p;
2398: extern int sys_nerr;
2399: extern char *sys_errlist[];
2400: extern errno;
2401:
2402: if (errno >= sys_nerr)
2403: p = "Gloryovsky: a New Error!";
2404: else
2405: p = sys_errlist[errno];
2406: fprintf(stderr, "%s: %s: %s\n", Progname, s, p);
2407: }
2408: SHAR_EOF
2409: # End of shell archive
2410: exit 0
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.