1: #define VERSION "3.02 6-04-89"
2: #define PUBDIR "/usr/spool/uucppublic"
3:
4: /*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz;
5: <-xtx-*> cc386 -Ox -DMD rz.c -o $B/rz; size $B/rz
6: *
7: * rz.c By Chuck Forsberg
8: *
9: * cc -O rz.c -o rz USG (3.0) Unix
10: * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3
11: *
12: * ln rz rb; ln rz rx For either system
13: *
14: * ln rz /usr/bin/rzrmail For remote mail. Make this the
15: * login shell. rzrmail then calls
16: * rmail(1) to deliver mail.
17: *
18: * To compile on VMS:
19: *
20: * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB
21: * cc rz.c
22: * cc vvmodem.c
23: * link rz,vvmodem
24: * rz :== $disk:[username.subdir]rz.exe
25: * For high speed, try increasing the SYSGEN parameter TTY_TYPAHDSZ to 256.
26: *
27: *
28: * Unix is a trademark of Western Electric Company
29: *
30: * A program for Unix to receive files and commands from computers running
31: * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
32: * rz uses Unix buffered input to reduce wasted CPU time.
33: *
34: *
35: * This version implements numerous enhancements including ZMODEM
36: * Run Length Encoding and variable length headers. These
37: * features were not funded by the original Telenet development
38: * contract.
39: *
40: * This software may be freely used for non commercial and
41: * educational (didactic only) purposes. This software may also
42: * be freely used to support file transfer operations to or from
43: * licensed Omen Technology products. Any programs which use
44: * part or all of this software must be provided in source form
45: * with this notice intact except by written permission from Omen
46: * Technology Incorporated.
47: *
48: * Use of this software for commercial or administrative purposes
49: * except when exclusively limited to interfacing Omen Technology
50: * products requires a per port license payment of $20.00 US per
51: * port (less in quantity). Use of this code by inclusion,
52: * decompilation, reverse engineering or any other means
53: * constitutes agreement to these conditions and acceptance of
54: * liability to license the materials and payment of reasonable
55: * legal costs necessary to enforce this license agreement.
56: *
57: *
58: * Omen Technology Inc FAX: 503-621-3745
59: * Post Office Box 4681
60: * Portland OR 97208
61: *
62: * This code is made available in the hope it will be useful,
63: * BUT WITHOUT ANY WARRANTY OF ANY KIND OR LIABILITY FOR ANY
64: * DAMAGES OF ANY KIND.
65: *
66: *
67: *
68: * Iff the program is invoked by rzCOMMAND, output is piped to
69: * "COMMAND filename" (Unix only)
70: *
71: * Some systems (Venix, Coherent, Regulus) may not support tty raw mode
72: * read(2) the same way as Unix. ONEREAD must be defined to force one
73: * character reads for these systems. Added 7-01-84 CAF
74: *
75: * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF
76: *
77: * BIX added 6-30-87 to support BIX(TM) upload protocol used by the
78: * Byte Information Exchange.
79: *
80: * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
81: * doesn't work properly (even though it compiles without error!),
82: *
83: * SEGMENTS=n added 2-21-88 as a model for CP/M programs
84: * for CP/M-80 systems that cannot overlap modem and disk I/O.
85: *
86: * VMS flavor hacks begin with rz version 2.00
87: *
88: * -DMD may be added to compiler command line to compile in
89: * Directory-creating routines from Public Domain TAR by John Gilmore
90: *
91: * HOWMANY may be tuned for best performance
92: *
93: * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
94: */
95:
96: #ifdef vax11c
97: #include <types.h>
98: #include <stat.h>
99: #define LOGFILE "rzlog.tmp"
100: #include <stdio.h>
101: #include <signal.h>
102: #include <setjmp.h>
103: #include <ctype.h>
104: #include <errno.h>
105: #define OS "VMS"
106: #define BUFREAD
107: extern int errno;
108: #define SS_NORMAL SS$_NORMAL
109:
110: #ifndef PROGNAME
111: #define PROGNAME "rz"
112: #endif
113:
114:
115: #else
116:
117:
118: #define SS_NORMAL 0
119: #define LOGFILE "/tmp/rzlog"
120: #include <stdio.h>
121: #include <signal.h>
122: #include <setjmp.h>
123: #include <ctype.h>
124: #include <errno.h>
125: extern int errno;
126: FILE *popen();
127: #endif
128:
129: #define OK 0
130: #define FALSE 0
131: #define TRUE 1
132: #define ERROR (-1)
133:
134: /*
135: * Max value for HOWMANY is 255.
136: * A larger value reduces system overhead but may evoke kernel bugs.
137: * 133 corresponds to an XMODEM/CRC sector
138: */
139: #ifndef HOWMANY
140: #define HOWMANY 133
141: #endif
142:
143: /* Ward Christensen / CP/M parameters - Don't change these! */
144: #define ENQ 005
145: #define CAN ('X'&037)
146: #define XOFF ('s'&037)
147: #define XON ('q'&037)
148: #define SOH 1
149: #define STX 2
150: #define EOT 4
151: #define ACK 6
152: #define NAK 025
153: #define CPMEOF 032
154: #define WANTCRC 0103 /* send C not NAK to get crc not checksum */
155: #define TIMEOUT (-2)
156: #define RCDO (-3)
157: #define GCOUNT (-4)
158: #define ERRORMAX 5
159: #define RETRYMAX 5
160: #define WCEOT (-10)
161: #define PATHLEN 257 /* ready for 4.2 bsd ? */
162: #define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */
163:
164: int Zmodem=0; /* ZMODEM protocol requested */
165: int Nozmodem = 0; /* If invoked as "rb" */
166: unsigned Baudrate = 2400;
167: unsigned Effbaud = 2400;
168: #ifdef vax11c
169: #include "vrzsz.c" /* most of the system dependent stuff here */
170: #else
171: #include "rbsb.c" /* most of the system dependent stuff here */
172: #endif
173: #include "crctab.c"
174:
175: char *substr();
176: FILE *fout;
177:
178: /*
179: * Routine to calculate the free bytes on the current file system
180: * ~0 means many free bytes (unknown)
181: */
182: long getfree()
183: {
184: return(~0L); /* many free bytes ... */
185: }
186:
187: int Lastrx;
188: int Crcflg;
189: int Firstsec;
190: int Eofseen; /* indicates cpm eof (^Z) has been received */
191: int errors;
192: int Restricted=0; /* restricted; no /.. or ../ in filenames */
193: #ifdef ONEREAD
194: /* Sorry, Regulus and some others don't work right in raw mode! */
195: int Readnum = 1; /* Number of bytes to ask for in read() from modem */
196: #else
197: int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */
198: #endif
199:
200: #define DEFBYTL 2000000000L /* default rx file size */
201: long Bytesleft; /* number of bytes of incoming file left */
202: long Modtime; /* Unix style mod time for incoming file */
203: int Filemode; /* Unix style mode for incoming file */
204: char Pathname[PATHLEN];
205: char *Progname; /* the name by which we were called */
206:
207: int Batch=0;
208: int Topipe=0;
209: int MakeLCPathname=TRUE; /* make received pathname lower case */
210: int Verbose=0;
211: int Quiet=0; /* overrides logic that would otherwise set verbose */
212: int Nflag = 0; /* Don't really transfer files */
213: int Rxclob=FALSE; /* Clobber existing file */
214: int Rxbinary=FALSE; /* receive all files in bin mode */
215: int Rxascii=FALSE; /* receive files in ascii (translate) mode */
216: int Thisbinary; /* current file is to be received in bin mode */
217: int Blklen; /* record length of received packets */
218:
219: #ifdef SEGMENTS
220: int chinseg = 0; /* Number of characters received in this data seg */
221: char secbuf[1+(SEGMENTS+1)*1024];
222: #else
223: char secbuf[1025];
224: #endif
225:
226:
227: char linbuf[HOWMANY];
228: int Lleft=0; /* number of characters in linbuf */
229: time_t timep[2];
230: char Lzmanag; /* Local file management request */
231: char zconv; /* ZMODEM file conversion request */
232: char zmanag; /* ZMODEM file management request */
233: char ztrans; /* ZMODEM file transport request */
234: int Zctlesc; /* Encode control characters */
235: int Zrwindow = 1400; /* RX window size (controls garbage count) */
236:
237: jmp_buf tohere; /* For the interrupt on RX timeout */
238:
239: #define xsendline(c) sendline(c)
240:
241: #include "zm.c"
242:
243: #include "zmr.c"
244:
245: int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */
246:
247: alrm()
248: {
249: longjmp(tohere, -1);
250: }
251:
252: /* called by signal interrupt or terminate to clean things up */
253: bibi(n)
254: {
255: if (Zmodem)
256: zmputs(Attn);
257: canit(); mode(0);
258: fprintf(stderr, "rz: caught signal %d; exiting", n);
259: cucheck();
260: exit(128+n);
261: }
262:
263: main(argc, argv)
264: char *argv[];
265: {
266: register char *cp;
267: register npats;
268: char *virgin, **patts;
269: char *getenv();
270: int exitcode;
271:
272: Rxtimeout = 100;
273: setbuf(stderr, NULL);
274: if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
275: Restricted=TRUE;
276:
277: from_cu();
278: #ifdef vax11c
279: chkinvok(virgin = PROGNAME);
280: #else
281: chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */
282: #endif
283: npats = 0;
284: while (--argc) {
285: cp = *++argv;
286: if (*cp == '-') {
287: while( *++cp) {
288: switch(*cp) {
289: case '\\':
290: cp[1] = toupper(cp[1]); continue;
291: case '+':
292: Lzmanag = ZMAPND; break;
293: case 'a':
294: Rxascii=TRUE; break;
295: case 'b':
296: Rxbinary=TRUE; break;
297: case 'c':
298: Crcflg=TRUE; break;
299: #ifndef vax11c
300: case 'D':
301: Nflag = TRUE; break;
302: #endif
303: case 'e':
304: Zctlesc = 1; break;
305: case 'p':
306: Lzmanag = ZMPROT; break;
307: case 'q':
308: Quiet=TRUE; Verbose=0; break;
309: case 't':
310: if (--argc < 1) {
311: usage();
312: }
313: Rxtimeout = atoi(*++argv);
314: if (Rxtimeout<10 || Rxtimeout>1000)
315: usage();
316: break;
317: case 'w':
318: if (--argc < 1) {
319: usage();
320: }
321: Zrwindow = atoi(*++argv);
322: break;
323: case 'u':
324: MakeLCPathname=FALSE; break;
325: case 'v':
326: ++Verbose; break;
327: case 'y':
328: Rxclob=TRUE; break;
329: default:
330: usage();
331: }
332: }
333: }
334: else if ( !npats && argc>0) {
335: if (argv[0][0]) {
336: npats=argc;
337: patts=argv;
338: }
339: }
340: }
341: if (npats > 1)
342: usage();
343: if (Batch && npats)
344: usage();
345: if (Verbose) {
346: if (freopen(LOGFILE, "a", stderr)==NULL) {
347: printf("Can't open log file %s\n",LOGFILE);
348: exit(0200);
349: }
350: setbuf(stderr, NULL);
351: fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
352: }
353: if (Fromcu && !Quiet) {
354: if (Verbose == 0)
355: Verbose = 2;
356: }
357: vfile("%s %s for %s\n", Progname, VERSION, OS);
358: mode(1);
359: if (signal(SIGINT, bibi) == SIG_IGN) {
360: signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
361: }
362: else {
363: signal(SIGINT, bibi); signal(SIGKILL, bibi);
364: }
365: signal(SIGTERM, bibi);
366: if (wcreceive(npats, patts)==ERROR) {
367: exitcode=0200;
368: canit();
369: }
370: mode(0);
371: if (exitcode && !Zmodem) /* bellow again with all thy might. */
372: canit();
373: if (exitcode)
374: cucheck();
375: exit(exitcode ? exitcode:SS_NORMAL);
376: }
377:
378:
379: usage()
380: {
381: cucheck();
382: fprintf(stderr,"Usage: rz [-abeuvy] (ZMODEM)\n");
383: fprintf(stderr,"or rb [-abuvy] (YMODEM)\n");
384: fprintf(stderr,"or rx [-abcv] file (XMODEM or XMODEM-1k)\n");
385: fprintf(stderr," -a ASCII transfer (strip CR)\n");
386: fprintf(stderr," -b Binary transfer for all files\n");
387: #ifndef vax11c
388: fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n");
389: #endif
390: fprintf(stderr," -e Escape control characters (ZMODEM)\n");
391: fprintf(stderr," -v Verbose more v's give more info\n");
392: fprintf(stderr," -y Yes, clobber existing file if any\n");
393: fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
394: Progname, VERSION, OS);
395: fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
396: exit(SS_NORMAL);
397: }
398: /*
399: * Debugging information output interface routine
400: */
401: /* VARARGS1 */
402: vfile(f, a, b, c, d)
403: long a, b, c, d;
404: {
405: if (Verbose > 2) {
406: fprintf(stderr, f, a, b, c, d);
407: fprintf(stderr, "\n");
408: }
409: }
410:
411: /*
412: * Let's receive something already.
413: */
414:
415: char *rbmsg =
416: "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
417:
418: wcreceive(argc, argp)
419: char **argp;
420: {
421: register c;
422:
423: if (Batch || argc==0) {
424: Crcflg=1;
425: if ( !Quiet)
426: fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
427: if (c=tryz()) {
428: if (c == ZCOMPL)
429: return OK;
430: if (c == ERROR)
431: goto fubar;
432: c = rzfiles();
433: if (c)
434: goto fubar;
435: } else {
436: for (;;) {
437: if (wcrxpn(secbuf)== ERROR)
438: goto fubar;
439: if (secbuf[0]==0)
440: return OK;
441: if (procheader(secbuf) == ERROR)
442: goto fubar;
443: if (wcrx()==ERROR)
444: goto fubar;
445: }
446: }
447: } else {
448: Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
449:
450: procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
451: fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
452: if ((fout=fopen(Pathname, "w")) == NULL)
453: return ERROR;
454: if (wcrx()==ERROR)
455: goto fubar;
456: }
457: return OK;
458: fubar:
459: canit();
460: #ifndef vax11c
461: if (Topipe && fout) {
462: pclose(fout); return ERROR;
463: }
464: #endif
465: Modtime = 1;
466: if (fout)
467: fclose(fout);
468: #ifndef vax11c
469: if (Restricted) {
470: unlink(Pathname);
471: fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
472: }
473: #endif
474: return ERROR;
475: }
476:
477:
478: /*
479: * Fetch a pathname from the other end as a C ctyle ASCIZ string.
480: * Length is indeterminate as long as less than Blklen
481: * A null string represents no more files (YMODEM)
482: */
483: wcrxpn(rpn)
484: char *rpn; /* receive a pathname */
485: {
486: register c;
487:
488: #ifdef NFGVMIN
489: readline(1);
490: #else
491: purgeline();
492: #endif
493:
494: et_tu:
495: Firstsec=TRUE; Eofseen=FALSE;
496: sendline(Crcflg?WANTCRC:NAK);
497: Lleft=0; /* Do read next time ... */
498: while ((c = wcgetsec(rpn, 100)) != 0) {
499: if (c == WCEOT) {
500: zperr( "Pathname fetch returned %d", c);
501: sendline(ACK);
502: Lleft=0; /* Do read next time ... */
503: readline(1);
504: goto et_tu;
505: }
506: return ERROR;
507: }
508: sendline(ACK);
509: return OK;
510: }
511:
512: /*
513: * Adapted from CMODEM13.C, written by
514: * Jack M. Wierda and Roderick W. Hart
515: */
516:
517: wcrx()
518: {
519: register int sectnum, sectcurr;
520: register char sendchar;
521: register char *p;
522: int cblklen; /* bytes to dump this block */
523:
524: Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
525: sendchar=Crcflg?WANTCRC:NAK;
526:
527: for (;;) {
528: sendline(sendchar); /* send it now, we're ready! */
529: Lleft=0; /* Do read next time ... */
530: sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
531: report(sectcurr);
532: if (sectcurr==(sectnum+1 &0377)) {
533: sectnum++;
534: cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
535: if (putsec(secbuf, cblklen)==ERROR)
536: return ERROR;
537: if ((Bytesleft-=cblklen) < 0)
538: Bytesleft = 0;
539: sendchar=ACK;
540: }
541: else if (sectcurr==(sectnum&0377)) {
542: zperr( "Received dup Sector");
543: sendchar=ACK;
544: }
545: else if (sectcurr==WCEOT) {
546: if (closeit())
547: return ERROR;
548: sendline(ACK);
549: Lleft=0; /* Do read next time ... */
550: return OK;
551: }
552: else if (sectcurr==ERROR)
553: return ERROR;
554: else {
555: zperr( "Sync Error");
556: return ERROR;
557: }
558: }
559: }
560:
561: /*
562: * Wcgetsec fetches a Ward Christensen type sector.
563: * Returns sector number encountered or ERROR if valid sector not received,
564: * or CAN CAN received
565: * or WCEOT if eot sector
566: * time is timeout for first char, set to 4 seconds thereafter
567: ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
568: * (Caller must do that when he is good and ready to get next sector)
569: */
570:
571: wcgetsec(rxbuf, maxtime)
572: char *rxbuf;
573: int maxtime;
574: {
575: register checksum, wcj, firstch;
576: register unsigned short oldcrc;
577: register char *p;
578: int sectcurr;
579:
580: for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
581:
582: if ((firstch=readline(maxtime))==STX) {
583: Blklen=1024; goto get2;
584: }
585: if (firstch==SOH) {
586: Blklen=128;
587: get2:
588: sectcurr=readline(1);
589: if ((sectcurr+(oldcrc=readline(1)))==0377) {
590: oldcrc=checksum=0;
591: for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
592: if ((firstch=readline(1)) < 0)
593: goto bilge;
594: oldcrc=updcrc(firstch, oldcrc);
595: checksum += (*p++ = firstch);
596: }
597: if ((firstch=readline(1)) < 0)
598: goto bilge;
599: if (Crcflg) {
600: oldcrc=updcrc(firstch, oldcrc);
601: if ((firstch=readline(1)) < 0)
602: goto bilge;
603: oldcrc=updcrc(firstch, oldcrc);
604: if (oldcrc & 0xFFFF)
605: zperr( "CRC");
606: else {
607: Firstsec=FALSE;
608: return sectcurr;
609: }
610: }
611: else if (((checksum-firstch)&0377)==0) {
612: Firstsec=FALSE;
613: return sectcurr;
614: }
615: else
616: zperr( "Checksum");
617: }
618: else
619: zperr("Sector number garbled");
620: }
621: /* make sure eot really is eot and not just mixmash */
622: #ifdef NFGVMIN
623: else if (firstch==EOT && readline(1)==TIMEOUT)
624: return WCEOT;
625: #else
626: else if (firstch==EOT && Lleft==0)
627: return WCEOT;
628: #endif
629: else if (firstch==CAN) {
630: if (Lastrx==CAN) {
631: zperr( "Sender CANcelled");
632: return ERROR;
633: } else {
634: Lastrx=CAN;
635: continue;
636: }
637: }
638: else if (firstch==TIMEOUT) {
639: if (Firstsec)
640: goto humbug;
641: bilge:
642: zperr( "TIMEOUT");
643: }
644: else
645: zperr( "Got 0%o sector header", firstch);
646:
647: humbug:
648: Lastrx=0;
649: while(readline(1)!=TIMEOUT)
650: ;
651: if (Firstsec) {
652: sendline(Crcflg?WANTCRC:NAK);
653: Lleft=0; /* Do read next time ... */
654: } else {
655: maxtime=40; sendline(NAK);
656: Lleft=0; /* Do read next time ... */
657: }
658: }
659: /* try to stop the bubble machine. */
660: canit();
661: return ERROR;
662: }
663:
664: #ifndef vax11c
665: /*
666: * This version of readline is reasoably well suited for
667: * reading many characters.
668: * (except, currently, for the Regulus version!)
669: *
670: * timeout is in tenths of seconds
671: */
672: readline(timeout)
673: int timeout;
674: {
675: register n;
676: static char *cdq; /* pointer for removing chars from linbuf */
677:
678: if (--Lleft >= 0) {
679: if (Verbose > 8) {
680: fprintf(stderr, "%02x ", *cdq&0377);
681: }
682: return (*cdq++ & 0377);
683: }
684: n = timeout/10;
685: if (n < 2)
686: n = 3;
687: if (Verbose > 5)
688: fprintf(stderr, "Calling read: alarm=%d Readnum=%d ",
689: n, Readnum);
690: if (setjmp(tohere)) {
691: #ifdef TIOCFLUSH
692: /* ioctl(0, TIOCFLUSH, 0); */
693: #endif
694: Lleft = 0;
695: if (Verbose>1)
696: fprintf(stderr, "Readline:TIMEOUT\n");
697: return TIMEOUT;
698: }
699: signal(SIGALRM, alrm); alarm(n);
700: Lleft=read(0, cdq=linbuf, Readnum);
701: alarm(0);
702: if (Verbose > 5) {
703: fprintf(stderr, "Read returned %d bytes\n", Lleft);
704: }
705: if (Lleft < 1)
706: return TIMEOUT;
707: --Lleft;
708: if (Verbose > 8) {
709: fprintf(stderr, "%02x ", *cdq&0377);
710: }
711: return (*cdq++ & 0377);
712: }
713:
714:
715:
716: /*
717: * Purge the modem input queue of all characters
718: */
719: purgeline()
720: {
721: Lleft = 0;
722: #ifdef USG
723: ioctl(0, TCFLSH, 0);
724: #else
725: lseek(0, 0L, 2);
726: #endif
727: }
728: #endif
729:
730:
731: /*
732: * Process incoming file information header
733: */
734: (name)
735: char *name;
736: {
737: register char *openmode, *p, **pp;
738:
739: /* set default parameters and overrides */
740: openmode = "w";
741: Thisbinary = (!Rxascii) || Rxbinary;
742: if (Lzmanag)
743: zmanag = Lzmanag;
744:
745: /*
746: * Process ZMODEM remote file management requests
747: */
748: if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */
749: Thisbinary = 0;
750: if (zconv == ZCBIN) /* Remote Binary override */
751: Thisbinary = TRUE;
752: else if (zmanag == ZMAPND)
753: openmode = "a";
754:
755: #ifndef BIX
756: /* Check for existing file */
757: if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
758: fclose(fout); return ERROR;
759: }
760: #endif
761:
762: Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
763:
764: p = name + 1 + strlen(name);
765: if (*p) { /* file coming from Unix or DOS system */
766: sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
767: #ifndef vax11c
768: if (Filemode & UNIXFILE)
769: ++Thisbinary;
770: #endif
771: if (Verbose) {
772: fprintf(stderr, "Incoming: %s %ld %lo %o\n",
773: name, Bytesleft, Modtime, Filemode);
774: }
775: }
776:
777: #ifdef BIX
778: if ((fout=fopen("scratchpad", openmode)) == NULL)
779: return ERROR;
780: return OK;
781: #else
782:
783: else { /* File coming from CP/M system */
784: for (p=name; *p; ++p) /* change / to _ */
785: if ( *p == '/')
786: *p = '_';
787:
788: if ( *--p == '.') /* zap trailing period */
789: *p = 0;
790: }
791:
792: #ifndef vax11c
793: if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
794: && !(Filemode&UNIXFILE))
795: uncaps(name);
796: #endif
797: if (Topipe > 0) {
798: sprintf(Pathname, "%s %s", Progname+2, name);
799: if (Verbose)
800: fprintf(stderr, "Topipe: %s %s\n",
801: Pathname, Thisbinary?"BIN":"ASCII");
802: #ifndef vax11c
803: if ((fout=popen(Pathname, "w")) == NULL)
804: return ERROR;
805: #endif
806: } else {
807: strcpy(Pathname, name);
808: if (Verbose) {
809: fprintf(stderr, "Receiving %s %s %s\n",
810: name, Thisbinary?"BIN":"ASCII", openmode);
811: }
812: checkpath(name);
813: if (Nflag)
814: name = "/dev/null";
815: #ifndef vax11c
816: if (name[0] == '!' || name[0] == '|') {
817: if ( !(fout = popen(name+1, "w"))) {
818: return ERROR;
819: }
820: Topipe = -1; return(OK);
821: }
822: #endif
823: #ifdef MD
824: fout = fopen(name, openmode);
825: if ( !fout)
826: if (make_dirs(name))
827: fout = fopen(name, openmode);
828: #else
829: fout = fopen(name, openmode);
830: #endif
831: if ( !fout)
832: return ERROR;
833: }
834: return OK;
835: #endif /* BIX */
836: }
837:
838: #ifdef MD
839: /*
840: * Directory-creating routines from Public Domain TAR by John Gilmore
841: */
842:
843: /*
844: * After a file/link/symlink/dir creation has failed, see if
845: * it's because some required directory was not present, and if
846: * so, create all required dirs.
847: */
848: make_dirs(pathname)
849: register char *pathname;
850: {
851: register char *p; /* Points into path */
852: int madeone = 0; /* Did we do anything yet? */
853: int save_errno = errno; /* Remember caller's errno */
854: char *strchr();
855:
856: if (errno != ENOENT)
857: return 0; /* Not our problem */
858:
859: for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
860: /* Avoid mkdir of empty string, if leading or double '/' */
861: if (p == pathname || p[-1] == '/')
862: continue;
863: /* Avoid mkdir where last part of path is '.' */
864: if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
865: continue;
866: *p = 0; /* Truncate the path there */
867: if ( !mkdir(pathname, 0777)) { /* Try to create it as a dir */
868: vfile("Made directory %s\n", pathname);
869: madeone++; /* Remember if we made one */
870: *p = '/';
871: continue;
872: }
873: *p = '/';
874: if (errno == EEXIST) /* Directory already exists */
875: continue;
876: /*
877: * Some other error in the mkdir. We return to the caller.
878: */
879: break;
880: }
881: errno = save_errno; /* Restore caller's errno */
882: return madeone; /* Tell them to retry if we made one */
883: }
884:
885: #if (MD != 2)
886: #define TERM_SIGNAL(status) ((status) & 0x7F)
887: #define TERM_COREDUMP(status) (((status) & 0x80) != 0)
888: #define TERM_VALUE(status) ((status) >> 8)
889: /*
890: * Make a directory. Compatible with the mkdir() system call on 4.2BSD.
891: */
892: mkdir(dpath, dmode)
893: char *dpath;
894: int dmode;
895: {
896: int cpid, status;
897: struct stat statbuf;
898:
899: if (stat(dpath,&statbuf) == 0) {
900: errno = EEXIST; /* Stat worked, so it already exists */
901: return -1;
902: }
903:
904: /* If stat fails for a reason other than non-existence, return error */
905: if (errno != ENOENT) return -1;
906:
907: switch (cpid = fork()) {
908:
909: case -1: /* Error in fork() */
910: return(-1); /* Errno is set already */
911:
912: case 0: /* Child process */
913: /*
914: * Cheap hack to set mode of new directory. Since this
915: * child process is going away anyway, we zap its umask.
916: * FIXME, this won't suffice to set SUID, SGID, etc. on this
917: * directory. Does anybody care?
918: */
919: status = umask(0); /* Get current umask */
920: status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
921: execl("/bin/mkdir", "mkdir", dpath, (char *)0);
922: _exit(-1); /* Can't exec /bin/mkdir */
923:
924: default: /* Parent process */
925: while (cpid != wait(&status)) ; /* Wait for kid to finish */
926: }
927:
928: if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
929: errno = EIO; /* We don't know why, but */
930: return -1; /* /bin/mkdir failed */
931: }
932:
933: return 0;
934: }
935: #endif /* MD != 2 */
936: #endif /* MD */
937:
938: /*
939: * Putsec writes the n characters of buf to receive file fout.
940: * If not in binary mode, carriage returns, and all characters
941: * starting with CPMEOF are discarded.
942: */
943: putsec(buf, n)
944: char *buf;
945: register n;
946: {
947: register char *p;
948:
949: if (n == 0)
950: return OK;
951: if (Thisbinary) {
952: for (p=buf; --n>=0; )
953: putc( *p++, fout);
954: }
955: else {
956: if (Eofseen)
957: return OK;
958: for (p=buf; --n>=0; ++p ) {
959: if ( *p == '\r')
960: continue;
961: if (*p == CPMEOF) {
962: Eofseen=TRUE; return OK;
963: }
964: putc(*p ,fout);
965: }
966: }
967: return OK;
968: }
969:
970: #ifndef vax11c
971: /*
972: * Send a character to modem. Small is beautiful.
973: */
974: sendline(c)
975: {
976: char d;
977:
978: d = c;
979: if (Verbose>6)
980: fprintf(stderr, "Sendline: %x\n", c);
981: write(1, &d, 1);
982: }
983:
984: flushmo() {}
985: #endif
986:
987:
988:
989:
990:
991: /* make string s lower case */
992: uncaps(s)
993: register char *s;
994: {
995: for ( ; *s; ++s)
996: if (isupper(*s))
997: *s = tolower(*s);
998: }
999: /*
1000: * IsAnyLower returns TRUE if string s has lower case letters.
1001: */
1002: IsAnyLower(s)
1003: register char *s;
1004: {
1005: for ( ; *s; ++s)
1006: if (islower(*s))
1007: return TRUE;
1008: return FALSE;
1009: }
1010:
1011: /*
1012: * substr(string, token) searches for token in string s
1013: * returns pointer to token within string if found, NULL otherwise
1014: */
1015: char *
1016: substr(s, t)
1017: register char *s,*t;
1018: {
1019: register char *ss,*tt;
1020: /* search for first char of token */
1021: for (ss=s; *s; s++)
1022: if (*s == *t)
1023: /* compare token with substring */
1024: for (ss=s,tt=t; ;) {
1025: if (*tt == 0)
1026: return s;
1027: if (*ss++ != *tt++)
1028: break;
1029: }
1030: return NULL;
1031: }
1032:
1033: /*
1034: * Log an error
1035: */
1036: /*VARARGS1*/
1037: zperr(s,p,u)
1038: char *s, *p, *u;
1039: {
1040: if (Verbose <= 0)
1041: return;
1042: fprintf(stderr, "Retry %d: ", errors);
1043: fprintf(stderr, s, p, u);
1044: fprintf(stderr, "\n");
1045: }
1046:
1047: /* send cancel string to get the other end to shut up */
1048: canit()
1049: {
1050: static char canistr[] = {
1051: 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
1052: };
1053:
1054: #ifdef vax11c
1055: raw_wbuf(strlen(canistr), canistr);
1056: purgeline();
1057: #else
1058: printf(canistr);
1059: Lleft=0; /* Do read next time ... */
1060: fflush(stdout);
1061: #endif
1062: }
1063:
1064:
1065: report(sct)
1066: int sct;
1067: {
1068: if (Verbose>1)
1069: fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
1070: }
1071:
1072: /*
1073: * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
1074: * If called as [-][dir/../]rzCOMMAND set the pipe flag
1075: * If called as rb use YMODEM protocol
1076: */
1077: chkinvok(s)
1078: char *s;
1079: {
1080: register char *p;
1081:
1082: p = s;
1083: while (*p == '-')
1084: s = ++p;
1085: while (*p)
1086: if (*p++ == '/')
1087: s = p;
1088: if (*s == 'v') {
1089: Verbose=1; ++s;
1090: }
1091: Progname = s;
1092: if (s[0]=='r' && s[1]=='z')
1093: Batch = TRUE;
1094: if (s[0]=='r' && s[1]=='b')
1095: Batch = Nozmodem = TRUE;
1096: if (s[2] && s[0]=='r' && s[1]=='b')
1097: Topipe = 1;
1098: if (s[2] && s[0]=='r' && s[1]=='z')
1099: Topipe = 1;
1100: }
1101:
1102: /*
1103: * Totalitarian Communist pathname processing
1104: */
1105: checkpath(name)
1106: char *name;
1107: {
1108: if (Restricted) {
1109: if (fopen(name, "r") != NULL) {
1110: canit();
1111: fprintf(stderr, "\r\nrz: %s exists\n", name);
1112: bibi(-1);
1113: }
1114: /* restrict pathnames to current tree or uucppublic */
1115: if ( substr(name, "../")
1116: || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
1117: canit();
1118: fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
1119: bibi(-1);
1120: }
1121: }
1122: }
1123:
1124: /*
1125: * Initialize for Zmodem receive attempt, try to activate Zmodem sender
1126: * Handles ZSINIT frame
1127: * Return ZFILE if Zmodem filename received, -1 on error,
1128: * ZCOMPL if transaction finished, else 0
1129: */
1130: tryz()
1131: {
1132: register c, n;
1133: register cmdzack1flg;
1134:
1135: if (Nozmodem) /* Check for "rb" program name */
1136: return 0;
1137:
1138:
1139: for (n=Zmodem?15:5; --n>=0; ) {
1140: /* Set buffer length (0) and capability flags */
1141: #ifdef SEGMENTS
1142: stohdr(SEGMENTS*1024L);
1143: #else
1144: stohdr(0L);
1145: #endif
1146: #ifdef CANBREAK
1147: Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
1148: #else
1149: Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
1150: #endif
1151: if (Zctlesc)
1152: Txhdr[ZF0] |= TESCCTL;
1153: Txhdr[ZF0] |= CANRLE;
1154: Txhdr[ZF1] = CANVHDR;
1155: /* tryzhdrtype may == ZRINIT */
1156: zshhdr(4,tryzhdrtype, Txhdr);
1157: if (tryzhdrtype == ZSKIP) /* Don't skip too far */
1158: tryzhdrtype = ZRINIT; /* CAF 8-21-87 */
1159: again:
1160: switch (zgethdr(Rxhdr, 0)) {
1161: case ZRQINIT:
1162: if (Rxhdr[ZF3] & 0x80)
1163: Usevhdrs = 1; /* we can var header */
1164: continue;
1165: case ZEOF:
1166: continue;
1167: case TIMEOUT:
1168: continue;
1169: case ZFILE:
1170: zconv = Rxhdr[ZF0];
1171: zmanag = Rxhdr[ZF1];
1172: ztrans = Rxhdr[ZF2];
1173: if (Rxhdr[ZF3] & ZCANVHDR)
1174: Usevhdrs = TRUE;
1175: tryzhdrtype = ZRINIT;
1176: c = zrdata(secbuf, 1024);
1177: mode(3);
1178: if (c == GOTCRCW)
1179: return ZFILE;
1180: zshhdr(4,ZNAK, Txhdr);
1181: goto again;
1182: case ZSINIT:
1183: Zctlesc = TESCCTL & Rxhdr[ZF0];
1184: if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
1185: stohdr(1L);
1186: zshhdr(4,ZACK, Txhdr);
1187: goto again;
1188: }
1189: zshhdr(4,ZNAK, Txhdr);
1190: goto again;
1191: case ZFREECNT:
1192: stohdr(getfree());
1193: zshhdr(4,ZACK, Txhdr);
1194: goto again;
1195: case ZCOMMAND:
1196: #ifdef vax11c
1197: return ERROR;
1198: #else
1199: cmdzack1flg = Rxhdr[ZF0];
1200: if (zrdata(secbuf, 1024) == GOTCRCW) {
1201: if (cmdzack1flg & ZCACK1)
1202: stohdr(0L);
1203: else
1204: stohdr((long)sys2(secbuf));
1205: purgeline(); /* dump impatient questions */
1206: do {
1207: zshhdr(4,ZCOMPL, Txhdr);
1208: }
1209: while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
1210: ackbibi();
1211: if (cmdzack1flg & ZCACK1)
1212: exec2(secbuf);
1213: return ZCOMPL;
1214: }
1215: zshhdr(4,ZNAK, Txhdr); goto again;
1216: #endif
1217: case ZCOMPL:
1218: goto again;
1219: default:
1220: continue;
1221: case ZFIN:
1222: ackbibi(); return ZCOMPL;
1223: case ZCAN:
1224: return ERROR;
1225: }
1226: }
1227: return 0;
1228: }
1229:
1230: /*
1231: * Receive 1 or more files with ZMODEM protocol
1232: */
1233: rzfiles()
1234: {
1235: register c;
1236:
1237: for (;;) {
1238: switch (c = rzfile()) {
1239: case ZEOF:
1240: case ZSKIP:
1241: switch (tryz()) {
1242: case ZCOMPL:
1243: return OK;
1244: default:
1245: return ERROR;
1246: case ZFILE:
1247: break;
1248: }
1249: continue;
1250: default:
1251: return c;
1252: case ERROR:
1253: return ERROR;
1254: }
1255: }
1256: }
1257:
1258: /*
1259: * Receive a file with ZMODEM protocol
1260: * Assumes file name frame is in secbuf
1261: */
1262: rzfile()
1263: {
1264: register c, n;
1265: long rxbytes;
1266:
1267: Eofseen=FALSE;
1268: if (procheader(secbuf) == ERROR) {
1269: return (tryzhdrtype = ZSKIP);
1270: }
1271:
1272: n = 20; rxbytes = 0l;
1273:
1274: for (;;) {
1275: #ifdef SEGMENTS
1276: chinseg = 0;
1277: #endif
1278: stohdr(rxbytes);
1279: zshhdr(4,ZRPOS, Txhdr);
1280: nxthdr:
1281: switch (c = zgethdr(Rxhdr, 0)) {
1282: default:
1283: vfile("rzfile: zgethdr returned %d", c);
1284: return ERROR;
1285: case ZNAK:
1286: case TIMEOUT:
1287: #ifdef SEGMENTS
1288: putsec(secbuf, chinseg);
1289: chinseg = 0;
1290: #endif
1291: if ( --n < 0) {
1292: vfile("rzfile: zgethdr returned %d", c);
1293: return ERROR;
1294: }
1295: case ZFILE:
1296: zrdata(secbuf, 1024);
1297: continue;
1298: case ZEOF:
1299: #ifdef SEGMENTS
1300: putsec(secbuf, chinseg);
1301: chinseg = 0;
1302: #endif
1303: if (rclhdr(Rxhdr) != rxbytes) {
1304: /*
1305: * Ignore eof if it's at wrong place - force
1306: * a timeout because the eof might have gone
1307: * out before we sent our zrpos.
1308: */
1309: errors = 0; goto nxthdr;
1310: }
1311: if (closeit()) {
1312: tryzhdrtype = ZFERR;
1313: vfile("rzfile: closeit returned <> 0");
1314: return ERROR;
1315: }
1316: vfile("rzfile: normal EOF");
1317: return c;
1318: case ERROR: /* Too much garbage in header search error */
1319: #ifdef SEGMENTS
1320: putsec(secbuf, chinseg);
1321: chinseg = 0;
1322: #endif
1323: if ( --n < 0) {
1324: vfile("rzfile: zgethdr returned %d", c);
1325: return ERROR;
1326: }
1327: zmputs(Attn);
1328: continue;
1329: case ZSKIP:
1330: #ifdef SEGMENTS
1331: putsec(secbuf, chinseg);
1332: chinseg = 0;
1333: #endif
1334: Modtime = 1;
1335: closeit();
1336: vfile("rzfile: Sender SKIPPED file");
1337: return c;
1338: case ZDATA:
1339: if (rclhdr(Rxhdr) != rxbytes) {
1340: if ( --n < 0) {
1341: return ERROR;
1342: }
1343: #ifdef SEGMENTS
1344: putsec(secbuf, chinseg);
1345: chinseg = 0;
1346: #endif
1347: zmputs(Attn); continue;
1348: }
1349: moredata:
1350: if (Verbose>1)
1351: fprintf(stderr, "\r%7ld ZMODEM%s ",
1352: rxbytes, Crc32r?" CRC-32":"");
1353: #ifdef SEGMENTS
1354: if (chinseg >= (1024 * SEGMENTS)) {
1355: putsec(secbuf, chinseg);
1356: chinseg = 0;
1357: }
1358: switch (c = zrdata(secbuf+chinseg, 1024))
1359: #else
1360: switch (c = zrdata(secbuf, 1024))
1361: #endif
1362: {
1363: case ZCAN:
1364: #ifdef SEGMENTS
1365: putsec(secbuf, chinseg);
1366: chinseg = 0;
1367: #endif
1368: vfile("rzfile: zgethdr returned %d", c);
1369: return ERROR;
1370: case ERROR: /* CRC error */
1371: #ifdef SEGMENTS
1372: putsec(secbuf, chinseg);
1373: chinseg = 0;
1374: #endif
1375: if ( --n < 0) {
1376: vfile("rzfile: zgethdr returned %d", c);
1377: return ERROR;
1378: }
1379: zmputs(Attn);
1380: continue;
1381: case TIMEOUT:
1382: #ifdef SEGMENTS
1383: putsec(secbuf, chinseg);
1384: chinseg = 0;
1385: #endif
1386: if ( --n < 0) {
1387: vfile("rzfile: zgethdr returned %d", c);
1388: return ERROR;
1389: }
1390: continue;
1391: case GOTCRCW:
1392: n = 20;
1393: #ifdef SEGMENTS
1394: chinseg += Rxcount;
1395: putsec(secbuf, chinseg);
1396: chinseg = 0;
1397: #else
1398: putsec(secbuf, Rxcount);
1399: #endif
1400: rxbytes += Rxcount;
1401: stohdr(rxbytes);
1402: zshhdr(4,ZACK, Txhdr);
1403: sendline(XON);
1404: goto nxthdr;
1405: case GOTCRCQ:
1406: n = 20;
1407: #ifdef SEGMENTS
1408: chinseg += Rxcount;
1409: #else
1410: putsec(secbuf, Rxcount);
1411: #endif
1412: rxbytes += Rxcount;
1413: stohdr(rxbytes);
1414: zshhdr(4,ZACK, Txhdr);
1415: goto moredata;
1416: case GOTCRCG:
1417: n = 20;
1418: #ifdef SEGMENTS
1419: chinseg += Rxcount;
1420: #else
1421: putsec(secbuf, Rxcount);
1422: #endif
1423: rxbytes += Rxcount;
1424: goto moredata;
1425: case GOTCRCE:
1426: n = 20;
1427: #ifdef SEGMENTS
1428: chinseg += Rxcount;
1429: #else
1430: putsec(secbuf, Rxcount);
1431: #endif
1432: rxbytes += Rxcount;
1433: goto nxthdr;
1434: }
1435: }
1436: }
1437: }
1438:
1439: /*
1440: * Send a string to the modem, processing for \336 (sleep 1 sec)
1441: * and \335 (break signal)
1442: */
1443: zmputs(s)
1444: char *s;
1445: {
1446: register c;
1447:
1448: while (*s) {
1449: switch (c = *s++) {
1450: case '\336':
1451: sleep(1); continue;
1452: case '\335':
1453: sendbrk(); continue;
1454: default:
1455: sendline(c);
1456: }
1457: }
1458: }
1459:
1460: /*
1461: * Close the receive dataset, return OK or ERROR
1462: */
1463: closeit()
1464: {
1465: time_t time();
1466:
1467: #ifndef vax11c
1468: if (Topipe) {
1469: if (pclose(fout)) {
1470: return ERROR;
1471: }
1472: return OK;
1473: }
1474: #endif
1475: if (fclose(fout)==ERROR) {
1476: fprintf(stderr, "file close ERROR\n");
1477: return ERROR;
1478: }
1479: #ifndef vax11c
1480: if (Modtime) {
1481: timep[0] = time(NULL);
1482: timep[1] = Modtime;
1483: utime(Pathname, timep);
1484: }
1485: #endif
1486: if ((Filemode&S_IFMT) == S_IFREG)
1487: chmod(Pathname, (07777 & Filemode));
1488: return OK;
1489: }
1490:
1491: /*
1492: * Ack a ZFIN packet, let byegones be byegones
1493: */
1494: ackbibi()
1495: {
1496: register n;
1497:
1498: vfile("ackbibi:");
1499: Readnum = 1;
1500: stohdr(0L);
1501: for (n=3; --n>=0; ) {
1502: purgeline();
1503: zshhdr(4,ZFIN, Txhdr);
1504: switch (readline(100)) {
1505: case 'O':
1506: readline(1); /* Discard 2nd 'O' */
1507: vfile("ackbibi complete");
1508: return;
1509: case RCDO:
1510: return;
1511: case TIMEOUT:
1512: default:
1513: break;
1514: }
1515: }
1516: }
1517:
1518:
1519:
1520: /*
1521: * Local console output simulation
1522: */
1523: bttyout(c)
1524: {
1525: if (Verbose || Fromcu)
1526: putc(c, stderr);
1527: }
1528:
1529: #ifndef vax11c
1530: /*
1531: * Strip leading ! if present, do shell escape.
1532: */
1533: sys2(s)
1534: register char *s;
1535: {
1536: if (*s == '!')
1537: ++s;
1538: return system(s);
1539: }
1540: /*
1541: * Strip leading ! if present, do exec.
1542: */
1543: exec2(s)
1544: register char *s;
1545: {
1546: if (*s == '!')
1547: ++s;
1548: mode(0);
1549: execl("/bin/sh", "sh", "-c", s);
1550: }
1551: #endif
1552: /* End of rz.c */