📄 rz.c
字号:
#define VERSION "1.03 05-18-86"#define PUBDIR "/usr/spool/uucppublic"/*% cc -DNFGVMIN -K -O % -o rz; size rz * * rz.c By Chuck Forsberg * * cc -O rz.c -o rz USG (3.0) Unix * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3 * * ln rz rb For either system * * ln rz /usr/bin/rbrmail For remote mail. Make this the * login shell. rbrmail then calls * rmail(1) to deliver mail. * * Unix is a trademark of Western Electric Company * * A program for Unix to receive files and commands from computers running * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. * rz uses Unix buffered input to reduce wasted CPU time. * * Iff the program is invoked by rzCOMMAND, output is piped to * "COMMAND filename" * * Some systems (Venix, Coherent, Regulus) may not support tty raw mode * read(2) the same way as Unix. ONEREAD must be defined to force one * character reads for these systems. Added 7-01-84 CAF * * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF * * NFGVMIN Added 1-13-85 CAF for PC-AT Xenix systems where c_cc[VMIN] * doesn't seem to work (even though it compiles without error!). * * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin */#define LOGFILE "/tmp/rzlog"#define zperr vfile#include <stdio.h>#include <signal.h>#include <setjmp.h>#include <ctype.h>FILE *popen();#define OK 0#define FALSE 0#define TRUE 1#define ERROR (-1)#define HOWMANY 133int Zmodem=0; /* ZMODEM protocol requested */int Nozmodem = 0; /* If invoked as "rb" */unsigned Baudrate;#include "rbsb.c" /* most of the system dependent stuff here */char *substr();FILE *fout;/* * Routine to calculate the free bytes on the current file system * ~0 means many free bytes (unknown) */long getfree(){ return(~0L); /* many free bytes ... */}char *Extensions[] = {".A",".ARC",".CCC",".CL",".CMD",".COM",".CRL",".DAT",".DIR",".EXE",".O",".OBJ",".OVL",".PAG",".REL",".SAV",".SUB",".SWP",".SYS",".TAR",".UTL",".a",".arc",".com",".dat",".o",".obj",".ovl",".sys",".tar",""};/* Ward Christensen / CP/M parameters - Don't change these! */#define ENQ 005#define CAN ('X'&037)#define XOFF ('s'&037)#define XON ('q'&037)#define SOH 1#define STX 2#define EOT 4#define ACK 6#define NAK 025#define CPMEOF 032#define WANTCRC 0103 /* send C not NAK to get crc not checksum */#define TIMEOUT (-2)#define ERRORMAX 5#define RETRYMAX 5#define WCEOT (-10)#define SECSIZ 128 /* cp/m's Magic Number record size */#define PATHLEN 257 /* ready for 4.2 bsd ? */#define KSIZE 1024 /* record size with k option */#define UNIXFILE 0x8000 /* happens to the the S_IFREG file mask bit for stat */int Lastrx;int Crcflg;int Firstsec;int Eofseen; /* indicates cpm eof (^Z) has been received */int errors;int Restricted=0; /* restricted; no /.. or ../ in filenames */int Badclose = 0; /* Error on last close */#ifdef ONEREAD/* Sorry, Regulus and some others don't work right in raw mode! */int Readnum = 1; /* Number of bytes to ask for in read() from modem */#elseint Readnum = KSIZE; /* Number of bytes to ask for in read() from modem */#endif#define DEFBYTL 2000000000L /* default rx file size */long Bytesleft; /* number of bytes of incoming file left */long Modtime; /* Unix style mod time for incoming file */short Filemode; /* Unix style mode for incoming file */char Pathname[PATHLEN];char *Progname; /* the name by which we were called */int Batch=0;int Wcsmask=0377;int Topipe=0;int MakeLCPathname=TRUE; /* make received pathname lower case */int Verbose=0;int Quiet=0; /* overrides logic that would otherwise set verbose */int Nflag = 0; /* Don't really transfer files */int Rxbinary=FALSE; /* receive all files in bin mode */int Thisbinary; /* current file is to be received in bin mode */int Blklen; /* record length of received packets */char secbuf[KSIZE];char linbuf[KSIZE];int Lleft=0; /* number of characters in linbuf */time_t timep[2];char zconv; /* ZMODEM file conversion request */char zmanag; /* ZMODEM file management request */char ztrans; /* ZMODEM file transport request */jmp_buf tohere; /* For the interrupt on RX timeout */unsigned short updcrc();#include "zm.c"alrm(){ longjmp(tohere, -1);}/* called by signal interrupt or terminate to clean things up */bibi(n){ if (Zmodem) zmputs(Attn); canit(); mode(0); fprintf(stderr, "sb: caught signal %d; exiting", n); exit(128+n);}main(argc, argv)char *argv[];{ register char *cp; register npats; char *virgin, **patts; char *getenv(); int exitcode; setbuf(stderr, NULL); if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh"))) Restricted=TRUE; chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */ npats = 0; while (--argc) { cp = *++argv; if (*cp == '-') { while( *++cp) { switch(*cp) { case '1': iofd = 1; break; case '7': Wcsmask = 0177; case 'b': Rxbinary=TRUE; break; case 'k': case 'c': Crcflg=TRUE; break; case 'D': Nflag = TRUE; break; case 'q': Quiet=TRUE; Verbose=0; break; case 'u': MakeLCPathname=FALSE; break; case 'v': ++Verbose; break; default: usage(); } } } else if ( !npats && argc>0) { if (argv[0][0]) { npats=argc; patts=argv; } } } if (npats > 1) usage(); if (Verbose) { if (freopen(LOGFILE, "a", stderr)==NULL) { printf("Can't open log file %s\n",LOGFILE); exit(0200); } setbuf(stderr, NULL); fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname); } if (fromcu() && !Quiet) { if (Verbose == 0) Verbose = 2; } mode(1); if (signal(SIGINT, bibi) == SIG_IGN) { signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); } else { signal(SIGINT, bibi); signal(SIGKILL, bibi); } if (wcreceive(npats, patts)==ERROR) { exitcode=0200; canit(); } mode(0); if (exitcode && !Zmodem) /* bellow again with all thy might. */ canit(); exit(exitcode);}usage(){ fprintf(stderr,"%s %s for %s by Chuck Forsberg\n", Progname, VERSION, OS); fprintf(stderr,"Usage: rz [-1buv] (ZMODEM Batch)\n"); fprintf(stderr,"or rb [-1buv] (YMODEM Batch)\n"); fprintf(stderr,"or rz [-1bcv] file (XMODEM)\n"); fprintf(stderr," -1 For cu(1): Use fd 1 for input\n"); fprintf(stderr," -b Binary transfer for all files\n"); fprintf(stderr," -u Allow all UPPER CASE names\n"); fprintf(stderr," -v Verbose more v's give more info\n"); fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n"); exit(1);}/* * Debugging information output interface routine *//* VARARGS1 */vfile(f, a, b, c)register char *f;{ if (Verbose > 1) { fprintf(stderr, f, a, b, c); fprintf(stderr, "\n"); }}/* * Let's receive something already. */wcreceive(argc, argp)char **argp;{ register c; if (Batch || argc==0) { Crcflg=(Wcsmask==0377); if ( !Quiet) fprintf(stderr, "rz: ready "); if (c=tryz()) { if (c == ZCOMPL) return OK; if (c == ERROR) goto fubar; c = rzfiles(); if (c) goto fubar; } else { for (;;) { if (wcrxpn(secbuf)== ERROR) goto fubar; if (secbuf[0]==0) return OK; if (procheader(secbuf) == ERROR) goto fubar; if (wcrx()==ERROR) goto fubar; } } } else { Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; strcpy(Pathname, *argp); checkpath(Pathname); fprintf(stderr, "\nrz: ready to receive %s ", Pathname); if ((fout=fopen(Pathname, "w")) == NULL) return ERROR; if (wcrx()==ERROR) goto fubar; } return OK;fubar: canit(); if (Topipe && fout) { pclose(fout); return ERROR; } if (fout) fclose(fout); if (Restricted) { unlink(Pathname); fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname); } return ERROR;}/* * Fetch a pathname from the other end as a C ctyle ASCIZ string. * Length is indeterminate as long as less than Blklen * A null string represents no more files (YMODEM) */wcrxpn(rpn)char *rpn; /* receive a pathname */{ register c;#ifdef NFGVMIN readline(1);#else purgeline();#endifet_tu: Firstsec=TRUE; Eofseen=FALSE; sendline(Crcflg?WANTCRC:NAK); Lleft=0; /* Do read next time ... */ while ((c = wcgetsec(rpn, 100)) != 0) { log( "Pathname fetch returned %d\n", c); if (c == WCEOT) { sendline(ACK); Lleft=0; /* Do read next time ... */ readline(1); goto et_tu; } return ERROR; } sendline(ACK); return OK;}/* * Adapted from CMODEM13.C, written by * Jack M. Wierda and Roderick W. Hart */wcrx(){ register int sectnum, sectcurr; register char sendchar; register char *p; int cblklen; /* bytes to dump this block */ Firstsec=TRUE;sectnum=0; Eofseen=FALSE; sendchar=Crcflg?WANTCRC:NAK; for (;;) { sendline(sendchar); /* send it now, we're ready! */ Lleft=0; /* Do read next time ... */ sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); report(sectcurr); if (sectcurr==(sectnum+1 &Wcsmask)) { if (sectnum==0 && !Thisbinary) { p=secbuf; sectcurr=Blklen; if (*p == 032) /* A hack for .arc files */ goto binbin; for (; *p != 032 && --sectcurr>=0; ++p) if (*p < 07 || (*p & 0200)) {binbin: Thisbinary++; if (Verbose) fprintf(stderr, "Changed to BIN\n"); break; } } sectnum++; cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; if (putsec(secbuf, cblklen)==ERROR) return ERROR; if ((Bytesleft-=cblklen) < 0) Bytesleft = 0; sendchar=ACK; } else if (sectcurr==(sectnum&Wcsmask)) { log( "Received dup Sector\n"); sendchar=ACK; } else if (sectcurr==WCEOT) { if (closeit()) return ERROR; sendline(ACK); Lleft=0; /* Do read next time ... */ return OK; } else if (sectcurr==ERROR) return ERROR; else { log( "Sync Error\n"); return ERROR; } }}/* * Wcgetsec fetches a Ward Christensen type sector. * Returns sector number encountered or ERROR if valid sector not received, * or CAN CAN received * or WCEOT if eot sector * time is timeout for first char, set to 4 seconds thereafter ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** * (Caller must do that when he is good and ready to get next sector) */wcgetsec(rxbuf, maxtime)char *rxbuf;int maxtime;{ register checksum, wcj, firstch; register unsigned short oldcrc; register char *p; int sectcurr; for (Lastrx=errors=0; errors<RETRYMAX; errors++) { if ((firstch=readline(maxtime))==STX) { Blklen=KSIZE; goto get2; } if (firstch==SOH) { Blklen=SECSIZ;get2: sectcurr=readline(1); if ((sectcurr+(oldcrc=readline(1)))==Wcsmask) { oldcrc=checksum=0; for (p=rxbuf,wcj=Blklen; --wcj>=0; ) { if ((firstch=readline(1)) < 0) goto bilge; oldcrc=updcrc(firstch, oldcrc); checksum += (*p++ = firstch); } if ((firstch=readline(1)) < 0) goto bilge; if (Crcflg) { oldcrc=updcrc(firstch, oldcrc); if ((firstch=readline(1)) < 0) goto bilge; oldcrc=updcrc(firstch, oldcrc); if (oldcrc & 0xFFFF) log("CRC=0%o\n", oldcrc); else { Firstsec=FALSE; return sectcurr; } } else if (((checksum-firstch)&Wcsmask)==0) { Firstsec=FALSE; return sectcurr; } else log( "Checksum Error\n"); } else log("Sector number garbled 0%o 0%o\n", sectcurr, oldcrc); } /* make sure eot really is eot and not just mixmash */#ifdef NFGVMIN else if (firstch==EOT && readline(1)==TIMEOUT) return WCEOT;#else else if (firstch==EOT && Lleft==0) return WCEOT;#endif else if (firstch==CAN) { if (Lastrx==CAN) { log( "Sender CANcelled\n"); return ERROR; } else { Lastrx=CAN; continue; } } else if (firstch==TIMEOUT) { if (Firstsec) goto humbug;bilge: log( "Timeout\n"); } else log( "Got 0%o sector header\n", firstch);humbug: Lastrx=0; while(readline(1)!=TIMEOUT) ; if (Firstsec) { sendline(Crcflg?WANTCRC:NAK); Lleft=0; /* Do read next time ... */ } else { maxtime=40; sendline(NAK); Lleft=0; /* Do read next time ... */ } } /* try to stop the bubble machine. */ canit(); return ERROR;}/* * This version of readline is reasoably well suited for * reading many characters. * (except, currently, for the Regulus version!) * * timeout is in tenths of seconds */readline(timeout)int timeout;{ register n; static char *cdq; /* pointer for removing chars from linbuf */ if (--Lleft >= 0) { if (Verbose > 8) { fprintf(stderr, "%02x ", *cdq&0377); } return (*cdq++ & Wcsmask); } n = timeout/10; if (n < 2) n = 3; if (Verbose > 3) fprintf(stderr, "Calling read: n=%d ", n); if (setjmp(tohere)) {#ifdef TIOCFLUSH/* ioctl(iofd, TIOCFLUSH, 0); */#endif Lleft = 0; if (Verbose>1) fprintf(stderr, "Readline:TIMEOUT\n"); return TIMEOUT; } signal(SIGALRM, alrm); alarm(n); Lleft=read(iofd, cdq=linbuf, Readnum); alarm(0); if (Verbose > 3) { fprintf(stderr, "Read returned %d bytes\n", Lleft); } if (Lleft < 1) return TIMEOUT; --Lleft; if (Verbose > 8) { fprintf(stderr, "%02x ", *cdq&0377); } return (*cdq++ & Wcsmask);}/* * Purge the modem input queue of all characters */purgeline(){ Lleft = 0;#ifdef USG ioctl(iofd, TCFLSH, 0);#else
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -