Path: utzoo!attcan!utgpu!jarvis.csri.toronto.edu!rutgers!apple!bionet!ames!elroy!usc!orion.cf.uci.edu!uci-ics!zardoz!dhw68k!bob From: bob@dhw68k.cts.com (Bob Best) Newsgroups: comp.os.minix Subject: zterm - background zmodem with dialer (Part 4/5) Message-ID: <23580@dhw68k.cts.com> Date: 8 Jun 89 13:37:55 GMT References: <23577@dhw68k.cts.com> Reply-To: bob@dhw68k.cts.com (Bob Best) Organization: Wolfskill & Dowling residence; Anaheim, CA (USA) Lines: 1535 #! /bin/sh # This is a shell archive. Remove anything before this line, then unpack # it by saving it into a file and typing "sh file". To overwrite existing # files, type "sh file -c". You can also feed this as standard input via # unshar, or by typing "sh 'rz.c' <<'END_OF_FILE' X#define VERSION "2.02 04-22-88" X#define PUBDIR "/usr/spool/uucppublic" X X/*% cc -compat -M2 -Ox -K -i -DMD % -o rz; size rz; X<-xtx-*> cc386 -Ox -DMD -DSEGMENTS=8 rz.c -o $B/rz; size $B/rz X * X * rz.c By Chuck Forsberg X * X * cc -O rz.c -o rz USG (3.0) Unix X * cc -O -DV7 rz.c -o rz Unix V7, BSD 2.8 - 4.3 X * X * ln rz rb; ln rz rx For either system X * X * ln rz /usr/bin/rzrmail For remote mail. Make this the X * login shell. rzrmail then calls X * rmail(1) to deliver mail. X * X * To compile on VMS: X * X * define LNK$LIBRARY SYS$LIBRARY:VAXCRTL.OLB X * cc rz.c X * cc vvmodem.c X * link rz,vvmodem X * rz :== $disk:[username.subdir]rz.exe X * X * X * Unix is a trademark of Western Electric Company X * X * A program for Unix to receive files and commands from computers running X * Professional-YAM, PowerCom, YAM, IMP, or programs supporting XMODEM. X * rz uses Unix buffered input to reduce wasted CPU time. X * X * Iff the program is invoked by rzCOMMAND, output is piped to X * "COMMAND filename" (Unix only) X * X * Some systems (Venix, Coherent, Regulus) may not support tty raw mode X * read(2) the same way as Unix. ONEREAD must be defined to force one X * character reads for these systems. Added 7-01-84 CAF X * X * Alarm signal handling changed to work with 4.2 BSD 7-15-84 CAF X * X * BIX added 6-30-87 to support BIX(TM) upload protocol used by the X * Byte Information Exchange. X * X * NFGVMIN Updated 2-18-87 CAF for Xenix systems where c_cc[VMIN] X * doesn't work properly (even though it compiles without error!), X * X * SEGMENTS=n added 2-21-88 as a model for CP/M programs X * for CP/M-80 systems that cannot overlap modem and disk I/O. X * X * VMS flavor hacks begin with rz version 2.00 X * X * -DMD may be added to compiler command line to compile in X * Directory-creating routines from Public Domain TAR by John Gilmore X * X * HOWMANY may be tuned for best performance X * X * USG UNIX (3.0) ioctl conventions courtesy Jeff Martin X */ X X#ifdef vax11c X#include X#include X#define LOGFILE "rzlog.tmp" X#include X#include X#include X#include X#include X#define OS "VMS" X#define BUFREAD Xextern int errno; X#define SS_NORMAL SS$_NORMAL X#else X#define SS_NORMAL 0 X#define LOGFILE "/tmp/rzlog" X#include X#include X#include X#include X#include Xextern int errno; XFILE *popen(); X#endif X X#define OK 0 X#define FALSE 0 X#define TRUE 1 X#define ERROR (-1) X X/* X * Max value for HOWMANY is 255. X * A larger value reduces system overhead but may evoke kernel bugs. X * 133 corresponds to an XMODEM/CRC sector X */ X#ifndef HOWMANY X#define HOWMANY 133 X#endif X X/* Ward Christensen / CP/M parameters - Don't change these! */ X#define ENQ 005 X#define CAN ('X'&037) X#define XOFF ('s'&037) X#define XON ('q'&037) X#define SOH 1 X#define STX 2 X#define EOT 4 X#define ACK 6 X#define NAK 025 X#define CPMEOF 032 X#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ X#define TIMEOUT (-2) X#define RCDO (-3) X#define ERRORMAX 5 X#define RETRYMAX 5 X#define WCEOT (-10) X#define PATHLEN 257 /* ready for 4.2 bsd ? */ X#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */ X Xint Zmodem=0; /* ZMODEM protocol requested */ Xint Nozmodem = 0; /* If invoked as "rb" */ Xunsigned Baudrate = 2400; X#ifdef vax11c X#include "vrzsz.c" /* most of the system dependent stuff here */ X#else X#include "rbsb.c" /* most of the system dependent stuff here */ X#endif X#include "crctab.c" X Xchar *substr(); XFILE *fout; X X/* X * Routine to calculate the free bytes on the current file system X * ~0 means many free bytes (unknown) X */ Xlong getfree() X{ X return(~0L); /* many free bytes ... */ X} X Xint Lastrx; Xint Crcflg; Xint Firstsec; Xint Eofseen; /* indicates cpm eof (^Z) has been received */ Xint errors; Xint Restricted=0; /* restricted; no /.. or ../ in filenames */ X#ifdef ONEREAD X/* Sorry, Regulus and some others don't work right in raw mode! */ Xint Readnum = 1; /* Number of bytes to ask for in read() from modem */ X#else Xint Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */ X#endif X X#define DEFBYTL 2000000000L /* default rx file size */ Xlong Bytesleft; /* number of bytes of incoming file left */ Xlong Modtime; /* Unix style mod time for incoming file */ Xint Filemode; /* Unix style mode for incoming file */ Xchar Pathname[PATHLEN]; Xchar *Progname; /* the name by which we were called */ X Xint Batch=0; Xint Topipe=0; Xint MakeLCPathname=TRUE; /* make received pathname lower case */ Xint Verbose=0; Xint Quiet=0; /* overrides logic that would otherwise set verbose */ Xint Nflag = 0; /* Don't really transfer files */ Xint Rxclob=FALSE; /* Clobber existing file */ Xint Rxbinary=FALSE; /* receive all files in bin mode */ Xint Rxascii=FALSE; /* receive files in ascii (translate) mode */ Xint Thisbinary; /* current file is to be received in bin mode */ Xint Blklen; /* record length of received packets */ X X#ifdef SEGMENTS Xint chinseg = 0; /* Number of characters received in this data seg */ Xchar secbuf[1+(SEGMENTS+1)*1024]; X#else Xchar secbuf[1025]; X#endif X X Xchar linbuf[HOWMANY]; Xint Lleft=0; /* number of characters in linbuf */ Xtime_t timep[2]; Xchar Lzmanag; /* Local file management request */ Xchar zconv; /* ZMODEM file conversion request */ Xchar zmanag; /* ZMODEM file management request */ Xchar ztrans; /* ZMODEM file transport request */ Xint Zctlesc; /* Encode control characters */ Xint Zrwindow = 1400; /* RX window size (controls garbage count) */ X Xjmp_buf tohere; /* For the interrupt on RX timeout */ X X#define xsendline(c) sendline(c) X#include "zm.c" X Xint tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ X Xalrm() X{ X longjmp(tohere, -1); X} X X/* called by signal interrupt or terminate to clean things up */ Xbibi(n) X{ X if (Zmodem) X zmputs(Attn); X canit(); mode(0); X fprintf(stderr, "rz: caught signal %d; exiting", n); X cucheck(); X exit(128+n); X} X Xmain(argc, argv) Xchar *argv[]; X{ X register char *cp; X register npats; X char *virgin, **patts; X char *getenv(); X int exitcode; X X Rxtimeout = 100; X setbuf(stderr, NULL); X if ((cp=getenv("SHELL")) && (substr(cp, "rsh") || substr(cp, "rksh"))) X Restricted=TRUE; X X from_cu(); X#ifdef vax11c X Progname = virgin = "rz"; X#else X chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */ X#endif X npats = 0; X while (--argc) { X cp = *++argv; X if (*cp == '-') { X while( *++cp) { X switch(*cp) { X case '\\': X cp[1] = toupper(cp[1]); continue; X case '+': X Lzmanag = ZMAPND; break; X case 'a': X Rxascii=TRUE; break; X case 'b': X Rxbinary=TRUE; break; X case 'c': X Crcflg=TRUE; break; X#ifndef vax11c X case 'D': X Nflag = TRUE; break; X#endif X case 'e': X Zctlesc = 1; break; X case 'p': X Lzmanag = ZMPROT; break; X case 'q': X Quiet=TRUE; Verbose=0; break; X case 't': X if (--argc < 1) { X usage(); X } X Rxtimeout = atoi(*++argv); X if (Rxtimeout<10 || Rxtimeout>1000) X usage(); X break; X case 'w': X if (--argc < 1) { X usage(); X } X Zrwindow = atoi(*++argv); X break; X case 'u': X MakeLCPathname=FALSE; break; X case 'v': X ++Verbose; break; X case 'y': X Rxclob=TRUE; break; X default: X usage(); X } X } X } X else if ( !npats && argc>0) { X if (argv[0][0]) { X npats=argc; X patts=argv; X } X } X } X if (npats > 1) X usage(); X if (Batch && npats) X usage(); X if (Verbose) { X if (freopen(LOGFILE, "a", stderr)==NULL) { X printf("Can't open log file %s\n",LOGFILE); X exit(0200); X } X setbuf(stderr, NULL); X fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname); X } X if (Fromcu && !Quiet) { X if (Verbose == 0) X Verbose = 2; X } X mode(1); X if (signal(SIGINT, bibi) == SIG_IGN) { X signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); X } X else { X signal(SIGINT, bibi); signal(SIGKILL, bibi); X } X signal(SIGTERM, bibi); X if (wcreceive(npats, patts)==ERROR) { X exitcode=0200; X canit(); X } X mode(0); X if (exitcode && !Zmodem) /* bellow again with all thy might. */ X canit(); X if (exitcode) X cucheck(); X exit(exitcode ? exitcode:SS_NORMAL); X} X X Xusage() X{ X cucheck(); X#ifdef vax11c X fprintf(stderr,"Usage: rz [-abeuvy]\n"); X#else X fprintf(stderr,"Usage: rz [-abeuvy] (ZMODEM)\n"); X fprintf(stderr,"or rb [-abuvy] (YMODEM)\n"); X fprintf(stderr,"or rx [-abcv] file (XMODEM or XMODEM-1k)\n"); X#endif X fprintf(stderr," -a ASCII transfer (strip CR)\n"); X fprintf(stderr," -b Binary transfer for all files\n"); X#ifndef vax11c X fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n"); X#endif X fprintf(stderr," -e Escape control characters (ZMODEM)\n"); X fprintf(stderr," -v Verbose more v's give more info\n"); X fprintf(stderr," -y Yes, clobber existing file if any\n"); X fprintf(stderr,"%s %s for %s by Chuck Forsberg, Omen Technology INC\n", X Progname, VERSION, OS); X fprintf(stderr, "\t\t\042The High Reliability Software\042\n"); X exit(SS_NORMAL); X} X/* X * Debugging information output interface routine X */ X/* VARARGS1 */ Xvfile(f, a, b, c) Xregister char *f; X{ X if (Verbose > 2) { X fprintf(stderr, f, a, b, c); X fprintf(stderr, "\n"); X } X} X X/* X * Let's receive something already. X */ X Xchar *rbmsg = X"%s ready. To begin transfer, type \"%s file ...\" to your modem program\r\n\n"; X Xwcreceive(argc, argp) Xchar **argp; X{ X register c; X X if (Batch || argc==0) { X Crcflg=1; X if ( !Quiet) X fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz"); X if (c=tryz()) { X if (c == ZCOMPL) X return OK; X if (c == ERROR) X goto fubar; X c = rzfiles(); X if (c) X goto fubar; X } else { X for (;;) { X if (wcrxpn(secbuf)== ERROR) X goto fubar; X if (secbuf[0]==0) X return OK; X if (procheader(secbuf) == ERROR) X goto fubar; X if (wcrx()==ERROR) X goto fubar; X } X } X } else { X Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; X X procheader(""); strcpy(Pathname, *argp); checkpath(Pathname); X fprintf(stderr, "\nrz: ready to receive %s\r\n", Pathname); X if ((fout=fopen(Pathname, "w")) == NULL) X return ERROR; X if (wcrx()==ERROR) X goto fubar; X } X return OK; Xfubar: X canit(); X#ifndef vax11c X if (Topipe && fout) { X pclose(fout); return ERROR; X } X#endif X if (fout) X fclose(fout); X#ifndef vax11c X if (Restricted) { X unlink(Pathname); X fprintf(stderr, "\r\nrz: %s removed.\r\n", Pathname); X } X#endif X return ERROR; X} X X X/* X * Fetch a pathname from the other end as a C ctyle ASCIZ string. X * Length is indeterminate as long as less than Blklen X * A null string represents no more files (YMODEM) X */ Xwcrxpn(rpn) Xchar *rpn; /* receive a pathname */ X{ X register c; X X#ifdef NFGVMIN X readline(1); X#else X purgeline(); X#endif X Xet_tu: X Firstsec=TRUE; Eofseen=FALSE; X sendline(Crcflg?WANTCRC:NAK); X Lleft=0; /* Do read next time ... */ X while ((c = wcgetsec(rpn, 100)) != 0) { X if (c == WCEOT) { X zperr( "Pathname fetch returned %d", c); X sendline(ACK); X Lleft=0; /* Do read next time ... */ X readline(1); X goto et_tu; X } X return ERROR; X } X sendline(ACK); X return OK; X} X X/* X * Adapted from CMODEM13.C, written by X * Jack M. Wierda and Roderick W. Hart X */ X Xwcrx() X{ X register int sectnum, sectcurr; X register char sendchar; X register char *p; X int cblklen; /* bytes to dump this block */ X X Firstsec=TRUE;sectnum=0; Eofseen=FALSE; X sendchar=Crcflg?WANTCRC:NAK; X X for (;;) { X sendline(sendchar); /* send it now, we're ready! */ X Lleft=0; /* Do read next time ... */ X sectcurr=wcgetsec(secbuf, (sectnum&0177)?50:130); X report(sectcurr); X if (sectcurr==(sectnum+1 &0377)) { X sectnum++; X cblklen = Bytesleft>Blklen ? Blklen:Bytesleft; X if (putsec(secbuf, cblklen)==ERROR) X return ERROR; X if ((Bytesleft-=cblklen) < 0) X Bytesleft = 0; X sendchar=ACK; X } X else if (sectcurr==(sectnum&0377)) { X zperr( "Received dup Sector"); X sendchar=ACK; X } X else if (sectcurr==WCEOT) { X if (closeit()) X return ERROR; X sendline(ACK); X Lleft=0; /* Do read next time ... */ X return OK; X } X else if (sectcurr==ERROR) X return ERROR; X else { X zperr( "Sync Error"); X return ERROR; X } X } X} X X/* X * Wcgetsec fetches a Ward Christensen type sector. X * Returns sector number encountered or ERROR if valid sector not received, X * or CAN CAN received X * or WCEOT if eot sector X * time is timeout for first char, set to 4 seconds thereafter X ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** X * (Caller must do that when he is good and ready to get next sector) X */ X Xwcgetsec(rxbuf, maxtime) Xchar *rxbuf; Xint maxtime; X{ X register checksum, wcj, firstch; X register unsigned short oldcrc; X register char *p; X int sectcurr; X X for (Lastrx=errors=0; errors=0; ) { X if ((firstch=readline(1)) < 0) X goto bilge; X oldcrc=updcrc(firstch, oldcrc); X checksum += (*p++ = firstch); X } X if ((firstch=readline(1)) < 0) X goto bilge; X if (Crcflg) { X oldcrc=updcrc(firstch, oldcrc); X if ((firstch=readline(1)) < 0) X goto bilge; X oldcrc=updcrc(firstch, oldcrc); X if (oldcrc & 0xFFFF) X zperr( "CRC"); X else { X Firstsec=FALSE; X return sectcurr; X } X } X else if (((checksum-firstch)&0377)==0) { X Firstsec=FALSE; X return sectcurr; X } X else X zperr( "Checksum"); X } X else X zperr("Sector number garbled"); X } X /* make sure eot really is eot and not just mixmash */ X#ifdef NFGVMIN X else if (firstch==EOT && readline(1)==TIMEOUT) X return WCEOT; X#else X else if (firstch==EOT && Lleft==0) X return WCEOT; X#endif X else if (firstch==CAN) { X if (Lastrx==CAN) { X zperr( "Sender CANcelled"); X return ERROR; X } else { X Lastrx=CAN; X continue; X } X } X else if (firstch==TIMEOUT) { X if (Firstsec) X goto humbug; Xbilge: X zperr( "TIMEOUT"); X } X else X zperr( "Got 0%o sector header", firstch); X Xhumbug: X Lastrx=0; X while(readline(1)!=TIMEOUT) X ; X if (Firstsec) { X sendline(Crcflg?WANTCRC:NAK); X Lleft=0; /* Do read next time ... */ X } else { X maxtime=40; sendline(NAK); X Lleft=0; /* Do read next time ... */ X } X } X /* try to stop the bubble machine. */ X canit(); X return ERROR; X} X X#ifndef vax11c X/* X * This version of readline is reasoably well suited for X * reading many characters. X * (except, currently, for the Regulus version!) X * X * timeout is in tenths of seconds X */ Xreadline(timeout) Xint timeout; X{ X register n; X static char *cdq; /* pointer for removing chars from linbuf */ X X if (--Lleft >= 0) { X if (Verbose > 8) { X fprintf(stderr, "%02x ", *cdq&0377); X } X return (*cdq++ & 0377); X } X n = timeout/10; X if (n < 2) X n = 3; X if (Verbose > 5) X fprintf(stderr, "Calling read: alarm=%d Readnum=%d ", X n, Readnum); X if (setjmp(tohere)) { X#ifdef TIOCFLUSH X/* ioctl(iofd, TIOCFLUSH, 0); */ X#endif X Lleft = 0; X if (Verbose>1) X fprintf(stderr, "Readline:TIMEOUT\n"); X return TIMEOUT; X } X signal(SIGALRM, alrm); alarm(n); X Lleft=read(iofd, cdq=linbuf, Readnum); X alarm(0); X if (Verbose > 5) { X fprintf(stderr, "Read returned %d bytes\n", Lleft); X } X if (Lleft < 1) X return TIMEOUT; X --Lleft; X if (Verbose > 8) { X fprintf(stderr, "%02x ", *cdq&0377); X } X return (*cdq++ & 0377); X} X X X X/* X * Purge the modem input queue of all characters X */ Xpurgeline() X{ X Lleft = 0; X#ifdef USG X ioctl(iofd, TCFLSH, 0); X#else X lseek(iofd, 0L, 2); X#endif X} X#endif X X X/* X * Process incoming file information header X */ Xprocheader(name) Xchar *name; X{ X register char *openmode, *p, **pp; X X /* set default parameters and overrides */ X openmode = "w"; X Thisbinary = (!Rxascii) || Rxbinary; X if (Lzmanag) X zmanag = Lzmanag; X X /* X * Process ZMODEM remote file management requests X */ X if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */ X Thisbinary = 0; X if (zconv == ZCBIN) /* Remote Binary override */ X Thisbinary = TRUE; X else if (zmanag == ZMAPND) X openmode = "a"; X X#ifndef BIX X /* Check for existing file */ X if (!Rxclob && (zmanag&ZMMASK) != ZMCLOB && (fout=fopen(name, "r"))) { X fclose(fout); return ERROR; X } X#endif X X Bytesleft = DEFBYTL; Filemode = 0; Modtime = 0L; X X p = name + 1 + strlen(name); X if (*p) { /* file coming from Unix or DOS system */ X sscanf(p, "%ld%lo%o", &Bytesleft, &Modtime, &Filemode); X#ifndef vax11c X if (Filemode & UNIXFILE) X ++Thisbinary; X#endif X if (Verbose) { X fprintf(stderr, "Incoming: %s %ld %lo %o\n", X name, Bytesleft, Modtime, Filemode); X } X } X X#ifdef BIX X if ((fout=fopen("scratchpad", openmode)) == NULL) X return ERROR; X return OK; X#else X X else { /* File coming from CP/M system */ X for (p=name; *p; ++p) /* change / to _ */ X if ( *p == '/') X *p = '_'; X X if ( *--p == '.') /* zap trailing period */ X *p = 0; X } X X#ifndef vax11c X if (!Zmodem && MakeLCPathname && !IsAnyLower(name) X && !(Filemode&UNIXFILE)) X uncaps(name); X#endif X if (Topipe) { X sprintf(Pathname, "%s %s", Progname+2, name); X if (Verbose) X fprintf(stderr, "Topipe: %s %s\n", X Pathname, Thisbinary?"BIN":"ASCII"); X#ifndef vax11c X if ((fout=popen(Pathname, "w")) == NULL) X return ERROR; X#endif X } else { X strcpy(Pathname, name); X if (Verbose) { X fprintf(stderr, "Receiving %s %s %s\n", X name, Thisbinary?"BIN":"ASCII", openmode); X } X checkpath(name); X if (Nflag) X name = "/dev/null"; X#ifdef MD X fout = fopen(name, openmode); X if ( !fout) X if (make_dirs(name)) X fout = fopen(name, openmode); X#else X fout = fopen(name, openmode); X#endif X if ( !fout) X return ERROR; X } X return OK; X#endif /* BIX */ X} X X#ifdef MD X/* X * Directory-creating routines from Public Domain TAR by John Gilmore X */ X X/* X * After a file/link/symlink/dir creation has failed, see if X * it's because some required directory was not present, and if X * so, create all required dirs. X */ Xmake_dirs(pathname) Xregister char *pathname; X{ X char str[128]; X register char *p; /* Points into path */ X int madeone = 0; /* Did we do anything yet? */ X int save_errno = errno; /* Remember caller's errno */ X X if (errno != ENOENT) X return 0; /* Not our problem */ X X for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) { X /* Avoid mkdir of empty string, if leading or double '/' */ X if (p == pathname || p[-1] == '/') X continue; X /* Avoid mkdir where last part of path is '.' */ X if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/')) X continue; X *p = 0; /* Truncate the path there */ X/* if ( !mkdir(pathname, 0777)) { /* Try to create it as a dir */ X/* RSB - no mkdir(2) in minix */ X strcpy(str,"/bin/mkdir "); X strcat(str,pathname); X if ( !system(str)) { X vfile("Made directory %s\n", pathname); X madeone++; /* Remember if we made one */ X *p = '/'; X continue; X } X *p = '/'; X if (errno == EEXIST) /* Directory already exists */ X continue; X /* X * Some other error in the mkdir. We return to the caller. X */ X break; X } X errno = save_errno; /* Restore caller's errno */ X return madeone; /* Tell them to retry if we made one */ X} X X#if (MD != 2) X#define TERM_SIGNAL(status) ((status) & 0x7F) X#define TERM_COREDUMP(status) (((status) & 0x80) != 0) X#define TERM_VALUE(status) ((status) >> 8) X/* X * Make a directory. Compatible with the mkdir() system call on 4.2BSD. X */ Xmkdir(dpath, dmode) Xchar *dpath; Xint dmode; X{ X int cpid, status; X struct stat statbuf; X X if (stat(dpath,&statbuf) == 0) { X errno = EEXIST; /* Stat worked, so it already exists */ X return -1; X } X X /* If stat fails for a reason other than non-existence, return error */ X if (errno != ENOENT) return -1; X X switch (cpid = fork()) { X X case -1: /* Error in fork() */ X return(-1); /* Errno is set already */ X X case 0: /* Child process */ X /* X * Cheap hack to set mode of new directory. Since this X * child process is going away anyway, we zap its umask. X * FIXME, this won't suffice to set SUID, SGID, etc. on this X * directory. Does anybody care? X */ X status = umask(0); /* Get current umask */ X status = umask(status | (0777 & ~dmode)); /* Set for mkdir */ X execl("/bin/mkdir", "mkdir", dpath, (char *)0); X _exit(-1); /* Can't exec /bin/mkdir */ X X default: /* Parent process */ X while (cpid != wait(&status)) ; /* Wait for kid to finish */ X } X X if (TERM_SIGNAL(status) != 0 || TERM_VALUE(status) != 0) { X errno = EIO; /* We don't know why, but */ X return -1; /* /bin/mkdir failed */ X } X X return 0; X} X#endif /* MD != 2 */ X#endif /* MD */ X X/* X * Putsec writes the n characters of buf to receive file fout. X * If not in binary mode, carriage returns, and all characters X * starting with CPMEOF are discarded. X */ Xputsec(buf, n) Xchar *buf; Xregister n; X{ X register char *p; X X if (n == 0) X return OK; X if (Thisbinary) { X for (p=buf; --n>=0; ) X putc( *p++, fout); X } X else { X if (Eofseen) X return OK; X for (p=buf; --n>=0; ++p ) { X if ( *p == '\r') X continue; X if (*p == CPMEOF) { X Eofseen=TRUE; return OK; X } X putc(*p ,fout); X } X } X return OK; X} X X#ifndef vax11c X/* X * Send a character to modem. Small is beautiful. X */ Xsendline(c) X{ X char d; X X d = c; X if (Verbose>6) X fprintf(stderr, "Sendline: %x\n", c); X write(1, &d, 1); X} X Xflushmo() {} X#endif X X X X X X/* make string s lower case */ Xuncaps(s) Xregister char *s; X{ X for ( ; *s; ++s) X if (isupper(*s)) X *s = tolower(*s); X} X/* X * IsAnyLower returns TRUE if string s has lower case letters. X */ XIsAnyLower(s) Xregister char *s; X{ X for ( ; *s; ++s) X if (islower(*s)) X return TRUE; X return FALSE; X} X X/* X * substr(string, token) searches for token in string s X * returns pointer to token within string if found, NULL otherwise X */ Xchar * Xsubstr(s, t) Xregister char *s,*t; X{ X register char *ss,*tt; X /* search for first char of token */ X for (ss=s; *s; s++) X if (*s == *t) X /* compare token with substring */ X for (ss=s,tt=t; ;) { X if (*tt == 0) X return s; X if (*ss++ != *tt++) X break; X } X return NULL; X} X X/* X * Log an error X */ X/*VARARGS1*/ Xzperr(s,p,u) Xchar *s, *p, *u; X{ X if (Verbose <= 0) X return; X fprintf(stderr, "Retry %d: ", errors); X fprintf(stderr, s, p, u); X fprintf(stderr, "\n"); X} X X/* send cancel string to get the other end to shut up */ Xcanit() X{ X static char canistr[] = { X 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 X }; X X#ifdef vax11c X raw_wbuf(strlen(canistr), canistr); X purgeline(); X#else X printf(canistr); X Lleft=0; /* Do read next time ... */ X fflush(stdout); X#endif X} X X Xreport(sct) Xint sct; X{ X if (Verbose>1) X fprintf(stderr,"%03d%c",sct,sct%10? ' ' : '\r'); X} X X#ifndef vax11c X/* X * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 X * If called as [-][dir/../]rzCOMMAND set the pipe flag X * If called as rb use YMODEM protocol X */ Xchkinvok(s) Xchar *s; X{ X register char *p; X X p = s; X while (*p == '-') X s = ++p; X while (*p) X if (*p++ == '/') X s = p; X if (*s == 'v') { X Verbose=1; ++s; X } X Progname = s; X if (s[0]=='r' && s[1]=='z') X Batch = TRUE; X if (s[0]=='r' && s[1]=='b') X Batch = Nozmodem = TRUE; X if (s[2] && s[0]=='r' && s[1]=='b') X Topipe=TRUE; X if (s[2] && s[0]=='r' && s[1]=='z') X Topipe=TRUE; X} X#endif X X/* X * Totalitarian Communist pathname processing X */ Xcheckpath(name) Xchar *name; X{ X if (Restricted) { X if (fopen(name, "r") != NULL) { X canit(); X fprintf(stderr, "\r\nrz: %s exists\n", name); X bibi(-1); X } X /* restrict pathnames to current tree or uucppublic */ X if ( substr(name, "../") X || (name[0]== '/' && strncmp(name, PUBDIR, strlen(PUBDIR))) ) { X canit(); X fprintf(stderr,"\r\nrz:\tSecurity Violation\r\n"); X bibi(-1); X } X } X} X X/* X * Initialize for Zmodem receive attempt, try to activate Zmodem sender X * Handles ZSINIT frame X * Return ZFILE if Zmodem filename received, -1 on error, X * ZCOMPL if transaction finished, else 0 X */ Xtryz() X{ X register c, n; X register cmdzack1flg; X X if (Nozmodem) /* Check for "rb" program name */ X return 0; X X X for (n=Zmodem?15:5; --n>=0; ) { X /* Set buffer length (0) and capability flags */ X#ifdef SEGMENTS X stohdr(SEGMENTS*1024L); X#else X stohdr(0L); X#endif X#ifdef CANBREAK X Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; X#else X Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; X#endif X if (Zctlesc) X Txhdr[ZF0] |= TESCCTL; X zshhdr(tryzhdrtype, Txhdr); X if (tryzhdrtype == ZSKIP) /* Don't skip too far */ X tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ Xagain: X switch (zgethdr(Rxhdr, 0)) { X case ZRQINIT: X continue; X case ZEOF: X continue; X case TIMEOUT: X continue; X case ZFILE: X zconv = Rxhdr[ZF0]; X zmanag = Rxhdr[ZF1]; X ztrans = Rxhdr[ZF2]; X tryzhdrtype = ZRINIT; X c = zrdata(secbuf, 1024); X mode(3); X if (c == GOTCRCW) X return ZFILE; X zshhdr(ZNAK, Txhdr); X goto again; X case ZSINIT: X Zctlesc = TESCCTL & Rxhdr[ZF0]; X if (zrdata(Attn, ZATTNLEN) == GOTCRCW) { X stohdr(1L); X zshhdr(ZACK, Txhdr); X goto again; X } X zshhdr(ZNAK, Txhdr); X goto again; X case ZFREECNT: X stohdr(getfree()); X zshhdr(ZACK, Txhdr); X goto again; X case ZCOMMAND: X#ifdef vax11c X return ERROR; X#else X cmdzack1flg = Rxhdr[ZF0]; X if (zrdata(secbuf, 1024) == GOTCRCW) { X if (cmdzack1flg & ZCACK1) X stohdr(0L); X else X stohdr((long)sys2(secbuf)); X purgeline(); /* dump impatient questions */ X do { X zshhdr(ZCOMPL, Txhdr); X } X while (++errors<20 && zgethdr(Rxhdr,1) != ZFIN); X ackbibi(); X if (cmdzack1flg & ZCACK1) X exec2(secbuf); X return ZCOMPL; X } X zshhdr(ZNAK, Txhdr); goto again; X#endif X case ZCOMPL: X goto again; X default: X continue; X case ZFIN: X ackbibi(); return ZCOMPL; X case ZCAN: X return ERROR; X } X } X return 0; X} X X/* X * Receive 1 or more files with ZMODEM protocol X */ Xrzfiles() X{ X register c; X X for (;;) { X switch (c = rzfile()) { X case ZEOF: X case ZSKIP: X switch (tryz()) { X case ZCOMPL: X return OK; X default: X return ERROR; X case ZFILE: X break; X } X continue; X default: X return c; X case ERROR: X return ERROR; X } X } X} X X/* X * Receive a file with ZMODEM protocol X * Assumes file name frame is in secbuf X */ Xrzfile() X{ X register c, n; X long rxbytes; X X Eofseen=FALSE; X if (procheader(secbuf) == ERROR) { X return (tryzhdrtype = ZSKIP); X } X X n = 20; rxbytes = 0l; X X for (;;) { X#ifdef SEGMENTS X chinseg = 0; X#endif X stohdr(rxbytes); X zshhdr(ZRPOS, Txhdr); Xnxthdr: X switch (c = zgethdr(Rxhdr, 0)) { X default: X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ZNAK: X case TIMEOUT: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X case ZFILE: X zrdata(secbuf, 1024); X continue; X case ZEOF: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if (rclhdr(Rxhdr) != rxbytes) { X /* X * Ignore eof if it's at wrong place - force X * a timeout because the eof might have gone X * out before we sent our zrpos. X */ X errors = 0; goto nxthdr; X } X if (closeit()) { X tryzhdrtype = ZFERR; X vfile("rzfile: closeit returned <> 0"); X return ERROR; X } X vfile("rzfile: normal EOF"); X return c; X case ERROR: /* Too much garbage in header search error */ X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case ZSKIP: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X closeit(); X vfile("rzfile: Sender SKIPPED file"); X return c; X case ZDATA: X if (rclhdr(Rxhdr) != rxbytes) { X if ( --n < 0) { X return ERROR; X } X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X zmputs(Attn); continue; X } Xmoredata: X if (Verbose>1) X fprintf(stderr, "\r%7ld ZMODEM%s ", X rxbytes, Crc32?" CRC-32":""); X#ifdef SEGMENTS X if (chinseg >= (1024 * SEGMENTS)) { X putsec(secbuf, chinseg); X chinseg = 0; X } X switch (c = zrdata(secbuf+chinseg, 1024)) X#else X switch (c = zrdata(secbuf, 1024)) X#endif X { X case ZCAN: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X case ERROR: /* CRC error */ X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X zmputs(Attn); X continue; X case TIMEOUT: X#ifdef SEGMENTS X putsec(secbuf, chinseg); X chinseg = 0; X#endif X if ( --n < 0) { X vfile("rzfile: zgethdr returned %d", c); X return ERROR; X } X continue; X case GOTCRCW: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X putsec(secbuf, chinseg); X chinseg = 0; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X sendline(XON); X goto nxthdr; X case GOTCRCQ: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK, Txhdr); X goto moredata; X case GOTCRCG: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X goto moredata; X case GOTCRCE: X n = 20; X#ifdef SEGMENTS X chinseg += Rxcount; X#else X putsec(secbuf, Rxcount); X#endif X rxbytes += Rxcount; X goto nxthdr; X } X } X } X} X X/* X * Send a string to the modem, processing for \336 (sleep 1 sec) X * and \335 (break signal) X */ Xzmputs(s) Xchar *s; X{ X register c; X X while (*s) { X switch (c = *s++) { X case '\336': X sleep(1); continue; X case '\335': X sendbrk(); continue; X default: X sendline(c); X } X } X} X X/* X * Close the receive dataset, return OK or ERROR X */ Xcloseit() X{ X#ifndef vax11c X if (Topipe) { X if (pclose(fout)) { X return ERROR; X } X return OK; X } X#endif X if (fclose(fout)==ERROR) { X fprintf(stderr, "file close ERROR\n"); X return ERROR; X } X#ifndef vax11c X if (Modtime) { X timep[0] = time(NULL); X timep[1] = Modtime; X utime(Pathname, timep); X } X#endif X if ((Filemode&S_IFMT) == S_IFREG) X chmod(Pathname, (07777 & Filemode)); X return OK; X} X X/* X * Ack a ZFIN packet, let byegones be byegones X */ Xackbibi() X{ X register n; X X vfile("ackbibi:"); X Readnum = 1; X stohdr(0L); X for (n=3; --n>=0; ) { X purgeline(); X zshhdr(ZFIN, Txhdr); X switch (readline(100)) { X case 'O': X readline(1); /* Discard 2nd 'O' */ X vfile("ackbibi complete"); X return; X case RCDO: X return; X case TIMEOUT: X default: X break; X } X } X} X X X X/* X * Local console output simulation X */ Xbttyout(c) X{ X if (Verbose || Fromcu) X putc(c, stderr); X} X X#ifndef vax11c X/* X * Strip leading ! if present, do shell escape. X */ Xsys2(s) Xregister char *s; X{ X if (*s == '!') X ++s; X return system(s); X} X/* X * Strip leading ! if present, do exec. X */ Xexec2(s) Xregister char *s; X{ X if (*s == '!') X ++s; X mode(0); X execl("/bin/sh", "sh", "-c", s); X} X#endif X/* End of rz.c */ END_OF_FILE if test 30798 -ne `wc -c <'rz.c'`; then echo shar: \"'rz.c'\" unpacked with wrong size! fi # end of 'rz.c' fi echo shar: End of archive 4 \(of 5\). >ark4isdone MISSING="" for I in 1 2 3 4 5 ; do if test ! -f ark${I}isdone ; then MISSING="${MISSING} ${I}" fi done if test "${MISSING}" = "" ; then echo You have unpacked all 5 archives. rm -f ark[1-9]isdone else echo You still need to unpack the following archives: echo " " ${MISSING} fi ## End of shell archive. exit 0 -- Bob Best uucp: {spsd, zardoz, felix}!dhw68k!bob InterNet: bob@dhw68k.cts.com