📄 sz.c
字号:
#define VERSION "sz 1.03 05-18-86"#define PUBDIR "/usr/spool/uucppublic"/*% cc -O -K sz.c -o sz; size sz * sz.c By Chuck Forsberg * * cc -O sz.c -o sz USG (SYS III/V) Unix * cc -O -DV7 sz.c -o sz Unix Version 7, 2.8 - 4.3 BSD * * ******* Some systems (Venix, Coherent, Regulus) do not ******* * ******* support tty raw mode read(2) identically to ******* * ******* Unix. ONEREAD must be defined to force one ******* * ******* character reads for these systems. ******* * * A program for Unix to send files and commands to computers running * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. * * Sz uses buffered I/O to greatly reduce CPU time compared to UMODEM. * * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin *//* * Attention string to be executed by receiver to interrupt streaming data * when an error is detected. A pause (0336) may be needed before the * ^C (03) or after it. */char Myattn[] = { 03, 0336, 0 };unsigned updcrc();char *substr(), *getenv();#define LOGFILE "/tmp/szlog"#define zperr vfile#include <stdio.h>#include <signal.h>#include <setjmp.h>#include <ctype.h>#define PATHLEN 256#define OK 0#define FALSE 0#define TRUE 1#define ERROR (-1)#define HOWMANY 2int Zmodem=0; /* ZMODEM protocol requested */unsigned Baudrate;#include "rbsb.c" /* most of the system dependent stuff here */FILE *in;/* 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 WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */#define TIMEOUT (-2)#define RETRYMAX 10#define SECSIZ 128 /* cp/m's Magic Number record size */#define KSIZE 1024char Lastrx;char Crcflg;int Wcsmask=0377;int Verbose=0;int Modem=0; /* MODEM - don't send pathnames */int Restricted=0; /* restricted; no /.. or ../ in filenames */int Quiet=0; /* overrides logic that would otherwise set verbose */int Ascii=0; /* Add CR's for brain damaged programs */int Fullname=0; /* transmit full pathname */int Unlinkafter=0; /* Unlink file after it is sent */int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */int firstsec;int errcnt=0; /* number of files unreadable */int blklen=SECSIZ; /* length of transmitted records */int Optiong; /* Let it rip no wait for sector ACK's */int Noeofseen;int Totsecs; /* total number of sectors this file */char txbuf[KSIZE];int Filcnt=0; /* count of number of files opened */int Lfseen=0;unsigned Rxbuflen = 16384; /* Receiver's max buffer length */int Rxflags = 0;char Lzconv; /* Local ZMODEM file conversion request */char Lzmanag; /* Local ZMODEM file management request */char Lztrans;char zconv; /* ZMODEM file conversion request */char zmanag; /* ZMODEM file management request */char ztrans; /* ZMODEM file transport request */int Command; /* Send a command, then exit. */char *Cmdstr; /* Pointer to the command string */int Cmdtries = 11;int Cmdack1; /* Rx ACKs command, then do it */int Exitcode;int Testattn; /* Force receiver to send Attn, etc with qbf. */char *qbf="The quick brown fox jumped over the lazy dog's back 1234567890\r\n";jmp_buf tohere; /* For the interrupt on RX timeout */jmp_buf intrjmp; /* For the interrupt on RX CAN *//* called by signal interrupt or terminate to clean things up */bibi(n){ canit(); fflush(stdout); mode(0); fprintf(stderr, "sz: caught signal %d; exiting\n", n); if (n == SIGQUIT) abort(); exit(128+n);}/* Called when Zmodem gets an interrupt (^X) */onintr(){ signal(SIGINT, SIG_IGN); longjmp(intrjmp, -1);}#define sendline(c) putchar(c & Wcsmask)#define xsendline(c) putchar(c)flushmo(){ fflush(stdout);}#include "zm.c"main(argc, argv)char *argv[];{ register char *cp; register npats; int agcnt; char **agcv; char **patts; static char xXbuf[BUFSIZ]; if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rsh"))) Restricted=TRUE; Rxtimeout = 600; npats=0; if (argc<2) usage(); setbuf(stdout, xXbuf); while (--argc) { cp = *++argv; if (*cp++ == '-' && *cp) { while ( *cp) { switch(*cp++) { case '+': Lzmanag = ZMAPND; break; case '1': iofd = 1; break; case '7': Wcsmask=0177; break; case 'a': Lzconv = ZCNL; Ascii = TRUE; break; case 'b': Lzconv = ZCBIN; break; case 'C': if (--argc < 1) { usage(); } Cmdtries = atoi(*++argv); break; case 'i': Cmdack1 = ZCACK1; /* **** FALL THROUGH TO **** */ case 'c': if (--argc != 1) { usage(); } Command = TRUE; Cmdstr = *++argv; break; case 'd': ++Dottoslash; /* **** FALL THROUGH TO **** */ case 'f': Fullname=TRUE; break; case 'k': blklen=KSIZE; break; case 'N': Lzmanag = ZMCRC; break; case 'n': Lzmanag = ZMNEW; break; case 'r': Lzconv = ZCRESUM; case 'q': Quiet=TRUE; Verbose=0; break; case 'T': Testattn = TRUE; break; case 'u': ++Unlinkafter; break; case 'v': ++Verbose; break; case 'X': ++Modem; break; case 'y': Lzmanag = ZMCLOB; break; default: usage(); } } } else if ( !npats && argc>0) { if (argv[0][0]) { npats=argc; patts=argv; if ( !strcmp(*patts, "-")) iofd = 1; } } } if (npats < 1 && !Command) usage(); if (Verbose) { if (freopen(LOGFILE, "a", stderr)==NULL) { printf("Can't open log file %s\n",LOGFILE); exit(0200); } setbuf(stderr, NULL); } 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); signal(SIGQUIT, bibi); } if ( !Modem) { if (!Command) { printf("rz\r"); fflush(stdout); } if (!Command && !Quiet && Verbose != 1) { fprintf(stderr, "sz: %d file%s requested:\r\n", npats, npats>1?"s":""); for ( agcnt=npats, agcv=patts; --agcnt>=0; ) { fprintf(stderr, "%s ", *agcv++); } fprintf(stderr, "\r\n"); printf("\r\n\bSending in Batch Mode\r\n"); } stohdr(0L); if (Command) Txhdr[ZF0] = ZCOMMAND; zshhdr(ZRQINIT, Txhdr); } fflush(stdout); if (Command) { if (getzrxinit()) { Exitcode=0200; canit(); } else if (zsendcmd(Cmdstr, 1+strlen(Cmdstr))) { Exitcode=0200; canit(); } } else if (wcsend(npats, patts)==ERROR) { Exitcode=0200; canit(); } fflush(stdout); mode(0); exit((errcnt != 0) | Exitcode); /*NOTREACHED*/}wcsend(argc, argp)char *argp[];{ register n; Crcflg=FALSE; firstsec=TRUE; for (n=0; n<argc; ++n) { Totsecs = 0; if (wcs(argp[n])==ERROR) return ERROR; } Totsecs = 0; if (Filcnt==0) { /* bitch if we couldn't open ANY files */ fprintf(stderr,"\r\nCan't open any requested files.\r\n"); return ERROR; } if (Zmodem) saybibi(); else wctxpn(""); return OK;}wcs(oname)char *oname;{ register c; register char *p; struct stat f; char name[PATHLEN]; strcpy(name, oname); if (Restricted) { /* restrict pathnames to current tree or uucppublic */ if ( substr(name, "../") || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) { canit(); fprintf(stderr,"\r\nsz:\tSecurity Violation\r\n"); return ERROR; } } if ( !strcmp(oname, "-")) { if ((p = getenv("ONAME")) && *p) strcpy(name, p); else sprintf(name, "s%d.sz", getpid()); in = stdin; } else if ((in=fopen(oname, "r"))==NULL) { ++errcnt; return OK; /* pass over it, there may be others */ } ++Noeofseen; /* Check for directory or block special files */ fstat(fileno(in), &f); c = f.st_mode & S_IFMT; if (c == S_IFDIR || c == S_IFBLK) { fclose(in); return OK; } ++Filcnt; switch (wctxpn(name)) { case ERROR: return ERROR; case ZSKIP: return OK; } if (!Zmodem && wctx()==ERROR) return ERROR; if (Unlinkafter) unlink(oname); return 0;}/* * generate and transmit pathname block consisting of * pathname (null terminated), * file length, mode time and file mode in octal * as provided by the Unix fstat call. * N.B.: modifies the passed name, may extend it! */wctxpn(name)char *name;{ register char *p, *q; char name2[PATHLEN]; struct stat f; if (Modem) { if ((in!=stdin) && *name && fstat(fileno(in), &f)!= -1) { fprintf(stderr, "Sending %s, %ld blocks: ", name, f.st_size>>7); } fprintf(stderr, "Give your local XMODEM receive command now.\r\n"); return OK; } logent("\r\nAwaiting pathname nak for %s\r\n", *name?name:"<END>"); if ( !Zmodem) if (getnak()) return ERROR; q = (char *) 0; if (Dottoslash) { /* change . to . */ for (p=name; *p; ++p) { if (*p == '/') q = p; else if (*p == '.') *(q=p) = '/'; } if (q && strlen(++q) > 8) { /* If name>8 chars */ q += 8; /* make it .ext */ strcpy(name2, q); /* save excess of name */ *q = '.'; strcpy(++q, name2); /* add it back */ } } for (p=name, q=txbuf ; *p; ) if ((*q++ = *p++) == '/' && !Fullname) q = txbuf; *q++ = 0; p=q; while (q < (txbuf + KSIZE)) *q++ = 0; if (!Ascii && (in!=stdin) && *name && fstat(fileno(in), &f)!= -1) sprintf(p, "%lu %lo %o", f.st_size, f.st_mtime, f.st_mode); /* force 1k blocks if name won't fit in 128 byte block */ if (txbuf[125]) blklen=KSIZE; else { /* A little goodie for IMP/KMD */ if (Zmodem) blklen = SECSIZ; txbuf[127] = f.st_size >>7; txbuf[126] = f.st_size >>15; } if (Zmodem) return zsendfile(txbuf, 1+strlen(p)+(p-txbuf)); if (wcputsec(txbuf, 0, SECSIZ)==ERROR) return ERROR; return OK;}getnak(){ register firstch; Lastrx = 0; for (;;) { switch (firstch = readock(800,1)) { case ZPAD: if (getzrxinit()) return ERROR; Ascii = 0; return FALSE; case TIMEOUT: logent("Timeout on pathname\n"); return TRUE; case WANTG: mode(2); /* Set cbreak, XON/XOFF, etc. */ Optiong = TRUE; blklen=KSIZE; case WANTCRC: Crcflg = TRUE; case NAK: return FALSE; case CAN: if (Lastrx == CAN) return TRUE; default: break; } Lastrx = firstch; }}wctx(){ register int sectnum, attempts, firstch; firstsec=TRUE; while ((firstch=readock(400, 2))!=NAK && firstch != WANTCRC && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) ; if (firstch==CAN) { logent("Receiver CANcelled\n"); return ERROR; } if (firstch==WANTCRC) Crcflg=TRUE; if (firstch==WANTG) Crcflg=TRUE; sectnum=1; while (filbuf(txbuf, blklen)) { if (wcputsec(txbuf, sectnum, blklen)==ERROR) { return ERROR; } else sectnum++; } if (Verbose>1) fprintf(stderr, " Closing "); fclose(in); attempts=0; do { logent(" EOT "); purgeline(); sendline(EOT); fflush(stdout); ++attempts; } while ((firstch=(readock(100, 1)) != ACK) && attempts < RETRYMAX); if (attempts == RETRYMAX) { logent("No ACK on EOT\n"); return ERROR; } else return OK;}wcputsec(buf, sectnum, cseclen)char *buf;int sectnum;int cseclen; /* data length of this sector to send */{ register checksum, wcj; register char *cp; unsigned oldcrc; int firstch; int attempts; firstch=0; /* part of logic to detect CAN CAN */ if (Verbose>1) fprintf(stderr, "\rSector %3d %2dk ", Totsecs, Totsecs/8 ); for (attempts=0; attempts <= RETRYMAX; attempts++) { Lastrx= firstch; sendline(cseclen==KSIZE?STX:SOH); sendline(sectnum); sendline(-sectnum -1); oldcrc=checksum=0; for (wcj=cseclen,cp=buf; --wcj>=0; ) { sendline(*cp); oldcrc=updcrc(*cp, oldcrc); checksum += *cp++; } if (Crcflg) { oldcrc=updcrc(0,updcrc(0,oldcrc)); sendline((int)oldcrc>>8); sendline((int)oldcrc); } else sendline(checksum); if (Optiong) { firstsec = FALSE; return OK; } firstch = readock(400, (Noeofseen&§num) ? 2:1);gotnak: switch (firstch) { case CAN: if(Lastrx == CAN) {cancan: logent("Cancelled\n"); return ERROR; } break; case TIMEOUT: logent("Timeout on sector ACK\n"); continue; case WANTCRC: if (firstsec) Crcflg = TRUE; case NAK: logent("NAK on sector\n"); continue; case ACK: firstsec=FALSE; Totsecs += (cseclen>>7); return OK; case ERROR: logent("Got burst for sector ACK\n"); break; default: logent("Got %02x for sector ACK\n", firstch); break; } for (;;) { Lastrx = firstch; if ((firstch = readock(400, 2)) == TIMEOUT) break; if (firstch == NAK || firstch == WANTCRC)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -