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 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 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 #include <stdarg.h> 88 89 #define OK 0 90 #define FALSE 0 91 #define TRUE 1 92 #undef ERROR 93 #define ERROR (-1) 94 95 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 ); 129 /* 130 * Debugging information output interface routine 131 */ 132 void vfile(const char *s, ...); 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 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 */ 162 163 int Zmodem=0; /* ZMODEM protocol requested */ 164 int Nozmodem = 0; /* If invoked as "rb" */ 165 unsigned Baudrate = 2400; 166 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 172 173 #include "crctab.c" 174 175 FILE *fout; 176 177 /* 178 * Routine to calculate the free bytes on the current file system 179 * ~0 means many free bytes (unknown) 180 */ 181 long getfree() 182 { 183 return(~0L); /* many free bytes ... */ 184 } 185 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 198 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 */ 205 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 */ 217 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 224 225 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) */ 235 236 jmp_buf tohere; /* For the interrupt on RX timeout */ 237 238 #define xsendline(c) sendline(c) 239 #include "zm.c" 240 241 int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ 242 243 void alrm(sig) 244 int sig; 245 { 246 longjmp(tohere, -1); 247 } 248 249 /* called by signal interrupt or terminate to clean things up */ 250 void bibi(int n) 251 { 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); 258 } 259 260 int main(int argc, char *argv[]) 261 { 262 register char *cp; 263 register int npats; 264 char *virgin, **patts; 265 int exitcode = 0; 266 267 Rxtimeout = 100; 268 setbuf(stderr, (char *)NULL); 269 if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) 270 Restricted=TRUE; 271 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(); 307 } 308 Rxtimeout = atoi(*++argv); 309 if (Rxtimeout<10 || Rxtimeout>1000) 310 usage(); 311 break; 312 case 'w': 313 if (--argc < 1) { 314 usage(); 315 } 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(); 326 } 327 } 328 } 329 else if ( !npats && argc>0) { 330 if (argv[0][0]) { 331 npats=argc; 332 patts=argv; 333 } 334 } 335 } 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); 344 } 345 setbuf(stderr, (char *)NULL); 346 fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname); 347 } 348 if (Fromcu && !Quiet) { 349 if (Verbose == 0) 350 Verbose = 2; 351 } 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); 356 } 357 else { 358 signal(SIGINT, bibi); signal(SIGKILL, bibi); 359 } 360 signal(SIGTERM, bibi); 361 if (wcreceive(npats, patts)==ERROR) { 362 exitcode=0200; 363 canit(); 364 } 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); 373 } 374 375 376 int usage() 377 { 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); 398 } 399 400 void vfile(const char *string, ...) 401 { 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"); 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 int wcreceive(int argc, char **argp) 419 { 420 register int c; 421 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; 444 } 445 } 446 } else { 447 Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; 448 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; 455 } 456 return OK; 457 fubar: 458 canit(); 459 #ifndef vax11c 460 if (Topipe && fout) { 461 pclose(fout); return ERROR; 462 } 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); 470 } 471 #endif 472 return ERROR; 473 } 474 475 476 /* 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) 480 * 481 * Parameter rpn is for receiving a pathname 482 */ 483 int wcrxpn(char *rpn) 484 { 485 register int c; 486 487 #ifdef NFGVMIN 488 readline(1); 489 #else 490 purgeline(); 491 #endif 492 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; 504 } 505 return ERROR; 506 } 507 sendline(ACK); 508 return OK; 509 } 510 511 /* 512 * Adapted from CMODEM13.C, written by 513 * Jack M. Wierda and Roderick W. Hart 514 */ 515 516 int wcrx() 517 { 518 register int sectnum, sectcurr; 519 register char sendchar; 520 int cblklen; /* bytes to dump this block */ 521 522 Firstsec=TRUE;sectnum=0; Eofseen=FALSE; 523 sendchar=Crcflg?WANTCRC:NAK; 524 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; 538 } 539 else if (sectcurr==(sectnum&0377)) { 540 zperr( "Received dup Sector"); 541 sendchar=ACK; 542 } 543 else if (sectcurr==WCEOT) { 544 if (closeit()) 545 return ERROR; 546 sendline(ACK); 547 Lleft=0; /* Do read next time ... */ 548 return OK; 549 } 550 else if (sectcurr==ERROR) 551 return ERROR; 552 else { 553 zperr( "Sync Error"); 554 return ERROR; 555 } 556 } 557 } 558 559 /* 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) 567 */ 568 569 int wcgetsec(char *rxbuf, int maxtime) 570 { 571 register int checksum, wcj, firstch; 572 register unsigned short oldcrc; 573 register char *p; 574 int sectcurr; 575 576 for (Lastrx=errors=0; errors<RETRYMAX; errors++) { 577 578 if ((firstch=readline(maxtime))==STX) { 579 Blklen=1024; goto get2; 580 } 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); 592 } 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; 605 } 606 } 607 else if (((checksum-firstch)&0377)==0) { 608 Firstsec=FALSE; 609 return sectcurr; 610 } 611 else 612 zperr( "Checksum"); 613 } 614 else 615 zperr("Sector number garbled"); 616 } 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; 632 } 633 } 634 else if (firstch==TIMEOUT) { 635 if (Firstsec) 636 goto humbug; 637 bilge: 638 zperr( "TIMEOUT"); 639 } 640 else 641 zperr( "Got 0%o sector header", firstch); 642 643 humbug: 644 Lastrx=0; 645 while(readline(1)!=TIMEOUT) 646 ; 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 ... */ 653 } 654 } 655 /* try to stop the bubble machine. */ 656 canit(); 657 return ERROR; 658 } 659 660 #ifndef vax11c 661 /* 662 * This version of readline is reasoably well suited for 663 * reading many characters. 664 * (except, currently, for the Regulus version!) 665 * 666 * timeout is in tenths of seconds 667 */ 668 int readline(int timeout) 669 { 670 register int n; 671 static char *cdq; /* pointer for removing chars from linbuf */ 672 673 if (--Lleft >= 0) { 674 if (Verbose > 8) { 675 fprintf(stderr, "%02x ", *cdq&0377); 676 } 677 return (*cdq++ & 0377); 678 } 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; 693 } 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); 699 } 700 if (Lleft < 1) 701 return TIMEOUT; 702 --Lleft; 703 if (Verbose > 8) { 704 fprintf(stderr, "%02x ", *cdq&0377); 705 } 706 return (*cdq++ & 0377); 707 } 708 709 710 711 /* 712 * Purge the modem input queue of all characters 713 */ 714 void purgeline() 715 { 716 Lleft = 0; 717 #ifdef USG 718 ioctl(iofd, TCFLSH, 0); 719 #else 720 lseek(iofd, 0L, 2); 721 #endif 722 } 723 #endif 724 725 726 /* 727 * Process incoming file information header 728 */ 729 int procheader(char *name) 730 { 731 register char *openmode, *p; 732 733 /* set default parameters and overrides */ 734 openmode = "w"; 735 Thisbinary = (!Rxascii) || Rxbinary; 736 if (Lzmanag) 737 zmanag = Lzmanag; 738 739 /* 740 * Process ZMODEM remote file management requests 741 */ 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"; 748 749 #ifndef BIX 750 /* Check for existing file */ 751 if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) { 752 fclose(fout); return ERROR; 753 } 754 #endif 755 756 Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; 757 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); 768 } 769 } 770 771 #ifdef BIX 772 if ((fout=fopen("scratchpad", openmode)) == NULL) 773 return ERROR; 774 return OK; 775 #else 776 777 else { /* File coming from CP/M system */ 778 for (p=name; *p; ++p) /* change / to _ */ 779 if ( *p == '/') 780 *p = '_'; 781 782 if ( *--p == '.') /* zap trailing period */ 783 *p = 0; 784 } 785 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); 805 } 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; 814 } 815 Topipe = -1; return(OK); 816 } 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; 829 } 830 return OK; 831 #endif /* BIX */ 832 } 833 834 #ifdef MD 835 /* 836 * Directory-creating routines from Public Domain TAR by John Gilmore 837 */ 838 839 /* 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. 843 */ 844 int make_dirs(char *pathname) 845 { 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(); 850 851 if (errno != ENOENT) 852 return 0; /* Not our problem */ 853 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; 867 } 868 *p = '/'; 869 if (errno == EEXIST) /* Directory already exists */ 870 continue; 871 /* 872 * Some other error in the makedir. We return to the caller. 873 */ 874 break; 875 } 876 errno = save_errno; /* Restore caller's errno */ 877 return madeone; /* Tell them to retry if we made one */ 878 } 879 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) 884 /* 885 * Make a directory. Compatible with the mkdir() system call on 4.2BSD. 886 */ 887 int makedir(char *dpath, int dmode) 888 { 889 int cpid, status; 890 struct stat statbuf; 891 892 if (stat(dpath,&statbuf) == 0) { 893 errno = EEXIST; /* Stat worked, so it already exists */ 894 return -1; 895 } 896 897 /* If stat fails for a reason other than non-existence, return error */ 898 if (errno != ENOENT) return -1; 899 900 switch (cpid = fork()) { 901 902 case -1: /* Error in fork() */ 903 return(-1); /* Errno is set already */ 904 905 case 0: /* Child process */ 906 /* 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? 911 */ 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 */ 916 917 default: /* Parent process */ 918 while (cpid != wait(&status)) ; /* Wait for kid to finish */ 919 } 920 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 */ 924 } 925 926 return 0; 927 } 928 #endif /* MD != 2 */ 929 #endif /* MD */ 930 931 /* 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. 935 */ 936 int putsec(char *buf, int n) 937 { 938 register char *p; 939 940 if (n == 0) 941 return OK; 942 if (Thisbinary) { 943 for (p=buf; --n>=0; ) 944 putc( *p++, fout); 945 } 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; 954 } 955 putc(*p ,fout); 956 } 957 } 958 return OK; 959 } 960 961 #ifndef vax11c 962 /* 963 * Send a character to modem. Small is beautiful. 964 */ 965 void sendline(int c) 966 { 967 char d; 968 969 d = c; 970 if (Verbose>6) 971 fprintf(stderr, "Sendline: %x\n", c); 972 write(1, &d, 1); 973 } 974 975 void flushmo() {} 976 #endif 977 978 979 980 981 982 /* make string s lower case */ 983 void uncaps(char *s) 984 { 985 for ( ; *s; ++s) 986 if (isupper(*s)) 987 *s = tolower(*s); 988 } 989 /* 990 * IsAnyLower returns TRUE if string s has lower case letters. 991 */ 992 int IsAnyLower(char *s) 993 { 994 for ( ; *s; ++s) 995 if (islower(*s)) 996 return TRUE; 997 return FALSE; 998 } 999 1000 /* 1001 * substr(string, token) searches for token in string s 1002 * returns pointer to token within string if found, NULL otherwise 1003 */ 1004 char * 1005 substr(char *s, char *t) 1006 { 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; 1017 } 1018 return (char *)NULL; 1019 } 1020 1021 /* 1022 * Log an error 1023 */ 1024 /*VARARGS1*/ 1025 void zperr(char *s, char *p, char *u) 1026 { 1027 if (Verbose <= 0) 1028 return; 1029 fprintf(stderr, "Retry %d: ", errors); 1030 fprintf(stderr, s, p, u); 1031 fprintf(stderr, "\n"); 1032 } 1033 1034 /* send cancel string to get the other end to shut up */ 1035 void canit() 1036 { 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 1039 }; 1040 1041 #ifdef vax11c 1042 raw_wbuf(strlen(canistr), canistr); 1043 purgeline(); 1044 #else 1045 printf(canistr); 1046 Lleft=0; /* Do read next time ... */ 1047 fflush(stdout); 1048 #endif 1049 } 1050 1051 1052 void report(int sct) 1053 { 1054 if (Verbose>1) 1055 fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r'); 1056 } 1057 1058 #ifndef vax11c 1059 /* 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 1063 */ 1064 void chkinvok(char *s) 1065 { 1066 register char *p; 1067 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; 1076 } 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; 1086 } 1087 #endif 1088 1089 /* 1090 * Totalitarian Communist pathname processing 1091 */ 1092 void checkpath(char *name) 1093 { 1094 if (Restricted) { 1095 if (fopen(name, "r") != NULL) { 1096 canit(); 1097 fprintf(stderr, "\r\nrz: %s exists\n", name); 1098 bibi(-1); 1099 } 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); 1106 } 1107 } 1108 } 1109 1110 /* 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 1115 */ 1116 int tryz() 1117 { 1118 register int c, n; 1119 register int cmdzack1flg; 1120 1121 if (Nozmodem) /* Check for "rb" program name */ 1122 return 0; 1123 1124 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; 1167 } 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); 1187 } 1188 while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN); 1189 ackbibi(); 1190 if (cmdzack1flg & ZCACK1) 1191 exec2(secbuf); 1192 return ZCOMPL; 1193 } 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; 1204 } 1205 } 1206 return 0; 1207 } 1208 1209 /* 1210 * Receive 1 or more files with ZMODEM protocol 1211 */ 1212 int rzfiles() 1213 { 1214 register int c; 1215 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; 1227 } 1228 continue; 1229 default: 1230 return c; 1231 case ERROR: 1232 return ERROR; 1233 } 1234 } 1235 } 1236 1237 /* 1238 * Receive a file with ZMODEM protocol 1239 * Assumes file name frame is in secbuf 1240 */ 1241 int rzfile() 1242 { 1243 register int c, n; 1244 long rxbytes; 1245 1246 Eofseen=FALSE; 1247 if (procheader(secbuf) == ERROR) { 1248 return (tryzhdrtype = ZSKIP); 1249 } 1250 1251 n = 20; rxbytes = 0l; 1252 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; 1273 } 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) { 1283 /* 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. 1287 */ 1288 errors = 0; goto nxthdr; 1289 } 1290 if (closeit()) { 1291 tryzhdrtype = ZFERR; 1292 vfile("rzfile: closeit returned <> 0"); 1293 return ERROR; 1294 } 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; 1305 } 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; 1320 } 1321 #ifdef SEGMENTS 1322 putsec(secbuf, chinseg); 1323 chinseg = 0; 1324 #endif 1325 zmputs(Attn); continue; 1326 } 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; 1335 } 1336 switch (c = zrdata(secbuf+chinseg, 1024)) 1337 #else 1338 switch (c = zrdata(secbuf, 1024)) 1339 #endif 1340 { 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; 1356 } 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; 1367 } 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; 1412 } 1413 } 1414 } 1415 } 1416 1417 /* 1418 * Send a string to the modem, processing for \336 (sleep 1 sec) 1419 * and \335 (break signal) 1420 */ 1421 void zmputs(char *s) 1422 { 1423 register int c; 1424 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); 1433 } 1434 } 1435 } 1436 1437 /* 1438 * Close the receive dataset, return OK or ERROR 1439 */ 1440 int closeit() 1441 { 1442 time_t q; 1443 1444 #ifndef vax11c 1445 if (Topipe) { 1446 if (pclose(fout)) { 1447 return ERROR; 1448 } 1449 return OK; 1450 } 1451 #endif 1452 if (fclose(fout)==ERROR) { 1453 fprintf(stderr, "file close ERROR\n"); 1454 return ERROR; 1455 } 1456 #ifndef vax11c 1457 if (Modtime) { 1458 timep[0] = time(&q); 1459 timep[1] = Modtime; 1460 utime(Pathname, (struct utimbuf *) timep); 1461 } 1462 #endif 1463 if ((Filemode&S_IFMT) == S_IFREG) 1464 chmod(Pathname, (07777 & Filemode)); 1465 return OK; 1466 } 1467 1468 /* 1469 * Ack a ZFIN packet, let byegones be byegones 1470 */ 1471 void ackbibi() 1472 { 1473 register int n; 1474 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; 1491 } 1492 } 1493 } 1494 1495 1496 1497 /* 1498 * Local console output simulation 1499 */ 1500 void bttyout(int c) 1501 { 1502 if (Verbose || Fromcu) 1503 putc(c, stderr); 1504 } 1505 1506 #ifndef vax11c 1507 /* 1508 * Strip leading ! if present, do shell escape. 1509 */ 1510 int sys2(char *s) 1511 { 1512 if (*s == '!') 1513 ++s; 1514 return system(s); 1515 } 1516 /* 1517 * Strip leading ! if present, do exec. 1518 */ 1519 void exec2(char *s) 1520 { 1521 if (*s == '!') 1522 ++s; 1523 mode(0); 1524 execl("/bin/sh", "sh", "-c", s); 1525 } 1526 #endif 1527 /* End of rz.c */ 1528