Improve the process for GNU tools
[minix3.git] / minix / commands / zmodem / rz.c
blob946be48fb1b4880c24656292ab8b0b1cd2d562e5
1 #define VERSION "2.03 05-17-88"
2 #define PUBDIR "/usr/spool/uucppublic"
4 /*% cc -compat -M2 -Ox -K -i -DMD -DOMEN % -o rz; size rz;
5 <-xtx-*> cc386 -Ox -DMD -DOMEN -DSEGMENTS=8 rz.c -o $B/rz; size $B/rz
7 * rz.c By Chuck Forsberg
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
12 * ln rz rb; ln rz rx For either system
14 * ln rz /usr/bin/rzrmail For remote mail. Make this the
15 * login shell. rzrmail then calls
16 * rmail(1) to deliver mail.
18 * To compile on VMS:
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
27 * Unix is a trademark of Western Electric Company
29 * A program for Unix to receive files and commands from computers running
30 * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM.
31 * rz uses Unix buffered input to reduce wasted CPU time.
33 * Iff the program is invoked by rzCOMMAND, output is piped to
34 * "COMMAND filename" (Unix only)
36 * Some systems (Venix, Coherent, Regulus) may not support tty raw mode
37 * read(2) the same way as Unix. ONEREAD must be defined to force one
38 * character reads for these systems. Added 7-01-84 CAF
40 * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF
42 * BIX added 6-30-87 to support BIX(TM) upload protocol used by the
43 * Byte Information Exchange.
45 * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN]
46 * doesn't work properly (even though it compiles without error!),
48 * SEGMENTS=n added 2-21-88 as a model for CP/M programs
49 * for CP/M-80 systems that cannot overlap modem and disk I/O.
51 * VMS flavor hacks begin with rz version 2.00
53 * -DMD may be added to compiler command line to compile in
54 * Directory-creating routines from Public Domain TAR by John Gilmore
56 * HOWMANY may be tuned for best performance
58 * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin
61 #include <sys/types.h>
63 #ifdef vax11c
64 #include <types.h>
65 #include <stat.h>
66 #define LOGFILE "rzlog.tmp"
67 #define OS "VMS"
68 #define BUFREAD
69 extern int errno;
70 #define SS_NORMAL SS$_NORMAL
71 #else
72 /* Not vax11c */
73 #define SS_NORMAL 0
74 #define LOGFILE "/tmp/rzlog"
75 #endif
77 #include <time.h>
78 #include <ctype.h>
79 #include <errno.h>
80 #include <signal.h>
81 #include <setjmp.h>
82 #include <string.h>
83 #include <stdlib.h>
84 #include <unistd.h>
85 #include <utime.h>
86 #include <stdio.h>
87 #include <stdarg.h>
89 #define OK 0
90 #define FALSE 0
91 #define TRUE 1
92 #undef ERROR
93 #define ERROR (-1)
96 long getfree(void);
97 void alrm(int sig );
98 int main(int argc , char *argv []);
99 int usage(void);
100 int wcreceive(int argc , char **argp );
101 int wcrxpn(char *rpn );
102 int wcrx(void);
103 int wcgetsec(char *rxbuf , int maxtime );
104 int readline(int timeout );
105 void purgeline(void);
106 int procheader(char *name );
107 int make_dirs(char *pathname );
108 int makedir(char *dpath , int dmode );
109 int putsec(char *buf , int n );
110 void sendline(int c );
111 void flushmo(void);
112 void uncaps(char *s );
113 int IsAnyLower(char *s );
114 char *substr(char *s , char *t );
115 void zperr();
116 void canit(void);
117 void report(int sct );
118 void chkinvok(char *s );
119 void checkpath(char *name );
120 int tryz(void);
121 int rzfiles(void);
122 int rzfile(void);
123 void zmputs(char *s );
124 int closeit(void);
125 void ackbibi(void);
126 void bttyout(int c );
127 int sys2(char *s );
128 void exec2(char *s );
130 * Debugging information output interface routine
132 void vfile(const char *s, ...);
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
139 #ifndef HOWMANY
140 #define HOWMANY 133
141 #endif
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 ERRORMAX 5
158 #define RETRYMAX 5
159 #define WCEOT (-10)
160 #define PATHLEN 257 /* ready for 4.2 bsd ? */
161 #define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */
163 int Zmodem=0; /* ZMODEM protocol requested */
164 int Nozmodem = 0; /* If invoked as "rb" */
165 unsigned Baudrate = 2400;
167 #ifdef vax11c
168 #include "vrzsz.c" /* most of the system dependent stuff here */
169 #else
170 #include "rbsb.c" /* most of the system dependent stuff here */
171 #endif
173 #include "crctab.c"
175 FILE *fout;
178 * Routine to calculate the free bytes on the current file system
179 * ~0 means many free bytes (unknown)
181 long getfree()
183 return(~0L); /* many free bytes ... */
186 int Lastrx;
187 int Crcflg;
188 int Firstsec;
189 int Eofseen; /* indicates cpm eof (^Z) has been received */
190 int errors;
191 int Restricted=0; /* restricted; no /.. or ../ in filenames */
192 #ifdef ONEREAD
193 /* Sorry, Regulus and some others don't work right in raw mode! */
194 int Readnum = 1; /* Number of bytes to ask for in read() from modem */
195 #else
196 int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */
197 #endif
199 #define DEFBYTL 2000000000L /* default rx file size */
200 long Bytesleft; /* number of bytes of incoming file left */
201 long Modtime; /* Unix style mod time for incoming file */
202 int Filemode; /* Unix style mode for incoming file */
203 char Pathname[PATHLEN];
204 char *Progname; /* the name by which we were called */
206 int Batch=0;
207 int Topipe=0;
208 int MakeLCPathname=TRUE; /* make received pathname lower case */
209 int Verbose=0;
210 int Quiet=0; /* overrides logic that would otherwise set verbose */
211 int Nflag = 0; /* Don't really transfer files */
212 int Rxclob=FALSE; /* Clobber existing file */
213 int Rxbinary=FALSE; /* receive all files in bin mode */
214 int Rxascii=FALSE; /* receive files in ascii (translate) mode */
215 int Thisbinary; /* current file is to be received in bin mode */
216 int Blklen; /* record length of received packets */
218 #ifdef SEGMENTS
219 int chinseg = 0; /* Number of characters received in this data seg */
220 char secbuf[1+(SEGMENTS+1)*1024];
221 #else
222 char secbuf[1025];
223 #endif
226 char linbuf[HOWMANY];
227 int Lleft=0; /* number of characters in linbuf */
228 time_t timep[2];
229 char Lzmanag; /* Local file management request */
230 char zconv; /* ZMODEM file conversion request */
231 char zmanag; /* ZMODEM file management request */
232 char ztrans; /* ZMODEM file transport request */
233 int Zctlesc; /* Encode control characters */
234 int Zrwindow = 1400; /* RX window size (controls garbage count) */
236 jmp_buf tohere; /* For the interrupt on RX timeout */
238 #define xsendline(c) sendline(c)
239 #include "zm.c"
241 int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */
243 void alrm(sig)
244 int sig;
246 longjmp(tohere, -1);
249 /* called by signal interrupt or terminate to clean things up */
250 void bibi(int n)
252 if (Zmodem)
253 zmputs(Attn);
254 canit(); mode(0);
255 fprintf(stderr, "rz: caught signal %d; exiting\n", n);
256 cucheck();
257 exit(128+n);
260 int main(int argc, char *argv[])
262 register char *cp;
263 register int npats;
264 char *virgin, **patts;
265 int exitcode = 0;
267 Rxtimeout = 100;
268 setbuf(stderr, (char *)NULL);
269 if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh")))
270 Restricted=TRUE;
272 from_cu();
273 #ifdef vax11c
274 Progname = virgin = "rz";
275 #else
276 chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */
277 #endif
278 npats = 0;
279 while (--argc) {
280 cp = *++argv;
281 if (*cp == '-') {
282 while( *++cp) {
283 switch(*cp) {
284 case '\\':
285 cp[1] = toupper(cp[1]); continue;
286 case '+':
287 Lzmanag = ZMAPND; break;
288 case 'a':
289 Rxascii=TRUE; break;
290 case 'b':
291 Rxbinary=TRUE; break;
292 case 'c':
293 Crcflg=TRUE; break;
294 #ifndef vax11c
295 case 'D':
296 Nflag = TRUE; break;
297 #endif
298 case 'e':
299 Zctlesc = 1; break;
300 case 'p':
301 Lzmanag = ZMPROT; break;
302 case 'q':
303 Quiet=TRUE; Verbose=0; break;
304 case 't':
305 if (--argc < 1) {
306 usage();
308 Rxtimeout = atoi(*++argv);
309 if (Rxtimeout<10 || Rxtimeout>1000)
310 usage();
311 break;
312 case 'w':
313 if (--argc < 1) {
314 usage();
316 Zrwindow = atoi(*++argv);
317 break;
318 case 'u':
319 MakeLCPathname=FALSE; break;
320 case 'v':
321 ++Verbose; break;
322 case 'y':
323 Rxclob=TRUE; break;
324 default:
325 usage();
329 else if ( !npats && argc>0) {
330 if (argv[0][0]) {
331 npats=argc;
332 patts=argv;
336 if (npats > 1)
337 usage();
338 if (Batch && npats)
339 usage();
340 if (Verbose) {
341 if (freopen(LOGFILE, "a", stderr)==NULL) {
342 printf("Can't open log file %s\n",LOGFILE);
343 exit(0200);
345 setbuf(stderr, (char *)NULL);
346 fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);
348 if (Fromcu && !Quiet) {
349 if (Verbose == 0)
350 Verbose = 2;
352 vfile("%s %s for %s\n", Progname, VERSION, OS);
353 mode(1);
354 if (signal(SIGINT, bibi) == SIG_IGN) {
355 signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN);
357 else {
358 signal(SIGINT, bibi); signal(SIGKILL, bibi);
360 signal(SIGTERM, bibi);
361 if (wcreceive(npats, patts)==ERROR) {
362 exitcode=0200;
363 canit();
365 mode(0);
366 vfile("exitcode = %d\n",exitcode);
367 if (exitcode && !Zmodem) /* bellow again with all thy might. */
368 canit();
369 if (exitcode)
370 cucheck();
371 if (Verbose) putc('\n', stderr);
372 exit(exitcode ? exitcode:SS_NORMAL);
376 int usage()
378 cucheck();
379 #ifdef vax11c
380 fprintf(stderr,"Usage: rz [-abeuvy]\n");
381 #else
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 #endif
386 fprintf(stderr," -a ASCII transfer (strip CR)\n");
387 fprintf(stderr," -b Binary transfer for all files\n");
388 #ifndef vax11c
389 fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n");
390 #endif
391 fprintf(stderr," -e Escape control characters (ZMODEM)\n");
392 fprintf(stderr," -v Verbose more v's give more info\n");
393 fprintf(stderr," -y Yes, clobber existing file if any\n");
394 fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n",
395 Progname, VERSION, OS);
396 fprintf(stderr, "\t\t\042The High Reliability Software\042\n");
397 exit(SS_NORMAL);
400 void vfile(const char *string, ...)
402 if (Verbose > 2) {
403 va_list args;
404 va_start(args, string);
405 vfprintf(stderr, string, args);
406 va_end(args);
407 fprintf(stderr, "\n");
412 * Let's receive something already.
415 char *rbmsg =
416 "%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n";
418 int wcreceive(int argc, char **argp)
420 register int c;
422 if (Batch || argc==0) {
423 Crcflg=1;
424 if ( !Quiet)
425 fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz");
426 if ((c=tryz())) {
427 if (c == ZCOMPL)
428 return OK;
429 if (c == ERROR)
430 goto fubar;
431 c = rzfiles();
432 if (c)
433 goto fubar;
434 } else {
435 for (;;) {
436 if (wcrxpn(secbuf)== ERROR)
437 goto fubar;
438 if (secbuf[0]==0)
439 return OK;
440 if (procheader(secbuf) == ERROR)
441 goto fubar;
442 if (wcrx()==ERROR)
443 goto fubar;
446 } else {
447 Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
449 procheader(""); strcpy(Pathname, *argp); checkpath(Pathname);
450 fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname);
451 if ((fout=fopen(Pathname, "w")) == NULL)
452 return ERROR;
453 if (wcrx()==ERROR)
454 goto fubar;
456 return OK;
457 fubar:
458 canit();
459 #ifndef vax11c
460 if (Topipe && fout) {
461 pclose(fout); return ERROR;
463 #endif
464 if (fout)
465 fclose(fout);
466 #ifndef vax11c
467 if (Restricted) {
468 unlink(Pathname);
469 fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname);
471 #endif
472 return ERROR;
477 * Fetch a pathname from the other end as a C ctyle ASCIZ string.
478 * Length is indeterminate as long as less than Blklen
479 * A null string represents no more files (YMODEM)
481 * Parameter rpn is for receiving a pathname
483 int wcrxpn(char *rpn)
485 register int c;
487 #ifdef NFGVMIN
488 readline(1);
489 #else
490 purgeline();
491 #endif
493 et_tu:
494 Firstsec=TRUE; Eofseen=FALSE;
495 sendline(Crcflg?WANTCRC:NAK);
496 Lleft=0; /* Do read next time ... */
497 while ((c = wcgetsec(rpn, 100)) != 0) {
498 if (c == WCEOT) {
499 zperr( "Pathname fetch returned %d", c);
500 sendline(ACK);
501 Lleft=0; /* Do read next time ... */
502 readline(1);
503 goto et_tu;
505 return ERROR;
507 sendline(ACK);
508 return OK;
512 * Adapted from CMODEM13.C, written by
513 * Jack M. Wierda and Roderick W. Hart
516 int wcrx()
518 register int sectnum, sectcurr;
519 register char sendchar;
520 int cblklen; /* bytes to dump this block */
522 Firstsec=TRUE;sectnum=0; Eofseen=FALSE;
523 sendchar=Crcflg?WANTCRC:NAK;
525 for (;;) {
526 sendline(sendchar); /* send it now, we're ready! */
527 Lleft=0; /* Do read next time ... */
528 sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130);
529 report(sectcurr);
530 if (sectcurr==((sectnum+1) &0377)) {
531 sectnum++;
532 cblklen = Bytesleft>Blklen ? Blklen:Bytesleft;
533 if (putsec(secbuf, cblklen)==ERROR)
534 return ERROR;
535 if ((Bytesleft-=cblklen) < 0)
536 Bytesleft = 0;
537 sendchar=ACK;
539 else if (sectcurr==(sectnum&0377)) {
540 zperr( "Received dup Sector");
541 sendchar=ACK;
543 else if (sectcurr==WCEOT) {
544 if (closeit())
545 return ERROR;
546 sendline(ACK);
547 Lleft=0; /* Do read next time ... */
548 return OK;
550 else if (sectcurr==ERROR)
551 return ERROR;
552 else {
553 zperr( "Sync Error");
554 return ERROR;
560 * Wcgetsec fetches a Ward Christensen type sector.
561 * Returns sector number encountered or ERROR if valid sector not received,
562 * or CAN CAN received
563 * or WCEOT if eot sector
564 * time is timeout for first char, set to 4 seconds thereafter
565 ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK **************
566 * (Caller must do that when he is good and ready to get next sector)
569 int wcgetsec(char *rxbuf, int maxtime)
571 register int checksum, wcj, firstch;
572 register unsigned short oldcrc;
573 register char *p;
574 int sectcurr;
576 for (Lastrx=errors=0; errors<RETRYMAX; errors++) {
578 if ((firstch=readline(maxtime))==STX) {
579 Blklen=1024; goto get2;
581 if (firstch==SOH) {
582 Blklen=128;
583 get2:
584 sectcurr=readline(1);
585 if ((sectcurr+(oldcrc=readline(1)))==0377) {
586 oldcrc=checksum=0;
587 for (p=rxbuf,wcj=Blklen; --wcj>=0; ) {
588 if ((firstch=readline(1)) < 0)
589 goto bilge;
590 oldcrc=updcrc(firstch, oldcrc);
591 checksum += (*p++ = firstch);
593 if ((firstch=readline(1)) < 0)
594 goto bilge;
595 if (Crcflg) {
596 oldcrc=updcrc(firstch, oldcrc);
597 if ((firstch=readline(1)) < 0)
598 goto bilge;
599 oldcrc=updcrc(firstch, oldcrc);
600 if (oldcrc & 0xFFFF)
601 zperr( "CRC");
602 else {
603 Firstsec=FALSE;
604 return sectcurr;
607 else if (((checksum-firstch)&0377)==0) {
608 Firstsec=FALSE;
609 return sectcurr;
611 else
612 zperr( "Checksum");
614 else
615 zperr("Sector number garbled");
617 /* make sure eot really is eot and not just mixmash */
618 #ifdef NFGVMIN
619 else if (firstch==EOT && readline(1)==TIMEOUT)
620 return WCEOT;
621 #else
622 else if (firstch==EOT && Lleft==0)
623 return WCEOT;
624 #endif
625 else if (firstch==CAN) {
626 if (Lastrx==CAN) {
627 zperr( "Sender CANcelled");
628 return ERROR;
629 } else {
630 Lastrx=CAN;
631 continue;
634 else if (firstch==TIMEOUT) {
635 if (Firstsec)
636 goto humbug;
637 bilge:
638 zperr( "TIMEOUT");
640 else
641 zperr( "Got 0%o sector header", firstch);
643 humbug:
644 Lastrx=0;
645 while(readline(1)!=TIMEOUT)
647 if (Firstsec) {
648 sendline(Crcflg?WANTCRC:NAK);
649 Lleft=0; /* Do read next time ... */
650 } else {
651 maxtime=40; sendline(NAK);
652 Lleft=0; /* Do read next time ... */
655 /* try to stop the bubble machine. */
656 canit();
657 return ERROR;
660 #ifndef vax11c
662 * This version of readline is reasoably well suited for
663 * reading many characters.
664 * (except, currently, for the Regulus version!)
666 * timeout is in tenths of seconds
668 int readline(int timeout)
670 register int n;
671 static char *cdq; /* pointer for removing chars from linbuf */
673 if (--Lleft >= 0) {
674 if (Verbose > 8) {
675 fprintf(stderr, "%02x ", *cdq&0377);
677 return (*cdq++ & 0377);
679 n = timeout/10;
680 if (n < 2)
681 n = 3;
682 if (Verbose > 5)
683 fprintf(stderr, "Calling read: alarm=%d Readnum=%d ",
684 n, Readnum);
685 if (setjmp(tohere)) {
686 #ifdef TIOCFLUSH
687 /* ioctl(iofd, TIOCFLUSH, 0); */
688 #endif
689 Lleft = 0;
690 if (Verbose>1)
691 fprintf(stderr, "Readline:TIMEOUT\n");
692 return TIMEOUT;
694 signal(SIGALRM, alrm); alarm(n);
695 Lleft=read(iofd, cdq=linbuf, Readnum);
696 alarm(0);
697 if (Verbose > 5) {
698 fprintf(stderr, "Read returned %d bytes\n", Lleft);
700 if (Lleft < 1)
701 return TIMEOUT;
702 --Lleft;
703 if (Verbose > 8) {
704 fprintf(stderr, "%02x ", *cdq&0377);
706 return (*cdq++ & 0377);
712 * Purge the modem input queue of all characters
714 void purgeline()
716 Lleft = 0;
717 #ifdef USG
718 ioctl(iofd, TCFLSH, 0);
719 #else
720 lseek(iofd, 0L, 2);
721 #endif
723 #endif
727 * Process incoming file information header
729 int procheader(char *name)
731 register char *openmode, *p;
733 /* set default parameters and overrides */
734 openmode = "w";
735 Thisbinary = (!Rxascii) || Rxbinary;
736 if (Lzmanag)
737 zmanag = Lzmanag;
740 * Process ZMODEM remote file management requests
742 if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */
743 Thisbinary = 0;
744 if (zconv == ZCBIN) /* Remote Binary override */
745 Thisbinary = TRUE;
746 else if (zmanag == ZMAPND)
747 openmode = "a";
749 #ifndef BIX
750 /* Check for existing file */
751 if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) {
752 fclose(fout); return ERROR;
754 #endif
756 Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L;
758 p = name + 1 + strlen(name);
759 if (*p) { /* file coming from Unix or DOS system */
760 sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode);
761 #ifndef vax11c
762 if (Filemode & UNIXFILE)
763 ++Thisbinary;
764 #endif
765 if (Verbose) {
766 fprintf(stderr, "\nIncoming: %s %ld %lo %o\n",
767 name, Bytesleft, Modtime, Filemode);
771 #ifdef BIX
772 if ((fout=fopen("scratchpad", openmode)) == NULL)
773 return ERROR;
774 return OK;
775 #else
777 else { /* File coming from CP/M system */
778 for (p=name; *p; ++p) /* change / to _ */
779 if ( *p == '/')
780 *p = '_';
782 if ( *--p == '.') /* zap trailing period */
783 *p = 0;
786 #ifndef vax11c
787 if (!Zmodem && MakeLCPathname && !IsAnyLower(name)
788 && !(Filemode&UNIXFILE))
789 uncaps(name);
790 #endif
791 if (Topipe > 0) {
792 sprintf(Pathname, "%s %s", Progname+2, name);
793 if (Verbose)
794 fprintf(stderr, "Topipe: %s %s\n",
795 Pathname, Thisbinary?"BIN":"ASCII");
796 #ifndef vax11c
797 if ((fout=popen(Pathname, "w")) == NULL)
798 return ERROR;
799 #endif
800 } else {
801 strcpy(Pathname, name);
802 if (Verbose) {
803 fprintf(stderr, "Receiving %s %s %s\n",
804 name, Thisbinary?"BIN":"ASCII", openmode);
806 checkpath(name);
807 if (Nflag)
808 name = "/dev/null";
809 #ifndef vax11c
810 #ifdef OMEN
811 if (name[0] == '!' || name[0] == '|') {
812 if ( !(fout = popen(name+1, "w"))) {
813 return ERROR;
815 Topipe = -1; return(OK);
817 #endif
818 #endif
819 #ifdef MD
820 fout = fopen(name, openmode);
821 if ( !fout)
822 if (make_dirs(name))
823 fout = fopen(name, openmode);
824 #else
825 fout = fopen(name, openmode);
826 #endif
827 if ( !fout)
828 return ERROR;
830 return OK;
831 #endif /* BIX */
834 #ifdef MD
836 * Directory-creating routines from Public Domain TAR by John Gilmore
840 * After a file/link/symlink/dir creation has failed, see if
841 * it's because some required directory was not present, and if
842 * so, create all required dirs.
844 int make_dirs(char *pathname)
846 register char *p; /* Points into path */
847 int madeone = 0; /* Did we do anything yet? */
848 int save_errno = errno; /* Remember caller's errno */
849 char *strchr();
851 if (errno != ENOENT)
852 return 0; /* Not our problem */
854 for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) {
855 /* Avoid mkdir of empty string, if leading or double '/' */
856 if (p == pathname || p[-1] == '/')
857 continue;
858 /* Avoid mkdir where last part of path is '.' */
859 if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/'))
860 continue;
861 *p = 0; /* Truncate the path there */
862 if ( !makedir(pathname, 0777)) { /* Try to create it as a dir */
863 vfile("Made directory %s\n", pathname);
864 madeone++; /* Remember if we made one */
865 *p = '/';
866 continue;
868 *p = '/';
869 if (errno == EEXIST) /* Directory already exists */
870 continue;
872 * Some other error in the makedir. We return to the caller.
874 break;
876 errno = save_errno; /* Restore caller's errno */
877 return madeone; /* Tell them to retry if we made one */
880 #if (MD != 2)
881 #define TERM_SIGNAL(status) ((status) & 0x7F)
882 #define TERM_COREDUMP(status) (((status) & 0x80) != 0)
883 #define TERM_VALUE(status) ((status) >> 8)
885 * Make a directory. Compatible with the mkdir() system call on 4.2BSD.
887 int makedir(char *dpath, int dmode)
889 int cpid, status;
890 struct stat statbuf;
892 if (stat(dpath,&statbuf) == 0) {
893 errno = EEXIST; /* Stat worked, so it already exists */
894 return -1;
897 /* If stat fails for a reason other than non-existence, return error */
898 if (errno != ENOENT) return -1;
900 switch (cpid = fork()) {
902 case -1: /* Error in fork() */
903 return(-1); /* Errno is set already */
905 case 0: /* Child process */
907 * Cheap hack to set mode of new directory. Since this
908 * child process is going away anyway, we zap its umask.
909 * FIXME, this won't suffice to set SUID, SGID, etc. on this
910 * directory. Does anybody care?
912 status = umask(0); /* Get current umask */
913 status = umask(status | (0777 & ~dmode)); /* Set for mkdir */
914 execl("/bin/mkdir", "mkdir", dpath, (char *)0);
915 _exit(-1); /* Can't exec /bin/mkdir */
917 default: /* Parent process */
918 while (cpid != wait(&status)) ; /* Wait for kid to finish */
921 if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) {
922 errno = EIO; /* We don't know why, but */
923 return -1; /* /bin/mkdir failed */
926 return 0;
928 #endif /* MD != 2 */
929 #endif /* MD */
932 * Putsec writes the n characters of buf to receive file fout.
933 * If not in binary mode, carriage returns, and all characters
934 * starting with CPMEOF are discarded.
936 int putsec(char *buf, int n)
938 register char *p;
940 if (n == 0)
941 return OK;
942 if (Thisbinary) {
943 for (p=buf; --n>=0; )
944 putc( *p++, fout);
946 else {
947 if (Eofseen)
948 return OK;
949 for (p=buf; --n>=0; ++p ) {
950 if ( *p == '\r')
951 continue;
952 if (*p == CPMEOF) {
953 Eofseen=TRUE; return OK;
955 putc(*p ,fout);
958 return OK;
961 #ifndef vax11c
963 * Send a character to modem. Small is beautiful.
965 void sendline(int c)
967 char d;
969 d = c;
970 if (Verbose>6)
971 fprintf(stderr, "Sendline: %x\n", c);
972 write(1, &d, 1);
975 void flushmo() {}
976 #endif
982 /* make string s lower case */
983 void uncaps(char *s)
985 for ( ; *s; ++s)
986 if (isupper(*s))
987 *s = tolower(*s);
990 * IsAnyLower returns TRUE if string s has lower case letters.
992 int IsAnyLower(char *s)
994 for ( ; *s; ++s)
995 if (islower(*s))
996 return TRUE;
997 return FALSE;
1001 * substr(string, token) searches for token in string s
1002 * returns pointer to token within string if found, NULL otherwise
1004 char *
1005 substr(char *s, char *t)
1007 register char *ss,*tt;
1008 /* search for first char of token */
1009 for (ss=s; *s; s++)
1010 if (*s == *t)
1011 /* compare token with substring */
1012 for (ss=s,tt=t; ;) {
1013 if (*tt == 0)
1014 return s;
1015 if (*ss++ != *tt++)
1016 break;
1018 return (char *)NULL;
1022 * Log an error
1024 /*VARARGS1*/
1025 void zperr(char *s, char *p, char *u)
1027 if (Verbose <= 0)
1028 return;
1029 fprintf(stderr, "Retry %d: ", errors);
1030 fprintf(stderr, s, p, u);
1031 fprintf(stderr, "\n");
1034 /* send cancel string to get the other end to shut up */
1035 void canit()
1037 static char canistr[] = {
1038 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0
1041 #ifdef vax11c
1042 raw_wbuf(strlen(canistr), canistr);
1043 purgeline();
1044 #else
1045 printf("%s", canistr);
1046 Lleft=0; /* Do read next time ... */
1047 fflush(stdout);
1048 #endif
1052 void report(int sct)
1054 if (Verbose>1)
1055 fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r');
1058 #ifndef vax11c
1060 * If called as [-][dir/../]vrzCOMMAND set Verbose to 1
1061 * If called as [-][dir/../]rzCOMMAND set the pipe flag
1062 * If called as rb use YMODEM protocol
1064 void chkinvok(char *s)
1066 register char *p;
1068 p = s;
1069 while (*p == '-')
1070 s = ++p;
1071 while (*p)
1072 if (*p++ == '/')
1073 s = p;
1074 if (*s == 'v') {
1075 Verbose=1; ++s;
1077 Progname = s;
1078 if (s[0]=='r' && s[1]=='z')
1079 Batch = TRUE;
1080 if (s[0]=='r' && s[1]=='b')
1081 Batch = Nozmodem = TRUE;
1082 if (s[2] && s[0]=='r' && s[1]=='b')
1083 Topipe = 1;
1084 if (s[2] && s[0]=='r' && s[1]=='z')
1085 Topipe = 1;
1087 #endif
1090 * Totalitarian Communist pathname processing
1092 void checkpath(char *name)
1094 if (Restricted) {
1095 if (fopen(name, "r") != NULL) {
1096 canit();
1097 fprintf(stderr, "\r\nrz: %s exists\n", name);
1098 bibi(-1);
1100 /* restrict pathnames to current tree or uucppublic */
1101 if ( substr(name, "../")
1102 || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) {
1103 canit();
1104 fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n");
1105 bibi(-1);
1111 * Initialize for Zmodem receive attempt, try to activate Zmodem sender
1112 * Handles ZSINIT frame
1113 * Return ZFILE if Zmodem filename received, -1 on error,
1114 * ZCOMPL if transaction finished, else 0
1116 int tryz()
1118 register int c, n;
1119 register int cmdzack1flg;
1121 if (Nozmodem) /* Check for "rb" program name */
1122 return 0;
1125 for (n=Zmodem?15:5; --n>=0; ) {
1126 /* Set buffer length (0) and capability flags */
1127 #ifdef SEGMENTS
1128 stohdr(SEGMENTS*1024L);
1129 #else
1130 stohdr(0L);
1131 #endif
1132 #ifdef CANBREAK
1133 Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK;
1134 #else
1135 Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO;
1136 #endif
1137 if (Zctlesc)
1138 Txhdr[ZF0] |= TESCCTL;
1139 zshhdr(tryzhdrtype, Txhdr);
1140 if (tryzhdrtype == ZSKIP) /* Don't skip too far */
1141 tryzhdrtype = ZRINIT; /* CAF 8-21-87 */
1142 again:
1143 switch (zgethdr(Rxhdr, 0)) {
1144 case ZRQINIT:
1145 continue;
1146 case ZEOF:
1147 continue;
1148 case TIMEOUT:
1149 continue;
1150 case ZFILE:
1151 zconv = Rxhdr[ZF0];
1152 zmanag = Rxhdr[ZF1];
1153 ztrans = Rxhdr[ZF2];
1154 tryzhdrtype = ZRINIT;
1155 c = zrdata(secbuf, 1024);
1156 mode(3);
1157 if (c == GOTCRCW)
1158 return ZFILE;
1159 zshhdr(ZNAK, Txhdr);
1160 goto again;
1161 case ZSINIT:
1162 Zctlesc = TESCCTL & Rxhdr[ZF0];
1163 if (zrdata(Attn, ZATTNLEN) == GOTCRCW) {
1164 stohdr(1L);
1165 zshhdr(ZACK, Txhdr);
1166 goto again;
1168 zshhdr(ZNAK, Txhdr);
1169 goto again;
1170 case ZFREECNT:
1171 stohdr(getfree());
1172 zshhdr(ZACK, Txhdr);
1173 goto again;
1174 case ZCOMMAND:
1175 #ifdef vax11c
1176 return ERROR;
1177 #else
1178 cmdzack1flg = Rxhdr[ZF0];
1179 if (zrdata(secbuf, 1024) == GOTCRCW) {
1180 if (cmdzack1flg & ZCACK1)
1181 stohdr(0L);
1182 else
1183 stohdr((long)sys2(secbuf));
1184 purgeline(); /* dump impatient questions */
1185 do {
1186 zshhdr(ZCOMPL, Txhdr);
1188 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN);
1189 ackbibi();
1190 if (cmdzack1flg & ZCACK1)
1191 exec2(secbuf);
1192 return ZCOMPL;
1194 zshhdr(ZNAK, Txhdr); goto again;
1195 #endif
1196 case ZCOMPL:
1197 goto again;
1198 default:
1199 continue;
1200 case ZFIN:
1201 ackbibi(); return ZCOMPL;
1202 case ZCAN:
1203 return ERROR;
1206 return 0;
1210 * Receive 1 or more files with ZMODEM protocol
1212 int rzfiles()
1214 register int c;
1216 for (;;) {
1217 switch (c = rzfile()) {
1218 case ZEOF:
1219 case ZSKIP:
1220 switch (tryz()) {
1221 case ZCOMPL:
1222 return OK;
1223 default:
1224 return ERROR;
1225 case ZFILE:
1226 break;
1228 continue;
1229 default:
1230 return c;
1231 case ERROR:
1232 return ERROR;
1238 * Receive a file with ZMODEM protocol
1239 * Assumes file name frame is in secbuf
1241 int rzfile()
1243 register int c, n;
1244 long rxbytes;
1246 Eofseen=FALSE;
1247 if (procheader(secbuf) == ERROR) {
1248 return (tryzhdrtype = ZSKIP);
1251 n = 20; rxbytes = 0l;
1253 for (;;) {
1254 #ifdef SEGMENTS
1255 chinseg = 0;
1256 #endif
1257 stohdr(rxbytes);
1258 zshhdr(ZRPOS, Txhdr);
1259 nxthdr:
1260 switch (c = zgethdr(Rxhdr, 0)) {
1261 default:
1262 vfile("rzfile: zgethdr returned %d", c);
1263 return ERROR;
1264 case ZNAK:
1265 case TIMEOUT:
1266 #ifdef SEGMENTS
1267 putsec(secbuf, chinseg);
1268 chinseg = 0;
1269 #endif
1270 if ( --n < 0) {
1271 vfile("rzfile: zgethdr returned %d", c);
1272 return ERROR;
1274 case ZFILE:
1275 zrdata(secbuf, 1024);
1276 continue;
1277 case ZEOF:
1278 #ifdef SEGMENTS
1279 putsec(secbuf, chinseg);
1280 chinseg = 0;
1281 #endif
1282 if (rclhdr(Rxhdr) != rxbytes) {
1284 * Ignore eof if it's at wrong place - force
1285 * a timeout because the eof might have gone
1286 * out before we sent our zrpos.
1288 errors = 0; goto nxthdr;
1290 if (closeit()) {
1291 tryzhdrtype = ZFERR;
1292 vfile("rzfile: closeit returned <> 0");
1293 return ERROR;
1295 vfile("rzfile: normal EOF");
1296 return c;
1297 case ERROR: /* Too much garbage in header search error */
1298 #ifdef SEGMENTS
1299 putsec(secbuf, chinseg);
1300 chinseg = 0;
1301 #endif
1302 if ( --n < 0) {
1303 vfile("rzfile: zgethdr returned %d", c);
1304 return ERROR;
1306 zmputs(Attn);
1307 continue;
1308 case ZSKIP:
1309 #ifdef SEGMENTS
1310 putsec(secbuf, chinseg);
1311 chinseg = 0;
1312 #endif
1313 closeit();
1314 vfile("rzfile: Sender SKIPPED file");
1315 return c;
1316 case ZDATA:
1317 if (rclhdr(Rxhdr) != rxbytes) {
1318 if ( --n < 0) {
1319 return ERROR;
1321 #ifdef SEGMENTS
1322 putsec(secbuf, chinseg);
1323 chinseg = 0;
1324 #endif
1325 zmputs(Attn); continue;
1327 moredata:
1328 if (Verbose>1)
1329 fprintf(stderr, "\r%7ld ZMODEM%s ",
1330 rxbytes, Crc32?" CRC-32":"");
1331 #ifdef SEGMENTS
1332 if (chinseg >= (1024 * SEGMENTS)) {
1333 putsec(secbuf, chinseg);
1334 chinseg = 0;
1336 switch (c = zrdata(secbuf+chinseg, 1024))
1337 #else
1338 switch (c = zrdata(secbuf, 1024))
1339 #endif
1341 case ZCAN:
1342 #ifdef SEGMENTS
1343 putsec(secbuf, chinseg);
1344 chinseg = 0;
1345 #endif
1346 vfile("rzfile: zgethdr returned %d", c);
1347 return ERROR;
1348 case ERROR: /* CRC error */
1349 #ifdef SEGMENTS
1350 putsec(secbuf, chinseg);
1351 chinseg = 0;
1352 #endif
1353 if ( --n < 0) {
1354 vfile("rzfile: zgethdr returned %d", c);
1355 return ERROR;
1357 zmputs(Attn);
1358 continue;
1359 case TIMEOUT:
1360 #ifdef SEGMENTS
1361 putsec(secbuf, chinseg);
1362 chinseg = 0;
1363 #endif
1364 if ( --n < 0) {
1365 vfile("rzfile: zgethdr returned %d", c);
1366 return ERROR;
1368 continue;
1369 case GOTCRCW:
1370 n = 20;
1371 #ifdef SEGMENTS
1372 chinseg += Rxcount;
1373 putsec(secbuf, chinseg);
1374 chinseg = 0;
1375 #else
1376 putsec(secbuf, Rxcount);
1377 #endif
1378 rxbytes += Rxcount;
1379 stohdr(rxbytes);
1380 zshhdr(ZACK, Txhdr);
1381 sendline(XON);
1382 goto nxthdr;
1383 case GOTCRCQ:
1384 n = 20;
1385 #ifdef SEGMENTS
1386 chinseg += Rxcount;
1387 #else
1388 putsec(secbuf, Rxcount);
1389 #endif
1390 rxbytes += Rxcount;
1391 stohdr(rxbytes);
1392 zshhdr(ZACK, Txhdr);
1393 goto moredata;
1394 case GOTCRCG:
1395 n = 20;
1396 #ifdef SEGMENTS
1397 chinseg += Rxcount;
1398 #else
1399 putsec(secbuf, Rxcount);
1400 #endif
1401 rxbytes += Rxcount;
1402 goto moredata;
1403 case GOTCRCE:
1404 n = 20;
1405 #ifdef SEGMENTS
1406 chinseg += Rxcount;
1407 #else
1408 putsec(secbuf, Rxcount);
1409 #endif
1410 rxbytes += Rxcount;
1411 goto nxthdr;
1418 * Send a string to the modem, processing for \336 (sleep 1 sec)
1419 * and \335 (break signal)
1421 void zmputs(char *s)
1423 register int c;
1425 while (*s) {
1426 switch (c = *s++) {
1427 case '\336':
1428 sleep(1); continue;
1429 case '\335':
1430 sendbrk(); continue;
1431 default:
1432 sendline(c);
1438 * Close the receive dataset, return OK or ERROR
1440 int closeit()
1442 time_t q;
1444 #ifndef vax11c
1445 if (Topipe) {
1446 if (pclose(fout)) {
1447 return ERROR;
1449 return OK;
1451 #endif
1452 if (fclose(fout)==ERROR) {
1453 fprintf(stderr, "file close ERROR\n");
1454 return ERROR;
1456 #ifndef vax11c
1457 if (Modtime) {
1458 timep[0] = time(&q);
1459 timep[1] = Modtime;
1460 utime(Pathname, (struct utimbuf *) timep);
1462 #endif
1463 if ((Filemode&S_IFMT) == S_IFREG)
1464 chmod(Pathname, (07777 & Filemode));
1465 return OK;
1469 * Ack a ZFIN packet, let byegones be byegones
1471 void ackbibi()
1473 register int n;
1475 vfile("ackbibi:");
1476 Readnum = 1;
1477 stohdr(0L);
1478 for (n=3; --n>=0; ) {
1479 purgeline();
1480 zshhdr(ZFIN, Txhdr);
1481 switch (readline(100)) {
1482 case 'O':
1483 readline(1); /* Discard 2nd 'O' */
1484 vfile("ackbibi complete");
1485 return;
1486 case RCDO:
1487 return;
1488 case TIMEOUT:
1489 default:
1490 break;
1498 * Local console output simulation
1500 void bttyout(int c)
1502 if (Verbose || Fromcu)
1503 putc(c, stderr);
1506 #ifndef vax11c
1508 * Strip leading ! if present, do shell escape.
1510 int sys2(char *s)
1512 if (*s == '!')
1513 ++s;
1514 return system(s);
1517 * Strip leading ! if present, do exec.
1519 void exec2(char *s)
1521 if (*s == '!')
1522 ++s;
1523 mode(0);
1524 execl("/bin/sh", "sh", "-c", s);
1526 #endif
1527 /* End of rz.c */