source: trunk/minix/commands/zmodem/rz.c@ 9

Last change on this file since 9 was 9, checked in by Mattia Monga, 13 years ago

Minix 3.1.2a

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