📄 lrz.c
字号:
/* lrz - receive files with x/y/zmodem Copyright (C) until 1988 Chuck Forsberg (Omen Technology INC) Copyright (C) 1994 Matt Porter, Michael D. Black Copyright (C) 1996, 1997 Uwe Ohse This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation; either version 2, or (at your option) any later version. This program is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. originally written by Chuck Forsberg*/#include "zglobal.h"#define SS_NORMAL 0#include <stdio.h>#include <stdlib.h>#include <signal.h>#include <ctype.h>#include <errno.h>#include <getopt.h>#ifdef HAVE_UTIME_H#include <utime.h>#endif#include "timing.h"#include "long-options.h"#include "xstrtoul.h"#include "error.h"#ifndef STRICT_PROTOTYPESextern time_t time();extern char *strerror();extern char *strstr();#endif#ifndef HAVE_ERRNO_DECLARATIONextern int errno;#endif#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#endifunsigned Baudrate = 2400;FILE *fout;int Lastrx;int Crcflg;int Firstsec;int errors;int Restricted=1; /* restricted; no /.. or ../ in filenames */int Readnum = HOWMANY; /* Number of bytes to ask for in read() from modem */int skip_if_not_found;char *Pathname;const char *program_name; /* the name by which we were called */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 try_resume=FALSE;int allow_remote_commands=FALSE;int junk_path=FALSE;int no_timeout=FALSE;enum zm_type_enum protocol;int under_rsh=FALSE;int zmodem_requested=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;#endifint in_tcpsync=0;int tcpsync_flag=1;int tcp_socket=-1;int tcp_flag=0;char *tcp_server_address=NULL;char tcp_buf[256]="";#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC)static int o_sync = 0;#endifstatic int rzfiles __P ((struct zm_fileinfo *));static int tryz __P ((void));static void checkpath __P ((const char *name));static void chkinvok __P ((const char *s));static void report __P ((int sct));static void uncaps __P ((char *s));static int IsAnyLower __P ((const char *s));static int putsec __P ((struct zm_fileinfo *zi, char *buf, size_t n));static int make_dirs __P ((char *pathname));static int procheader __P ((char *name, struct zm_fileinfo *));static int wcgetsec __P ((size_t *Blklen, char *rxbuf, unsigned int maxtime));static int wcrx __P ((struct zm_fileinfo *));static int wcrxpn __P ((struct zm_fileinfo *, char *rpn));static int wcreceive __P ((int argc, char **argp));static int rzfile __P ((struct zm_fileinfo *));static void usage __P ((int exitcode, const char *what));static void usage1 __P ((int exitcode));static void exec2 __P ((const char *s));static int closeit __P ((struct zm_fileinfo *));static void ackbibi __P ((void));static int sys2 __P ((const char *s));static void zmputs __P ((const char *s));static size_t getfree __P ((void));static long buffersize=32768;static unsigned long min_bps=0;static long min_bps_time=120;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) */int tryzhdrtype=ZRINIT; /* Header type to send corresponding to Last rx close */time_t stop_time;#ifdef ENABLE_SYSLOG# if defined(ENABLE_SYSLOG_FORCE) || defined(ENABLE_SYSLOG_DEFAULT)int enable_syslog=TRUE;# elseint enable_syslog=FALSE;# endif#define DO_SYSLOG_FNAME(message) do { \ if (enable_syslog) { \ const char *shortname; \ if (!zi->fname) \ shortname="no.name"; \ else { \ shortname=strrchr(zi->fname,'/'); \ if (!shortname) \ shortname=zi->fname; \ else \ shortname++; \ } \ lsyslog message ; \ } \} while(0)#define DO_SYSLOG(message) do { \ if (enable_syslog) { \ lsyslog message ; \ } \} while(0)#else#define DO_SYSLOG_FNAME(message) do { } while(0)#define DO_SYSLOG(message) do { } while(0)#endif/* called by signal interrupt or terminate to clean things up */RETSIGTYPEbibi(int n){ if (zmodem_requested) zmputs(Attn); canit(STDOUT_FILENO); io_mode(0,0); error(128+n,0,_("caught signal %d; exiting"), n);}static struct option const long_options[] ={ {"append", no_argument, NULL, '+'}, {"ascii", no_argument, NULL, 'a'}, {"binary", no_argument, NULL, 'b'}, {"bufsize", required_argument, NULL, 'B'}, {"allow-commands", no_argument, NULL, 'C'}, {"allow-remote-commands", no_argument, NULL, 'C'}, {"escape", no_argument, NULL, 'e'}, {"rename", no_argument, NULL, 'E'}, {"help", no_argument, NULL, 'h'}, {"crc-check", no_argument, NULL, 'H'}, {"junk-path", no_argument, NULL, 'j'}, {"errors", required_argument, NULL, 3}, {"disable-timeouts", no_argument, NULL, 'O'}, {"disable-timeout", no_argument, NULL, 'O'}, /* i can't get it right */ {"min-bps", required_argument, NULL, 'm'}, {"min-bps-time", required_argument, NULL, 'M'}, {"newer", no_argument, NULL, 'n'}, {"newer-or-longer", no_argument, NULL, 'N'}, {"protect", no_argument, NULL, 'p'}, {"resume", no_argument, NULL, 'r'}, {"restricted", no_argument, NULL, 'R'}, {"quiet", no_argument, NULL, 'q'}, {"stop-at", required_argument, NULL, 's'}, {"timesync", no_argument, NULL, 'S'}, {"timeout", required_argument, NULL, 't'}, {"keep-uppercase", no_argument, NULL, 'u'}, {"unrestrict", no_argument, NULL, 'U'}, {"verbose", no_argument, NULL, 'v'}, {"windowsize", required_argument, NULL, 'w'}, {"with-crc", no_argument, NULL, 'c'}, {"xmodem", no_argument, NULL, 'X'}, {"ymodem", no_argument, NULL, 1}, {"zmodem", no_argument, NULL, 'Z'}, {"overwrite", no_argument, NULL, 'y'}, {"null", no_argument, NULL, 'D'}, {"syslog", optional_argument, NULL , 2}, {"delay-startup", required_argument, NULL, 4}, {"o-sync", no_argument, NULL, 5}, {"o_sync", no_argument, NULL, 5}, {"tcp-server", no_argument, NULL, 6}, {"tcp-client", required_argument, NULL, 7}, {NULL,0,NULL,0}};static voidshow_version(void){ printf ("%s (%s) %s\n", program_name, PACKAGE, VERSION);}intmain(int argc, char *argv[]){ register char *cp; register int npats; char **patts=NULL; /* keep compiler quiet */ int exitcode=0; int c; unsigned int startup_delay=0; Rxtimeout = 100; setbuf(stderr, NULL); if ((cp=getenv("SHELL")) && (strstr(cp, "rsh") || strstr(cp, "rksh") || strstr(cp,"rbash") || strstr(cp, "rshell"))) under_rsh=TRUE; if ((cp=getenv("ZMODEM_RESTRICTED"))!=NULL) Restricted=2; /* make temporary and unfinished files */ umask(0077); from_cu(); chkinvok(argv[0]); /* if called as [-]rzCOMMAND set flag */#ifdef ENABLE_SYSLOG openlog(program_name,LOG_PID,ENABLE_SYSLOG);#endif setlocale (LC_ALL, ""); bindtextdomain (PACKAGE, LOCALEDIR); textdomain (PACKAGE); parse_long_options (argc, argv, show_version, usage1); while ((c = getopt_long (argc, argv, "a+bB:cCDeEhm:M:OprRqs:St:uUvw:XZy", long_options, (int *) 0)) != EOF) { unsigned long int tmp; char *tmpptr; enum strtol_error s_err; switch (c) { case 0: break; case '+': Lzmanag = ZF1_ZMAPND; break; case 'a': Rxascii=TRUE; break; case 'b': Rxbinary=TRUE; break; case 'B': if (strcmp(optarg,"auto")==0) buffersize=-1; else buffersize=strtol(optarg,NULL,10); break; case 'c': Crcflg=TRUE; break; case 'C': allow_remote_commands=TRUE; break; case 'D': Nflag = TRUE; break; case 'E': Lzmanag = ZF1_ZMCHNG; break; case 'e': Zctlesc = 1; break; case 'h': usage(0,NULL); break; case 'H': Lzmanag= ZF1_ZMCRC; break; case 'j': junk_path=TRUE; break; case 'm': s_err = xstrtoul (optarg, &tmpptr, 0, &tmp, "km"); min_bps = tmp; if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("min_bps"), s_err); break; case 'M': s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); min_bps_time = tmp; if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("min_bps_time"), s_err); if (min_bps_time<=1) usage(2,_("min_bps_time must be > 1")); break; case 'N': Lzmanag = ZF1_ZMNEWL; break; case 'n': Lzmanag = ZF1_ZMNEW; break; case 'O': no_timeout=TRUE; break; case 'p': Lzmanag = ZF1_ZMPROT; break; case 'q': Quiet=TRUE; Verbose=0; break; case 's': if (isdigit((unsigned char) (*optarg))) { struct tm *tm; time_t t; int hh,mm; char *nex; hh = strtoul (optarg, &nex, 10); if (hh>23) usage(2,_("hour to large (0..23)")); if (*nex!=':') usage(2, _("unparsable stop time\n")); nex++; mm = strtoul (optarg, &nex, 10); if (mm>59) usage(2,_("minute to large (0..59)")); t=time(NULL); tm=localtime(&t); tm->tm_hour=hh; tm->tm_min=hh; stop_time=mktime(tm); if (stop_time<t) stop_time+=86400L; /* one day more */ if (stop_time - t <10) usage(2,_("stop time to small")); } else { s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); stop_time = tmp + time(0); if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("stop-at"), s_err); if (tmp<10) usage(2,_("stop time to small")); } break; case 'r': if (try_resume) Lzmanag= ZF1_ZMCRC; else try_resume=TRUE; break; case 'R': Restricted++; break; case 'S':#ifdef ENABLE_TIMESYNC timesync_flag++; if (timesync_flag==2) {#ifdef HAVE_SETTIMEOFDAY error(0,0,_("don't have settimeofday, will not set time\n"));#endif if (getuid()!=0) error(0,0, _("not running as root (this is good!), can not set time\n")); }#endif break; case 't': s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); Rxtimeout = tmp; if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("timeout"), s_err); if (Rxtimeout<10 || Rxtimeout>1000) usage(2,_("timeout out of range 10..1000")); break; case 'w': s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); Zrwindow = tmp; if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("window size"), s_err); break; case 'u': MakeLCPathname=FALSE; break; case 'U': if (!under_rsh) Restricted=0; else { DO_SYSLOG((LOG_INFO,"--unrestrict option used under restricted shell")); error(1,0, _("security violation: can't do that under restricted shell\n")); } break; case 'v': ++Verbose; break; case 'X': protocol=ZM_XMODEM; break; case 1: protocol=ZM_YMODEM; break; case 'Z': protocol=ZM_ZMODEM; break; case 'y': Rxclob=TRUE; break; case 2:#ifdef ENABLE_SYSLOG# ifndef ENABLE_SYSLOG_FORCE if (optarg && (!strcmp(optarg,"off") || !strcmp(optarg,"no"))) { if (under_rsh) error(0,0, _("cannot turnoff syslog")); else enable_syslog=FALSE; } else enable_syslog=TRUE;# else error(0,0, _("cannot turnoff syslog"));# endif#endif case 3: s_err = xstrtoul (optarg, NULL, 0, &tmp, "km"); bytes_per_error = tmp; if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("bytes_per_error"), s_err); if (bytes_per_error<100) usage(2,_("bytes-per-error should be >100")); break; case 4: s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); startup_delay = tmp; if (s_err != LONGINT_OK) STRTOL_FATAL_ERROR (optarg, _("startup delay"), s_err); break; case 5:#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC) o_sync=1;#else error(0,0, _("O_SYNC not supported by the kernel"));#endif break; case 6: tcp_flag=2; break; case 7: tcp_flag=3; tcp_server_address=(char *)strdup(optarg); if (!tcp_server_address) error(1,0,_("out of memory")); break; default: usage(2,NULL); } } if (getuid()!=geteuid()) { error(1,0, _("this program was never intended to be used setuid\n")); } /* initialize zsendline tab */ zsendline_init();#ifdef HAVE_SIGINTERRUPT siginterrupt(SIGALRM,1);#endif if (startup_delay) sleep(startup_delay); npats = argc - optind; patts=&argv[optind]; if (npats > 1) usage(2,_("garbage on commandline")); if (protocol!=ZM_XMODEM && npats) usage(2, _("garbage on commandline")); if (Restricted && allow_remote_commands) { allow_remote_commands=FALSE; } if (Fromcu && !Quiet) { if (Verbose == 0) Verbose = 2; } vfile("%s %s\n", program_name, VERSION); if (tcp_flag==2) { char buf[256];#ifdef MAXHOSTNAMELEN char hn[MAXHOSTNAMELEN];#else char hn[256];#endif char *p,*q; int d; /* tell receiver to receive via tcp */ d=tcp_server(buf); p=strchr(buf+1,'<'); p++; q=strchr(p,'>'); *q=0; if (gethostname(hn,sizeof(hn))==-1) { error(1,0, _("hostname too long\n")); } fprintf(stdout,"connect with lrz --tcp-client \"%s:%s\"\n",hn,p); fflush(stdout); /* ok, now that this file is sent we can switch to tcp */ tcp_socket=tcp_accept(d); dup2(tcp_socket,0); dup2(tcp_socket,1); } if (tcp_flag==3) { char buf[256]; char *p; p=strchr(tcp_server_address,':'); if (!p) error(1,0, _("illegal server address\n")); *p++=0; sprintf(buf,"[%s] <%s>\n",tcp_server_address,p); fprintf(stdout,"connecting to %s\n",buf); fflush(stdout); /* we need to switch to tcp mode */ tcp_socket=tcp_connect(buf); dup2(tcp_socket,0); dup2(tcp_socket,1); } io_mode(0,1); readline_setup(0, HOWMANY, MAX_BLOCK*2); if (signal(SIGINT, bibi) == SIG_IGN) signal(SIGINT, SIG_IGN); else signal(SIGINT, bibi); signal(SIGTERM, bibi); signal(SIGPIPE, bibi); if (wcreceive(npats, patts)==ERROR) { exitcode=0200; canit(STDOUT_FILENO); } io_mode(0,0); if (exitcode && !zmodem_requested) /* bellow again with all thy might. */ canit(STDOUT_FILENO); if (Verbose) { fputs("\r\n",stderr); if (exitcode) fputs(_("Transfer incomplete\n"),stderr); else fputs(_("Transfer complete\n"),stderr); } exit(exitcode);}static voidusage1(int exitcode){ usage(exitcode,NULL);}static voidusage(int exitcode, const char *what)
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -