📄 lrz.c
字号:
/* lrz.c cosmetic modifications by Matt Porter * from rz.c By Chuck Forsberg * * A program for Linux to receive files and commands from computers running * zmodem, ymodem, or xmodem protocols. * lrz uses Unix buffered input to reduce wasted CPU time. * */#include "config.h"#if STDC_HEADERS# include <string.h>#else# ifdef HAVE_STRINGS_H# include <strings.h># endif# ifndef HAVE_STRCHR# define strchr index# define strrchr rindex# endifchar *strchr (), *strrchr ();# ifndef HAVE_MEMCPY# define memcpy(d, s, n) bcopy ((s), (d), (n))# define memmove(d, s, n) bcopy ((s), (d), (n))# endif#endif#define SS_NORMAL 0#define LOGFILE "/var/adm/rzlog"#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <ctype.h>#include <errno.h>#ifdef TIME_WITH_SYS_TIME# include <sys/time.h># include <time.h>#else# ifdef HAVE_SYS_TIME_H# include <sys/time.h># else# include <time.h># endif#endif#include "timing.h"extern int errno;FILE *popen();#define OK 0#define FALSE 0#define TRUE 1#define ERROR (-1)#define MAX_BLOCK 8192/* * Max value for HOWMANY is 255 if NFGVMIN is not defined. * A larger value reduces system overhead but may evoke kernel bugs. * 133 corresponds to an XMODEM/CRC sector */#ifndef HOWMANY#ifdef NFGVMIN#define HOWMANY MAX_BLOCK#else#define HOWMANY 255#endif#endif/* 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 RCDO (-3)#define ERRORMAX 5#define RETRYMAX 5#define WCEOT (-10)#define PATHLEN 257 /* ready for 4.2 bsd ? */#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */int Zmodem=0; /* ZMODEM protocol requested */int Nozmodem = 0; /* If invoked as "rb" */unsigned Baudrate = 2400;#include "rbsb.c" /* most of the system dependent stuff here */#include "crctab.c"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 ... */}int Lastrx;int Crcflg;int Firstsec;int Eofseen; /* indicates cpm eof (^Z) has been received */int errors;int Restricted=1; /* restricted; no /.. or ../ in filenames */int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */#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 */int Filemode; /* Unix style mode for incoming file */char Pathname[PATHLEN];char *Progname; /* the name by which we were called */int Batch=0;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 Rxclob=FALSE; /* Clobber existing file */int Rxbinary=FALSE; /* receive all files in bin mode */int Rxascii=FALSE; /* receive files in ascii (translate) mode */int Thisbinary; /* current file is to be received in bin mode */int Blklen; /* record length of received packets */long rxbytes;int try_resume=FALSE;int allow_remote_commands=FALSE;int no_timeout=FALSE;#ifdef SEGMENTSint chinseg = 0; /* Number of characters received in this data seg */char secbuf[1+(SEGMENTS+1)*MAX_BLOCK];#elsechar secbuf[MAX_BLOCK + 1];#endif#ifdef ENABLE_TIMESYNCint timesync_flag=0;int in_timesync=0;#endifchar linbuf[HOWMANY];int Lleft=0; /* number of characters in linbuf */time_t timep[2];char Lzmanag; /* Local file management request */char zconv; /* ZMODEM file conversion request */char zmanag; /* ZMODEM file management request */char ztrans; /* ZMODEM file transport request */int Zctlesc; /* Encode control characters */int Zrwindow = 1400; /* RX window size (controls garbage count) */#define xsendline(c) sendline(c)char *readline_ptr; /* pointer for removing chars from linbuf */#define READLINE_PF(timeout) \ (--Lleft >= 0? (*readline_ptr++ & 0377) : readline(timeout))#include "zm.c"int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */RETSIGTYPEalrm(int dummy){ /* doesn't need to do anything */}/* called by signal interrupt or terminate to clean things up */RETSIGTYPEbibi(n){ if (Zmodem) zmputs(Attn); canit(); mode(0); fprintf(stderr, "lrz: caught signal %d; exiting", n); cucheck(); exit(128+n);}main(argc, argv)char *argv[];{ register char *cp; register npats; char *virgin, **patts; char *getenv(); int exitcode=0; int under_rsh=FALSE; Rxtimeout = 100; setbuf(stderr, NULL); if ((cp=getenv("SHELL")) && (strstr(cp, "rsh") || strstr(cp, "rksh") || strstr(cp,"rbash"))) under_rsh=TRUE; if ((cp=getenv("ZMODEM_RESTRICTED"))!=NULL) Restricted=2; from_cu(); chkinvok(virgin=argv[0]); /* if called as [-]rzCOMMAND set flag */ npats = 0; while (--argc) { cp = *++argv; if (*cp == '-') { while( *++cp) { switch(*cp) { case '\\': cp[1] = toupper(cp[1]); continue; case '+': Lzmanag = ZMAPND; break; case 'a': Rxascii=TRUE; break; case 'b': Rxbinary=TRUE; break; case 'c': Crcflg=TRUE; break; case 'C': allow_remote_commands=TRUE; break; case 'D': Nflag = TRUE; break; case 'e': Zctlesc = 1; break; case 'h': usage(); break; case 'O': no_timeout=TRUE; break; case 'p': Lzmanag = ZMPROT; break; case 'q': Quiet=TRUE; Verbose=0; break; case 'r': try_resume=TRUE; break; case 'R': Restricted++; break; case 'S':#ifdef ENABLE_TIMESYNC timesync_flag++; if (timesync_flag==2) {#ifdef HAVE_SETTIMEOFDAY fputs("don't have settimeofday, will not set time\n", stderr);#endif if (getuid()!=0) fputs("not running as root (this is good!), can not set time\n", stderr); }#endif break; case 't': if (--argc < 1) { usage(); } Rxtimeout = atoi(*++argv); if (Rxtimeout<10 || Rxtimeout>1000) usage(); break; case 'w': if (--argc < 1) { usage(); } Zrwindow = atoi(*++argv); break; case 'u': MakeLCPathname=FALSE; break; case 'U': if (!under_rsh) Restricted=0; else { fputs("security violation: running under restricted shell\n", stderr); exit(1); } break; case 'v': ++Verbose; break; case 'y': Rxclob=TRUE; break; default: usage(); } } } else if ( !npats && argc>0) { if (argv[0][0]) { npats=argc; patts=argv; } } } if (npats > 1) usage(); if (Batch && npats) usage(); if (Restricted && allow_remote_commands) allow_remote_commands=FALSE; if (Verbose) {#if 0 if (freopen(LOGFILE, "a", stderr)==NULL) { printf("Can't open log file %s\n",LOGFILE); exit(1); } fprintf(stderr, "argv[0]=%s Progname=%s\n", virgin, Progname);#endif setbuf(stderr, NULL); } if (Fromcu && !Quiet) { if (Verbose == 0) Verbose = 2; } vfile("%s %s for %s\n", Progname, VERSION, OS); mode(1);#ifndef linux if (signal(SIGINT, bibi) == SIG_IGN) { signal(SIGINT, SIG_IGN); signal(SIGKILL, SIG_IGN); } else { signal(SIGINT, bibi); signal(SIGKILL, bibi); } signal(SIGTERM, bibi);#endif if (wcreceive(npats, patts)==ERROR) { exitcode=0200; canit(); } mode(0); if (exitcode && !Zmodem) /* bellow again with all thy might. */ canit(); if (exitcode) cucheck(); exit(exitcode ? exitcode:SS_NORMAL);}usage(){ cucheck(); fprintf(stderr,"Usage: lrz [-abeuvy] [-L FILE] (ZMODEM)\n"); fprintf(stderr,"or lrb [-abuvy] [-L FILE] (YMODEM)\n"); fprintf(stderr,"or lrx [-abcv] [-L FILE] file (XMODEM or XMODEM-1k)\n"); fprintf(stderr," -a ASCII transfer (strip CR)\n"); fprintf(stderr," -b Binary transfer for all files\n"); fprintf(stderr," -c Use 16 bit CRC (XMODEM)\n"); fprintf(stderr," -e Escape control characters (ZMODEM)\n"); fprintf(stderr," -h Help, print this usage message\n"); fprintf(stderr," -R restricted, more secure mode\n"); fprintf(stderr," -v Verbose more v's give more info\n"); fprintf(stderr," -y Yes, clobber existing file if any\n"); fprintf(stderr,"\t%s version %s for %s %s\n", Progname, VERSION, CPU, OS); exit(SS_NORMAL);}/* * Debugging information output interface routine *//* VARARGS1 */vfile(f, a, b, c)register char *f;{ if (Verbose > 2) { fprintf(stderr, f, a, b, c); fprintf(stderr, "\n"); }}/* * Let's receive something already. */char *rbmsg ="%s waiting to receive.";wcreceive(argc, argp)char **argp;{ register c; if (Batch || argc==0) { Crcflg=1; if ( !Quiet) fprintf(stderr, rbmsg, Progname, Nozmodem?"sb":"sz"); 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; procheader(""); strcpy(Pathname, *argp); checkpath(Pathname); fprintf(stderr, "\n%s: ready to receive %s\r\n", Progname, Pathname); if ((fout=fopen(Pathname, "w")) == NULL) return ERROR; if (wcrx()==ERROR) goto fubar; timing(1); } return OK;fubar: canit(); if (Topipe && fout) { pclose(fout); return ERROR; } if (fout) fclose(fout); if (Restricted) { unlink(Pathname); fprintf(stderr, "\r\n%s: %s removed.\r\n", Progname, 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) { if (c == WCEOT) { zperr( "Pathname fetch returned %d", c); 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 &0377)) { 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&0377)) { zperr( "Received dup Sector"); 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 { zperr( "Sync Error"); return ERROR; } }}/*
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -