wht@n4hgf.uucp (Warren Tucker) (01/06/91)
Submitted-by: wht@n4hgf.uucp (Warren Tucker) Posting-number: Volume 16, Issue 43 Archive-name: ecu3/part19 ---- Cut Here and feed the following to sh ---- #!/bin/sh # This is part 19 of ecu3 if touch 2>&1 | fgrep 'amc' > /dev/null then TOUCH=touch else TOUCH=true fi # ============= z/ecurz.c ============== if test ! -d 'z'; then echo 'x - creating directory z' mkdir 'z' fi echo 'x - extracting z/ecurz.c (Text)' sed 's/^X//' << 'SHAR_EOF' > 'z/ecurz.c' && Xchar *numeric_revision = "ecurz 3.04"; X/*+------------------------------------------------------------------------- X ecurz.c - X/Y/ZMODEM receive program X Derived from public domain source by Chuck Forsberg, Omen Technologies X Adaptation for ecu 1989 wht@n4hgf.Mt-Park.GA.US X X Defined functions: X SIGALRM_handler() X arg_token(parsestr,termchars) X bye_bye(sig) X cancel_transaction(sig) X close_and_report() X flushline() X fname_split(cmd,arg,arg_max_quan,narg_rtn) X fname_too_long(fname) X fname_truncated() X getfree() X isanylc(str) X main(argc,argv,envp) X make_dirs(pathname) X mkdir(dpath,dmode) X procheader(name) X purgeline() X readline(timeout) X rzfile() X rzfiles() X send_ZFIN_and_exit() X send_cancel(error) X sendline(c) X substr(str,token) X sys2(shellcmd) X tryz() X uncaps(str) X usage(fail_reason) X wcgetsec(rxbuf,maxtime) X wcreceive(argc,argp) X wcrx() X wcrxpn(rpn) X write_sec_to_disk(buf,n) X xsendline(c) X X Usage: ecurz -Z [-abeuy] (ZMODEM) X ecurz -Y [-abuy] (YMODEM) X ecurz -X [-abc] file (XMODEM or XMODEM-1k) X X -a ASCII transfer (strip CR) X -b Binary transfer for all files X -c Use 16 bit CRC (XMODEM) X -e Escape control characters (ZMODEM) X -p protect local files (ZMODEM) X -t <tenths> rx timeout seconds X -+ force append X -u convert uppercase filenames to lower case X -y Yes, clobber existing file if any X -. line fd to use X -, log protocol packets X X--------------------------------------------------------------------------*/ X/*+:EDITS:*/ X/*:12-18-1990-21:26-wht@n4hgf-better output control */ X/*:10-04-1990-14:01-wht@n4hgf-add file finish warning for me */ X/*:09-19-1990-19:36-wht@n4hgf-ecu_log_event now gets pid for log from caller */ X/*:08-23-1990-14:14-wht@n4hgf-sending ZACK was erroneously counted as error */ X/*:08-14-1990-20:40-wht@n4hgf-ecu3.00-flush old edit history */ X X#include <stdio.h> X#include <signal.h> X#include <setjmp.h> X#include <ctype.h> X#include <errno.h> X#include <fcntl.h> X#include "zmodem.h" X#include "zlint.h" X Xchar *strrchr(); X X#if defined(M_UNIX) Xchar *fname_truncated(); X#endif X Xextern unsigned short crctab[]; Xextern unsigned long total_data_chars_xfered; /* zcurses.c */ Xextern int force_no_curses; Xextern int errno; Xextern char *sys_errlist[]; Xextern char Attn[]; /* Attention string rx sends to tx on err */ Xextern int Crc32; /* Display flag indicating 32 bit CRC being received */ Xextern int Rxcount; /* Count of data bytes received */ Xextern char Rxhdr[]; /* Received header */ Xextern char Txhdr[]; /* Transmitted header */ Xextern int Rxtimeout; /* Tenths of seconds to wait for something */ Xextern char s256[]; X X/* Max value for VMIN_COUNT is 255. A larger value reduces system Xoverhead but may evoke kernel bugs. 133 corresponds to an XMODEM/CRC Xsector */ X#if !defined(VMIN_COUNT) X#define VMIN_COUNT 133 X#endif Xunsigned char vmin_count = VMIN_COUNT; Xint Readnum = VMIN_COUNT; /* num bytes to ask for in read() from modem */ X X#define DEFBYTL 2000000000L /* default rx file size */ X#define RETRYMAX 5 X XFILE *fout; Xchar Lzmanag; /* Local file management request */ Xchar Pathname[PATHLEN]; Xchar curr_dir[256]; Xchar linbuf[VMIN_COUNT]; Xchar s128[128]; Xchar secbuf[1025]; Xchar zconv; /* ZMODEM file conversion request */ Xchar zmanag; /* ZMODEM file management request */ Xchar ztrans; /* ZMODEM file transport request */ Xint Batch=0; Xint Blklen; /* record length of received packets */ Xint Crcflg; Xint Eofseen; /* indicates cpm eof (^Z) has been received */ Xint Filcnt=0; /* count of number of files opened */ Xint Filemode; /* Unix style mode for incoming file */ Xint Firstsec; Xint Lastrx; Xint Lleft=0; /* number of characters in linbuf */ Xint MakeLCPathname=1; /* make received pathname lower case */ Xint Nozmodem = 0; /* If invoked as "rb" */ Xint Rxascii=0; /* receive files in ascii (translate) mode */ Xint Rxbinary=0; /* receive all files in bin mode */ Xint Rxclob=0; /* Clobber existing file */ Xint Thisbinary; /* current file is to be received in bin mode */ Xint Twostop = 0; /* use two stop bits */ Xint Zctlesc; /* Encode control characters */ Xint Zmodem=0; /* ZMODEM protocol requested */ Xint Zrwindow = 1400; /* RX window size (controls garbage count) */ Xint ecusz_flag = 0; Xint skip_count = 0; /* skipped files */ Xint errors; Xint iofd = 0; Xint force_no_curses = 0; Xint can_on_eof = 0; Xint log_packets = 0; Xint npats = 0; Xint oldBlklen = -1; /* last block length */ Xint this_file_errors = 0; Xint tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */ Xjmp_buf tohere; /* For the interrupt on RX timeout */ Xlong Bytesleft; /* number of bytes of incoming file left */ Xlong Modtime; /* Unix style mod time for incoming file */ Xlong TotalToReceive = 0L; Xlong rx_char_count = 0L; Xlong tx_char_count = 0L; Xstruct stat fout_stat; Xtime_t timep[2]; Xunsigned Baudrate; Xunsigned long this_file_length; Xint required_type = 0; Xchar *bottom_label = (char *)0; X X/*+----------------------------------------------------------------------- X arg_token(parsestr,termchars) X XGet next token from string parsestr ((char *)0 on 2nd, 3rd, etc. Xcalls), where tokens are nonempty strings separated by runs of chars Xfrom termchars. Writes nulls into parsestr to end tokens. Xtermchars need not remain constant from call to call. X XTreats multiple occurrences of a termchar as one delimiter (does not Xallow null fields). X------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xstatic char *arg_token_static = (char *)0; Xchar *arg_token(parsestr,termchars) Xchar *parsestr; Xchar *termchars; X{ Xregister int first = 1; Xregister char *termptr; Xregister char *parseptr; Xchar *token; X X if(parsestr == (char *)0 && arg_token_static == (char *)0) X return((char *)0); X X if(parsestr) X parseptr = parsestr; X else X parseptr = arg_token_static; X X while(*parseptr) X { X if(!strchr(termchars,*parseptr)) X break; X parseptr++; X } X X if(!*parseptr) X { X arg_token_static = (char *)0; X return((char *)0); X } X X token = parseptr; X if(*token == '\'') X { X token++; X parseptr++; X while(*parseptr) X { X if(*parseptr == '\'') X { X arg_token_static = parseptr + 1; X *parseptr = 0; X return(token); X } X parseptr++; X } X arg_token_static = (char *)0; X return(token); X } X while(*parseptr) X { X if(strchr(termchars,*parseptr)) X { X *parseptr = 0; X arg_token_static = parseptr + 1; X while(*arg_token_static) X { X if(!strchr(termchars,*arg_token_static)) X break; X arg_token_static++; X } X return(token); X } X parseptr++; X } X arg_token_static = (char *)0; X return(token); X} /* end of arg_token */ X#endif X X/*+------------------------------------------------------------------------- X fname_split(cmd,arg,arg_max_quan,&narg) X--------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xvoid Xfname_split(cmd,arg,arg_max_quan,narg_rtn) Xchar *cmd; Xchar **arg; Xint arg_max_quan; Xint *narg_rtn; X{ Xregister itmp; Xregister narg; X X for(itmp = 0; itmp < arg_max_quan; itmp++) X arg[itmp] = (char *)0; X arg[0] = arg_token(cmd,"/"); X X for(narg = 1; narg < arg_max_quan; ++narg) X { X if((arg[narg] = arg_token((char *)0,"/")) == (char *)0) X break; X } X X *narg_rtn = narg; X X} /* end of fname_split */ X#endif X X#if defined(M_UNIX) X#define MAX_COMPONENT_LEN 14 X#define MAX_PATH_COMPONENTS 16 Xstatic char trunc_fname[257]; Xstatic char *trunc_components[MAX_PATH_COMPONENTS]; Xstatic int trunc_components_quan; Xstatic int trunc_absolute_path; X#endif X X/*+------------------------------------------------------------------------- X fname_too_long(fname) - check for any pathname component too long X--------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xint Xfname_too_long(fname) Xregister char *fname; X{ Xregister int itmp; Xregister char **cpptr; X X if(trunc_absolute_path = (*fname == '/')) X fname++; X strncpy(trunc_fname,fname,sizeof(trunc_fname) - 1); X fname_split(trunc_fname,trunc_components, X MAX_PATH_COMPONENTS,&trunc_components_quan); X itmp = trunc_components_quan; X cpptr = trunc_components; X while(itmp--) X { X if(strlen(*cpptr) > MAX_COMPONENT_LEN) X return(1); X cpptr++; X } X return(0); X} /* end of fname_too_long */ X#endif X X/*+------------------------------------------------------------------------- X fname_truncated() - build truncated path last checked by fname_too_long X--------------------------------------------------------------------------*/ X#if defined(M_UNIX) Xchar * Xfname_truncated() X{ Xregister int icomp; Xchar new_fname[257]; Xregister char *cptr = new_fname; X X if(trunc_absolute_path) X { X *cptr = '/'; X *(cptr + 1) = 0; X } X else X *cptr = 0; X for(icomp = 0; icomp < trunc_components_quan; icomp++) X { X if(strlen(trunc_components[icomp]) > MAX_COMPONENT_LEN) X *(trunc_components[icomp] + MAX_COMPONENT_LEN) = 0; X strcat(cptr,trunc_components[icomp]); X if(icomp < trunc_components_quan - 1) X strcat(cptr,"/"); X } X strcpy(trunc_fname,cptr); X return(trunc_fname); X X} /* end of fname_truncated */ X#endif X X/*+------------------------------------------------------------------------- X substr(str,token) X X searches for token in string str returns pointer to token within X string if found,NULL otherwise X--------------------------------------------------------------------------*/ Xchar * Xsubstr(str,token) Xregister char *str,*token; X{ Xregister char *ss,*tt; X X /* search for first char of token */ X for(ss=str; *str; str++) X if(*str == *token) X /* compare token with substring */ X for(ss=str,tt=token; ;) X { X if(*tt == 0) X return(str); X if(*ss++ != *tt++) X break; X } X return(NULL); X} /* end of substr */ X X/*+------------------------------------------------------------------------- X getfree() X X Routine to calculate the free bytes on the current file system ~0 X means many free bytes (unknown) X--------------------------------------------------------------------------*/ Xlong Xgetfree() X{ X return(~0L); /* many free bytes ... */ X} /* end of getfree */ X X/*+------------------------------------------------------------------------- X usage(fail_reason) X--------------------------------------------------------------------------*/ Xvoid Xusage(fail_reason) Xchar *fail_reason; X{ X fprintf(stderr,"%s\n",fail_reason); X exit(255); X} /* end of usage */ X X/*+------------------------------------------------------------------------- X SIGALRM_handler() X--------------------------------------------------------------------------*/ Xvoid XSIGALRM_handler() X{ X report_tx_ind(0); X report_rx_ind(0); X longjmp(tohere,-1); X} /* end of SIGALRM_handler */ X X/*+------------------------------------------------------------------------- X bye_bye(sig) X--------------------------------------------------------------------------*/ Xvoid Xbye_bye(sig) Xint sig; X{ X exit(sig+128); X} /* end of bye_bye */ X X/*+------------------------------------------------------------------------- X cancel_transaction(sig) Xcalled by signal interrupt or terminate to clean things up X--------------------------------------------------------------------------*/ Xvoid Xcancel_transaction(sig) X{ X if(Zmodem) X zmputs(Attn); X send_cancel(1); X mode(0); X if(sig >= 0) X { X sprintf(s128,"ecurz aborted (signal %d)",sig); X report_str(s128,0); X } X report_tx_ind(0); X report_rx_ind(0); X report_uninit(0); X bye_bye(sig); X} /* end of cancel_transaction */ X X/*+------------------------------------------------------------------------- X sendline(c) - send a character to DCE X--------------------------------------------------------------------------*/ Xsendline(c) Xchar c; X{ X write(iofd,&c,1); X ++tx_char_count; X} /* end of sendline */ X X/*+------------------------------------------------------------------------- X xsendline(c) X--------------------------------------------------------------------------*/ Xxsendline(c) X{ X sendline(c); X} /* end of xsendline */ X X/*+------------------------------------------------------------------------- X flushline() X--------------------------------------------------------------------------*/ Xflushline() X{ X} /* end of flushline */ X X/*+------------------------------------------------------------------------- X purgeline() - purge the modem input queue of all characters X--------------------------------------------------------------------------*/ Xpurgeline() X{ X Lleft = 0; X#if defined(M_XENIX) || defined(M_UNIX) X ioctl(iofd,TCFLSH,0); X#else X lseek(iofd,0L,2); X#endif X} /* end of purgeline */ X X/*+------------------------------------------------------------------------- X wcreceive(argc,argp) X--------------------------------------------------------------------------*/ Xwcreceive(argc,argp) Xint argc; Xchar **argp; X{ Xregister c; X X if(Batch || argc==0) X { X Crcflg=1; X c=tryz(); X if(Zmodem) X { X report_protocol_type("ZMODEM"); X report_protocol_crc_type((Crc32) ? "/CRC32" : "/CRC16"); X } X if(c) X { 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 { X report_protocol_type("YMODEM"); X report_protocol_crc_type((Crcflg) ? "/CRC" : "/CHK"); X for(;;) X { 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 report_str("Receiving data",0); X if(wcrx()==ERROR) X goto fubar; X } X } X } X else X { X report_protocol_type("XMODEM"); X report_protocol_crc_type((Crcflg) ? "/CRC" : "/CHK"); X Bytesleft = DEFBYTL; X Filemode = 0; X Modtime = 0L; X procheader(""); X strcpy(Pathname,*argp); X#if defined(M_UNIX) X if(fname_too_long(Pathname)) X { X strcpy(s128,"truncated: "); X strncat(s128,Pathname,sizeof(s128) - 12); X ecu_log_event(getppid(),s128); X report_str(s128,-1); X strcpy(Pathname,fname_truncated()); X } X#endif X if((fout=fopen(Pathname,"w")) == NULL) X { X sprintf(s128,"%-0.85s: %-0.40s",Pathname,sys_errlist[errno]); X report_str(s128,1); X ecu_log_event(getppid(),s128); X goto fubar; X } X X ++Filcnt; X report_file_rcv_started( Pathname,0L,Modtime,Filemode); X this_file_length = 0; X report_rxpos(0L); X report_str("Receiving data",0); X if(wcrx()==ERROR) X goto fubar; X } X return(OK); Xfubar: X send_cancel(1); X if(fout) X { X fflush(fout); X fstat(fileno(fout),&fout_stat); X report_file_byte_io((long)fout_stat.st_size); X report_file_close(); X fclose(fout); X } X return(ERROR); X} /* end of wcreceive */ X X/*+------------------------------------------------------------------------- X wcgetsec(rxbuf,maxtime) X X Wcgetsec fetches a Ward Christensen type sector. Returns sector X number encountered or ERROR if valid sector not received, or CAN CAN X received or WCEOT if eot sector time is timeout for first char,set to X 4 seconds thereafter. NO ACK IS SENT IF SECTOR IS RECEIVED OK. Caller X must do that when he is good and ready to get next sector. X--------------------------------------------------------------------------*/ Xunsigned int Xwcgetsec(rxbuf,maxtime) Xchar *rxbuf; Xint maxtime; X{ Xregister unsigned int firstch; Xregister unsigned short oldcrc; Xregister unsigned char checksum; Xregister wcj; Xregister char *p; Xint sectcurr; X X for(Lastrx=errors=0; errors<RETRYMAX; errors++) X { X X firstch=readline(maxtime); X if((firstch == STX) || (firstch == SOH)) X { X oldBlklen = Blklen; X if(firstch == STX) X Blklen=1024; X else X Blklen=128; X if(oldBlklen != Blklen) X report_rxblklen(Blklen); X X sectcurr=readline(1); X if((sectcurr + (oldcrc=readline(1))) == 0xFF) X { X oldcrc=checksum=0; X for(p=rxbuf,wcj=Blklen; --wcj>=0; ) X { 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 { X oldcrc=updcrc(firstch,oldcrc); X if((firstch=readline(1)) < 0) X goto bilge; X oldcrc=updcrc(firstch,oldcrc); X if(oldcrc) X { X sprintf(s128,"CRC error = 0x%04x",oldcrc); X report_str(s128,1); X } X else X { X Firstsec=0; X return(sectcurr); X } X } X else if((checksum-firstch)==0) X { X Firstsec=0; X return(sectcurr); X } X else X report_str("checksum error",1); X } X else X { X report_last_txhdr("Noise",0); X sprintf(s128,"Sector garbled 0x%x 0x%x",sectcurr,oldcrc); X report_str(s128,1); X } X } X /* make sure eot really is eot and not just mixmash */ X#if defined(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==EOT) X { X report_str("Noisy EOT",2); X } X else if(firstch==CAN) X { X if(Lastrx==CAN) X { X report_str("Sender CANcelled",1); X report_last_rxhdr("CAN",1); X return(ERROR); X } else X { X Lastrx=CAN; X continue; X } X } X else if(firstch==TIMEOUT) X { X if(Firstsec) X goto humbug; Xbilge: X report_str("Timeout",1); X } X else X { X sprintf(s128,"Got 0x%02x sector header",firstch); X report_str(s128,1); X } X Xhumbug: X Lastrx=0; X while(readline(1)!=TIMEOUT) X ; X if(Firstsec) X { X sendline(Crcflg?WANTCRC:NAK); X report_last_txhdr(Crcflg ? "WANTCRC" : "NAK",0); X Lleft=0; /* Do read next time ... */ X } else X { X maxtime=40; X sendline(NAK); X report_last_txhdr("NAK",1); X Lleft=0; /* Do read next time ... */ X } X } X /* try to stop the bubble machine. */ X send_cancel(1); X return(ERROR); X} /* end of wcgetsec */ X X/*+------------------------------------------------------------------------- X wcrxpn(rpn) X X Fetch a pathname from the other end. Length is indeterminate as long X as less than Blklen. During YMODEM xfers, a null string represents no X more files. X--------------------------------------------------------------------------*/ Xwcrxpn(rpn) Xchar *rpn; /* receive a pathname */ X{ Xregister c; X X#if defined(NFGVMIN) X readline(1); X#else X purgeline(); X#endif X Xet_tu: X Firstsec=1; X Eofseen=0; X sendline(Crcflg?WANTCRC:NAK); X report_last_txhdr(Crcflg ? "WANTCRC" : "NAK",0); X Lleft=0; /* Do read next time ... */ X while((c = wcgetsec(rpn,100)) != 0) X { X if(c == WCEOT) X { X sprintf(s128,"Pathname fetch returned %d",c); X report_str(s128,1); X sendline(ACK); X report_last_txhdr("ACK",0); X Lleft=0; /* Do read next time ... */ X readline(1); X goto et_tu; X } X return(ERROR); X } X sendline(ACK); X report_last_txhdr("ACK",0); X return(OK); X} /* end of wcrxpn */ X X/*+------------------------------------------------------------------------- X write_sec_to_disk(buf,n) X X Putsec writes the n characters of buf to receive file fout. If not in X binary mode, carriage returns, and all characters starting with CPMEOF X are discarded. X--------------------------------------------------------------------------*/ Xwrite_sec_to_disk(buf,n) Xchar *buf; Xregister n; X{ Xregister char *p; X X if(n == 0) X return(OK); X if(Thisbinary) X { X for(p=buf; --n>=0; ) X putc( *p++,fout); X } X else X { X if(Eofseen) X return(OK); X for(p=buf; --n>=0; ++p ) X { X if( *p == '\r') X continue; X if(*p == CPMEOF) X { X Eofseen=1; X fflush(fout); X fstat(fileno(fout),&fout_stat); X report_rxpos(fout_stat.st_size); X return(OK); X } X putc(*p ,fout); X } X } X fflush(fout); X fstat(fileno(fout),&fout_stat); X report_rxpos(fout_stat.st_size); X if(this_file_length != 0) X { X int pct; X#ifdef WHT X FILE *fp; X#endif X sprintf(s128,"Receiving data (%u%% complete)", X (unsigned int)( X pct = ((unsigned long)fout_stat.st_size * (unsigned long)100) X / this_file_length)); X#ifdef WHT X if(pct == 90) X { X fp= fopen("/dev/morse","a"); X fputs("i",fp); X fclose(fp); X } X#endif X report_str(s128,0); X } X return(OK); X} /* end of write_sec_to_disk */ X X/*+------------------------------------------------------------------------- X wcrx() - receive an X/YMODEM sector X X Adapted from CMODEM13.C,written by Jack M. Wierda and Roderick W. Hart X--------------------------------------------------------------------------*/ Xint Xwcrx() X{ Xregister unsigned int sectnum,sectcurr; Xregister unsigned char sendchar; Xregister unsigned char *p; Xint cblklen; /* bytes to dump this block */ X X Firstsec=1; X sectnum=0; X Eofseen=0; X sendchar=Crcflg ? WANTCRC : NAK; X report_last_txhdr(Crcflg ? "WANTCRC" : "NAK",0); X X for(;;) X { X sendline(sendchar); /* send it now,we're ready! */ X if(sendchar == ACK) X report_last_txhdr("ACK",0); X Lleft=0; /* Do read next time ... */ X sectcurr=wcgetsec(secbuf,(sectnum&0177)?50:130); X sprintf(s128,"Block %d received",sectnum); X report_last_rxhdr(s128,0); X fstat(fileno(fout),&fout_stat); X report_rxpos(fout_stat.st_size); X if(sectcurr == (sectnum+1 & 0xFF)) X { X sectnum++; X cblklen = Bytesleft>Blklen ? Blklen : Bytesleft; X if(write_sec_to_disk(secbuf,cblklen) == ERROR) X return(ERROR); X if((Bytesleft-=cblklen) < 0) X Bytesleft = 0; X sendchar=ACK; X } X else if(sectcurr == sectnum) X { X report_str("Received duplicate Sector",-1); X sendchar = ACK; X } X else if(sectcurr == WCEOT) X { X if(close_and_report()) X return(ERROR); X sendline(ACK); X report_last_txhdr("ACK",0); X Lleft=0; /* Do read next time ... */ X return(OK); X } X else if(sectcurr==ERROR) X return(ERROR); X else X { X report_str( "Sync Error",1); X return(ERROR); X } X } X} /* end of wcrx */ X X/*+------------------------------------------------------------------------- X readline(timeout) X X read one or more characters timeout is in tenths of seconds X--------------------------------------------------------------------------*/ Xreadline(timeout) Xint timeout; X{ Xregister n; Xstatic unsigned char *cdq; /* pointer for removing chars from linbuf */ X X if(--Lleft >= 0) X return(*cdq++); X X n = timeout/10; X if(n < 2) X n = 3; X if(setjmp(tohere)) X { X Lleft = 0; X return(TIMEOUT); X } X signal(SIGALRM,SIGALRM_handler); X alarm(n); X Lleft = read(iofd,cdq = linbuf,Readnum); X alarm(0); X rx_char_count += Lleft; X X if(Lleft < 1) X return(TIMEOUT); X X --Lleft; X return(*cdq++); X X} /* end of readline */ X X/*+------------------------------------------------------------------------- X mkdir(dpath,dmode) X Directory-creating routines from Public Domain TAR by John Gilmore X Make a directory. Compatible with the mkdir() system call on 4.2BSD. X--------------------------------------------------------------------------*/ X#if defined(MD) 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) Xmkdir(dpath,dmode) Xchar *dpath; Xint dmode; X{ Xint cpid,status; Xstruct stat statbuf; X X if(stat(dpath,&statbuf) == 0) X { 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) X return(-1); X X switch(cpid = fork()) X { 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 { X errno = EIO; /* We don't know why,but */ X return(-1); /* /bin/mkdir failed */ X } X X return(0); X} /* end of mkdir */ X#endif /* MD != 2 */ X#endif /* if defined(MD) */ X X/*+------------------------------------------------------------------------- X make_dirs(pathname) X X Directory-creating routines from Public Domain TAR by John Gilmore X After a file/link/symlink/dir creation has failed, see if it's because X some required directory was not present, and if so, create all X required dirs. X--------------------------------------------------------------------------*/ X#if defined(MD) Xmake_dirs(pathname) Xregister char *pathname; X{ 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 { 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 { X sprintf(s128,"Made directory %s",pathname); X report_str(s128,-1); 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} /* end of make_dirs */ X#endif /* MD */ X X/*+------------------------------------------------------------------------- X uncaps(str) - make string str lower case X--------------------------------------------------------------------------*/ Xvoid Xuncaps(str) Xregister char *str; X{ Xregister int itmp; X X while(itmp = *str) X { X if(isupper(itmp)) X *str = tolower(itmp); X str++; X } X} /* end of uncaps */ X X/*+------------------------------------------------------------------------- X isanylc(str) - returns 1 if string str has any lower case letters X--------------------------------------------------------------------------*/ Xint Xisanylc(str) Xregister char *str; X{ X while(*str) X { X if(islower(*str)) X return(1); X str++; X } X return(0); X} /* end of isanylc */ X X/*+------------------------------------------------------------------------- X procheader(name) - process incoming file information header X--------------------------------------------------------------------------*/ Xint Xprocheader(name) Xchar *name; X{ Xregister char *openmode,*p,**pp; X#if defined(M_UNIX) Xchar *cptr; Xchar name2[PATHLEN]; X#endif 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 = 1; X else if(zmanag == ZMAPND) X openmode = "a"; X X report_xfer_mode(Thisbinary ? "BINARY" : "ASCII"); X this_file_errors = 0; X X Bytesleft = DEFBYTL; X Filemode = 0; X Modtime = 0L; X this_file_length = 0; X X if(strlen(name)) X p = name + 1 + strlen(name); X else X p = name; X X#if defined(M_UNIX) X if(fname_too_long(name)) X { X strcpy(s128,"truncated: "); X strncat(s128,name,sizeof(s128) - 12); X ecu_log_event(getppid(),s128); X report_str(s128,-1); X name = fname_truncated(); X } X#endif X X if(*p) X { /* file coming from Unix or DOS system */ X int sscanf_count; X int SerialNumber; X int Filesleft; X long TotalLeft; X X sscanf_count = sscanf(p,"%ld%lo%o%d&d&ld", X &Bytesleft,&Modtime,&Filemode,&SerialNumber, X &Filesleft,&TotalLeft); X X switch(sscanf_count) X { X case 6: /* TotalLeft */ X if(!TotalToReceive) X TotalToReceive = TotalLeft; X case 5: /* Filesleft */ X if(!npats) X npats = Filesleft; X default: X break; X } X X if((zmanag & ZMMASK) == ZMNEW) X { X if(stat(name,&fout_stat) == 0) /* if file accessable ... */ X { X if(Modtime <= fout_stat.st_mtime) /* ... and not older */ X { X sprintf(s128,"RECEIVE skipped: %s (same or later date)", X name); X report_str(s128 + 8,-1); X skip_count++; X report_error_count(); X#if defined(LOG_SKIP) X ecu_log_event(getppid(),s128); X#endif X return(ERROR); X } X } X } X /* Check for existing file */ X else if(!Rxclob && ((zmanag & ZMMASK) != ZMCLOB) && X (fout=fopen(name,"r"))) X { X fclose(fout); X sprintf(s128,"RECEIVE skipped: %s (already exists)",name); X report_str(s128 + 8,-1); X skip_count++; X report_error_count(); X#if defined(LOG_SKIP) X ecu_log_event(getppid(),s128); X#endif X return(ERROR); X } X X if(Filemode & UNIXFILE) X ++Thisbinary; X ++Filcnt; X X report_file_rcv_started( name, X (Bytesleft != DEFBYTL) ? Bytesleft : 0,Modtime,Filemode); X report_rxpos(0L); X report_str("",0); /* get rid of End of File */ X if(Bytesleft != DEFBYTL) X { X long min_100; X this_file_length = Bytesleft; X min_100 = 2L + (((Bytesleft * 11L)) * 10L) / (Baudrate * 6L); X sprintf(s128,"Receive time this file ~= %2lu:%02lu", X min_100 / 100,((min_100 % 100) * 60L) / 100L); X if(TotalToReceive) X { X min_100 = 2L + X (((TotalToReceive * 11L)) * 10L) / (Baudrate * 6L); X if(Baudrate > 4800) X { X min_100 *= 13; X min_100 /= 9; /* yech ... empirical */ X } X sprintf(&s128[strlen(s128)],", transaction ~= %2lu:%02lu", X min_100 / 100,((min_100 % 100) * 60L) / 100L); X } X report_transaction(s128); X sprintf(s128,"Receiving data (%d%% complete)",(int)0); X report_str(s128,0); X } X } X else X { /* File coming from CP/M system */ X long now; X for(p=name; *p; ++p) /* change / to _ */ X { X if( *p == '/') X *p = '_'; X } X X if( *--p == '.') /* zap trailing period */ X *p = 0; X time(&now); X ++Filcnt; X report_file_rcv_started( name, X (Bytesleft != DEFBYTL) ? Bytesleft : 0,now,0); X } X X if(!Zmodem && MakeLCPathname && !isanylc(name) && !(Filemode&UNIXFILE)) X uncaps(name); X X strcpy(Pathname,name); X report_xfer_mode(Thisbinary?"BINARY":"ASCII"); X fout = fopen(name,openmode); X#if defined(MD) X if( !fout) X if(make_dirs(name)) X fout = fopen(name,openmode); X#endif X if( !fout) X return(ERROR); X this_file_errors = 0; X return(OK); X} /* end of procheader */ X X/*+------------------------------------------------------------------------- X send_cancel(error) - send cancel string X--------------------------------------------------------------------------*/ Xsend_cancel(error) Xint error; X{ Xstatic char canistr[] = X{ X 24,24,24,24,24,24,24,24,24,24,8,8,8,8,8,8,8,8,8,8,0 X}; Xregister char *cptr = canistr; X X report_str("",0); X report_last_txhdr("^X CAN",!!error); X while(*cptr) X sendline(*cptr++); X Lleft=0; X} /* end of send_cancel */ X X/*+------------------------------------------------------------------------- X tryz() 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--------------------------------------------------------------------------*/ Xint Xtryz() X{ Xregister c,n; X X if(Nozmodem) /* Check for "rb" program name */ X return(0); X X for(n=Zmodem?15:5; --n>=0; ) X { X /* Set buffer length (0) and capability flags */ X stohdr(0L); X X#if defined(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 { 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 X strcpy(s128,"Transfer: "); X switch(zmanag & ZMMASK) X { X case 0: X strcat(s128,"if destination nonexistent"); X break; X case ZMAPND: /* Append contents to existing file (if any) */ X strcat(s128,"append to destination"); X break; X case ZMCLOB: /* Replace existing file */ X strcat(s128,"absolute (overwrite)"); X break; X case ZMNEW: X strcat(s128,"if source newer"); X break; X default: X sprintf(s128 + strlen(s128), X "absolute (%02x)",zmanag & ZMMASK); X break; X } X report_str(s128,2); X 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 { X stohdr(1L); X zshhdr(ZACK,Txhdr); X report_str("",-1); X goto again; X } X zshhdr(ZNAK,Txhdr); X goto again; X case ZFREECNT: X stohdr(getfree()); X zshhdr(ZACK,Txhdr); X report_str("",-1); X goto again; X case ZCOMMAND: X if(zrdata(secbuf,1024) == GOTCRCW) X { X stohdr(-1L); X purgeline(); /* dump impatient questions */ X while(errors < 20) X { X zshhdr(ZCOMPL,Txhdr); X if(zgethdr(Rxhdr,1) == ZFIN) X break; X } X send_ZFIN_and_exit(); X return(ZCOMPL); X } X zshhdr(ZNAK,Txhdr); X goto again; X case ZCOMPL: X goto again; X default: X continue; X case ZFIN: X send_ZFIN_and_exit(); X return(ZCOMPL); X case ZCAN: X return(ERROR); X } X } X return(0); X} /* end of tryz */ X X/*+------------------------------------------------------------------------- X rzfile() - receive a file with ZMODEM protocol X X assumes file name frame is in secbuf X--------------------------------------------------------------------------*/ Xrzfile() X{ Xregister c,n; Xlong rxbytes; X X Eofseen=0; X if(procheader(secbuf) == ERROR) X { X return(tryzhdrtype = ZSKIP); X } X X n = 20; X rxbytes = 0l; X X for(;;) X { X if(rxbytes) X report_str("Sending ZRPOS",1); X stohdr(rxbytes); X zshhdr(ZRPOS,Txhdr); Xnxthdr: X switch(c = zgethdr(Rxhdr,0)) X { X default: X sprintf(s128,"zgethdr returned %02x",c); X report_str(s128,1); X return(ERROR); X case ZNAK: X case TIMEOUT: X if( --n < 0) X { X sprintf(s128,"zgethdr returned %02x",c); X report_str(s128,1); X return(ERROR); X } X case ZFILE: X zrdata(secbuf,1024); X continue; X case ZEOF: X if(rclhdr(Rxhdr) != rxbytes) X { 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; X goto nxthdr; X } X if(can_on_eof) X { X send_cancel(0); X send_cancel(0); X close_and_report(); X report_uninit(0); X exit(0); X } X if(close_and_report()) X { X tryzhdrtype = ZFERR; X return(ERROR); X } X report_str("End of file",0); X return(c); X case ERROR: /* Too much garbage in header search error */ X if( --n < 0) X { X sprintf(s128,"zgethdr returned %02x",c); X report_str(s128,1); X return(ERROR); X } X zmputs(Attn); X continue; X case ZSKIP: X close_and_report(); X sprintf(s128,"rzfile: Sender SKIPPED file"); X report_str(s128,1); X return(c); X case ZDATA: X if(rclhdr(Rxhdr) != rxbytes) X { X if( --n < 0) X { X return(ERROR); X } X zmputs(Attn); X continue; X } Xmoredata: X switch(c = zrdata(secbuf,1024)) X { X case ZCAN: X sprintf(s128,"zgethdr returned %02x",c); X report_str(s128,1); X return(ERROR); X case ERROR: /* CRC error */ X if( --n < 0) X { X sprintf(s128,"zgethdr returned %02x",c); X report_str(s128,1); X return(ERROR); X } X zmputs(Attn); X continue; X case TIMEOUT: X if( --n < 0) X { X sprintf(s128,"zgethdr returned %02x",c); X report_str(s128,1); X return(ERROR); X } X continue; X case GOTCRCW: X n = 20; X write_sec_to_disk(secbuf,Rxcount); X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK,Txhdr); X sendline(XON); X report_str("",-1); X goto nxthdr; X case GOTCRCQ: X n = 20; X write_sec_to_disk(secbuf,Rxcount); X rxbytes += Rxcount; X stohdr(rxbytes); X zshhdr(ZACK,Txhdr); X report_str("",-1); X goto moredata; X case GOTCRCG: X n = 20; X write_sec_to_disk(secbuf,Rxcount); X rxbytes += Rxcount; X goto moredata; X case GOTCRCE: X n = 20; X write_sec_to_disk(secbuf,Rxcount); X rxbytes += Rxcount; X goto nxthdr; X } X } X } X} /* end of rzfile */ X X/*+------------------------------------------------------------------------- X rzfiles() - receive file(s) with ZMODEM protocol X--------------------------------------------------------------------------*/ Xrzfiles() X{ Xregister c; X X for(;;) X { X switch(c = rzfile()) X { X case ZEOF: X case ZSKIP: X switch(tryz()) X { 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} /* end of rzfiles */ X X/*+------------------------------------------------------------------------- X close_and_report() - close the received file, set mod time and chmod X(specifically exclude set uid and gid from chmod) X--------------------------------------------------------------------------*/ Xclose_and_report() X{ X fflush(fout); X fstat(fileno(fout),&fout_stat); X report_file_byte_io((long)fout_stat.st_size); X report_file_close(); X X if(fclose(fout)==ERROR) X return(ERROR); X X#if defined(LOG_XFER) X sprintf(s256,"RECEIVE success: %s (%ld bytes)",Pathname,fout_stat.st_size); X ecu_log_event(getppid(),s256); X#endif X X if(Modtime) X { X timep[0] = time(NULL); X timep[1] = Modtime; X utime(Pathname,timep); X } X X if((Filemode & S_IFMT) == S_IFREG) X { X Filemode &= ~(S_ISUID | S_ISGID); X chmod(Pathname,(07777 & Filemode)); X } X X return(OK); X X} /* end of close_and_report */ X X/*+------------------------------------------------------------------------- X send_ZFIN_and_exit() - send ZFIN packet and wait for "OO" ack X--------------------------------------------------------------------------*/ Xsend_ZFIN_and_exit() X{ Xregister n; X X Readnum = 1; X stohdr(0L); X for(n = 0; n < 4; n++) X { X purgeline(); X zshhdr(ZFIN,Txhdr); X switch(readline(100)) X { X case 'O': X readline(1); /* Discard 2nd 'O' */ X return; X case RCDO: X return; X case TIMEOUT: X default: X break; X } X } X} /* end of send_ZFIN_and_exit */ X X/*+------------------------------------------------------------------------- X sys2(shellcmd) - execute shell command X X Strip leading ! if present X--------------------------------------------------------------------------*/ Xsys2(shellcmd) Xregister char *shellcmd; X{ X if(*shellcmd == '!') X ++shellcmd; X return(system(shellcmd)); X} /* end of sys2 */ X X/*+------------------------------------------------------------------------- X main(argc,argv,envp) X--------------------------------------------------------------------------*/ Xmain(argc,argv,envp) Xint argc; Xchar **argv; Xchar **envp; X{ Xregister char *cp; Xchar **patts; Xchar *getenv(); Xint exitcode = 0; Xchar **gargv = argv; Xint gargc = argc; X X signal(SIGINT,bye_bye); X signal(SIGTERM,bye_bye); X X get_curr_dir(curr_dir,sizeof(curr_dir)); X X Rxtimeout = 100; X X npats = 0; X while(--argc) X { X cp = *++argv; X if(*cp == '-') X { X while( *++cp) X { X switch(*cp) X { X case 'X': X required_type = 1; X Batch = 0; X break; X case 'Y': X required_type = 1; X Nozmodem = 1; X Batch = 1; X break; X case 'Z': X required_type = 1; X Nozmodem = 0; X Batch = 1; X break; X case '+': X Lzmanag = ZMAPND; X break; X case 'a': X Rxascii=1; X break; X case 'b': X Rxbinary=1; X break; X case 'c': X Crcflg=1; X break; X case 'e': X Zctlesc = 1; X break; X case 'p': X Lzmanag = ZMPROT; X break; X case '@': X force_no_curses = 1; X break; X case ',': X log_packets = 1; X break; X case ':': X can_on_eof = 1; X break; X case '.': X if(--argc < 1) X { X usage("no iofd after -."); X } X iofd = atoi(*++argv); X break; X case 't': X if(--argc < 1) X { X usage("no rcvr timeout after -t"); X } X Rxtimeout = atoi(*++argv); X if(Rxtimeout<10 || Rxtimeout>1000) X usage("illegal timeout: must be 10 <= t <= 1000"); X break; X case 'w': X if(--argc < 1) X { X usage("no Zrwindow after -w"); X } X Zrwindow = atoi(*++argv); X break; X case 'C': X if(--argc < 1) X usage("no label after -C"); X bottom_label = *++argv; X break; X case 'u': X MakeLCPathname=0; X break; X case 'y': X Rxclob=1; X break; X default: X sprintf(s128,"Unknown switch -%c",*cp); X usage(s128); X } X } X } X else if( !npats && argc>0) X { X if(argv[0][0]) X { X npats=argc; X patts=argv; X } X } X } X X if(determine_output_mode()) X { X setbuf(stdout,NULL); X setbuf(stderr,NULL); X } X X if(!required_type || !iofd) X { X printf("can only be run by ecu\n"); X exit(255); X } X X if(log_packets) X { X char log_packets_name[64]; X int iargv; X sprintf(log_packets_name,"/tmp/rz%05d.plog",getpid()); X unlink(log_packets_name); X log_packets = open(log_packets_name,O_CREAT|O_WRONLY,0644); X if(log_packets < 0) X log_packets = 0; X else X { X write(log_packets,"exec: ",6); X for(iargv = 0; iargv < gargc; iargv++) X { X write(log_packets,gargv[iargv],strlen(gargv[iargv])); X write(log_packets," ",1); X } X write(log_packets,"\n",1); X } X } X X X if(Batch && npats) X usage("Cannot specify batch receive and filename"); X if(npats > 1) X usage("only one filename allowed"); X sprintf(s128,"%s",numeric_revision); X report_init(s128); X mode(1); X signal(SIGINT,cancel_transaction); X signal(SIGTERM,cancel_transaction); X signal(SIGQUIT,cancel_transaction); X if(wcreceive(npats,patts)==ERROR) X { X exitcode=0200; X send_cancel(1); X } X mode(0); X if(exitcode && !Zmodem) /* bellow again with all thy might. */ X send_cancel(1); X report_uninit(0); X exit(exitcode); X} X X/* vi: set tabstop=4 shiftwidth=4: */ X/* end of ecurz.c */ SHAR_EOF $TOUCH -am 1223021690 'z/ecurz.c' && chmod 0644 z/ecurz.c || echo 'restore of z/ecurz.c failed' Wc_c="`wc -c < 'z/ecurz.c'`" test 41299 -eq "$Wc_c" || echo 'z/ecurz.c: original size 41299, current size' "$Wc_c" true || echo 'restore of z/ecusz.c failed' echo End of part 19, continue with part 20 exit 0 -------------------------------------------------------------------- Warren Tucker, TuckerWare emory!n4hgf!wht or wht@n4hgf.Mt-Park.GA.US Hacker Extraordinaire d' async PADs, pods, proteins and protocols exit 0 # Just in case... -- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM Sterling Software, IMD UUCP: uunet!sparky!kent Phone: (402) 291-8300 FAX: (402) 291-4362 Please send comp.sources.misc-related mail to kent@uunet.uu.net.