diff options
author | Bernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org> | 2011-10-10 11:48:48 +0159 |
---|---|---|
committer | Bernhard Rosenkraenzer <Bernhard.Rosenkranzer@linaro.org> | 2011-10-10 11:55:55 +0159 |
commit | 2cbcbec2a3530c1e947a23e9497f0bfefb453278 (patch) | |
tree | 3223c7336c0602155addcba81a9d348fb455e650 | |
download | lrzsz-2cbcbec2a3530c1e947a23e9497f0bfefb453278.tar.gz |
-rw-r--r-- | canit.c | 46 | ||||
-rw-r--r-- | crctab.c | 140 | ||||
-rw-r--r-- | error.c | 210 | ||||
-rw-r--r-- | error.h | 65 | ||||
-rw-r--r-- | long-options.c | 83 | ||||
-rw-r--r-- | long-options.h | 10 | ||||
-rw-r--r-- | lrz.c | 2313 | ||||
-rw-r--r-- | lsyslog.c | 81 | ||||
-rw-r--r-- | lsz.c | 2492 | ||||
-rw-r--r-- | protname.c | 41 | ||||
-rw-r--r-- | rbsb.c | 506 | ||||
-rw-r--r-- | tcp.c | 169 | ||||
-rw-r--r-- | timing.c | 186 | ||||
-rw-r--r-- | timing.h | 1 | ||||
-rw-r--r-- | xstrtol.c | 180 | ||||
-rw-r--r-- | xstrtol.h | 66 | ||||
-rw-r--r-- | xstrtoul.c | 2 | ||||
-rw-r--r-- | xstrtoul.h | 7 | ||||
-rw-r--r-- | zglobal.h | 463 | ||||
-rw-r--r-- | zm.c | 982 | ||||
-rw-r--r-- | zmodem.h | 142 | ||||
-rw-r--r-- | zperr.c | 113 | ||||
-rw-r--r-- | zreadline.c | 136 |
23 files changed, 8434 insertions, 0 deletions
@@ -0,0 +1,46 @@ +/* + canit - cancel zmodem connection + 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. +*/ +#include "zglobal.h" + +#define SS_NORMAL 0 +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <setjmp.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> + +/* send cancel string to get the other end to shut up */ +void +canit (int fd) +{ + static char canistr[] = + { + 24, 24, 24, 24, 24, 24, 24, 24, 24, 24, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 0 + }; + purgeline(fd); + write(fd,canistr,strlen(canistr)); + if (fd==0) + write(1,canistr,strlen(canistr)); +} + diff --git a/crctab.c b/crctab.c new file mode 100644 index 0000000..6b9bada --- /dev/null +++ b/crctab.c @@ -0,0 +1,140 @@ +/* + * Crc calculation stuff + */ + +/* crctab calculated by Mark G. Mendel, Network Systems Corporation */ +unsigned short crctab[256] = { + 0x0000, 0x1021, 0x2042, 0x3063, 0x4084, 0x50a5, 0x60c6, 0x70e7, + 0x8108, 0x9129, 0xa14a, 0xb16b, 0xc18c, 0xd1ad, 0xe1ce, 0xf1ef, + 0x1231, 0x0210, 0x3273, 0x2252, 0x52b5, 0x4294, 0x72f7, 0x62d6, + 0x9339, 0x8318, 0xb37b, 0xa35a, 0xd3bd, 0xc39c, 0xf3ff, 0xe3de, + 0x2462, 0x3443, 0x0420, 0x1401, 0x64e6, 0x74c7, 0x44a4, 0x5485, + 0xa56a, 0xb54b, 0x8528, 0x9509, 0xe5ee, 0xf5cf, 0xc5ac, 0xd58d, + 0x3653, 0x2672, 0x1611, 0x0630, 0x76d7, 0x66f6, 0x5695, 0x46b4, + 0xb75b, 0xa77a, 0x9719, 0x8738, 0xf7df, 0xe7fe, 0xd79d, 0xc7bc, + 0x48c4, 0x58e5, 0x6886, 0x78a7, 0x0840, 0x1861, 0x2802, 0x3823, + 0xc9cc, 0xd9ed, 0xe98e, 0xf9af, 0x8948, 0x9969, 0xa90a, 0xb92b, + 0x5af5, 0x4ad4, 0x7ab7, 0x6a96, 0x1a71, 0x0a50, 0x3a33, 0x2a12, + 0xdbfd, 0xcbdc, 0xfbbf, 0xeb9e, 0x9b79, 0x8b58, 0xbb3b, 0xab1a, + 0x6ca6, 0x7c87, 0x4ce4, 0x5cc5, 0x2c22, 0x3c03, 0x0c60, 0x1c41, + 0xedae, 0xfd8f, 0xcdec, 0xddcd, 0xad2a, 0xbd0b, 0x8d68, 0x9d49, + 0x7e97, 0x6eb6, 0x5ed5, 0x4ef4, 0x3e13, 0x2e32, 0x1e51, 0x0e70, + 0xff9f, 0xefbe, 0xdfdd, 0xcffc, 0xbf1b, 0xaf3a, 0x9f59, 0x8f78, + 0x9188, 0x81a9, 0xb1ca, 0xa1eb, 0xd10c, 0xc12d, 0xf14e, 0xe16f, + 0x1080, 0x00a1, 0x30c2, 0x20e3, 0x5004, 0x4025, 0x7046, 0x6067, + 0x83b9, 0x9398, 0xa3fb, 0xb3da, 0xc33d, 0xd31c, 0xe37f, 0xf35e, + 0x02b1, 0x1290, 0x22f3, 0x32d2, 0x4235, 0x5214, 0x6277, 0x7256, + 0xb5ea, 0xa5cb, 0x95a8, 0x8589, 0xf56e, 0xe54f, 0xd52c, 0xc50d, + 0x34e2, 0x24c3, 0x14a0, 0x0481, 0x7466, 0x6447, 0x5424, 0x4405, + 0xa7db, 0xb7fa, 0x8799, 0x97b8, 0xe75f, 0xf77e, 0xc71d, 0xd73c, + 0x26d3, 0x36f2, 0x0691, 0x16b0, 0x6657, 0x7676, 0x4615, 0x5634, + 0xd94c, 0xc96d, 0xf90e, 0xe92f, 0x99c8, 0x89e9, 0xb98a, 0xa9ab, + 0x5844, 0x4865, 0x7806, 0x6827, 0x18c0, 0x08e1, 0x3882, 0x28a3, + 0xcb7d, 0xdb5c, 0xeb3f, 0xfb1e, 0x8bf9, 0x9bd8, 0xabbb, 0xbb9a, + 0x4a75, 0x5a54, 0x6a37, 0x7a16, 0x0af1, 0x1ad0, 0x2ab3, 0x3a92, + 0xfd2e, 0xed0f, 0xdd6c, 0xcd4d, 0xbdaa, 0xad8b, 0x9de8, 0x8dc9, + 0x7c26, 0x6c07, 0x5c64, 0x4c45, 0x3ca2, 0x2c83, 0x1ce0, 0x0cc1, + 0xef1f, 0xff3e, 0xcf5d, 0xdf7c, 0xaf9b, 0xbfba, 0x8fd9, 0x9ff8, + 0x6e17, 0x7e36, 0x4e55, 0x5e74, 0x2e93, 0x3eb2, 0x0ed1, 0x1ef0 +}; + +/* + * updcrc macro derived from article Copyright (C) 1986 Stephen Satchell. + * NOTE: First srgument must be in range 0 to 255. + * Second argument is referenced twice. + * + * Programmers may incorporate any or all code into their programs, + * giving proper credit within the source. Publication of the + * source routines is permitted so long as proper credit is given + * to Stephen Satchell, Satchell Evaluations and Chuck Forsberg, + * Omen Technology. + */ + +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) + +/* + * Copyright (C) 1986 Gary S. Brown. You may use this program, or + * code or tables extracted from it, as desired without restriction. + */ + +/* First, the polynomial itself and its table of feedback terms. The */ +/* polynomial is */ +/* X^32+X^26+X^23+X^22+X^16+X^12+X^11+X^10+X^8+X^7+X^5+X^4+X^2+X^1+X^0 */ +/* Note that we take it "backwards" and put the highest-order term in */ +/* the lowest-order bit. The X^32 term is "implied"; the LSB is the */ +/* X^31 term, etc. The X^0 term (usually shown as "+1") results in */ +/* the MSB being 1. */ + +/* Note that the usual hardware shift register implementation, which */ +/* is what we're using (we're merely optimizing it by doing eight-bit */ +/* chunks at a time) shifts bits into the lowest-order term. In our */ +/* implementation, that means shifting towards the right. Why do we */ +/* do it this way? Because the calculated CRC must be transmitted in */ +/* order from highest-order term to lowest-order term. UARTs transmit */ +/* characters in order from LSB to MSB. By storing the CRC this way, */ +/* we hand it to the UART in the order low-byte to high-byte; the UART */ +/* sends each low-bit to hight-bit; and the result is transmission bit */ +/* by bit from highest- to lowest-order term without requiring any bit */ +/* shuffling on our part. Reception works similarly. */ + +/* The feedback terms table consists of 256, 32-bit entries. Notes: */ +/* */ +/* The table can be generated at runtime if desired; code to do so */ +/* is shown later. It might not be obvious, but the feedback */ +/* terms simply represent the results of eight shift/xor opera- */ +/* tions for all combinations of data and CRC register values. */ +/* */ +/* The values must be right-shifted by eight bits by the "updcrc" */ +/* logic; the shift must be unsigned (bring in zeroes). On some */ +/* hardware you could probably optimize the shift in assembler by */ +/* using byte-swap instructions. */ + +long cr3tab[] = { /* CRC polynomial 0xedb88320 */ +0x00000000, 0x77073096, 0xee0e612c, 0x990951ba, 0x076dc419, 0x706af48f, 0xe963a535, 0x9e6495a3, +0x0edb8832, 0x79dcb8a4, 0xe0d5e91e, 0x97d2d988, 0x09b64c2b, 0x7eb17cbd, 0xe7b82d07, 0x90bf1d91, +0x1db71064, 0x6ab020f2, 0xf3b97148, 0x84be41de, 0x1adad47d, 0x6ddde4eb, 0xf4d4b551, 0x83d385c7, +0x136c9856, 0x646ba8c0, 0xfd62f97a, 0x8a65c9ec, 0x14015c4f, 0x63066cd9, 0xfa0f3d63, 0x8d080df5, +0x3b6e20c8, 0x4c69105e, 0xd56041e4, 0xa2677172, 0x3c03e4d1, 0x4b04d447, 0xd20d85fd, 0xa50ab56b, +0x35b5a8fa, 0x42b2986c, 0xdbbbc9d6, 0xacbcf940, 0x32d86ce3, 0x45df5c75, 0xdcd60dcf, 0xabd13d59, +0x26d930ac, 0x51de003a, 0xc8d75180, 0xbfd06116, 0x21b4f4b5, 0x56b3c423, 0xcfba9599, 0xb8bda50f, +0x2802b89e, 0x5f058808, 0xc60cd9b2, 0xb10be924, 0x2f6f7c87, 0x58684c11, 0xc1611dab, 0xb6662d3d, +0x76dc4190, 0x01db7106, 0x98d220bc, 0xefd5102a, 0x71b18589, 0x06b6b51f, 0x9fbfe4a5, 0xe8b8d433, +0x7807c9a2, 0x0f00f934, 0x9609a88e, 0xe10e9818, 0x7f6a0dbb, 0x086d3d2d, 0x91646c97, 0xe6635c01, +0x6b6b51f4, 0x1c6c6162, 0x856530d8, 0xf262004e, 0x6c0695ed, 0x1b01a57b, 0x8208f4c1, 0xf50fc457, +0x65b0d9c6, 0x12b7e950, 0x8bbeb8ea, 0xfcb9887c, 0x62dd1ddf, 0x15da2d49, 0x8cd37cf3, 0xfbd44c65, +0x4db26158, 0x3ab551ce, 0xa3bc0074, 0xd4bb30e2, 0x4adfa541, 0x3dd895d7, 0xa4d1c46d, 0xd3d6f4fb, +0x4369e96a, 0x346ed9fc, 0xad678846, 0xda60b8d0, 0x44042d73, 0x33031de5, 0xaa0a4c5f, 0xdd0d7cc9, +0x5005713c, 0x270241aa, 0xbe0b1010, 0xc90c2086, 0x5768b525, 0x206f85b3, 0xb966d409, 0xce61e49f, +0x5edef90e, 0x29d9c998, 0xb0d09822, 0xc7d7a8b4, 0x59b33d17, 0x2eb40d81, 0xb7bd5c3b, 0xc0ba6cad, +0xedb88320, 0x9abfb3b6, 0x03b6e20c, 0x74b1d29a, 0xead54739, 0x9dd277af, 0x04db2615, 0x73dc1683, +0xe3630b12, 0x94643b84, 0x0d6d6a3e, 0x7a6a5aa8, 0xe40ecf0b, 0x9309ff9d, 0x0a00ae27, 0x7d079eb1, +0xf00f9344, 0x8708a3d2, 0x1e01f268, 0x6906c2fe, 0xf762575d, 0x806567cb, 0x196c3671, 0x6e6b06e7, +0xfed41b76, 0x89d32be0, 0x10da7a5a, 0x67dd4acc, 0xf9b9df6f, 0x8ebeeff9, 0x17b7be43, 0x60b08ed5, +0xd6d6a3e8, 0xa1d1937e, 0x38d8c2c4, 0x4fdff252, 0xd1bb67f1, 0xa6bc5767, 0x3fb506dd, 0x48b2364b, +0xd80d2bda, 0xaf0a1b4c, 0x36034af6, 0x41047a60, 0xdf60efc3, 0xa867df55, 0x316e8eef, 0x4669be79, +0xcb61b38c, 0xbc66831a, 0x256fd2a0, 0x5268e236, 0xcc0c7795, 0xbb0b4703, 0x220216b9, 0x5505262f, +0xc5ba3bbe, 0xb2bd0b28, 0x2bb45a92, 0x5cb36a04, 0xc2d7ffa7, 0xb5d0cf31, 0x2cd99e8b, 0x5bdeae1d, +0x9b64c2b0, 0xec63f226, 0x756aa39c, 0x026d930a, 0x9c0906a9, 0xeb0e363f, 0x72076785, 0x05005713, +0x95bf4a82, 0xe2b87a14, 0x7bb12bae, 0x0cb61b38, 0x92d28e9b, 0xe5d5be0d, 0x7cdcefb7, 0x0bdbdf21, +0x86d3d2d4, 0xf1d4e242, 0x68ddb3f8, 0x1fda836e, 0x81be16cd, 0xf6b9265b, 0x6fb077e1, 0x18b74777, +0x88085ae6, 0xff0f6a70, 0x66063bca, 0x11010b5c, 0x8f659eff, 0xf862ae69, 0x616bffd3, 0x166ccf45, +0xa00ae278, 0xd70dd2ee, 0x4e048354, 0x3903b3c2, 0xa7672661, 0xd06016f7, 0x4969474d, 0x3e6e77db, +0xaed16a4a, 0xd9d65adc, 0x40df0b66, 0x37d83bf0, 0xa9bcae53, 0xdebb9ec5, 0x47b2cf7f, 0x30b5ffe9, +0xbdbdf21c, 0xcabac28a, 0x53b39330, 0x24b4a3a6, 0xbad03605, 0xcdd70693, 0x54de5729, 0x23d967bf, +0xb3667a2e, 0xc4614ab8, 0x5d681b02, 0x2a6f2b94, 0xb40bbe37, 0xc30c8ea1, 0x5a05df1b, 0x2d02ef8d +}; + +#ifdef NFGM +long +UPDC32(b, c) +long c; +{ + return (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)); +} + +#else + +#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) +#endif + +/* End of crctab.c */ @@ -0,0 +1,210 @@ +/* error.c -- error handler for noninteractive utilities + Copyright (C) 1990, 91, 92, 93, 94, 95, 96 Free Software Foundation, Inc. + +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. */ + +/* Written by David MacKenzie <djm@gnu.ai.mit.edu>. */ + +#ifdef HAVE_CONFIG_H +# include <config.h> +#endif + +#include <stdio.h> + +#if HAVE_VPRINTF || HAVE_DOPRNT || _LIBC || defined(__cplusplus) +# if __STDC__ || defined(__cplusplus) +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +# else +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +# endif +#else +# define va_alist a1, a2, a3, a4, a5, a6, a7, a8 +# define va_dcl char *a1, *a2, *a3, *a4, *a5, *a6, *a7, *a8; +#endif + +#if STDC_HEADERS || _LIBC +# include <stdlib.h> +# include <string.h> +#else +void exit (); +#endif + +#ifndef _ +# define _(String) String +#endif + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +void (*error_print_progname) ( +#if __STDC__ - 0 + void +#endif + ); + +/* This variable is incremented each time `error' is called. */ +unsigned int error_message_count; + +#ifdef _LIBC +/* In the GNU C library, there is a predefined variable for this. */ + +# define program_name program_invocation_name +# include <errno.h> + +#else + +/* The calling program should define program_name and set it to the + name of the executing program. */ +extern char *program_name; + +# if HAVE_STRERROR +# ifndef strerror /* On some systems, strerror is a macro */ +char *strerror (); +# endif +# else +static char * +private_strerror (errnum) + int errnum; +{ + extern char *sys_errlist[]; + extern int sys_nerr; + + if (errnum > 0 && errnum <= sys_nerr) + return sys_errlist[errnum]; + return _("Unknown system error"); +} +# define strerror private_strerror +# endif /* HAVE_STRERROR */ +#endif /* _LIBC */ + +/* Print the program name and error message MESSAGE, which is a printf-style + format string with optional args. + If ERRNUM is nonzero, print its corresponding system error message. + Exit with status STATUS if it is nonzero. */ +/* VARARGS */ + +void +#if defined(VA_START) && __STDC__ +error (int status, int errnum, const char *message, ...) +#else +error (status, errnum, message, va_alist) + int status; + int errnum; + char *message; + va_dcl +#endif +{ +#if defined(VA_START) + va_list args; +#endif + + if (error_print_progname) + (*error_print_progname) (); + else + { + fflush (stdout); + fprintf (stderr, "%s: ", program_name); + } + +#if defined(VA_START) + VA_START(args, message); +# if HAVE_VPRINTF || _LIBC + vfprintf (stderr, message, args); +# else + _doprnt (message, args, stderr); +# endif + va_end (args); +#else + fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8); +#endif + + ++error_message_count; + if (errnum) + fprintf (stderr, ": %s", strerror (errnum)); + putc ('\n', stderr); + fflush (stderr); + if (status) + exit (status); +} + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +int error_one_per_line; + +void +#if defined(VA_START) && __STDC__ +error_at_line (int status, int errnum, const char *file_name, + unsigned int line_number, const char *message, ...) +#else +error_at_line (status, errnum, file_name, line_number, message, va_alist) + int status; + int errnum; + const char *file_name; + unsigned int line_number; + char *message; + va_dcl +#endif +{ +#ifdef VA_START + va_list args; +#endif + + if (error_one_per_line) + { + static const char *old_file_name; + static unsigned int old_line_number; + + if (old_line_number == line_number && + (file_name == old_file_name || !strcmp (old_file_name, file_name))) + /* Simply return and print nothing. */ + return; + + old_file_name = file_name; + old_line_number = line_number; + } + + if (error_print_progname) + (*error_print_progname) (); + else + { + fflush (stdout); + fprintf (stderr, "%s:", program_name); + } + + if (file_name != NULL) + fprintf (stderr, "%s:%d: ", file_name, line_number); + +#ifdef VA_START + VA_START (args, message); +# if HAVE_VPRINTF || _LIBC + vfprintf (stderr, message, args); +# else + _doprnt (message, args, stderr); +# endif + va_end (args); +#else + fprintf (stderr, message, a1, a2, a3, a4, a5, a6, a7, a8); +#endif + + ++error_message_count; + if (errnum) + fprintf (stderr, ": %s", strerror (errnum)); + putc ('\n', stderr); + fflush (stderr); + if (status) + exit (status); +} @@ -0,0 +1,65 @@ +/* error.h -- declaration for error-reporting function + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + +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. */ + +#ifndef _error_h_ +#define _error_h_ + +#ifndef __attribute__ +/* This feature is available in gcc versions 2.5 and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 5) || __STRICT_ANSI__ +# define __attribute__(Spec) /* empty */ +# endif +/* The __-protected variants of `format' and `printf' attributes + are accepted by gcc versions 2.6.4 (effectively 2.7) and later. */ +# if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ < 7) +# define __format__ format +# define __printf__ printf +# endif +#endif + +#if defined (__STDC__) && __STDC__ + +/* Print a message with `fprintf (stderr, FORMAT, ...)'; + if ERRNUM is nonzero, follow it with ": " and strerror (ERRNUM). + If STATUS is nonzero, terminate the program with `exit (STATUS)'. */ + +extern void error (int status, int errnum, const char *format, ...) + __attribute__ ((__format__ (__printf__, 3, 4))); + +extern void error_at_line (int status, int errnum, const char *fname, + unsigned int lineno, const char *format, ...) + __attribute__ ((__format__ (__printf__, 5, 6))); + +/* If NULL, error will flush stdout, then print on stderr the program + name, a colon and a space. Otherwise, error will call this + function without parameters instead. */ +extern void (*error_print_progname) (void); + +#else +void error (); +void error_at_line (); +extern void (*error_print_progname) (); +#endif + +/* This variable is incremented each time `error' is called. */ +extern unsigned int error_message_count; + +/* Sometimes we want to have at most one error per line. This + variable controls whether this mode is selected or not. */ +extern int error_one_per_line; + +#endif /* _error_h_ */ diff --git a/long-options.c b/long-options.c new file mode 100644 index 0000000..fe069fd --- /dev/null +++ b/long-options.c @@ -0,0 +1,83 @@ +/* Utility to accept --help and --version options as unobtrusively as possible. + Copyright (C) 1993, 1994 Free Software Foundation, Inc. + + 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., 675 Mass Ave, Cambridge, MA 02139, USA. */ + +/* Jim Meyering (meyering@comco.com) */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#include <stdio.h> +#include <getopt.h> +#include "long-options.h" + +static struct option const long_options[] = +{ + {"help", no_argument, 0, 'h'}, + {"version", no_argument, 0, 'v'}, + {0, 0, 0, 0} +}; + +/* Process long options --help and --version, but only if argc == 2. + Be careful not to gobble up `--'. */ +#ifdef __cplusplus +void parse_long_options (int argc, char **argv, + void (*version)(void), void (*usage)(int)) +#else +void +parse_long_options (argc, argv,version, usage) + int argc; + char **argv; + void (*version)(); + void (*usage)(); +#endif +{ + int c; + int saved_opterr; + int saved_optind; + + saved_opterr = opterr; + saved_optind = optind; + + /* Don't print an error message for unrecognized options. */ + opterr = 0; + + if (argc == 2 + && (c = getopt_long (argc, argv, "+", long_options, (int *) 0)) != EOF) + { + switch (c) + { + case 'h': + (*usage) (0); + + case 'v': + (*version) (); + /* printf ("%s (%s) %s\n", command_name, package, version_string); */ + exit (0); + + default: + /* Don't process any other long-named options. */ + break; + } + } + + /* Restore previous value. */ + opterr = saved_opterr; + + /* Restore optind in case it has advanced past a leading `--'. */ + optind = saved_optind; +} diff --git a/long-options.h b/long-options.h new file mode 100644 index 0000000..14459cd --- /dev/null +++ b/long-options.h @@ -0,0 +1,10 @@ +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(args) args +#else +#define __P(args) () +#endif + +void parse_long_options __P ((int _argc, char **_argv, + void (*_version) (void), + void (*_usage) (int))); @@ -0,0 +1,2313 @@ +/* + 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_PROTOTYPES +extern time_t time(); +extern char *strerror(); +#endif + +#ifndef HAVE_ERRNO_DECLARATION +extern 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 +#endif + +unsigned 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 SEGMENTS +static int chinseg = 0; /* Number of characters received in this data seg */ +#endif +static char *secbuf; + +#ifdef ENABLE_TIMESYNC +static int timesync_flag=0; +static int in_timesync=0; +#endif +int tcp_socket=-1; +int tcp_flag=0; +char *tcp_server_address=NULL; + +#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC) +static int o_sync = 0; +#endif +static 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; +# else +int 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 */ +RETSIGTYPE +bibi(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 void +show_version(void) +{ + printf ("%s (GNU %s) %s\n", program_name, PACKAGE, VERSION); +} + +int +main(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")); + } + +#ifdef SEGMENTS + secbuf=malloc(1+(SEGMENTS+1)*MAX_BLOCK); +#else + secbuf=malloc(MAX_BLOCK+1); +#endif + if (!secbuf) error(1,0,_("out of memory")); + + /* 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 void +usage1(int exitcode) +{ + usage(exitcode,NULL); +} + +static void +usage(int exitcode, const char *what) +{ + FILE *f=stdout; + + if (exitcode) + { + if (what) + fprintf(stderr, "%s: %s\n",program_name,what); + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + exit(exitcode); + } + + fprintf(f, _("%s version %s\n"), program_name, + VERSION); + + fprintf(f,_("Usage: %s [options] [filename.if.xmodem]\n"), program_name); + fputs(_("Receive files with ZMODEM/YMODEM/XMODEM protocol\n"),f); + fputs(_( + " (X) = option applies to XMODEM only\n" + " (Y) = option applies to YMODEM only\n" + " (Z) = option applies to ZMODEM only\n" + ),f); + fputs(_( +" -+, --append append to existing files\n" +" -a, --ascii ASCII transfer (change CR/LF to LF)\n" +" -b, --binary binary transfer\n" +" -B, --bufsize N buffer N bytes (N==auto: buffer whole file)\n" +" -c, --with-crc Use 16 bit CRC (X)\n" +" -C, --allow-remote-commands allow execution of remote commands (Z)\n" +" -D, --null write all received data to /dev/null\n" +" --delay-startup N sleep N seconds before doing anything\n" +" -e, --escape Escape control characters (Z)\n" +" -E, --rename rename any files already existing\n" +" --errors N generate CRC error every N bytes (debugging)\n" +" -h, --help Help, print this usage message\n" +" -m, --min-bps N stop transmission if BPS below N\n" +" -M, --min-bps-time N for at least N seconds (default: 120)\n" +" -O, --disable-timeouts disable timeout code, wait forever for data\n" +" --o-sync open output file(s) in synchronous write mode\n" +" -p, --protect protect existing files\n" +" -q, --quiet quiet, no progress reports\n" +" -r, --resume try to resume interrupted file transfer (Z)\n" +" -R, --restricted restricted, more secure mode\n" +" -s, --stop-at {HH:MM|+N} stop transmission at HH:MM or in N seconds\n" +" -S, --timesync request remote time (twice: set local time)\n" +" --syslog[=off] turn syslog on or off, if possible\n" +" -t, --timeout N set timeout to N tenths of a second\n" +" --tcp-server open socket, wait for connection (Z)\n" +" --tcp-client ADDR:PORT open socket, connect to ... (Z)\n" +" -u, --keep-uppercase keep upper case filenames\n" +" -U, --unrestrict disable restricted mode (if allowed to)\n" +" -v, --verbose be verbose, provide debugging information\n" +" -w, --windowsize N Window is N bytes (Z)\n" +" -X --xmodem use XMODEM protocol\n" +" -y, --overwrite Yes, clobber existing file if any\n" +" --ymodem use YMODEM protocol\n" +" -Z, --zmodem use ZMODEM protocol\n" +"\n" +"short options use the same arguments as the long ones\n" + ),f); + exit(exitcode); +} + +/* + * Let's receive something already. + */ + +static int +wcreceive(int argc, char **argp) +{ + int c; + struct zm_fileinfo zi; +#ifdef ENABLE_SYSLOG + const char *shortname=NULL;; +#endif + zi.fname=NULL; + zi.modtime=0; + zi.mode=0; + zi.bytes_total=0; + zi.bytes_sent=0; + zi.bytes_received=0; + zi.bytes_skipped=0; + zi.eof_seen=0; + + if (protocol!=ZM_XMODEM || argc==0) { + Crcflg=1; + if ( !Quiet) + vstringf(_("%s waiting to receive."), program_name); + if ((c=tryz())!=0) { + if (c == ZCOMPL) + return OK; + if (c == ERROR) + goto fubar; + c = rzfiles(&zi); + +#ifdef ENABLE_SYSLOG + shortname=NULL; +#endif + if (c) + goto fubar; + } else { + for (;;) { + if (Verbose > 1 +#ifdef ENABLE_SYSLOG + || enable_syslog +#endif + ) + timing(1,NULL); +#ifdef ENABLE_SYSLOG + shortname=NULL; +#endif + if (wcrxpn(&zi,secbuf)== ERROR) + goto fubar; + if (secbuf[0]==0) + return OK; + if (procheader(secbuf, &zi) == ERROR) + goto fubar; +#ifdef ENABLE_SYSLOG + shortname=strrchr(zi.fname,'/'); + if (shortname) + shortname++; + else + shortname=zi.fname; +#endif + if (wcrx(&zi)==ERROR) + goto fubar; + + if (Verbose > 1 +#ifdef ENABLE_SYSLOG + || enable_syslog +#endif + ) { + double d; + long bps; + d=timing(0,NULL); + if (d==0) + d=0.5; /* can happen if timing uses time() */ + bps=(zi.bytes_received-zi.bytes_skipped)/d; + + if (Verbose>1) { + vstringf( + _("\rBytes received: %7ld/%7ld BPS:%-6ld \r\n"), + (long) zi.bytes_received, (long) zi.bytes_total, bps); + } +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_INFO,"%s/%s: %ld Bytes, %ld BPS", + shortname,protname(),zi.bytes_received, bps); +#endif + } + } + } + } else { + char dummy[128]; + dummy[0]='\0'; /* pre-ANSI HPUX cc demands this */ + dummy[1]='\0'; /* procheader uses name + 1 + strlen(name) */ + zi.bytes_total = DEFBYTL; + + if (Verbose > 1 +#ifdef ENABLE_SYSLOG + || enable_syslog +#endif + ) + timing(1,NULL); + procheader(dummy, &zi); + + if (Pathname) + free(Pathname); + errno=0; + Pathname=malloc(PATH_MAX+1); + if (!Pathname) + error(1,0,_("out of memory")); + + strcpy(Pathname, *argp); + checkpath(Pathname); +#ifdef ENABLE_SYSLOG + shortname=strrchr(*argp,'/'); + if (shortname) + shortname++; + else + shortname=*argp; +#endif + vchar('\n'); + vstringf(_("%s: ready to receive %s"), program_name, Pathname); + vstring("\r\n"); + + if ((fout=fopen(Pathname, "w")) == NULL) { +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_ERR,"%s/%s: cannot open: %m", + shortname,protname()); +#endif + return ERROR; + } + if (wcrx(&zi)==ERROR) { + goto fubar; + } + if (Verbose > 1 +#ifdef ENABLE_SYSLOG + || enable_syslog +#endif + ) { + double d; + long bps; + d=timing(0,NULL); + if (d==0) + d=0.5; /* can happen if timing uses time() */ + bps=(zi.bytes_received-zi.bytes_skipped)/d; + if (Verbose) { + vstringf( + _("\rBytes received: %7ld BPS:%-6ld \r\n"), + (long) zi.bytes_received, bps); + } +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_INFO,"%s/%s: %ld Bytes, %ld BPS", + shortname,protname(),zi.bytes_received, bps); +#endif + } + } + return OK; +fubar: +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_ERR,"%s/%s: got error", + shortname ? shortname : "no.name", protname()); +#endif + canit(STDOUT_FILENO); + if (Topipe && fout) { + pclose(fout); return ERROR; + } + if (fout) + fclose(fout); + + if (Restricted && Pathname) { + unlink(Pathname); + vstringf(_("\r\n%s: %s removed.\r\n"), program_name, 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) + */ +static int +wcrxpn(struct zm_fileinfo *zi, char *rpn) +{ + register int c; + size_t Blklen=0; /* record length of received packets */ + +#ifdef NFGVMIN + READLINE_PF(1); +#else + purgeline(0); +#endif + +et_tu: + Firstsec=TRUE; + zi->eof_seen=FALSE; + sendline(Crcflg?WANTCRC:NAK); + flushmo(); + purgeline(0); /* Do read next time ... */ + while ((c = wcgetsec(&Blklen, rpn, 100)) != 0) { + if (c == WCEOT) { + zperr( _("Pathname fetch returned EOT")); + sendline(ACK); + flushmo(); + purgeline(0); /* Do read next time ... */ + READLINE_PF(1); + goto et_tu; + } + return ERROR; + } + sendline(ACK); + flushmo(); + return OK; +} + +/* + * Adapted from CMODEM13.C, written by + * Jack M. Wierda and Roderick W. Hart + */ +static int +wcrx(struct zm_fileinfo *zi) +{ + register int sectnum, sectcurr; + register char sendchar; + size_t Blklen; + + Firstsec=TRUE;sectnum=0; + zi->eof_seen=FALSE; + sendchar=Crcflg?WANTCRC:NAK; + + for (;;) { + sendline(sendchar); /* send it now, we're ready! */ + flushmo(); + purgeline(0); /* Do read next time ... */ + sectcurr=wcgetsec(&Blklen, secbuf, + (unsigned int) ((sectnum&0177) ? 50 : 130)); + report(sectcurr); + if (sectcurr==((sectnum+1) &0377)) { + sectnum++; + /* if using xmodem we don't know how long a file is */ + if (zi->bytes_total && R_BYTESLEFT(zi) < Blklen) + Blklen=R_BYTESLEFT(zi); + zi->bytes_received+=Blklen; + if (putsec(zi, secbuf, Blklen)==ERROR) + return ERROR; + sendchar=ACK; + } + else if (sectcurr==(sectnum&0377)) { + zperr( _("Received dup Sector")); + sendchar=ACK; + } + else if (sectcurr==WCEOT) { + if (closeit(zi)) + return ERROR; + sendline(ACK); + flushmo(); + purgeline(0); /* Do read next time ... */ + return OK; + } + else if (sectcurr==ERROR) + return ERROR; + else { + zperr( _("Sync Error")); + return ERROR; + } + } +} + +/* + * Wcgetsec fetches a Ward Christensen type sector. + * Returns sector number encountered or ERROR if valid sector not received, + * or CAN CAN received + * or WCEOT if eot sector + * time is timeout for first char, set to 4 seconds thereafter + ***************** NO ACK IS SENT IF SECTOR IS RECEIVED OK ************** + * (Caller must do that when he is good and ready to get next sector) + */ +static int +wcgetsec(size_t *Blklen, char *rxbuf, unsigned int maxtime) +{ + register int checksum, wcj, firstch; + register unsigned short oldcrc; + register char *p; + int sectcurr; + + for (Lastrx=errors=0; errors<RETRYMAX; errors++) { + + if ((firstch=READLINE_PF(maxtime))==STX) { + *Blklen=1024; goto get2; + } + if (firstch==SOH) { + *Blklen=128; +get2: + sectcurr=READLINE_PF(1); + if ((sectcurr+(oldcrc=READLINE_PF(1)))==0377) { + oldcrc=checksum=0; + for (p=rxbuf,wcj=*Blklen; --wcj>=0; ) { + if ((firstch=READLINE_PF(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + checksum += (*p++ = firstch); + } + if ((firstch=READLINE_PF(1)) < 0) + goto bilge; + if (Crcflg) { + oldcrc=updcrc(firstch, oldcrc); + if ((firstch=READLINE_PF(1)) < 0) + goto bilge; + oldcrc=updcrc(firstch, oldcrc); + if (oldcrc & 0xFFFF) + zperr( _("CRC")); + else { + Firstsec=FALSE; + return sectcurr; + } + } + else if (((checksum-firstch)&0377)==0) { + Firstsec=FALSE; + return sectcurr; + } + else + zperr( _("Checksum")); + } + else + zperr(_("Sector number garbled")); + } + /* make sure eot really is eot and not just mixmash */ +#ifdef NFGVMIN + else if (firstch==EOT && READLINE_PF(1)==TIMEOUT) + return WCEOT; +#else + else if (firstch==EOT && READLINE_PF>0) + return WCEOT; +#endif + else if (firstch==CAN) { + if (Lastrx==CAN) { + zperr( _("Sender Cancelled")); + return ERROR; + } else { + Lastrx=CAN; + continue; + } + } + else if (firstch==TIMEOUT) { + if (Firstsec) + goto humbug; +bilge: + zperr( _("TIMEOUT")); + } + else + zperr( _("Got 0%o sector header"), firstch); + +humbug: + Lastrx=0; + { + int cnt=1000; + while(cnt-- && READLINE_PF(1)!=TIMEOUT) + ; + } + if (Firstsec) { + sendline(Crcflg?WANTCRC:NAK); + flushmo(); + purgeline(0); /* Do read next time ... */ + } else { + maxtime=40; + sendline(NAK); + flushmo(); + purgeline(0); /* Do read next time ... */ + } + } + /* try to stop the bubble machine. */ + canit(STDOUT_FILENO); + return ERROR; +} + +#define ZCRC_DIFFERS (ERROR+1) +#define ZCRC_EQUAL (ERROR+2) +/* + * do ZCRC-Check for open file f. + * check at most check_bytes bytes (crash recovery). if 0 -> whole file. + * remote file size is remote_bytes. + */ +static int +do_crc_check(FILE *f, size_t remote_bytes, size_t check_bytes) +{ + struct stat st; + unsigned long crc; + unsigned long rcrc; + size_t n; + int c; + int t1=0,t2=0; + if (-1==fstat(fileno(f),&st)) { + DO_SYSLOG((LOG_ERR,"cannot fstat open file: %s",strerror(errno))); + return ERROR; + } + if (check_bytes==0 && ((size_t) st.st_size)!=remote_bytes) + return ZCRC_DIFFERS; /* shortcut */ + + crc=0xFFFFFFFFL; + n=check_bytes; + if (n==0) + n=st.st_size; + while (n-- && ((c = getc(f)) != EOF)) + crc = UPDC32(c, crc); + crc = ~crc; + clearerr(f); /* Clear EOF */ + fseek(f, 0L, 0); + + while (t1<3) { + stohdr(check_bytes); + zshhdr(ZCRC, Txhdr); + while(t2<3) { + size_t tmp; + c = zgethdr(Rxhdr, 0, &tmp); + rcrc=(unsigned long) tmp; + switch (c) { + default: /* ignore */ + break; + case ZFIN: + return ERROR; + case ZRINIT: + return ERROR; + case ZCAN: + if (Verbose) + vstringf(_("got ZCAN")); + return ERROR; + break; + case ZCRC: + if (crc!=rcrc) + return ZCRC_DIFFERS; + return ZCRC_EQUAL; + break; + } + } + } + return ERROR; +} + +/* + * Process incoming file information header + */ +static int +procheader(char *name, struct zm_fileinfo *zi) +{ + const char *openmode; + char *p; + static char *name_static=NULL; + char *nameend; + + if (name_static) + free(name_static); + if (junk_path) { + p=strrchr(name,'/'); + if (p) { + p++; + if (!*p) { + /* alert - file name ended in with a / */ + if (Verbose) + vstringf(_("file name ends with a /, skipped: %s\n"),name); + DO_SYSLOG((LOG_ERR,"file name ends with a /, skipped: %s", name)); + return ERROR; + } + name=p; + } + } + name_static=malloc(strlen(name)+1); + if (!name_static) + error(1,0,_("out of memory")); + strcpy(name_static,name); + zi->fname=name_static; + + if (Verbose>2) { + vstringf(_("zmanag=%d, Lzmanag=%d\n"),zmanag,Lzmanag); + vstringf(_("zconv=%d\n"),zconv); + } + + /* set default parameters and overrides */ + openmode = "w"; + Thisbinary = (!Rxascii) || Rxbinary; + if (Lzmanag) + zmanag = Lzmanag; + + /* + * Process ZMODEM remote file management requests + */ + if (!Rxbinary && zconv == ZCNL) /* Remote ASCII override */ + Thisbinary = 0; + if (zconv == ZCBIN) /* Remote Binary override */ + Thisbinary = TRUE; + if (Thisbinary && zconv == ZCBIN && try_resume) + zconv=ZCRESUM; + if (zmanag == ZF1_ZMAPND && zconv!=ZCRESUM) + openmode = "a"; + if (skip_if_not_found) + openmode="r+"; + +#ifdef ENABLE_TIMESYNC + in_timesync=0; + if (timesync_flag && 0==strcmp(name,"$time$.t")) + in_timesync=1; +#endif + + zi->bytes_total = DEFBYTL; + zi->mode = 0; + zi->eof_seen = 0; + zi->modtime = 0; + + nameend = name + 1 + strlen(name); + if (*nameend) { /* file coming from Unix or DOS system */ + long modtime; + long bytes_total; + int mode; + sscanf(nameend, "%ld%lo%o", &bytes_total, &modtime, &mode); + zi->modtime=modtime; + zi->bytes_total=bytes_total; + zi->mode=mode; + if (zi->mode & UNIXFILE) + ++Thisbinary; + } + + /* Check for existing file */ + if (zconv != ZCRESUM && !Rxclob && (zmanag&ZF1_ZMMASK) != ZF1_ZMCLOB + && (zmanag&ZF1_ZMMASK) != ZF1_ZMAPND +#ifdef ENABLE_TIMESYNC + && !in_timesync +#endif + && (fout=fopen(name, "r"))) { + struct stat sta; + char *tmpname; + char *ptr; + int i; + if (zmanag == ZF1_ZMNEW || zmanag==ZF1_ZMNEWL) { + if (-1==fstat(fileno(fout),&sta)) { +#ifdef ENABLE_SYSLOG + int e=errno; +#endif + if (Verbose) + vstringf(_("file exists, skipped: %s\n"),name); + DO_SYSLOG((LOG_ERR,"cannot fstat open file %s: %s", + name,strerror(e))); + return ERROR; + } + if (zmanag == ZF1_ZMNEW) { + if (sta.st_mtime > zi->modtime) { + DO_SYSLOG((LOG_INFO,"skipping %s: newer file exists", name)); + return ERROR; /* skips file */ + } + } else { + /* newer-or-longer */ + if (((size_t) sta.st_size) >= zi->bytes_total + && sta.st_mtime > zi->modtime) { + DO_SYSLOG((LOG_INFO,"skipping %s: longer+newer file exists", name)); + return ERROR; /* skips file */ + } + } + fclose(fout); + } else if (zmanag==ZF1_ZMCRC) { + int r=do_crc_check(fout,zi->bytes_total,0); + if (r==ERROR) { + fclose(fout); + return ERROR; + } + if (r!=ZCRC_DIFFERS) { + return ERROR; /* skips */ + } + fclose(fout); + } else { + size_t namelen; + fclose(fout); + if ((zmanag & ZF1_ZMMASK)!=ZF1_ZMCHNG) { + if (Verbose) + vstringf(_("file exists, skipped: %s\n"),name); + return ERROR; + } + /* try to rename */ + namelen=strlen(name); + tmpname=alloca(namelen+5); + memcpy(tmpname,name,namelen); + ptr=tmpname+namelen; + *ptr++='.'; + i=0; + do { + sprintf(ptr,"%d",i++); + } while (i<1000 && stat(tmpname,&sta)==0); + if (i==1000) + return ERROR; + free(name_static); + name_static=malloc(strlen(tmpname)+1); + if (!name_static) + error(1,0,_("out of memory")); + strcpy(name_static,tmpname); + zi->fname=name_static; + } + } + + if (!*nameend) { /* File coming from CP/M system */ + for (p=name_static; *p; ++p) /* change / to _ */ + if ( *p == '/') + *p = '_'; + + if ( *--p == '.') /* zap trailing period */ + *p = 0; + } + +#ifdef ENABLE_TIMESYNC + if (in_timesync) + { + long t=time(0); + long d=t-zi->modtime; + if (d<0) + d=0; + if ((Verbose && d>60) || Verbose > 1) + vstringf(_("TIMESYNC: here %ld, remote %ld, diff %ld seconds\n"), + (long) t, (long) zi->modtime, d); +#ifdef HAVE_SETTIMEOFDAY + if (timesync_flag > 1 && d > 10) + { + struct timeval tv; + tv.tv_sec=zi->modtime; + tv.tv_usec=0; + if (settimeofday(&tv,NULL)) + vstringf(_("TIMESYNC: cannot set time: %s\n"), + strerror(errno)); + } +#endif + return ERROR; /* skips file */ + } +#endif /* ENABLE_TIMESYNC */ + + if (!zmodem_requested && MakeLCPathname && !IsAnyLower(name_static) + && !(zi->mode&UNIXFILE)) + uncaps(name_static); + if (Topipe > 0) { + if (Pathname) + free(Pathname); + Pathname=malloc((PATH_MAX)*2); + if (!Pathname) + error(1,0,_("out of memory")); + sprintf(Pathname, "%s %s", program_name+2, name_static); + if (Verbose) { + vstringf("%s: %s %s\n", + _("Topipe"), + Pathname, Thisbinary?"BIN":"ASCII"); + } + if ((fout=popen(Pathname, "w")) == NULL) + return ERROR; + } else { + if (protocol==ZM_XMODEM) + /* we don't have the filename yet */ + return OK; /* dummy */ + if (Pathname) + free(Pathname); + Pathname=malloc((PATH_MAX)*2); + if (!Pathname) + error(1,0,_("out of memory")); + strcpy(Pathname, name_static); + if (Verbose) { + /* overwrite the "waiting to receive" line */ + vstring("\r \r"); + vstringf(_("Receiving: %s\n"), name_static); + } + checkpath(name_static); + if (Nflag) + { + /* cast because we might not have a prototyp for strdup :-/ */ + free(name_static); + name_static=(char *) strdup("/dev/null"); + if (!name_static) + { + fprintf(stderr,"%s: %s\n", program_name, _("out of memory")); + exit(1); + } + } +#ifdef OMEN + /* looks like a security hole -- uwe */ + if (name_static[0] == '!' || name_static[0] == '|') { + if ( !(fout = popen(name_static+1, "w"))) { + return ERROR; + } + Topipe = -1; return(OK); + } +#endif + if (Thisbinary && zconv==ZCRESUM) { + struct stat st; + fout = fopen(name_static, "r+"); + if (fout && 0==fstat(fileno(fout),&st)) + { + int can_resume=TRUE; + if (zmanag==ZF1_ZMCRC) { + int r=do_crc_check(fout,zi->bytes_total,st.st_size); + if (r==ERROR) { + fclose(fout); + return ZFERR; + } + if (r==ZCRC_DIFFERS) { + can_resume=FALSE; + } + } + if ((unsigned long)st.st_size > zi->bytes_total) { + can_resume=FALSE; + } + /* retransfer whole blocks */ + zi->bytes_skipped = st.st_size & ~(1023); + if (can_resume) { + if (fseek(fout, (long) zi->bytes_skipped, SEEK_SET)) { + fclose(fout); + return ZFERR; + } + } + else + zi->bytes_skipped=0; /* resume impossible, file has changed */ + goto buffer_it; + } + zi->bytes_skipped=0; + if (fout) + fclose(fout); + } + fout = fopen(name_static, openmode); +#ifdef ENABLE_MKDIR + if ( !fout && Restricted < 2) { + if (make_dirs(name_static)) + fout = fopen(name_static, openmode); + } +#endif + if ( !fout) + { +#ifdef ENABLE_SYSLOG + int e=errno; +#endif + zpfatal(_("cannot open %s"), name_static); + DO_SYSLOG((LOG_ERR,"%s: cannot open: %s", + protname(),strerror(e))); + return ERROR; + } + } +buffer_it: + if (Topipe == 0) { + static char *s=NULL; + static size_t last_length=0; +#if defined(F_GETFD) && defined(F_SETFD) && defined(O_SYNC) + if (o_sync) { + int oldflags; + oldflags = fcntl (fileno(fout), F_GETFD, 0); + if (oldflags>=0 && !(oldflags & O_SYNC)) { + oldflags|=O_SYNC; + fcntl (fileno(fout), F_SETFD, oldflags); /* errors don't matter */ + } + } +#endif + + if (buffersize==-1 && s) { + if (zi->bytes_total>last_length) { + free(s); + s=NULL; + last_length=0; + } + } + if (!s && buffersize) { + last_length=32768; + if (buffersize==-1) { + if (zi->bytes_total>0) + last_length=zi->bytes_total; + } else + last_length=buffersize; + /* buffer `4096' bytes pages */ + last_length=(last_length+4095)&0xfffff000; + s=malloc(last_length); + if (!s) { + zpfatal(_("out of memory")); + exit(1); + } + } + if (s) { +#ifdef SETVBUF_REVERSED + setvbuf(fout,_IOFBF,s,last_length); +#else + setvbuf(fout,s,_IOFBF,last_length); +#endif + } + } + zi->bytes_received=zi->bytes_skipped; + + return OK; +} + +#ifdef ENABLE_MKDIR +/* + * Directory-creating routines from Public Domain TAR by John Gilmore + */ + +/* + * After a file/link/symlink/dir creation has failed, see if + * it's because some required directory was not present, and if + * so, create all required dirs. + */ +static int +make_dirs(char *pathname) +{ + register char *p; /* Points into path */ + int madeone = 0; /* Did we do anything yet? */ + int save_errno = errno; /* Remember caller's errno */ + + if (errno != ENOENT) + return 0; /* Not our problem */ + + for (p = strchr(pathname, '/'); p != NULL; p = strchr(p+1, '/')) { + /* Avoid mkdir of empty string, if leading or double '/' */ + if (p == pathname || p[-1] == '/') + continue; + /* Avoid mkdir where last part of path is '.' */ + if (p[-1] == '.' && (p == pathname+1 || p[-2] == '/')) + continue; + *p = 0; /* Truncate the path there */ + if ( !mkdir(pathname, 0777)) { /* Try to create it as a dir */ + vfile("Made directory %s\n", pathname); + madeone++; /* Remember if we made one */ + *p = '/'; + continue; + } + *p = '/'; + if (errno == EEXIST) /* Directory already exists */ + continue; + /* + * Some other error in the mkdir. We return to the caller. + */ + break; + } + errno = save_errno; /* Restore caller's errno */ + return madeone; /* Tell them to retry if we made one */ +} + +#endif /* ENABLE_MKDIR */ + +/* + * Putsec writes the n characters of buf to receive file fout. + * If not in binary mode, carriage returns, and all characters + * starting with CPMEOF are discarded. + */ +static int +putsec(struct zm_fileinfo *zi, char *buf, size_t n) +{ + register char *p; + + if (n == 0) + return OK; + if (Thisbinary) { + if (fwrite(buf,n,1,fout)!=1) + return ERROR; + } + else { + if (zi->eof_seen) + return OK; + for (p=buf; n>0; ++p,n-- ) { + if ( *p == '\r') + continue; + if (*p == CPMEOF) { + zi->eof_seen=TRUE; + return OK; + } + putc(*p ,fout); + } + } + return OK; +} + +/* make string s lower case */ +static void +uncaps(char *s) +{ + for ( ; *s; ++s) + if (isupper((unsigned char)(*s))) + *s = tolower(*s); +} +/* + * IsAnyLower returns TRUE if string s has lower case letters. + */ +static int +IsAnyLower(const char *s) +{ + for ( ; *s; ++s) + if (islower((unsigned char)(*s))) + return TRUE; + return FALSE; +} + +static void +report(int sct) +{ + if (Verbose>1) + { + vstringf(_("Blocks received: %d"),sct); + vchar('\r'); + } +} + +/* + * If called as [-][dir/../]vrzCOMMAND set Verbose to 1 + * If called as [-][dir/../]rzCOMMAND set the pipe flag + * If called as rb use YMODEM protocol + */ +static void +chkinvok(const char *s) +{ + const char *p; + + p = s; + while (*p == '-') + s = ++p; + while (*p) + if (*p++ == '/') + s = p; + if (*s == 'v') { + Verbose=1; ++s; + } + program_name = s; + if (*s == 'l') + s++; /* lrz -> rz */ + protocol=ZM_ZMODEM; + if (s[0]=='r' && s[1]=='x') + protocol=ZM_XMODEM; + if (s[0]=='r' && (s[1]=='b' || s[1]=='y')) + protocol=ZM_YMODEM; + if (s[2] && protocol!=ZM_XMODEM) + Topipe = 1; +} + +/* + * Totalitarian Communist pathname processing + */ +static void +checkpath(const char *name) +{ + if (Restricted) { + const char *p; + p=strrchr(name,'/'); + if (p) + p++; + else + p=name; + /* don't overwrite any file in very restricted mode. + * don't overwrite hidden files in restricted mode */ + if ((Restricted==2 || *name=='.') && fopen(name, "r") != NULL) { + canit(STDOUT_FILENO); + vstring("\r\n"); + vstringf(_("%s: %s exists\n"), + program_name, name); + bibi(-1); + } + /* restrict pathnames to current tree or uucppublic */ + if ( strstr(name, "../") +#ifdef PUBDIR + || (name[0]== '/' && strncmp(name, PUBDIR, + strlen(PUBDIR))) +#endif + ) { + canit(STDOUT_FILENO); + vstring("\r\n"); + vstringf(_("%s:\tSecurity Violation"),program_name); + vstring("\r\n"); + bibi(-1); + } + if (Restricted > 1) { + if (name[0]=='.' || strstr(name,"/.")) { + canit(STDOUT_FILENO); + vstring("\r\n"); + vstringf(_("%s:\tSecurity Violation"),program_name); + vstring("\r\n"); + bibi(-1); + } + } + } +} + +/* + * Initialize for Zmodem receive attempt, try to activate Zmodem sender + * Handles ZSINIT frame + * Return ZFILE if Zmodem filename received, -1 on error, + * ZCOMPL if transaction finished, else 0 + */ +static int +tryz(void) +{ + register int c, n; + register int cmdzack1flg; + int zrqinits_received=0; + size_t bytes_in_block=0; + + if (protocol!=ZM_ZMODEM) /* Check for "rb" program name */ + return 0; + + for (n=zmodem_requested?15:5; + (--n + zrqinits_received) >=0 && zrqinits_received<10; ) { + /* Set buffer length (0) and capability flags */ +#ifdef SEGMENTS + stohdr(SEGMENTS*MAX_BLOCK); +#else + stohdr(0L); +#endif +#ifdef CANBREAK + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO|CANBRK; +#else + Txhdr[ZF0] = CANFC32|CANFDX|CANOVIO; +#endif +#ifdef ENABLE_TIMESYNC + if (timesync_flag) + Txhdr[ZF1] |= ZF1_TIMESYNC; +#endif + if (Zctlesc) + Txhdr[ZF0] |= TESCCTL; /* TESCCTL == ESCCTL */ + zshhdr(tryzhdrtype, Txhdr); + + if (tryzhdrtype == ZSKIP) /* Don't skip too far */ + tryzhdrtype = ZRINIT; /* CAF 8-21-87 */ +again: + switch (zgethdr(Rxhdr, 0, NULL)) { + case ZRQINIT: + /* getting one ZRQINIT is totally ok. Normally a ZFILE follows + * (and might be in our buffer, so don't purge it). But if we + * get more ZRQINITs than the sender has started up before us + * and sent ZRQINITs while waiting. + */ + zrqinits_received++; + continue; + + case ZEOF: + continue; + case TIMEOUT: + continue; + case ZFILE: + zconv = Rxhdr[ZF0]; + if (!zconv) + /* resume with sz -r is impossible (at least with unix sz) + * if this is not set */ + zconv=ZCBIN; + if (Rxhdr[ZF1] & ZF1_ZMSKNOLOC) { + Rxhdr[ZF1] &= ~(ZF1_ZMSKNOLOC); + skip_if_not_found=TRUE; + } + zmanag = Rxhdr[ZF1]; + ztrans = Rxhdr[ZF2]; + tryzhdrtype = ZRINIT; + c = zrdata(secbuf, MAX_BLOCK,&bytes_in_block); + io_mode(0,3); + if (c == GOTCRCW) + return ZFILE; + zshhdr(ZNAK, Txhdr); + goto again; + case ZSINIT: + /* this once was: + * Zctlesc = TESCCTL & Rxhdr[ZF0]; + * trouble: if rz get --escape flag: + * - it sends TESCCTL to sz, + * get a ZSINIT _without_ TESCCTL (yeah - sender didn't know), + * overwrites Zctlesc flag ... + * - sender receives TESCCTL and uses "|=..." + * so: sz escapes, but rz doesn't unescape ... not good. + */ + Zctlesc |= TESCCTL & Rxhdr[ZF0]; + if (zrdata(Attn, ZATTNLEN,&bytes_in_block) == GOTCRCW) { + stohdr(1L); + zshhdr(ZACK, Txhdr); + goto again; + } + zshhdr(ZNAK, Txhdr); + goto again; + case ZFREECNT: + stohdr(getfree()); + zshhdr(ZACK, Txhdr); + goto again; + case ZCOMMAND: + cmdzack1flg = Rxhdr[ZF0]; + if (zrdata(secbuf, MAX_BLOCK,&bytes_in_block) == GOTCRCW) { + if (Verbose) + { + vstringf("%s: %s\n", program_name, + _("remote command execution requested")); + vstringf("%s: %s\n", program_name, secbuf); + } + if (!allow_remote_commands) + { + if (Verbose) + vstringf("%s: %s\n", program_name, + _("not executed")); + zshhdr(ZCOMPL, Txhdr); + DO_SYSLOG((LOG_INFO,"rexec denied: %s",secbuf)); + return ZCOMPL; + } + DO_SYSLOG((LOG_INFO,"rexec allowed: %s",secbuf)); + if (cmdzack1flg & ZCACK1) + stohdr(0L); + else + stohdr((size_t)sys2(secbuf)); + purgeline(0); /* dump impatient questions */ + do { + zshhdr(ZCOMPL, Txhdr); + } + while (++errors<20 && zgethdr(Rxhdr,1, NULL) != ZFIN); + ackbibi(); + if (cmdzack1flg & ZCACK1) + exec2(secbuf); + return ZCOMPL; + } + zshhdr(ZNAK, Txhdr); + goto again; + case ZCOMPL: + goto again; + default: + continue; + case ZFIN: + ackbibi(); + return ZCOMPL; + case ZRINIT: + if (Verbose) + vstringf(_("got ZRINIT")); + return ERROR; + case ZCAN: + if (Verbose) + vstringf(_("got ZCAN")); + return ERROR; + } + } + return 0; +} + + +/* + * Receive 1 or more files with ZMODEM protocol + */ +static int +rzfiles(struct zm_fileinfo *zi) +{ + register int c; + + for (;;) { + timing(1,NULL); + c = rzfile(zi); + switch (c) { + case ZEOF: + if (Verbose > 1 +#ifdef ENABLE_SYSLOG + || enable_syslog +#endif + ) { + double d; + long bps; + d=timing(0,NULL); + if (d==0) + d=0.5; /* can happen if timing uses time() */ + bps=(zi->bytes_received-zi->bytes_skipped)/d; + if (Verbose > 1) { + vstringf( + _("\rBytes received: %7ld/%7ld BPS:%-6ld \r\n"), + (long) zi->bytes_received, (long) zi->bytes_total, bps); + } + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: %ld Bytes, %ld BPS",shortname, + protname(), (long) zi->bytes_total,bps)); + } + /* FALL THROUGH */ + case ZSKIP: + if (c==ZSKIP) + { + if (Verbose) + vstringf(_("Skipped")); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: skipped",shortname,protname())); + } + switch (tryz()) { + case ZCOMPL: + return OK; + default: + return ERROR; + case ZFILE: + break; + } + continue; + default: + return c; + case ERROR: + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error",shortname,protname())); + return ERROR; + } + } +} + +/* "OOSB" means Out Of Sync Block. I once thought that if sz sents + * blocks a,b,c,d, of which a is ok, b fails, we might want to save + * c and d. But, alas, i never saw c and d. + */ +#define SAVE_OOSB +#ifdef SAVE_OOSB +typedef struct oosb_t { + size_t pos; + size_t len; + char *data; + struct oosb_t *next; +} oosb_t; +struct oosb_t *anker=NULL; +#endif + +/* + * Receive a file with ZMODEM protocol + * Assumes file name frame is in secbuf + */ +static int +rzfile(struct zm_fileinfo *zi) +{ + register int c, n; + long last_rxbytes=0; + unsigned long last_bps=0; + long not_printed=0; + time_t low_bps=0; + size_t bytes_in_block=0; + + zi->eof_seen=FALSE; + + n = 20; + + if (procheader(secbuf,zi) == ERROR) { + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: procheader error", + shortname,protname())); + return (tryzhdrtype = ZSKIP); + } + + for (;;) { +#ifdef SEGMENTS + chinseg = 0; +#endif + stohdr(zi->bytes_received); + zshhdr(ZRPOS, Txhdr); + goto skip_oosb; +nxthdr: +#ifdef SAVE_OOSB + if (anker) { + oosb_t *akt,*last,*next; + for (akt=anker,last=NULL;akt;last= akt ? akt : last ,akt=next) { + if (akt->pos==zi->bytes_received) { + putsec(zi, akt->data, akt->len); + zi->bytes_received += akt->len; + vfile("using saved out-of-sync-paket %lx, len %ld", + akt->pos,akt->len); + goto nxthdr; + } + next=akt->next; + if (akt->pos<zi->bytes_received) { + vfile("removing unneeded saved out-of-sync-paket %lx, len %ld", + akt->pos,akt->len); + if (last) + last->next=akt->next; + else + anker=akt->next; + free(akt->data); + free(akt); + akt=NULL; + } + } + } +#endif + skip_oosb: + c = zgethdr(Rxhdr, 0, NULL); + switch (c) { + default: + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: zgethdr returned %d",shortname, + protname(),c)); + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + case ZNAK: + case TIMEOUT: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: zgethdr returned %s",shortname, + protname(),c == ZNAK ? "ZNAK" : "TIMEOUT")); + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + case ZFILE: + zrdata(secbuf, MAX_BLOCK,&bytes_in_block); + continue; + case ZEOF: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if (rclhdr(Rxhdr) != (long) zi->bytes_received) { + /* + * Ignore eof if it's at wrong place - force + * a timeout because the eof might have gone + * out before we sent our zrpos. + */ + errors = 0; goto nxthdr; + } + if (closeit(zi)) { + tryzhdrtype = ZFERR; + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: closeit return <>0", + shortname, protname())); + vfile("rzfile: closeit returned <> 0"); + return ERROR; + } + vfile("rzfile: normal EOF"); + return c; + case ERROR: /* Too much garbage in header search error */ +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: zgethdr returned %d", + shortname, protname(),c)); + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + zmputs(Attn); + continue; + case ZSKIP: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + closeit(zi); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: sender skipped", + shortname, protname())); + vfile("rzfile: Sender SKIPPED file"); + return c; + case ZDATA: + if (rclhdr(Rxhdr) != (long) zi->bytes_received) { +#if defined(SAVE_OOSB) + oosb_t *neu; + size_t pos=rclhdr(Rxhdr); +#endif + if ( --n < 0) { + vfile("rzfile: out of sync"); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: error: out of sync", + shortname, protname())); + return ERROR; + } +#if defined(SAVE_OOSB) + switch (c = zrdata(secbuf, MAX_BLOCK,&bytes_in_block)) + { + case GOTCRCW: + case GOTCRCG: + case GOTCRCE: + case GOTCRCQ: + if (pos>zi->bytes_received) { + neu=malloc(sizeof(oosb_t)); + if (neu) + neu->data=malloc(bytes_in_block); + if (neu && neu->data) { +#ifdef ENABLE_SYSLOG +/* call syslog to tell me if this happens */ + lsyslog(LOG_ERR, + "saving out-of-sync-block %lx, len %lu", + pos, (unsigned long) bytes_in_block); +#endif + vfile("saving out-of-sync-block %lx, len %lu",pos, + (unsigned long) bytes_in_block); + memcpy(neu->data,secbuf,bytes_in_block); + neu->pos=pos; + neu->len=bytes_in_block; + neu->next=anker; + anker=neu; + } + else if (neu) + free(neu); + } + } +#endif +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + zmputs(Attn); continue; + } +moredata: + if ((Verbose>1 || min_bps || stop_time) + && (not_printed > (min_bps ? 3 : 7) + || zi->bytes_received > last_bps / 2 + last_rxbytes)) { + int minleft = 0; + int secleft = 0; + time_t now; + double d; + d=timing(0,&now); + if (d==0) + d=0.5; /* timing() might use time() */ + last_bps=zi->bytes_received/d; + if (last_bps > 0) { + minleft = (R_BYTESLEFT(zi))/last_bps/60; + secleft = ((R_BYTESLEFT(zi))/last_bps)%60; + } + if (min_bps) { + if (low_bps) { + if (last_bps<min_bps) { + if (now-low_bps>=min_bps_time) { + /* too bad */ + vfile(_("rzfile: bps rate %ld below min %ld"), + last_bps, min_bps); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: bps rate low: %ld < %ld", + shortname, protname(), last_bps, min_bps)); + return ERROR; + } + } + else + low_bps=0; + } else if (last_bps<min_bps) { + low_bps=now; + } + } + if (stop_time && now>=stop_time) { + /* too bad */ + vfile(_("rzfile: reached stop time")); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: reached stop time", + shortname, protname())); + return ERROR; + } + + if (Verbose > 1) { + vstringf(_("\rBytes received: %7ld/%7ld BPS:%-6ld ETA %02d:%02d "), + (long) zi->bytes_received, (long) zi->bytes_total, + last_bps, minleft, secleft); + last_rxbytes=zi->bytes_received; + not_printed=0; + } + } else if (Verbose) + not_printed++; +#ifdef SEGMENTS + if (chinseg >= (MAX_BLOCK * SEGMENTS)) { + putsec(secbuf, chinseg); + chinseg = 0; + } + switch (c = zrdata(secbuf+chinseg, MAX_BLOCK,&bytes_in_block)) +#else + switch (c = zrdata(secbuf, MAX_BLOCK,&bytes_in_block)) +#endif + { + case ZCAN: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + vfile("rzfile: zrdata returned %d", c); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: zrdata returned ZCAN", + shortname, protname())); + return ERROR; + case ERROR: /* CRC error */ +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + vfile("rzfile: zgethdr returned %d", c); + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: zrdata returned ERROR", + shortname, protname())); + return ERROR; + } + zmputs(Attn); + continue; + case TIMEOUT: +#ifdef SEGMENTS + putsec(secbuf, chinseg); + chinseg = 0; +#endif + if ( --n < 0) { + DO_SYSLOG_FNAME((LOG_INFO, "%s/%s: zrdata returned TIMEOUT", + shortname, protname())); + vfile("rzfile: zgethdr returned %d", c); + return ERROR; + } + continue; + case GOTCRCW: + n = 20; +#ifdef SEGMENTS + chinseg += bytes_in_block; + putsec(zi, secbuf, chinseg); + chinseg = 0; +#else + putsec(zi, secbuf, bytes_in_block); +#endif + zi->bytes_received += bytes_in_block; + stohdr(zi->bytes_received); + zshhdr(ZACK | 0x80, Txhdr); + goto nxthdr; + case GOTCRCQ: + n = 20; +#ifdef SEGMENTS + chinseg += bytes_in_block; +#else + putsec(zi, secbuf, bytes_in_block); +#endif + zi->bytes_received += bytes_in_block; + stohdr(zi->bytes_received); + zshhdr(ZACK, Txhdr); + goto moredata; + case GOTCRCG: + n = 20; +#ifdef SEGMENTS + chinseg += bytes_in_block; +#else + putsec(zi, secbuf, bytes_in_block); +#endif + zi->bytes_received += bytes_in_block; + goto moredata; + case GOTCRCE: + n = 20; +#ifdef SEGMENTS + chinseg += bytes_in_block; +#else + putsec(zi, secbuf, bytes_in_block); +#endif + zi->bytes_received += bytes_in_block; + goto nxthdr; + } + } + } +} + +/* + * Send a string to the modem, processing for \336 (sleep 1 sec) + * and \335 (break signal) + */ +static void +zmputs(const char *s) +{ + const char *p; + + while (s && *s) + { + p=strpbrk(s,"\335\336"); + if (!p) + { + write(1,s,strlen(s)); + return; + } + if (p!=s) + { + write(1,s,(size_t) (p-s)); + s=p; + } + if (*p=='\336') + sleep(1); + else + sendbrk(0); + p++; + } +} + +/* + * Close the receive dataset, return OK or ERROR + */ +static int +closeit(struct zm_fileinfo *zi) +{ + int ret; + if (Topipe) { + if (pclose(fout)) { + return ERROR; + } + return OK; + } + ret=fclose(fout); + if (ret) { + zpfatal(_("file close error")); + /* this may be any sort of error, including random data corruption */ + + unlink(Pathname); + return ERROR; + } + if (zi->modtime) { +#ifdef HAVE_STRUCT_UTIMBUF + struct utimbuf timep; + timep.actime = time(NULL); + timep.modtime = zi->modtime; + utime(Pathname, &timep); +#else + time_t timep[2]; + timep[0] = time(NULL); + timep[1] = zi->modtime; + utime(Pathname, timep); +#endif + } +#ifdef S_ISREG + if (S_ISREG(zi->mode)) { +#else + if ((zi->mode&S_IFMT) == S_IFREG) { +#endif + /* we must not make this program executable if running + * under rsh, because the user might have uploaded an + * unrestricted shell. + */ + if (under_rsh) + chmod(Pathname, (00666 & zi->mode)); + else + chmod(Pathname, (07777 & zi->mode)); + } + return OK; +} + +/* + * Ack a ZFIN packet, let byegones be byegones + */ +static void +ackbibi(void) +{ + int n; + + vfile("ackbibi:"); + Readnum = 1; + stohdr(0L); + for (n=3; --n>=0; ) { + purgeline(0); + zshhdr(ZFIN, Txhdr); + switch (READLINE_PF(100)) { + case 'O': + READLINE_PF(1); /* Discard 2nd 'O' */ + vfile("ackbibi complete"); + return; + case RCDO: + return; + case TIMEOUT: + default: + break; + } + } +} + +/* + * Strip leading ! if present, do shell escape. + */ +static int +sys2(const char *s) +{ + if (*s == '!') + ++s; + return system(s); +} + +/* + * Strip leading ! if present, do exec. + */ +static void +exec2(const char *s) +{ + if (*s == '!') + ++s; + io_mode(0,0); + execl("/bin/sh", "sh", "-c", s); + zpfatal("execl"); + exit(1); +} + +/* + * Routine to calculate the free bytes on the current file system + * ~0 means many free bytes (unknown) + */ +static size_t +getfree(void) +{ + return((size_t) (~0L)); /* many free bytes ... */ +} + +/* End of lrz.c */ diff --git a/lsyslog.c b/lsyslog.c new file mode 100644 index 0000000..6baf4a2 --- /dev/null +++ b/lsyslog.c @@ -0,0 +1,81 @@ +/* + lsyslog.c - wrapper for the syslog function + Copyright (C) 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. + +*/ +#include "config.h" +#ifdef ENABLE_SYSLOG +#include "zglobal.h" +#include <pwd.h> +#include <stdlib.h> +#include <string.h> +#endif + +#if __STDC__ +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +# define WAYTOGO +#else +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +#endif + +void +#ifdef WAYTOGO +lsyslog(int prio, const char *format, ...) +#else +lsyslog(prio,format,va_alist) + int prio; + const char *format; + va_dcl +#endif +{ +#ifdef ENABLE_SYSLOG + static char *username=NULL; + static char uid_string[20]=""; /* i'd really hate this function to fail! */ + char *s=NULL; + static int init_done=0; + va_list ap; + if (!enable_syslog) + return; + if (!init_done) { + uid_t uid; + struct passwd *pwd; + init_done=1; + uid=getuid(); + pwd=getpwuid(uid); + if (pwd && pwd->pw_name && *pwd->pw_name) { + username=strdup(pwd->pw_name); + } + if (!username) { + username=uid_string; + sprintf(uid_string,"#%lu",(unsigned long) uid); + } + } + + VA_START(ap, format); + vasprintf(&s,format, ap); + va_end(ap); + syslog(prio,"[%s] %s",username,s); + free(s); +#else + (void) prio; /* get rid of warning */ + (void) format; /* get rid of warning */ +#endif +} + @@ -0,0 +1,2492 @@ +/* + lsz - send 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" + +/* char *getenv(); */ + +#define SS_NORMAL 0 +#include <stdio.h> +#include <stdlib.h> +#include <signal.h> +#include <setjmp.h> +#include <ctype.h> +#include <errno.h> +#include <getopt.h> + +#ifndef R_OK +# define R_OK 4 +#endif + +#if defined(HAVE_SYS_MMAN_H) && defined(HAVE_MMAP) +# include <sys/mman.h> +size_t mm_size; +void *mm_addr=NULL; +#else +# undef HAVE_MMAP +#endif +#include "timing.h" +#include "long-options.h" +#include "xstrtoul.h" +#include "error.h" + +#ifndef STRICT_PROTOTYPES +extern time_t time(); +extern char *strerror(); +#endif + +#ifndef HAVE_ERRNO_DECLARATION +extern int errno; +#endif + +unsigned Baudrate=2400; /* Default, should be set by first mode() call */ +unsigned Txwindow; /* Control the size of the transmitted window */ +unsigned Txwspac; /* Spacing between zcrcq requests */ +unsigned Txwcnt; /* Counter used to space ack requests */ +size_t Lrxpos; /* Receiver's last reported offset */ +int errors; +enum zm_type_enum protocol; +int under_rsh=FALSE; +extern int turbo_escape; +static int no_unixmode; + +int Canseek=1; /* 1: can; 0: only rewind, -1: neither */ + +static int zsendfile __P ((struct zm_fileinfo *zi, const char *buf, size_t blen)); +static int getnak __P ((void)); +static int wctxpn __P ((struct zm_fileinfo *)); +static int wcs __P ((const char *oname, const char *remotename)); +static size_t zfilbuf __P ((struct zm_fileinfo *zi)); +static size_t filbuf __P ((char *buf, size_t count)); +static int getzrxinit __P ((void)); +static int calc_blklen __P ((long total_sent)); +static int sendzsinit __P ((void)); +static int wctx __P ((struct zm_fileinfo *)); +static int zsendfdata __P ((struct zm_fileinfo *)); +static int getinsync __P ((struct zm_fileinfo *, int flag)); +static void countem __P ((int argc, char **argv)); +static void chkinvok __P ((const char *s)); +static void usage __P ((int exitcode, const char *what)); +static int zsendcmd __P ((const char *buf, size_t blen)); +static void saybibi __P ((void)); +static int wcsend __P ((int argc, char *argp[])); +static int wcputsec __P ((char *buf, int sectnum, size_t cseclen)); +static void usage1 __P ((int exitcode)); + +#ifdef ENABLE_SYSLOG +#define DO_SYSLOG(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) +#else +#define DO_SYSLOG(message) do { } while(0) +#endif + +#define ZSDATA(x,y,z) \ + do { if (Crc32t) {zsda32(x,y,z); } else {zsdata(x,y,z);}} while(0) +#ifdef HAVE_MMAP +#define DATAADR (mm_addr ? ((char *)mm_addr)+zi->bytes_sent : txbuf) +#else +#define DATAADR (txbuf) +#endif + +int Filesleft; +long Totalleft; +size_t buffersize=16384; +#ifdef HAVE_MMAP +int use_mmap=1; +#endif + +/* + * Attention string to be executed by receiver to interrupt streaming data + * when an error is detected. A pause (0336) may be needed before the + * ^C (03) or after it. + */ +#ifdef READCHECK +char Myattn[] = { 0 }; +#else +char Myattn[] = { 03, 0336, 0 }; +#endif + +FILE *input_f; + +#define MAX_BLOCK 8192 +char *txbuf; + +long vpos = 0; /* Number of bytes read from file */ + +char Lastrx; +char Crcflg; +int Verbose=0; +int Restricted=0; /* restricted; no /.. or ../ in filenames */ +int Quiet=0; /* overrides logic that would otherwise set verbose */ +int Ascii=0; /* Add CR's for brain damaged programs */ +int Fullname=0; /* transmit full pathname */ +int Unlinkafter=0; /* Unlink file after it is sent */ +int Dottoslash=0; /* Change foo.bar.baz to foo/bar/baz */ +int firstsec; +int errcnt=0; /* number of files unreadable */ +size_t blklen=128; /* length of transmitted records */ +int Optiong; /* Let it rip no wait for sector ACK's */ +int Totsecs; /* total number of sectors this file */ +int Filcnt=0; /* count of number of files opened */ +int Lfseen=0; +unsigned Rxbuflen = 16384; /* Receiver's max buffer length */ +unsigned Tframlen = 0; /* Override for tx frame length */ +unsigned blkopt=0; /* Override value for zmodem blklen */ +int Rxflags = 0; +int Rxflags2 = 0; +size_t bytcnt; +int Wantfcs32 = TRUE; /* want to send 32 bit FCS */ +char Lzconv; /* Local ZMODEM file conversion request */ +char Lzmanag; /* Local ZMODEM file management request */ +int Lskipnocor; +char Lztrans; +char zconv; /* ZMODEM file conversion request */ +char zmanag; /* ZMODEM file management request */ +char ztrans; /* ZMODEM file transport request */ +int command_mode; /* Send a command, then exit. */ +int Cmdtries = 11; +int Cmdack1; /* Rx ACKs command, then do it */ +int Exitcode; +int enable_timesync=0; +size_t Lastsync; /* Last offset to which we got a ZRPOS */ +int Beenhereb4; /* How many times we've been ZRPOS'd same place */ + +int no_timeout=FALSE; +size_t max_blklen=1024; +size_t start_blklen=0; +int zmodem_requested; +time_t stop_time=0; +char *tcp_server_address=0; +int tcp_socket=-1; +int tcp_flag=0; + +int error_count; +#define OVERHEAD 18 +#define OVER_ERR 20 + +#define MK_STRING(x) #x + +#ifdef ENABLE_SYSLOG +# if defined(ENABLE_SYSLOG_FORCE) || defined(ENABLE_SYSLOG_DEFAULT) +int enable_syslog=TRUE; +# else +int enable_syslog=FALSE; +# endif +#endif + +jmp_buf intrjmp; /* For the interrupt on RX CAN */ + +static long min_bps; +static long min_bps_time; + +static int io_mode_fd=0; +static int zrqinits_sent=0; +static int play_with_sigint=0; + +/* called by signal interrupt or terminate to clean things up */ +RETSIGTYPE +bibi (int n) +{ + canit(STDOUT_FILENO); + fflush (stdout); + io_mode (io_mode_fd,0); + if (n == 99) + error (0, 0, _ ("io_mode(,2) in rbsb.c not implemented\n")); + else + error (0, 0, _ ("caught signal %d; exiting"), n); + if (n == SIGQUIT) + abort (); + exit (128 + n); +} + +/* Called when ZMODEM gets an interrupt (^C) */ +static RETSIGTYPE +onintr(int n) +{ + signal(SIGINT, SIG_IGN); + n++; /* use it */ + longjmp(intrjmp, -1); +} + +int Zctlesc; /* Encode control characters */ +const char *program_name = "sz"; +int Zrwindow = 1400; /* RX window size (controls garbage count) */ + +static struct option const long_options[] = +{ + {"append", no_argument, NULL, '+'}, + {"twostop", no_argument, NULL, '2'}, + {"try-8k", no_argument, NULL, '8'}, + {"start-8k", no_argument, NULL, '9'}, + {"try-4k", no_argument, NULL, '4'}, + {"start-4k", no_argument, NULL, '5'}, + {"ascii", no_argument, NULL, 'a'}, + {"binary", no_argument, NULL, 'b'}, + {"bufsize", required_argument, NULL, 'B'}, + {"cmdtries", required_argument, NULL, 'C'}, + {"command", required_argument, NULL, 'c'}, + {"immediate-command", required_argument, NULL, 'i'}, + {"dot-to-slash", no_argument, NULL, 'd'}, + {"full-path", no_argument, NULL, 'f'}, + {"escape", no_argument, NULL, 'e'}, + {"rename", no_argument, NULL, 'E'}, + {"help", no_argument, NULL, 'h'}, + {"crc-check", no_argument, NULL, 'H'}, + {"1024", no_argument, NULL, 'k'}, + {"1k", no_argument, NULL, 'k'}, + {"packetlen", required_argument, NULL, 'L'}, + {"framelen", required_argument, NULL, 'l'}, + {"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'}, + {"16-bit-crc", no_argument, NULL, 'o'}, + {"disable-timeouts", no_argument, NULL, 'O'}, + {"disable-timeout", no_argument, NULL, 'O'}, /* i can't get it right */ + {"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'}, + {"syslog", optional_argument, NULL , 2}, + {"timesync", no_argument, NULL, 'S'}, + {"timeout", required_argument, NULL, 't'}, + {"turbo", no_argument, NULL, 'T'}, + {"unlink", no_argument, NULL, 'u'}, + {"unrestrict", no_argument, NULL, 'U'}, + {"verbose", no_argument, NULL, 'v'}, + {"windowsize", required_argument, NULL, 'w'}, + {"xmodem", no_argument, NULL, 'X'}, + {"ymodem", no_argument, NULL, 1}, + {"zmodem", no_argument, NULL, 'Z'}, + {"overwrite", no_argument, NULL, 'y'}, + {"overwrite-or-skip", no_argument, NULL, 'Y'}, + + {"delay-startup", required_argument, NULL, 4}, + {"tcp-server", no_argument, NULL, 6}, + {"tcp-client", required_argument, NULL, 7}, + {"no-unixmode", no_argument, NULL, 8}, + {NULL, 0, NULL, 0} +}; + +static void +show_version(void) +{ + printf ("%s (%s) %s\n", program_name, PACKAGE, VERSION); +} + + +int +main(int argc, char **argv) +{ + char *cp; + int npats; + int dm; + int i; + int stdin_files; + char **patts; + int c; + const char *Cmdstr=NULL; /* Pointer to the command string */ + unsigned int startup_delay=0; + + if (((cp = getenv("ZNULLS")) != NULL) && *cp) + Znulls = atoi(cp); + if (((cp=getenv("SHELL"))!=NULL) && (strstr(cp, "rsh") || strstr(cp, "rksh") + || strstr(cp, "rbash") || strstr(cp,"rshell"))) + { + under_rsh=TRUE; + Restricted=1; + } + if ((cp=getenv("ZMODEM_RESTRICTED"))!=NULL) + Restricted=1; + from_cu(); + chkinvok(argv[0]); + +#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); + + Rxtimeout = 600; + + while ((c = getopt_long (argc, argv, + "2+48abB:C:c:dfeEghHi:kL:l:m:M:NnOopRrqsSt:TUuvw:XYy", + 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 '2': Twostop = TRUE; break; + case '8': + if (max_blklen==8192) + start_blklen=8192; + else + max_blklen=8192; + break; + case '9': /* this is a longopt .. */ + start_blklen=8192; + max_blklen=8192; + break; + case '4': + if (max_blklen==4096) + start_blklen=4096; + else + max_blklen=4096; + break; + case '5': /* this is a longopt .. */ + start_blklen=4096; + max_blklen=4096; + break; + case 'a': Lzconv = ZCNL; Ascii = TRUE; break; + case 'b': Lzconv = ZCBIN; break; + case 'B': + if (0==strcmp(optarg,"auto")) + buffersize= (size_t) -1; + else + buffersize=strtol(optarg,NULL,10); +#ifdef HAVE_MMAP + use_mmap=0; +#endif + break; + case 'C': + s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); + Cmdtries = tmp; + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("command tries"), s_err); + break; + case 'i': + Cmdack1 = ZCACK1; + /* **** FALL THROUGH TO **** */ + case 'c': + command_mode = TRUE; + Cmdstr = optarg; + break; + case 'd': + ++Dottoslash; + /* **** FALL THROUGH TO **** */ + case 'f': Fullname=TRUE; break; + case 'e': Zctlesc = 1; break; + case 'E': Lzmanag = ZF1_ZMCHNG; break; + case 'h': usage(0,NULL); break; + case 'H': Lzmanag = ZF1_ZMCRC; break; + case 'k': start_blklen=1024; break; + case 'L': + s_err = xstrtoul (optarg, NULL, 0, &tmp, "ck"); + blkopt = tmp; + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("packetlength"), s_err); + if (blkopt<24 || blkopt>MAX_BLOCK) + { + char meld[256]; + sprintf(meld, + _("packetlength out of range 24..%ld"), + (long) MAX_BLOCK); + usage(2,meld); + } + break; + case 'l': + s_err = xstrtoul (optarg, NULL, 0, &tmp, "ck"); + Tframlen = tmp; + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("framelength"), s_err); + if (Tframlen<32 || Tframlen>MAX_BLOCK) + { + char meld[256]; + sprintf(meld, + _("framelength out of range 32..%ld"), + (long) MAX_BLOCK); + usage(2,meld); + } + 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); + if (min_bps<0) + usage(2,_("min_bps must be >= 0")); + 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': Wantfcs32 = FALSE; break; + case 'O': no_timeout = TRUE; break; + case 'p': Lzmanag = ZF1_ZMPROT; break; + case 'r': + if (Lzconv == ZCRESUM) + Lzmanag = ZF1_ZMCRC; + else + Lzconv = ZCRESUM; + break; + case 'R': Restricted = TRUE; 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 'S': enable_timesync=1; break; + case 'T': turbo_escape=1; 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 'u': ++Unlinkafter; break; + case 'U': + if (!under_rsh) + Restricted=0; + else + error(1,0, + _("security violation: can't do that under restricted shell\n")); + break; + case 'v': ++Verbose; break; + case 'w': + s_err = xstrtoul (optarg, NULL, 0, &tmp, NULL); + Txwindow = tmp; + if (s_err != LONGINT_OK) + STRTOL_FATAL_ERROR (optarg, _("window size"), s_err); + if (Txwindow < 256) + Txwindow = 256; + Txwindow = (Txwindow/64) * 64; + Txwspac = Txwindow/4; + if (blkopt > Txwspac + || (!blkopt && Txwspac < MAX_BLOCK)) + blkopt = Txwspac; + break; + case 'X': protocol=ZM_XMODEM; break; + case 1: protocol=ZM_YMODEM; break; + case 'Z': protocol=ZM_ZMODEM; break; + case 'Y': + Lskipnocor = TRUE; + /* **** FALLL THROUGH TO **** */ + case 'y': + Lzmanag = ZF1_ZMCLOB; 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 + 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 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; + case 8: no_unixmode=1; break; + default: + usage (2,NULL); + break; + } + } + + if (getuid()!=geteuid()) { + error(1,0, + _("this program was never intended to be used setuid\n")); + } + + txbuf=malloc(MAX_BLOCK); + if (!txbuf) error(1,0,_("out of memory")); + + zsendline_init(); + + if (start_blklen==0) { + if (protocol == ZM_ZMODEM) { + start_blklen=1024; + if (Tframlen) { + start_blklen=max_blklen=Tframlen; + } + } + else + start_blklen=128; + } + + if (argc<2) + usage(2,_("need at least one file to send")); + + if (startup_delay) + sleep(startup_delay); + +#ifdef HAVE_SIGINTERRUPT + /* we want interrupted system calls to fail and not to be restarted. */ + siginterrupt(SIGALRM,1); +#endif + + + npats = argc - optind; + patts=&argv[optind]; + + if (npats < 1 && !command_mode) + usage(2,_("need at least one file to send")); + if (command_mode && Restricted) { + printf(_("Can't send command in restricted mode\n")); + exit(1); + } + + 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); + } + + + { + /* we write max_blocklen (data) + 18 (ZModem protocol overhead) + * + escape overhead (about 4 %), so buffer has to be + * somewhat larger than max_blklen + */ + char *s=malloc(max_blklen+1024); + if (!s) + { + zperr(_("out of memory")); + exit(1); + } +#ifdef SETVBUF_REVERSED + setvbuf(stdout,_IOFBF,s,max_blklen+1024); +#else + setvbuf(stdout,s,_IOFBF,max_blklen+1024); +#endif + } + blklen=start_blklen; + + for (i=optind,stdin_files=0;i<argc;i++) { + if (0==strcmp(argv[i],"-")) + stdin_files++; + } + + if (stdin_files>1) { + usage(1,_("can read only one file from stdin")); + } else if (stdin_files==1) { + io_mode_fd=1; + } + io_mode(io_mode_fd,1); + readline_setup(io_mode_fd, 128, 256); + + if (signal(SIGINT, bibi) == SIG_IGN) + signal(SIGINT, SIG_IGN); + else { + signal(SIGINT, bibi); + play_with_sigint=1; + } + signal(SIGTERM, bibi); + signal(SIGPIPE, bibi); + signal(SIGHUP, bibi); + + if ( protocol!=ZM_XMODEM) { + if (protocol==ZM_ZMODEM) { + printf("rz\r"); + fflush(stdout); + } + countem(npats, patts); + if (protocol == ZM_ZMODEM) { + /* throw away any input already received. This doesn't harm + * as we invite the receiver to send it's data again, and + * might be useful if the receiver has already died or + * if there is dirt left if the line + */ +#ifdef HAVE_SELECT + struct timeval t; + unsigned char throwaway; + fd_set f; +#endif + + purgeline(io_mode_fd); + +#ifdef HAVE_SELECT + t.tv_sec = 0; + t.tv_usec = 0; + + FD_ZERO(&f); + FD_SET(io_mode_fd,&f); + + while (select(1,&f,NULL,NULL,&t)) { + if (0==read(io_mode_fd,&throwaway,1)) /* EOF ... */ + break; + } +#endif + + purgeline(io_mode_fd); + stohdr(0L); + if (command_mode) + Txhdr[ZF0] = ZCOMMAND; + zshhdr(ZRQINIT, Txhdr); + zrqinits_sent++; +#if defined(ENABLE_TIMESYNC) + if (Rxflags2 != ZF1_TIMESYNC) + /* disable timesync if there are any flags we don't know. + * dsz/gsz seems to use some other flags! */ + enable_timesync=FALSE; + if (Rxflags2 & ZF1_TIMESYNC && enable_timesync) { + Totalleft+=6; /* TIMESYNC never needs more */ + Filesleft++; + } +#endif + } + } + fflush(stdout); + + if (Cmdstr) { + if (getzrxinit()) { + Exitcode=0200; canit(STDOUT_FILENO); + } + else if (zsendcmd(Cmdstr, strlen(Cmdstr)+1)) { + Exitcode=0200; canit(STDOUT_FILENO); + } + } else if (wcsend(npats, patts)==ERROR) { + Exitcode=0200; + canit(STDOUT_FILENO); + } + fflush(stdout); + io_mode(io_mode_fd,0); + if (Exitcode) + dm=Exitcode; + else if (errcnt) + dm=1; + else + dm=0; + if (Verbose) + { + fputs("\r\n",stderr); + if (dm) + fputs(_("Transfer incomplete\n"),stderr); + else + fputs(_("Transfer complete\n"),stderr); + } + exit(dm); + /*NOTREACHED*/ +} + +static int +send_pseudo(const char *name, const char *data) +{ + char *tmp; + const char *p; + int ret=0; /* ok */ + size_t plen; + int fd; + int lfd; + + p = getenv ("TMPDIR"); + if (!p) + p = getenv ("TMP"); + if (!p) + p = "/tmp"; + tmp=malloc(PATH_MAX+1); + if (!tmp) + error(1,0,_("out of memory")); + + plen=strlen(p); + memcpy(tmp,p,plen); + tmp[plen++]='/'; + + lfd=0; + do { + if (lfd++==10) { + free(tmp); + vstringf (_ ("send_pseudo %s: cannot open tmpfile %s: %s"), + name, tmp, strerror (errno)); + vstring ("\r\n"); + return 1; + } + sprintf(tmp+plen,"%s.%lu.%d",name,(unsigned long) getpid(),lfd); + fd=open(tmp,O_WRONLY|O_CREAT|O_EXCL,0700); + /* is O_EXCL guaranted to not follow symlinks? + * I don`t know ... so be careful + */ + if (fd!=-1) { + struct stat st; + if (0!=lstat(tmp,&st)) { + vstringf (_ ("send_pseudo %s: cannot lstat tmpfile %s: %s"), + name, tmp, strerror (errno)); + vstring ("\r\n"); + unlink(tmp); + close(fd); + fd=-1; + } else { + if (S_ISLNK(st.st_mode)) { + vstringf (_ ("send_pseudo %s: avoiding symlink trap"),name); + vstring ("\r\n"); + unlink(tmp); + close(fd); + fd=-1; + } + } + } + } while (fd==-1); + if (write(fd,data,strlen(data))!=(signed long) strlen(data) + || close(fd)!=0) { + vstringf (_ ("send_pseudo %s: cannot write to tmpfile %s: %s"), + name, tmp, strerror (errno)); + vstring ("\r\n"); + free(tmp); + return 1; + } + + if (wcs (tmp,name) == ERROR) { + if (Verbose) + vstringf (_ ("send_pseudo %s: failed"),name); + else { + if (Verbose) + vstringf (_ ("send_pseudo %s: ok"),name); + Filcnt--; + } + vstring ("\r\n"); + ret=1; + } + unlink (tmp); + free(tmp); + return ret; +} + +static int +wcsend (int argc, char *argp[]) +{ + int n; + + Crcflg = FALSE; + firstsec = TRUE; + bytcnt = (size_t) -1; + + for (n = 0; n < argc; ++n) { + Totsecs = 0; + if (wcs (argp[n],NULL) == ERROR) + return ERROR; + } +#if defined(ENABLE_TIMESYNC) + if (Rxflags2 & ZF1_TIMESYNC && enable_timesync) { + /* implement Peter Mandrellas extension */ + char buf[60]; + time_t t = time (NULL); + struct tm *tm = localtime (&t); /* sets timezone */ + strftime (buf, sizeof (buf) - 1, "%H:%M:%S", tm); + if (Verbose) { + vstring ("\r\n"); + vstringf (_("Answering TIMESYNC at %s"),buf); + } +#if defined(HAVE_TIMEZONE_VAR) + sprintf(buf+strlen(buf),"%ld\r\n", timezone / 60); + if (Verbose) + vstringf (" (%s %ld)\r\n", _ ("timezone"), timezone / 60); +#else + if (Verbose) + vstringf (" (%s)\r\n", _ ("timezone unknown")); +#endif + send_pseudo("/$time$.t",buf); + } +#endif + Totsecs = 0; + if (Filcnt == 0) { /* bitch if we couldn't open ANY files */ +#if 0 + /* i *really* do not like this */ + if (protocol != ZM_XMODEM) { + const char *Cmdstr; /* Pointer to the command string */ + command_mode = TRUE; + Cmdstr = "echo \"lsz: Can't open any requested files\""; + if (getnak ()) { + Exitcode = 0200; + canit(STDOUT_FILENO); + } + if (!zmodem_requested) + canit(STDOUT_FILENO); + else if (zsendcmd (Cmdstr, 1 + strlen (Cmdstr))) { + Exitcode = 0200; + canit(STDOUT_FILENO); + } + Exitcode = 1; + return OK; + } +#endif + canit(STDOUT_FILENO); + vstring ("\r\n"); + vstringf (_ ("Can't open any requested files.")); + vstring ("\r\n"); + return ERROR; + } + if (zmodem_requested) + saybibi (); + else if (protocol != ZM_XMODEM) { + struct zm_fileinfo zi; + char *pa; + pa=alloca(PATH_MAX+1); + *pa='\0'; + zi.fname = pa; + zi.modtime = 0; + zi.mode = 0; + zi.bytes_total = 0; + zi.bytes_sent = 0; + zi.bytes_received = 0; + zi.bytes_skipped = 0; + wctxpn (&zi); + } + return OK; +} + +static int +wcs(const char *oname, const char *remotename) +{ +#if !defined(S_ISDIR) + int c; +#endif + struct stat f; + char *name; + struct zm_fileinfo zi; +#ifdef HAVE_MMAP + int dont_mmap_this=0; +#endif +#ifdef ENABLE_SYSLOG + const char *shortname; + shortname=strrchr(oname,'/'); + if (shortname) + shortname++; + else + shortname=oname; +#endif + + + if (Restricted) { + /* restrict pathnames to current tree or uucppublic */ + if ( strstr(oname, "../") +#ifdef PUBDIR + || (oname[0]== '/' && strncmp(oname, MK_STRING(PUBDIR), + strlen(MK_STRING(PUBDIR)))) +#endif + ) { + canit(STDOUT_FILENO); + vchar('\r'); + error(1,0, + _("security violation: not allowed to upload from %s"),oname); + } + } + + if (0==strcmp(oname,"-")) { + char *p=getenv("ONAME"); + name=alloca(PATH_MAX+1); + if (p) { + strcpy(name, p); + } else { + sprintf(name, "s%lu.lsz", (unsigned long) getpid()); + } + input_f=stdin; +#ifdef HAVE_MMAP + dont_mmap_this=1; +#endif + } else if ((input_f=fopen(oname, "r"))==NULL) { + int e=errno; + error(0,e, _("cannot open %s"),oname); + ++errcnt; + return OK; /* pass over it, there may be others */ + } else { + name=alloca(PATH_MAX+1); + strcpy(name, oname); + } +#ifdef HAVE_MMAP + if (!use_mmap || dont_mmap_this) +#endif + { + static char *s=NULL; + static size_t last_length=0; + struct stat st; + if (fstat(fileno(input_f),&st)==-1) + st.st_size=1024*1024; + if (buffersize==(size_t) -1 && s) { + if ((size_t) st.st_size > last_length) { + free(s); + s=NULL; + last_length=0; + } + } + if (!s && buffersize) { + last_length=16384; + if (buffersize==(size_t) -1) { + if (st.st_size>0) + last_length=st.st_size; + } else + last_length=buffersize; + /* buffer whole pages */ + last_length=(last_length+4095)&0xfffff000; + s=malloc(last_length); + if (!s) { + zpfatal(_("out of memory")); + exit(1); + } + } + if (s) { +#ifdef SETVBUF_REVERSED + setvbuf(input_f,_IOFBF,s,last_length); +#else + setvbuf(input_f,s,_IOFBF,last_length); +#endif + } + } + vpos = 0; + /* Check for directory or block special files */ + fstat(fileno(input_f), &f); +#if defined(S_ISDIR) + if (S_ISDIR(f.st_mode) || S_ISBLK(f.st_mode)) { +#else + c = f.st_mode & S_IFMT; + if (c == S_IFDIR || c == S_IFBLK) { +#endif + error(0,0, _("is not a file: %s"),name); + fclose(input_f); + return OK; + } + + if (remotename) { + /* disqualify const */ + union { + const char *c; + char *s; + } cheat; + cheat.c=remotename; + zi.fname=cheat.s; + } else + zi.fname=name; + zi.modtime=f.st_mtime; + zi.mode=f.st_mode; +#if defined(S_ISFIFO) + zi.bytes_total= (S_ISFIFO(f.st_mode)) ? DEFBYTL : f.st_size; +#else + zi.bytes_total= c == S_IFIFO ? DEFBYTL : f.st_size; +#endif + zi.bytes_sent=0; + zi.bytes_received=0; + zi.bytes_skipped=0; + zi.eof_seen=0; + timing(1,NULL); + + ++Filcnt; + switch (wctxpn(&zi)) { + case ERROR: +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_INFO, _("%s/%s: error occured"),protname(),shortname); +#endif + return ERROR; + case ZSKIP: + error(0,0, _("skipped: %s"),name); +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_INFO, _("%s/%s: skipped"),protname(),shortname); +#endif + return OK; + } + if (!zmodem_requested && wctx(&zi)==ERROR) + { +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_INFO, _("%s/%s: error occured"),protname(),shortname); +#endif + return ERROR; + } + if (Unlinkafter) + unlink(oname); + + if (Verbose > 1 +#ifdef ENABLE_SYSLOG + || enable_syslog +#endif + ) { + long bps; + double d=timing(0,NULL); + if (d==0) /* can happen if timing() uses time() */ + d=0.5; + bps=zi.bytes_sent/d; + vchar('\r'); + if (Verbose > 1) + vstringf(_("Bytes Sent:%7ld BPS:%-8ld \n"), + (long) zi.bytes_sent,bps); +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_INFO, "%s/%s: %ld Bytes, %ld BPS",shortname, + protname(), (long) zi.bytes_sent,bps); +#endif + } + return 0; +} + +/* + * generate and transmit pathname block consisting of + * pathname (null terminated), + * file length, mode time and file mode in octal + * as provided by the Unix fstat call. + * N.B.: modifies the passed name, may extend it! + */ +static int +wctxpn(struct zm_fileinfo *zi) +{ + register char *p, *q; + char *name2; + struct stat f; + + name2=alloca(PATH_MAX+1); + + if (protocol==ZM_XMODEM) { + if (Verbose && *zi->fname && fstat(fileno(input_f), &f)!= -1) { + vstringf(_("Sending %s, %ld blocks: "), + zi->fname, (long) (f.st_size>>7)); + } + vstringf(_("Give your local XMODEM receive command now.")); + vstring("\r\n"); + return OK; + } + if (!zmodem_requested) + if (getnak()) { + vfile("getnak failed"); + DO_SYSLOG((LOG_INFO, "%s/%s: getnak failed", + shortname,protname())); + return ERROR; + } + + q = (char *) 0; + if (Dottoslash) { /* change . to . */ + for (p=zi->fname; *p; ++p) { + if (*p == '/') + q = p; + else if (*p == '.') + *(q=p) = '/'; + } + if (q && strlen(++q) > 8) { /* If name>8 chars */ + q += 8; /* make it .ext */ + strcpy(name2, q); /* save excess of name */ + *q = '.'; + strcpy(++q, name2); /* add it back */ + } + } + + for (p=zi->fname, q=txbuf ; *p; ) + if ((*q++ = *p++) == '/' && !Fullname) + q = txbuf; + *q++ = 0; + p=q; + while (q < (txbuf + MAX_BLOCK)) + *q++ = 0; + /* note that we may lose some information here in case mode_t is wider than an + * int. But i believe sending %lo instead of %o _could_ break compatability + */ + if (!Ascii && (input_f!=stdin) && *zi->fname && fstat(fileno(input_f), &f)!= -1) + sprintf(p, "%lu %lo %o 0 %d %ld", (long) f.st_size, f.st_mtime, + (unsigned int)((no_unixmode) ? 0 : f.st_mode), + Filesleft, Totalleft); + if (Verbose) + vstringf(_("Sending: %s\n"),txbuf); + Totalleft -= f.st_size; + if (--Filesleft <= 0) + Totalleft = 0; + if (Totalleft < 0) + Totalleft = 0; + + /* force 1k blocks if name won't fit in 128 byte block */ + if (txbuf[125]) + blklen=1024; + else { /* A little goodie for IMP/KMD */ + txbuf[127] = (f.st_size + 127) >>7; + txbuf[126] = (f.st_size + 127) >>15; + } + if (zmodem_requested) + return zsendfile(zi,txbuf, 1+strlen(p)+(p-txbuf)); + if (wcputsec(txbuf, 0, 128)==ERROR) { + vfile("wcputsec failed"); + DO_SYSLOG((LOG_INFO, "%s/%s: wcputsec failed", + shortname,protname())); + return ERROR; + } + return OK; +} + +static int +getnak(void) +{ + int firstch; + int tries=0; + + Lastrx = 0; + for (;;) { + tries++; + switch (firstch = READLINE_PF(100)) { + case ZPAD: + if (getzrxinit()) + return ERROR; + Ascii = 0; /* Receiver does the conversion */ + return FALSE; + case TIMEOUT: + /* 30 seconds are enough */ + if (tries==3) { + zperr(_("Timeout on pathname")); + return TRUE; + } + /* don't send a second ZRQINIT _directly_ after the + * first one. Never send more then 4 ZRQINIT, because + * omen rz stops if it saw 5 of them */ + if ((zrqinits_sent>1 || tries>1) && zrqinits_sent<4) { + /* if we already sent a ZRQINIT we are using zmodem + * protocol and may send further ZRQINITs + */ + stohdr(0L); + zshhdr(ZRQINIT, Txhdr); + zrqinits_sent++; + } + continue; + case WANTG: + io_mode(io_mode_fd,2); /* Set cbreak, XON/XOFF, etc. */ + Optiong = TRUE; + blklen=1024; + case WANTCRC: + Crcflg = TRUE; + case NAK: + return FALSE; + case CAN: + if ((firstch = READLINE_PF(20)) == CAN && Lastrx == CAN) + return TRUE; + default: + break; + } + Lastrx = firstch; + } +} + + +static int +wctx(struct zm_fileinfo *zi) +{ + register size_t thisblklen; + register int sectnum, attempts, firstch; + + firstsec=TRUE; thisblklen = blklen; + vfile("wctx:file length=%ld", (long) zi->bytes_total); + + while ((firstch=READLINE_PF(Rxtimeout))!=NAK && firstch != WANTCRC + && firstch != WANTG && firstch!=TIMEOUT && firstch!=CAN) + ; + if (firstch==CAN) { + zperr(_("Receiver Cancelled")); + return ERROR; + } + if (firstch==WANTCRC) + Crcflg=TRUE; + if (firstch==WANTG) + Crcflg=TRUE; + sectnum=0; + for (;;) { + if (zi->bytes_total <= (zi->bytes_sent + 896L)) + thisblklen = 128; + if ( !filbuf(txbuf, thisblklen)) + break; + if (wcputsec(txbuf, ++sectnum, thisblklen)==ERROR) + return ERROR; + zi->bytes_sent += thisblklen; + } + fclose(input_f); + attempts=0; + do { + purgeline(io_mode_fd); + sendline(EOT); + flushmo(); + ++attempts; + } while ((firstch=(READLINE_PF(Rxtimeout)) != ACK) && attempts < RETRYMAX); + if (attempts == RETRYMAX) { + zperr(_("No ACK on EOT")); + return ERROR; + } + else + return OK; +} + +static int +wcputsec(char *buf, int sectnum, size_t cseclen) +{ + int checksum, wcj; + char *cp; + unsigned oldcrc; + int firstch; + int attempts; + + firstch=0; /* part of logic to detect CAN CAN */ + + if (Verbose>1) { + vchar('\r'); + if (protocol==ZM_XMODEM) { + vstringf(_("Xmodem sectors/kbytes sent: %3d/%2dk"), Totsecs, Totsecs/8 ); + } else { + vstringf(_("Ymodem sectors/kbytes sent: %3d/%2dk"), Totsecs, Totsecs/8 ); + } + } + for (attempts=0; attempts <= RETRYMAX; attempts++) { + Lastrx= firstch; + sendline(cseclen==1024?STX:SOH); + sendline(sectnum); + sendline(-sectnum -1); + oldcrc=checksum=0; + for (wcj=cseclen,cp=buf; --wcj>=0; ) { + sendline(*cp); + oldcrc=updcrc((0377& *cp), oldcrc); + checksum += *cp++; + } + if (Crcflg) { + oldcrc=updcrc(0,updcrc(0,oldcrc)); + sendline((int)oldcrc>>8); + sendline((int)oldcrc); + } + else + sendline(checksum); + + flushmo(); + if (Optiong) { + firstsec = FALSE; return OK; + } + firstch = READLINE_PF(Rxtimeout); +gotnak: + switch (firstch) { + case CAN: + if(Lastrx == CAN) { +cancan: + zperr(_("Cancelled")); return ERROR; + } + break; + case TIMEOUT: + zperr(_("Timeout on sector ACK")); continue; + case WANTCRC: + if (firstsec) + Crcflg = TRUE; + case NAK: + zperr(_("NAK on sector")); continue; + case ACK: + firstsec=FALSE; + Totsecs += (cseclen>>7); + return OK; + case ERROR: + zperr(_("Got burst for sector ACK")); break; + default: + zperr(_("Got %02x for sector ACK"), firstch); break; + } + for (;;) { + Lastrx = firstch; + if ((firstch = READLINE_PF(Rxtimeout)) == TIMEOUT) + break; + if (firstch == NAK || firstch == WANTCRC) + goto gotnak; + if (firstch == CAN && Lastrx == CAN) + goto cancan; + } + } + zperr(_("Retry Count Exceeded")); + return ERROR; +} + +/* fill buf with count chars padding with ^Z for CPM */ +static size_t +filbuf(char *buf, size_t count) +{ + int c; + size_t m; + + if ( !Ascii) { + m = read(fileno(input_f), buf, count); + if (m <= 0) + return 0; + while (m < count) + buf[m++] = 032; + return count; + } + m=count; + if (Lfseen) { + *buf++ = 012; --m; Lfseen = 0; + } + while ((c=getc(input_f))!=EOF) { + if (c == 012) { + *buf++ = 015; + if (--m == 0) { + Lfseen = TRUE; break; + } + } + *buf++ =c; + if (--m == 0) + break; + } + if (m==count) + return 0; + else + while (m--!=0) + *buf++ = CPMEOF; + return count; +} + +/* Fill buffer with blklen chars */ +static size_t +zfilbuf (struct zm_fileinfo *zi) +{ + size_t n; + + n = fread (txbuf, 1, blklen, input_f); + if (n < blklen) + zi->eof_seen = 1; + else { + /* save one empty paket in case file ends ob blklen boundary */ + int c = getc(input_f); + + if (c != EOF || !feof(input_f)) + ungetc(c, input_f); + else + zi->eof_seen = 1; + } + return n; +} + +static void +usage1 (int exitcode) +{ + usage (exitcode, NULL); +} + +static void +usage(int exitcode, const char *what) +{ + FILE *f=stdout; + + if (exitcode) + { + if (what) + fprintf(stderr, "%s: %s\n",program_name,what); + fprintf (stderr, _("Try `%s --help' for more information.\n"), + program_name); + exit(exitcode); + } + + fprintf(f, _("%s version %s\n"), program_name, + VERSION); + + fprintf(f,_("Usage: %s [options] file ...\n"), + program_name); + fprintf(f,_(" or: %s [options] -{c|i} COMMAND\n"),program_name); + fputs(_("Send file(s) with ZMODEM/YMODEM/XMODEM protocol\n"),f); + fputs(_( + " (X) = option applies to XMODEM only\n" + " (Y) = option applies to YMODEM only\n" + " (Z) = option applies to ZMODEM only\n" + ),f); + /* splitted into two halves for really bad compilers */ + fputs(_( +" -+, --append append to existing destination file (Z)\n" +" -2, --twostop use 2 stop bits\n" +" -4, --try-4k go up to 4K blocksize\n" +" --start-4k start with 4K blocksize (doesn't try 8)\n" +" -8, --try-8k go up to 8K blocksize\n" +" --start-8k start with 8K blocksize\n" +" -a, --ascii ASCII transfer (change CR/LF to LF)\n" +" -b, --binary binary transfer\n" +" -B, --bufsize N buffer N bytes (N==auto: buffer whole file)\n" +" -c, --command COMMAND execute remote command COMMAND (Z)\n" +" -C, --command-tries N try N times to execute a command (Z)\n" +" -d, --dot-to-slash change '.' to '/' in pathnames (Y/Z)\n" +" --delay-startup N sleep N seconds before doing anything\n" +" -e, --escape escape all control characters (Z)\n" +" -E, --rename force receiver to rename files it already has\n" +" -f, --full-path send full pathname (Y/Z)\n" +" -i, --immediate-command CMD send remote CMD, return immediately (Z)\n" +" -h, --help print this usage message\n" +" -k, --1k send 1024 byte packets (X)\n" +" -L, --packetlen N limit subpacket length to N bytes (Z)\n" +" -l, --framelen N limit frame length to N bytes (l>=L) (Z)\n" +" -m, --min-bps N stop transmission if BPS below N\n" +" -M, --min-bps-time N for at least N seconds (default: 120)\n" + ),f); + fputs(_( +" -n, --newer send file if source newer (Z)\n" +" -N, --newer-or-longer send file if source newer or longer (Z)\n" +" -o, --16-bit-crc use 16 bit CRC instead of 32 bit CRC (Z)\n" +" -O, --disable-timeouts disable timeout code, wait forever\n" +" -p, --protect protect existing destination file (Z)\n" +" -r, --resume resume interrupted file transfer (Z)\n" +" -R, --restricted restricted, more secure mode\n" +" -q, --quiet quiet (no progress reports)\n" +" -s, --stop-at {HH:MM|+N} stop transmission at HH:MM or in N seconds\n" +" --tcp-server open socket, wait for connection (Z)\n" +" --tcp-client ADDR:PORT open socket, connect to ... (Z)\n" +" -u, --unlink unlink file after transmission\n" +" -U, --unrestrict turn off restricted mode (if allowed to)\n" +" -v, --verbose be verbose, provide debugging information\n" +" -w, --windowsize N Window is N bytes (Z)\n" +" -X, --xmodem use XMODEM protocol\n" +" -y, --overwrite overwrite existing files\n" +" -Y, --overwrite-or-skip overwrite existing files, else skip\n" +" --ymodem use YMODEM protocol\n" +" -Z, --zmodem use ZMODEM protocol\n" +"\n" +"short options use the same arguments as the long ones\n" + ),f); + exit(exitcode); +} + +/* + * Get the receiver's init parameters + */ +static int +getzrxinit(void) +{ + static int dont_send_zrqinit=1; + int old_timeout=Rxtimeout; + int n; + struct stat f; + size_t rxpos; + int timeouts=0; + + Rxtimeout=100; /* 10 seconds */ + /* XXX purgeline(io_mode_fd); this makes _real_ trouble. why? -- uwe */ + + for (n=10; --n>=0; ) { + /* we might need to send another zrqinit in case the first is + * lost. But *not* if getting here for the first time - in + * this case we might just get a ZRINIT for our first ZRQINIT. + * Never send more then 4 ZRQINIT, because + * omen rz stops if it saw 5 of them. + */ + if (zrqinits_sent<4 && n!=10 && !dont_send_zrqinit) { + zrqinits_sent++; + stohdr(0L); + zshhdr(ZRQINIT, Txhdr); + } + dont_send_zrqinit=0; + + switch (zgethdr(Rxhdr, 1,&rxpos)) { + case ZCHALLENGE: /* Echo receiver's challenge numbr */ + stohdr(rxpos); + zshhdr(ZACK, Txhdr); + continue; + case ZCOMMAND: /* They didn't see our ZRQINIT */ + /* ??? Since when does a receiver send ZCOMMAND? -- uwe */ + continue; + case ZRINIT: + Rxflags = 0377 & Rxhdr[ZF0]; + Rxflags2 = 0377 & Rxhdr[ZF1]; + Txfcs32 = (Wantfcs32 && (Rxflags & CANFC32)); + { + int old=Zctlesc; + Zctlesc |= Rxflags & TESCCTL; + /* update table - was initialised to not escape */ + if (Zctlesc && !old) + zsendline_init(); + } + Rxbuflen = (0377 & Rxhdr[ZP0])+((0377 & Rxhdr[ZP1])<<8); + if ( !(Rxflags & CANFDX)) + Txwindow = 0; + vfile("Rxbuflen=%d Tframlen=%d", Rxbuflen, Tframlen); + if ( play_with_sigint) + signal(SIGINT, SIG_IGN); + io_mode(io_mode_fd,2); /* Set cbreak, XON/XOFF, etc. */ +#ifndef READCHECK + /* Use MAX_BLOCK byte frames if no sample/interrupt */ + if (Rxbuflen < 32 || Rxbuflen > MAX_BLOCK) { + Rxbuflen = MAX_BLOCK; + vfile("Rxbuflen=%d", Rxbuflen); + } +#endif + /* Override to force shorter frame length */ + if (Tframlen && Rxbuflen > Tframlen) + Rxbuflen = Tframlen; + if ( !Rxbuflen) + Rxbuflen = 1024; + vfile("Rxbuflen=%d", Rxbuflen); + + /* If using a pipe for testing set lower buf len */ + fstat(0, &f); +#if defined(S_ISCHR) + if (! (S_ISCHR(f.st_mode))) { +#else + if ((f.st_mode & S_IFMT) != S_IFCHR) { +#endif + Rxbuflen = MAX_BLOCK; + } + /* + * If input is not a regular file, force ACK's to + * prevent running beyond the buffer limits + */ + if ( !command_mode) { + fstat(fileno(input_f), &f); +#if defined(S_ISREG) + if (!(S_ISREG(f.st_mode))) { +#else + if ((f.st_mode & S_IFMT) != S_IFREG) { +#endif + Canseek = -1; + /* return ERROR; */ + } + } + /* Set initial subpacket length */ + if (blklen < 1024) { /* Command line override? */ + if (Baudrate > 300) + blklen = 256; + if (Baudrate > 1200) + blklen = 512; + if (Baudrate > 2400) + blklen = 1024; + } + if (Rxbuflen && blklen>Rxbuflen) + blklen = Rxbuflen; + if (blkopt && blklen > blkopt) + blklen = blkopt; + vfile("Rxbuflen=%d blklen=%d", Rxbuflen, blklen); + vfile("Txwindow = %u Txwspac = %d", Txwindow, Txwspac); + Rxtimeout=old_timeout; + return (sendzsinit()); + case ZCAN: + case TIMEOUT: + if (timeouts++==0) + continue; /* force one other ZRQINIT to be sent */ + return ERROR; + case ZRQINIT: + if (Rxhdr[ZF0] == ZCOMMAND) + continue; + default: + zshhdr(ZNAK, Txhdr); + continue; + } + } + return ERROR; +} + +/* Send send-init information */ +static int +sendzsinit(void) +{ + int c; + + if (Myattn[0] == '\0' && (!Zctlesc || (Rxflags & TESCCTL))) + return OK; + errors = 0; + for (;;) { + stohdr(0L); + if (Zctlesc) { + Txhdr[ZF0] |= TESCCTL; zshhdr(ZSINIT, Txhdr); + } + else + zsbhdr(ZSINIT, Txhdr); + ZSDATA(Myattn, 1+strlen(Myattn), ZCRCW); + c = zgethdr(Rxhdr, 1,NULL); + switch (c) { + case ZCAN: + return ERROR; + case ZACK: + return OK; + default: + if (++errors > 19) + return ERROR; + continue; + } + } +} + +/* Send file name and related info */ +static int +zsendfile(struct zm_fileinfo *zi, const char *buf, size_t blen) +{ + unsigned long crc; + size_t rxpos; + + /* we are going to send a ZFILE. There cannot be much useful + * stuff in the line right now (*except* ZCAN?). + */ +#if 0 + purgeline(io_mode_fd); /* might possibly fix stefan glasers problems */ +#endif + + for (;;) { + int gotblock; + int gotchar; + Txhdr[ZF0] = Lzconv; /* file conversion request */ + Txhdr[ZF1] = Lzmanag; /* file management request */ + if (Lskipnocor) + Txhdr[ZF1] |= ZF1_ZMSKNOLOC; + Txhdr[ZF2] = Lztrans; /* file transport request */ + Txhdr[ZF3] = 0; + zsbhdr(ZFILE, Txhdr); + ZSDATA(buf, blen, ZCRCW); +again: + gotblock = zgethdr(Rxhdr, 1, &rxpos); + switch (gotblock) { + case ZRINIT: + while ((gotchar = READLINE_PF(50)) > 0) + if (gotchar == ZPAD) { + goto again; + } + /* **** FALL THRU TO **** */ + default: + continue; + case ZRQINIT: /* remote site is sender! */ + if (Verbose) + vstringf(_("got ZRQINIT")); + DO_SYSLOG((LOG_INFO, "%s/%s: got ZRQINIT - sz talks to sz", + shortname,protname())); + return ERROR; + case ZCAN: + if (Verbose) + vstringf(_("got ZCAN")); + DO_SYSLOG((LOG_INFO, "%s/%s: got ZCAN - receiver canceled", + shortname,protname())); + return ERROR; + case TIMEOUT: + DO_SYSLOG((LOG_INFO, "%s/%s: got TIMEOUT", + shortname,protname())); + return ERROR; + case ZABORT: + DO_SYSLOG((LOG_INFO, "%s/%s: got ZABORT", + shortname,protname())); + return ERROR; + case ZFIN: + DO_SYSLOG((LOG_INFO, "%s/%s: got ZFIN", + shortname,protname())); + return ERROR; + case ZCRC: + crc = 0xFFFFFFFFL; +#ifdef HAVE_MMAP + if (use_mmap && !mm_addr) + { + struct stat st; + /* mmap on files of 0 length can give 0 as result .. under linux 2.2.9 at least */ + if (fstat (fileno (input_f), &st) == 0 && st.st_size!=0) { + mm_size = st.st_size; + mm_addr = mmap (0, mm_size, PROT_READ, + MAP_SHARED, fileno (input_f), 0); + if ((caddr_t) mm_addr == (caddr_t) - 1) + mm_addr = NULL; + else { + fclose (input_f); + input_f = NULL; + } + } + } + if (mm_addr) { + size_t i; + size_t count; + char *p=mm_addr; + count=(rxpos < mm_size && rxpos > 0)? rxpos: mm_size; + for (i=0;i<count;i++,p++) { + crc = UPDC32(*p, crc); + } + crc = ~crc; + } else +#endif + if (Canseek >= 0) { + if (rxpos==0) { + struct stat st; + if (0==fstat(fileno(input_f),&st)) { + rxpos=st.st_size; + } else + rxpos=-1; + } + while (rxpos-- && ((gotchar = getc(input_f)) != EOF)) + crc = UPDC32(gotchar, crc); + crc = ~crc; + clearerr(input_f); /* Clear EOF */ + fseek(input_f, 0L, 0); + } + stohdr(crc); + zsbhdr(ZCRC, Txhdr); + goto again; + case ZSKIP: + if (input_f) { + fclose(input_f); + input_f=NULL; + } +#ifdef HAVE_MMAP + else if (mm_addr) { + munmap(mm_addr,mm_size); + mm_addr=NULL; + } +#endif + + vfile("receiver skipped"); + DO_SYSLOG((LOG_INFO, "%s/%s: receiver skipped", + shortname, protname())); + return ZSKIP; + case ZRPOS: + /* + * Suppress zcrcw request otherwise triggered by + * lastsync==bytcnt + */ +#ifdef HAVE_MMAP + if (!mm_addr) +#endif + if (rxpos && fseek(input_f, (long) rxpos, 0)) { + int er=errno; + vfile("fseek failed: %s", strerror(er)); + DO_SYSLOG((LOG_INFO, "%s/%s: fseek failed: %s", + shortname, protname(), strerror(er))); + return ERROR; + } + if (rxpos) + zi->bytes_skipped=rxpos; + bytcnt = zi->bytes_sent = rxpos; + Lastsync = rxpos -1; + return zsendfdata(zi); + } + } +} + +/* Send the data in the file */ +static int +zsendfdata (struct zm_fileinfo *zi) +{ + static int c; + int newcnt; + static int junkcount; /* Counts garbage chars received by TX */ + static size_t last_txpos = 0; + static long last_bps = 0; + static long not_printed = 0; + static long total_sent = 0; + static time_t low_bps=0; + +#ifdef HAVE_MMAP + if (use_mmap && !mm_addr) + { + struct stat st; + if (fstat (fileno (input_f), &st) == 0 && st.st_size!=0) { + mm_size = st.st_size; + mm_addr = mmap (0, mm_size, PROT_READ, + MAP_SHARED, fileno (input_f), 0); + if ((caddr_t) mm_addr == (caddr_t) - 1) + mm_addr = NULL; + else { + fclose (input_f); + input_f = NULL; + } + } + } +#endif + + if (play_with_sigint) + signal (SIGINT, onintr); + + Lrxpos = 0; + junkcount = 0; + Beenhereb4 = 0; + somemore: + if (setjmp (intrjmp)) { + if (play_with_sigint) + signal (SIGINT, onintr); + waitack: + junkcount = 0; + c = getinsync (zi, 0); + gotack: + switch (c) { + default: + if (input_f) { + fclose (input_f); + input_f=NULL; + } + DO_SYSLOG((LOG_INFO, "%s/%s: got %d", + shortname, protname(), c)); + return ERROR; + case ZCAN: + if (input_f) { + fclose (input_f); + input_f=NULL; + } + DO_SYSLOG((LOG_INFO, "%s/%s: got ZCAN", + shortname, protname())); + return ERROR; + case ZSKIP: + if (input_f) { + fclose (input_f); + input_f=NULL; + } + DO_SYSLOG((LOG_INFO, "%s/%s: got ZSKIP", + shortname, protname())); + return ZSKIP; + case ZACK: + case ZRPOS: + break; + case ZRINIT: + return OK; + } +#ifdef READCHECK + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fdes) returns non 0 if a character is available + */ + while (rdchk (io_mode_fd)) { +#ifdef READCHECK_READS + switch (checked) +#else + switch (READLINE_PF (1)) +#endif + { + case CAN: + case ZPAD: + c = getinsync (zi, 1); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF | 0200: + READLINE_PF (100); + } + } +#endif + } + + newcnt = Rxbuflen; + Txwcnt = 0; + stohdr (zi->bytes_sent); + zsbhdr (ZDATA, Txhdr); + + do { + size_t n; + int e; + unsigned old = blklen; + blklen = calc_blklen (total_sent); + total_sent += blklen + OVERHEAD; + if (Verbose > 2 && blklen != old) + vstringf (_("blklen now %d\n"), blklen); +#ifdef HAVE_MMAP + if (mm_addr) { + if (zi->bytes_sent + blklen < mm_size) + n = blklen; + else { + n = mm_size - zi->bytes_sent; + zi->eof_seen = 1; + } + } else +#endif + n = zfilbuf (zi); + if (zi->eof_seen) { + e = ZCRCE; + if (Verbose>3) + vstring("e=ZCRCE/eof seen"); + } else if (junkcount > 3) { + e = ZCRCW; + if (Verbose>3) + vstring("e=ZCRCW/junkcount > 3"); + } else if (bytcnt == Lastsync) { + e = ZCRCW; + if (Verbose>3) + vstringf("e=ZCRCW/bytcnt == Lastsync == %ld", + (unsigned long) Lastsync); +#if 0 + /* what is this good for? Rxbuflen/newcnt normally are short - so after + * a few KB ZCRCW will be used? (newcnt is never incremented) + */ + } else if (Rxbuflen && (newcnt -= n) <= 0) { + e = ZCRCW; + if (Verbose>3) + vstringf("e=ZCRCW/Rxbuflen(newcnt=%ld,n=%ld)", + (unsigned long) newcnt,(unsigned long) n); +#endif + } else if (Txwindow && (Txwcnt += n) >= Txwspac) { + Txwcnt = 0; + e = ZCRCQ; + if (Verbose>3) + vstring("e=ZCRCQ/Window"); + } else { + e = ZCRCG; + if (Verbose>3) + vstring("e=ZCRCG"); + } + if ((Verbose > 1 || min_bps || stop_time) + && (not_printed > (min_bps ? 3 : 7) + || zi->bytes_sent > last_bps / 2 + last_txpos)) { + int minleft = 0; + int secleft = 0; + time_t now; + last_bps = (zi->bytes_sent / timing (0,&now)); + if (last_bps > 0) { + minleft = (zi->bytes_total - zi->bytes_sent) / last_bps / 60; + secleft = ((zi->bytes_total - zi->bytes_sent) / last_bps) % 60; + } + if (min_bps) { + if (low_bps) { + if (last_bps<min_bps) { + if (now-low_bps>=min_bps_time) { + /* too bad */ + if (Verbose) { + vstringf(_("zsendfdata: bps rate %ld below min %ld"), + last_bps, min_bps); + vstring("\r\n"); + } + DO_SYSLOG((LOG_INFO, "%s/%s: bps rate low: %ld <%ld", + shortname, protname(), last_bps, min_bps)); + return ERROR; + } + } else + low_bps=0; + } else if (last_bps < min_bps) { + low_bps=now; + } + } + if (stop_time && now>=stop_time) { + /* too bad */ + if (Verbose) { + vstring(_("zsendfdata: reached stop time")); + vstring("\r\n"); + } + DO_SYSLOG((LOG_INFO, "%s/%s: reached stop time", + shortname, protname())); + return ERROR; + } + + if (Verbose > 1) { + vchar ('\r'); + vstringf (_("Bytes Sent:%7ld/%7ld BPS:%-8ld ETA %02d:%02d "), + (long) zi->bytes_sent, (long) zi->bytes_total, + last_bps, minleft, secleft); + } + last_txpos = zi->bytes_sent; + } else if (Verbose) + not_printed++; + ZSDATA (DATAADR, n, e); + bytcnt = zi->bytes_sent += n; + if (e == ZCRCW) + goto waitack; +#ifdef READCHECK + /* + * If the reverse channel can be tested for data, + * this logic may be used to detect error packets + * sent by the receiver, in place of setjmp/longjmp + * rdchk(fdes) returns non 0 if a character is available + */ + fflush (stdout); + while (rdchk (io_mode_fd)) { +#ifdef READCHECK_READS + switch (checked) +#else + switch (READLINE_PF (1)) +#endif + { + case CAN: + case ZPAD: + c = getinsync (zi, 1); + if (c == ZACK) + break; + /* zcrce - dinna wanna starta ping-pong game */ + ZSDATA (txbuf, 0, ZCRCE); + goto gotack; + case XOFF: /* Wait a while for an XON */ + case XOFF | 0200: + READLINE_PF (100); + default: + ++junkcount; + } + } +#endif /* READCHECK */ + if (Txwindow) { + size_t tcount = 0; + while ((tcount = zi->bytes_sent - Lrxpos) >= Txwindow) { + vfile ("%ld (%ld,%ld) window >= %u", tcount, + (long) zi->bytes_sent, (long) Lrxpos, + Txwindow); + if (e != ZCRCQ) + ZSDATA (txbuf, 0, e = ZCRCQ); + c = getinsync (zi, 1); + if (c != ZACK) { + ZSDATA (txbuf, 0, ZCRCE); + goto gotack; + } + } + vfile ("window = %ld", tcount); + } + } while (!zi->eof_seen); + + + if (play_with_sigint) + signal (SIGINT, SIG_IGN); + + for (;;) { + stohdr (zi->bytes_sent); + zsbhdr (ZEOF, Txhdr); + switch (getinsync (zi, 0)) { + case ZACK: + continue; + case ZRPOS: + goto somemore; + case ZRINIT: + return OK; + case ZSKIP: + if (input_f) { + fclose (input_f); + input_f=NULL; + } + DO_SYSLOG((LOG_INFO, "%s/%s: got ZSKIP", + shortname, protname())); + return c; + default: + if (input_f) { + fclose (input_f); + input_f=NULL; + } + DO_SYSLOG((LOG_INFO, "%s/%s: got %d", + shortname, protname(), c)); + return ERROR; + } + } +} + +static int +calc_blklen(long total_sent) +{ + static long total_bytes=0; + static int calcs_done=0; + static long last_error_count=0; + static int last_blklen=0; + static long last_bytes_per_error=0; + unsigned long best_bytes=0; + long best_size=0; + long this_bytes_per_error; + long d; + unsigned int i; + if (total_bytes==0) + { + /* called from countem */ + total_bytes=total_sent; + return 0; + } + + /* it's not good to calc blklen too early */ + if (calcs_done++ < 5) { + if (error_count && start_blklen >1024) + return last_blklen=1024; + else + last_blklen/=2; + return last_blklen=start_blklen; + } + + if (!error_count) { + /* that's fine */ + if (start_blklen==max_blklen) + return start_blklen; + this_bytes_per_error=LONG_MAX; + goto calcit; + } + + if (error_count!=last_error_count) { + /* the last block was bad. shorten blocks until one block is + * ok. this is because very often many errors come in an + * short period */ + if (error_count & 2) + { + last_blklen/=2; + if (last_blklen < 32) + last_blklen = 32; + else if (last_blklen > 512) + last_blklen=512; + if (Verbose > 3) + vstringf(_("calc_blklen: reduced to %d due to error\n"), + last_blklen); + } + last_error_count=error_count; + last_bytes_per_error=0; /* force recalc */ + return last_blklen; + } + + this_bytes_per_error=total_sent / error_count; + /* we do not get told about every error, because + * there may be more than one error per failed block. + * but one the other hand some errors are reported more + * than once: If a modem buffers more than one block we + * get at least two ZRPOS for the same position in case + * *one* block has to be resent. + * so don't do this: + * this_bytes_per_error/=2; + */ + /* there has to be a margin */ + if (this_bytes_per_error<100) + this_bytes_per_error=100; + + /* be nice to the poor machine and do the complicated things not + * too often + */ + if (last_bytes_per_error>this_bytes_per_error) + d=last_bytes_per_error-this_bytes_per_error; + else + d=this_bytes_per_error-last_bytes_per_error; + if (d<4) + { + if (Verbose > 3) + { + vstringf(_("calc_blklen: returned old value %d due to low bpe diff\n"), + last_blklen); + vstringf(_("calc_blklen: old %ld, new %ld, d %ld\n"), + last_bytes_per_error,this_bytes_per_error,d ); + } + return last_blklen; + } + last_bytes_per_error=this_bytes_per_error; + +calcit: + if (Verbose > 3) + vstringf(_("calc_blklen: calc total_bytes=%ld, bpe=%ld, ec=%ld\n"), + total_bytes,this_bytes_per_error,(long) error_count); + for (i=32;i<=max_blklen;i*=2) { + long ok; /* some many ok blocks do we need */ + long failed; /* and that's the number of blocks not transmitted ok */ + unsigned long transmitted; + ok=total_bytes / i + 1; + failed=((long) i + OVERHEAD) * ok / this_bytes_per_error; + transmitted=total_bytes + ok * OVERHEAD + + failed * ((long) i+OVERHEAD+OVER_ERR); + if (Verbose > 4) + vstringf(_("calc_blklen: blklen %d, ok %ld, failed %ld -> %lu\n"), + i,ok,failed,transmitted); + if (transmitted < best_bytes || !best_bytes) + { + best_bytes=transmitted; + best_size=i; + } + } + if (best_size > 2*last_blklen) + best_size=2*last_blklen; + last_blklen=best_size; + if (Verbose > 3) + vstringf(_("calc_blklen: returned %d as best\n"), + last_blklen); + return last_blklen; +} + +/* + * Respond to receiver's complaint, get back in sync with receiver + */ +static int +getinsync(struct zm_fileinfo *zi, int flag) +{ + size_t rxpos; + + for (;;) { + int gotblock; + gotblock = zgethdr(Rxhdr, 0, &rxpos); + switch (gotblock) { + case ZCAN: + case ZABORT: + case ZFIN: + case TIMEOUT: + return ERROR; + case ZRPOS: + /* ************************************* */ + /* If sending to a buffered modem, you */ + /* might send a break at this point to */ + /* dump the modem's buffer. */ + if (input_f) + clearerr(input_f); /* In case file EOF seen */ +#ifdef HAVE_MMAP + if (!mm_addr) +#endif + if (fseek(input_f, (long) rxpos, 0)) + return ERROR; + zi->eof_seen = 0; + bytcnt = Lrxpos = zi->bytes_sent = rxpos; + if (Lastsync == rxpos) { + error_count++; + } + Lastsync = rxpos; + return ZRPOS; + case ZACK: + Lrxpos = rxpos; + if (flag || zi->bytes_sent == rxpos) + return ZACK; + continue; + case ZRINIT: + case ZSKIP: + if (input_f) { + fclose (input_f); + input_f=NULL; + } +#ifdef HAVE_MMAP + else if (mm_addr) { + munmap(mm_addr,mm_size); + mm_addr=NULL; + } +#endif + return ZSKIP; + case ERROR: + default: + error_count++; + zsbhdr(ZNAK, Txhdr); + continue; + } + } +} + + +/* Say "bibi" to the receiver, try to do it cleanly */ +static void +saybibi(void) +{ + for (;;) { + stohdr(0L); /* CAF Was zsbhdr - minor change */ + zshhdr(ZFIN, Txhdr); /* to make debugging easier */ + switch (zgethdr(Rxhdr, 0,NULL)) { + case ZFIN: + sendline('O'); + sendline('O'); + flushmo(); + case ZCAN: + case TIMEOUT: + return; + } + } +} + +/* Send command and related info */ +static int +zsendcmd(const char *buf, size_t blen) +{ + int c; + pid_t cmdnum; + size_t rxpos; + + cmdnum = getpid(); + errors = 0; + for (;;) { + stohdr((size_t) cmdnum); + Txhdr[ZF0] = Cmdack1; + zsbhdr(ZCOMMAND, Txhdr); + ZSDATA(buf, blen, ZCRCW); +listen: + Rxtimeout = 100; /* Ten second wait for resp. */ + c = zgethdr(Rxhdr, 1, &rxpos); + + switch (c) { + case ZRINIT: + goto listen; /* CAF 8-21-87 */ + case ERROR: + case TIMEOUT: + if (++errors > Cmdtries) + return ERROR; + continue; + case ZCAN: + case ZABORT: + case ZFIN: + case ZSKIP: + case ZRPOS: + return ERROR; + default: + if (++errors > 20) + return ERROR; + continue; + case ZCOMPL: + Exitcode = rxpos; + saybibi(); + return OK; + case ZRQINIT: + vfile("******** RZ *******"); + system("rz"); + vfile("******** SZ *******"); + goto listen; + } + } +} + +/* + * If called as lsb use YMODEM protocol + */ +static void +chkinvok (const char *s) +{ + const char *p; + + p = s; + while (*p == '-') + s = ++p; + while (*p) + if (*p++ == '/') + s = p; + if (*s == 'v') { + Verbose = 1; + ++s; + } + program_name = s; + if (*s == 'l') + s++; /* lsz -> sz */ + protocol = ZM_ZMODEM; + if (s[0] == 's' && s[1] == 'x') + protocol = ZM_XMODEM; + if (s[0] == 's' && (s[1] == 'b' || s[1] == 'y')) { + protocol = ZM_YMODEM; + } +} + +static void +countem (int argc, char **argv) +{ + struct stat f; + + for (Totalleft = 0, Filesleft = 0; --argc >= 0; ++argv) { + f.st_size = -1; + if (Verbose > 2) { + vstringf ("\nCountem: %03d %s ", argc, *argv); + } + if (access (*argv, R_OK) >= 0 && stat (*argv, &f) >= 0) { +#if defined(S_ISDIR) + if (!S_ISDIR(f.st_mode) && !S_ISBLK(f.st_mode)) { +#else + int c; + c = f.st_mode & S_IFMT; + if (c != S_IFDIR && c != S_IFBLK) { +#endif + ++Filesleft; + Totalleft += f.st_size; + } + } else if (strcmp (*argv, "-") == 0) { + ++Filesleft; + Totalleft += DEFBYTL; + } + if (Verbose > 2) + vstringf (" %ld", (long) f.st_size); + } + if (Verbose > 2) + vstringf (_("\ncountem: Total %d %ld\n"), + Filesleft, Totalleft); + calc_blklen (Totalleft); +} + +/* End of lsz.c */ + + diff --git a/protname.c b/protname.c new file mode 100644 index 0000000..c33657a --- /dev/null +++ b/protname.c @@ -0,0 +1,41 @@ +/* + protname.c - return the name of the protocol used + 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. + +*/ +#include "zglobal.h" + +/* this code was duplicate in lrz.c and lsz.c */ + +const char * +protname(void) +{ + const char *prot_name; + switch(protocol) { + case ZM_XMODEM: + prot_name="XMODEM"; + break; + case ZM_YMODEM: + prot_name="YMODEM"; + break; + default: + prot_name="ZMODEM"; + break; + } + return prot_name; +} @@ -0,0 +1,506 @@ +/* + rbsb.c - terminal handling stuff for lrzsz + 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 +*/ + +/* + * Rev 05-05-1988 + * ============== (not quite, but originated there :-). -- uwe + */ +#include "zglobal.h" + +#include <stdio.h> +#include <errno.h> + +#ifndef HAVE_ERRNO_DECLARATION +extern int errno; +#endif + +#ifdef USE_SGTTY +# ifdef LLITOUT +long Locmode; /* Saved "local mode" for 4.x BSD "new driver" */ +long Locbit = LLITOUT; /* Bit SUPPOSED to disable output translations */ +# endif +#endif + +#ifdef HAVE_SYS_IOCTL_H +#include <sys/ioctl.h> +#endif + +#ifdef MAJOR_IN_MKDEV +#include <sys/mkdev.h> +#else +# ifdef MAJOR_IN_SYSMACROS +# include <sys/sysmacros.h> +# endif +#endif + +#if defined(HOWMANY) && HOWMANY > 255 +#ifndef NFGVMIN +Howmany must be 255 or less +#endif +#endif + +static struct { + unsigned baudr; + speed_t speedcode; +} speeds[] = { + {110, B110}, + {300, B300}, + {600, B600}, + {1200, B1200}, + {2400, B2400}, + {4800, B4800}, + {9600, B9600}, +#ifdef B19200 + {19200, B19200}, +#endif +#ifdef B38400 + {38400, B38400}, +#endif +#ifdef B57600 + {57600, B57600}, +#endif +#ifdef B115200 + {115200, B115200}, +#endif +#ifdef B230400 + {230400, B230400}, +#endif +#ifdef B460800 + {460800, B460800}, +#endif +#ifdef EXTA + {19200, EXTA}, +#endif +#ifdef EXTB + {38400, EXTB}, +#endif + {0, 0} +}; + +static unsigned getspeed __P((speed_t)); + +static unsigned +getspeed(speed_t code) +{ + int n; + for (n=0; speeds[n].baudr; ++n) + if (speeds[n].speedcode == code) + return speeds[n].baudr; + return 38400; /* Assume fifo if ioctl failed */ +} + +/* + * return 1 if stdout and stderr are different devices + * indicating this program operating with a modem on a + * different line + */ +int Fromcu; /* Were called from cu or yam */ +int +from_cu(void) +{ +#ifdef HAVE_ST_RDEV + struct stat a, b; +#if defined(makedev) + dev_t help=makedev(0,0); +#else + int help=0; +#endif + + /* in case fstat fails */ + a.st_rdev=b.st_rdev=a.st_dev=b.st_dev=help; + + fstat(1, &a); fstat(2, &b); + +#if defined(major) && defined(minor) + if (major(a.st_rdev) != major(b.st_rdev) + || minor(a.st_rdev) != minor(b.st_rdev)) + Fromcu=1; + else if (major(a.st_dev) != major(b.st_dev) + || minor(a.st_dev) != minor(b.st_dev)) + Fromcu=1; + else + Fromcu=0; +#else + Fromcu = (a.st_rdev != b.st_rdev) || (a.st_dev != b.st_dev); +#endif +#else + Fromcu = 1; /* a bad guess .. */ +#endif + return Fromcu; +} + + + +int Twostop; /* Use two stop bits */ + + +#ifdef READCHECK_FIONREAD +/* + * Return non 0 if something to read from io descriptor f + */ +int +rdchk(int fd) +{ + static long lf; + + ioctl(fd, FIONREAD, &lf); + return ((int) lf); +} +#endif + +#ifdef READCHECK_GETFL +unsigned char checked = '\0' ; +/* + * Nonblocking I/O is a bit different in System V, Release 2 + */ +int +rdchk(int fd) +{ + int lf, savestat; + + savestat = fcntl(fd, F_GETFL) ; + if (savestat == -1) + return 0; +#ifdef OVERLY_PARANOID + if (-1==fcntl(fd, F_SETFL, savestat | O_NDELAY)) + return 0; + lf = read(fd, &checked, 1) ; + if (-1==fcntl(fd, F_SETFL, savestat)) { +#ifdef ENABLE_SYSLOG + if (enable_syslog) + lsyslog(LOG_CRIT,"F_SETFL failed in rdchk(): %s", + strerror(errno)); +#endif + zpfatal("rdchk: F_SETFL failed\n"); /* lose */ + /* there is really no way to recover. And we can't tell + * the other side what's going on if we can't write to + * fd, but we try. + */ + canit(fd); + exit(1); + } +#else + fcntl(fd, F_SETFL, savestat | O_NDELAY); + lf = read(fd, &checked, 1) ; + fcntl(fd, F_SETFL, savestat); +#endif + return(lf == -1 && errno==EWOULDBLOCK ? 0 : lf) ; +} +#endif + + + + + +#ifdef USE_TERMIOS +struct termios oldtty, tty; +#else +# if defined(USE_TERMIO) +struct termio oldtty, tty; +# else +struct sgttyb oldtty, tty; +struct tchars oldtch, tch; +# endif +#endif + + +/* + * mode(n) + * 3: save old tty stat, set raw mode with flow control + * 2: set XON/XOFF for sb/sz with ZMODEM or YMODEM-g + * 1: save old tty stat, set raw mode + * 0: restore original tty mode + */ +int +io_mode(int fd, int n) +{ + static int did0 = FALSE; + + vfile("mode:%d", n); + + switch(n) { + +#ifdef USE_TERMIOS + case 2: /* Un-raw mode used by sz, sb when -g detected */ + if(!did0) { + did0 = TRUE; + tcgetattr(fd,&oldtty); + } + tty = oldtty; + + tty.c_iflag = BRKINT|IXON; + + tty.c_oflag = 0; /* Transparent output */ + + tty.c_cflag &= ~PARENB; /* Disable parity */ + tty.c_cflag |= CS8; /* Set character size = 8 */ + if (Twostop) + tty.c_cflag |= CSTOPB; /* Set two stop bits */ + +#ifdef READCHECK + tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG; + tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030; /* Interrupt char */ +#else + tty.c_lflag = 0; + tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? 03 : 030; /* Interrupt char */ +#endif +#ifdef _POSIX_VDISABLE + if (((int) _POSIX_VDISABLE)!=(-1)) { + tty.c_cc[VQUIT] = _POSIX_VDISABLE; /* Quit char */ + } else { + tty.c_cc[VQUIT] = -1; /* Quit char */ + } +#else + tty.c_cc[VQUIT] = -1; /* Quit char */ +#endif +#ifdef NFGVMIN + tty.c_cc[VMIN] = 1; +#else + tty.c_cc[VMIN] = 3; /* This many chars satisfies reads */ +#endif + tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ + + tcsetattr(fd,TCSADRAIN,&tty); + + return OK; + case 1: + case 3: + if(!did0) { + did0 = TRUE; + tcgetattr(fd,&oldtty); + } + tty = oldtty; + + tty.c_iflag = IGNBRK; + if (n==3) /* with flow control */ + tty.c_iflag |= IXOFF; + + /* Setup raw mode: no echo, noncanonical (no edit chars), + * no signal generating chars, and no extended chars (^V, + * ^O, ^R, ^W). + */ + tty.c_lflag &= ~(ECHO | ICANON | ISIG | IEXTEN); + tty.c_oflag = 0; /* Transparent output */ + + tty.c_cflag &= ~(PARENB); /* Same baud rate, disable parity */ + /* Set character size = 8 */ + tty.c_cflag &= ~(CSIZE); + tty.c_cflag |= CS8; + if (Twostop) + tty.c_cflag |= CSTOPB; /* Set two stop bits */ +#ifdef NFGVMIN + tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */ +#else + tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */ +#endif + tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ + tcsetattr(fd,TCSADRAIN,&tty); + Baudrate = getspeed(cfgetospeed(&tty)); + return OK; + case 0: + if(!did0) + return ERROR; + tcdrain (fd); /* wait until everything is sent */ + tcflush (fd,TCIOFLUSH); /* flush input queue */ + tcsetattr (fd,TCSADRAIN,&oldtty); + tcflow (fd,TCOON); /* restart output */ + + return OK; +#endif + +#ifdef USE_TERMIO + case 2: /* Un-raw mode used by sz, sb when -g detected */ + if(!did0) + (void) ioctl(fd, TCGETA, &oldtty); + tty = oldtty; + + tty.c_iflag = BRKINT|IXON; + + tty.c_oflag = 0; /* Transparent output */ + + tty.c_cflag &= ~PARENB; /* Disable parity */ + tty.c_cflag |= CS8; /* Set character size = 8 */ + if (Twostop) + tty.c_cflag |= CSTOPB; /* Set two stop bits */ + + +#ifdef READCHECK + tty.c_lflag = protocol==ZM_ZMODEM ? 0 : ISIG; + tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? -1 : 030; /* Interrupt char */ +#else + tty.c_lflag = 0; + tty.c_cc[VINTR] = protocol==ZM_ZMODEM ? 03 : 030; /* Interrupt char */ +#endif + tty.c_cc[VQUIT] = -1; /* Quit char */ +#ifdef NFGVMIN + tty.c_cc[VMIN] = 1; +#else + tty.c_cc[VMIN] = 3; /* This many chars satisfies reads */ +#endif + tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ + + (void) ioctl(fd, TCSETAW, &tty); + did0 = TRUE; + return OK; + case 1: + case 3: + if(!did0) + (void) ioctl(fd, TCGETA, &oldtty); + tty = oldtty; + + tty.c_iflag = n==3 ? (IGNBRK|IXOFF) : IGNBRK; + + /* No echo, crlf mapping, delays, no erase/kill */ + tty.c_lflag &= ~(ECHO | ICANON | ISIG); + + tty.c_oflag = 0; /* Transparent output */ + + tty.c_cflag &= ~PARENB; /* Same baud rate, disable parity */ + tty.c_cflag |= CS8; /* Set character size = 8 */ + if (Twostop) + tty.c_cflag |= CSTOPB; /* Set two stop bits */ +#ifdef NFGVMIN + tty.c_cc[VMIN] = 1; /* This many chars satisfies reads */ +#else + tty.c_cc[VMIN] = HOWMANY; /* This many chars satisfies reads */ +#endif + tty.c_cc[VTIME] = 1; /* or in this many tenths of seconds */ + (void) ioctl(fd, TCSETAW, &tty); + did0 = TRUE; + Baudrate = getspeed(tty.c_cflag & CBAUD); + return OK; + case 0: + if(!did0) + return ERROR; + (void) ioctl(fd, TCSBRK, 1); /* Wait for output to drain */ + (void) ioctl(fd, TCFLSH, 0); /* Flush input queue */ + (void) ioctl(fd, TCSETAW, &oldtty); /* Restore modes */ + (void) ioctl(fd, TCXONC,1); /* Restart output */ + return OK; +#endif + + +#ifdef USE_SGTTY + /* + * NOTE: this should transmit all 8 bits and at the same time + * respond to XOFF/XON flow control. If no FIONREAD or other + * READCHECK alternative, also must respond to INTRRUPT char + * This doesn't work with V7. It should work with LLITOUT, + * but LLITOUT was broken on the machine I tried it on. + */ + case 2: /* Un-raw mode used by sz, sb when -g detected */ + if(!did0) { + ioctl(fd, TIOCEXCL, 0); + ioctl(fd, TIOCGETP, &oldtty); + ioctl(fd, TIOCGETC, &oldtch); +#ifdef LLITOUT + ioctl(fd, TIOCLGET, &Locmode); +#endif + } + tty = oldtty; + tch = oldtch; +#ifdef READCHECK + tch.t_intrc = Zmodem ? -1:030; /* Interrupt char */ +#else + tch.t_intrc = Zmodem ? 03:030; /* Interrupt char */ +#endif + tty.sg_flags |= (ODDP|EVENP|CBREAK); + tty.sg_flags &= ~(ALLDELAY|CRMOD|ECHO|LCASE); + ioctl(fd, TIOCSETP, &tty); + ioctl(fd, TIOCSETC, &tch); +#ifdef LLITOUT + ioctl(fd, TIOCLBIS, &Locbit); +#else + bibi(99); /* un-raw doesn't work w/o lit out */ +#endif + did0 = TRUE; + return OK; + case 1: + case 3: + if(!did0) { + ioctl(fd, TIOCEXCL, 0); + ioctl(fd, TIOCGETP, &oldtty); + ioctl(fd, TIOCGETC, &oldtch); +#ifdef LLITOUT + ioctl(fd, TIOCLGET, &Locmode); +#endif + } + tty = oldtty; + tty.sg_flags |= RAW; + tty.sg_flags &= ~ECHO; + ioctl(fd, TIOCSETP, &tty); + did0 = TRUE; + Baudrate = getspeed(tty.sg_ospeed); + return OK; + case 0: + if(!did0) + return ERROR; + ioctl(fd, TIOCSETP, &oldtty); + ioctl(fd, TIOCSETC, &oldtch); + ioctl(fd, TIOCNXCL, 0); +#ifdef LLITOUT + ioctl(fd, TIOCLSET, &Locmode); +#endif +#ifdef TIOCFLUSH + { int x=1; ioctl(fd,TIOCFLUSH,&x); } +#endif +#endif + + return OK; + default: + return ERROR; + } +} + +void +sendbrk(int fd) +{ +#ifdef USE_TERMIOS + tcsendbreak(fd,0); +#endif +#ifdef USE_TERMIO + ioctl(fd, TCSBRK, 0); +#endif +#ifdef USE_SGTTY +#ifdef TIOCSBRK + sleep(1); + ioctl(fd, TIOCSBRK, 0); + sleep(1); + ioctl(fd, TIOCCBRK, 0); +#endif +#endif +} + +void +purgeline(int fd) +{ + readline_purge(); +#ifdef TCFLSH + ioctl(fd, TCFLSH, 0); +#else + lseek(fd, 0L, 2); +#endif +} + +/* End of rbsb.c */ @@ -0,0 +1,169 @@ +/* + tcp.c - tcp handling for lrzsz + Copyright (C) 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 Uwe Ohse +*/ + +#include "config.h" + +#include <sys/types.h> +#include <sys/socket.h> +#include <netinet/in.h> +#include <netdb.h> +#ifdef HAVE_ARPA_INET_H +#include <arpa/inet.h> +#endif +#include <errno.h> +#include <ctype.h> +#include <stdio.h> +#include <signal.h> + +#include "zglobal.h" +#include <stdlib.h> +#include "error.h" + +static RETSIGTYPE +tcp_alarm_handler(int dummy) +{ + dummy++; /* doesn't need to do anything */ +} + + +/* server/lsz: + * Get a TCP socket, bind it, listen, figure out the port, + * and build the magic string for lrz in "buf". + */ +int +tcp_server (char *buf) +{ + int sock; + struct sockaddr_in s; + struct sockaddr_in t; + int on=1; + socklen_t len; + + if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + error(1,errno,"socket"); + } + if (setsockopt(sock, SOL_SOCKET, SO_REUSEADDR, (char *)&on, sizeof (on)) < 0) { + error(1,errno,"setsockopt (reuse address)"); + } + memset (&s, 0, sizeof (s)); + s.sin_family = AF_INET; + s.sin_port=0; /* let system fill it in */ + s.sin_addr.s_addr=htonl(INADDR_ANY); + if (bind(sock, (struct sockaddr *)&s, sizeof (s)) < 0) { + error(1,errno,"bind"); + } + len=sizeof(t); + if (getsockname (sock, (struct sockaddr *) &t, &len)) { + error(1,errno,"getsockname"); + } + sprintf(buf,"[%s] <%d>\n",inet_ntoa(t.sin_addr),ntohs(t.sin_port)); + + if (listen(sock, 1) < 0) { + error(1,errno,"listen"); + } + getsockname (sock, (struct sockaddr *) &t, &len); + + return (sock); +} + +/* server/lsz: accept a connection */ +int +tcp_accept (int d) +{ + int so; + struct sockaddr_in s; + socklen_t namelen; + int num=0; + + namelen = sizeof(s); + memset((char*)&s,0, namelen); + +retry: + signal(SIGALRM, tcp_alarm_handler); + alarm(30); + if ((so = accept(d, (struct sockaddr*)&s, &namelen)) < 0) { + if (errno == EINTR) { + if (++num<=5) + goto retry; + } + error(1,errno,"accept"); + } + alarm(0); + return so; +} + +/* client/lrz: + * "Connect" to the TCP socket decribed in "buf" and + * return the connected socket. + */ +int +tcp_connect (char *buf) +{ + int sock; + struct sockaddr_in s_in; + char *p; + char *q; + + memset(&s_in,0,sizeof(s_in)); + s_in.sin_family = AF_INET; + + /* i _really_ distrust scanf & co. Or maybe i distrust bad input */ + if (*buf!='[') { + error(1,0,_("tcp_connect: illegal format1\n")); + } + p=strchr(buf+1,']'); + if (!p) { + error(1,0,_("tcp_connect: illegal format2\n")); + } + *p++=0; + s_in.sin_addr.s_addr=inet_addr(buf+1); +#ifndef INADDR_NONE +#define INADDR_NONE (-1) +#endif + if (s_in.sin_addr.s_addr== (unsigned long) INADDR_NONE) { + struct hostent *h=gethostbyname(buf+1); + if (!h) + error(1,0,_("tcp_connect: illegal format3\n")); + memcpy(& s_in.sin_addr.s_addr,h->h_addr,h->h_length); + } + while (isspace((unsigned char)(*p))) + p++; + if (*p!='<') { + error(1,0,_("tcp_connect: illegal format4\n")); + } + q=strchr(p+1,'>'); + if (!q) + error(1,0,_("tcp_connect: illegal format5\n")); + s_in.sin_port = htons(strtol(p+1,NULL,10)); + + if ((sock = socket (AF_INET, SOCK_STREAM, IPPROTO_TCP)) < 0) { + error(1,errno,"socket"); + } + + signal(SIGALRM, tcp_alarm_handler); + alarm(30); + if (connect (sock, (struct sockaddr *) &s_in, sizeof (s_in)) < 0) { + error(1,errno,"connect"); + } + alarm(0); + return (sock); +} diff --git a/timing.c b/timing.c new file mode 100644 index 0000000..d776fc7 --- /dev/null +++ b/timing.c @@ -0,0 +1,186 @@ +/* + timing.c - Timing routines for computing elapsed wall time + Copyright (C) 1994 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 Michael D. Black, mblack@csihq.com +*/ + +#include "zglobal.h" + +#include "timing.h" + +#if HAVE_SYS_PARAM_H +#include <sys/param.h> +#endif + +#if !defined(TIME_WITH_SYS_TIME) && !defined(HAVE_SYS_TIME_H) + /* can't use gettimeofday without struct timeval */ +# undef HAVE_GETTIMEOFDAY +#endif + +/* Prefer gettimeofday to ftime to times. */ +#if defined(HAVE_GETTIMEOFDAY) +# undef HAVE_FTIME +# undef HAVE_TIMES +#else +# if defined(HAVE_FTIME) +# undef HAVE_TIMES +# endif +#endif + +#ifdef HAVE_FTIME +# include <sys/timeb.h> +#endif + +#ifdef HAVE_TIMES +# if HAVE_SYS_TIMES_H +# include <sys/times.h> +# endif +# ifdef _SC_CLK_TCK +# define HAVE_SC_CLK_TCK 1 +# else +# define HAVE_SC_CLK_TCK 0 +# endif +/* TIMES_TICK may have been set in policy.h, or we may be able to get + it using sysconf. If neither is the case, try to find a useful + definition from the system header files. */ +# if !defined(TIMES_TICK) && (!defined(HAVE_SYSCONF) || !defined(HAVE_SC_CLK_TCK)) +# ifdef CLK_TCK +# define TIMES_TICK CLK_TCK +# else /* ! defined (CLK_TCK) */ +# ifdef HZ +# define TIMES_TICK HZ +# endif /* defined (HZ) */ +# endif /* ! defined (CLK_TCK) */ +#else +# endif /* TIMES_TICK == 0 && (! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK) */ +# ifndef TIMES_TICK +# define TIMES_TICK 0 +# endif +#endif /* HAVE_TIMES */ + +#ifdef HAVE_GETTIMEOFDAY +/* collides with Solaris 2.5 prototype? */ +/* int gettimeofday (struct timeval *tv, struct timezone *tz); */ +#endif + +double +timing (int reset, time_t *nowp) +{ + static double elaptime, starttime, stoptime; + double yet; +#define NEED_TIME +#ifdef HAVE_GETTIMEOFDAY + struct timeval tv; + struct timezone tz; + +#ifdef DST_NONE + tz.tz_dsttime = DST_NONE; +#else + tz.tz_dsttime = 0; +#endif + gettimeofday (&tv, &tz); + yet=tv.tv_sec + tv.tv_usec/1000000.0; +#undef NEED_TIME +#endif +#ifdef HAVE_FTIME + static int fbad=0; + + if (! fbad) + { + struct timeb stime; + static struct timeb slast; + + (void) ftime (&stime); + + /* On some systems, such as SCO 3.2.2, ftime can go backwards in + time. If we detect this, we switch to using time. */ + if (slast.time != 0 + && (stime.time < slast.time + || (stime.time == slast.time && stime.millitm < slast.millitm))) + fbad = 1; + else + { + yet = stime.millitm / 1000.0 + stime.time; + slast = stime; + } + } + if (fbad) + yet=(double) time(NULL); +#undef NEED_TIME +#endif + +#ifdef HAVE_TIMES + struct tms s; + long i; + static int itick; + + if (itick == 0) + { +#if TIMES_TICK == 0 +#if HAVE_SYSCONF && HAVE_SC_CLK_TCK + itick = (int) sysconf (_SC_CLK_TCK); +#else /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */ + const char *z; + + z = getenv ("HZ"); + if (z != NULL) + itick = (int) strtol (z, (char **) NULL, 10); + + /* If we really couldn't get anything, just use 60. */ + if (itick == 0) + itick = 60; +#endif /* ! HAVE_SYSCONF || ! HAVE_SC_CLK_TCK */ +#else /* TIMES_TICK != 0 */ + itick = TIMES_TICK; +#endif /* TIMES_TICK == 0 */ + } + yet = ((double) times (&s)) / itick; +#undef NEED_TIME +#endif + +#ifdef NEED_TIME + yet=(double) time(NULL); +#endif + if (nowp) + *nowp=(time_t) yet; + if (reset) { + starttime = yet; + return starttime; + } + else { + stoptime = yet; + elaptime = stoptime - starttime; + return elaptime; + } +} + +/*#define TEST*/ +#ifdef TEST +main() +{ + int i; + printf("timing %g\n",timing(1)); + printf("timing %g\n",timing(0)); + for(i=0;i<20;i++){ + sleep(1); + printf("timing %g\n",timing(0)); + } +} +#endif diff --git a/timing.h b/timing.h new file mode 100644 index 0000000..41c7c9d --- /dev/null +++ b/timing.h @@ -0,0 +1 @@ +double timing __P ((int reset,time_t *now)); diff --git a/xstrtol.c b/xstrtol.c new file mode 100644 index 0000000..d7b4b56 --- /dev/null +++ b/xstrtol.c @@ -0,0 +1,180 @@ +/* A more useful interface to strtol. + Copyright (C) 1995, 1996 Free Software Foundation, Inc. + + 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. */ + +/* Jim Meyering (meyering@na-net.ornl.gov) */ + +#ifdef HAVE_CONFIG_H +#include <config.h> +#endif + +#ifdef STDC_HEADERS +#include <stdlib.h> +#endif + +#ifdef HAVE_STRING_H +# include <string.h> +#else +# include <strings.h> +# ifndef strchr +# define strchr index +# endif +#endif + +#define NDEBUG +#include <assert.h> + +#include <errno.h> +#ifndef errno +extern int errno; +#endif + +#if HAVE_LIMITS_H +# include <limits.h> +#endif + +#ifndef ULONG_MAX +# define ULONG_MAX ((unsigned long) ~(unsigned long) 0) +#endif + +#ifndef LONG_MAX +# define LONG_MAX ((long int) (ULONG_MAX >> 1)) +#endif + +#include "xstrtol.h" + +#define BKM_SCALE(x, scale_factor, error_return) \ + do \ + { \ + if ((x) > (double) __ZLONG_MAX / (scale_factor)) \ + return (error_return); \ + (x) *= (scale_factor); \ + } \ + while (0) + +__unsigned long int __strtol (); + +/* FIXME: comment. */ + +strtol_error +#ifdef __cplusplus +__xstrtol (const char *s, char **ptr, int base, + __unsigned long int *val, const char *valid_suffixes) +#else +__xstrtol (s, ptr, base, val, valid_suffixes) + const char *s; + char **ptr; + int base; + __unsigned long int *val; + const char *valid_suffixes; +#endif +{ + char *t_ptr; + char **p; + __unsigned long int tmp; + + assert (0 <= base && base <= 36); + + p = (ptr ? ptr : &t_ptr); + + errno = 0; + tmp = __strtol (s, p, base); + if (errno != 0) + return LONGINT_OVERFLOW; + if (*p == s) + return LONGINT_INVALID; + if (!valid_suffixes) + { + if (**p == '\0') + { + *val = tmp; + return LONGINT_OK; + } + else + return LONGINT_INVALID_SUFFIX_CHAR; + } + + if (**p != '\0' && strchr (valid_suffixes, **p)) + { + switch (**p) + { + case 'b': + BKM_SCALE (tmp, 512, LONGINT_OVERFLOW); + ++(*p); + break; + + case 'c': + ++(*p); + break; + + case 'B': + case 'k': + BKM_SCALE (tmp, 1024, LONGINT_OVERFLOW); + ++(*p); + break; + + case 'm': + BKM_SCALE (tmp, 1024 * 1024, LONGINT_OVERFLOW); + ++(*p); + break; + + case 'w': + BKM_SCALE (tmp, 2, LONGINT_OVERFLOW); + ++(*p); + break; + + default: + return LONGINT_INVALID_SUFFIX_CHAR; + break; + } + } + + *val = tmp; + return LONGINT_OK; +} + +#ifdef TESTING_XSTRTO + +#include <stdio.h> +#include "error.h" + +char *program_name; + +int +main (int argc, char** argv) +{ + strtol_error s_err; + int i; + + program_name = argv[0]; + for (i=1; i<argc; i++) + { + char *p; + __unsigned long int val; + + s_err = __xstrtol (argv[i], &p, 0, &val, "bckmw"); + if (s_err == LONGINT_OK) + { + printf ("%s->%lu (%s)\n", argv[i], val, p); + } + else + { + STRTOL_FATAL_ERROR (argv[i], "arg", s_err); + } + } + exit (0); +} +#endif /* TESTING_XSTRTO */ diff --git a/xstrtol.h b/xstrtol.h new file mode 100644 index 0000000..fd0c97f --- /dev/null +++ b/xstrtol.h @@ -0,0 +1,66 @@ +#ifndef _xstrtol_h_ +#define _xstrtol_h_ 1 + +#if STRING_TO_UNSIGNED +# define __xstrtol xstrtoul +# define __strtol strtoul +# define __unsigned unsigned +# define __ZLONG_MAX ULONG_MAX +#else +# define __xstrtol xstrtol +# define __strtol strtol +# define __unsigned /* empty */ +# define __ZLONG_MAX LONG_MAX +#endif + +#undef __P +#if defined (__STDC__) && __STDC__ +#define __P(x) x +#else +#define __P(x) () +#endif + +enum strtol_error + { + LONGINT_OK, LONGINT_INVALID, LONGINT_INVALID_SUFFIX_CHAR, LONGINT_OVERFLOW + }; +typedef enum strtol_error strtol_error; + +strtol_error + __xstrtol __P ((const char *s, char **ptr, int base, + __unsigned long int *val, const char *valid_suffixes)); + +#define _STRTOL_ERROR(exit_code, str, argument_type_string, err) \ + do \ + { \ + switch ((err)) \ + { \ + case LONGINT_OK: \ + abort (); \ + \ + case LONGINT_INVALID: \ + error ((exit_code), 0, "invalid %s `%s'", \ + (argument_type_string), (str)); \ + break; \ + \ + case LONGINT_INVALID_SUFFIX_CHAR: \ + error ((exit_code), 0, "invalid character following %s `%s'", \ + (argument_type_string), (str)); \ + break; \ + \ + case LONGINT_OVERFLOW: \ + /* FIXME: make this message dependent on STRING_TO_UNSIGNED */\ + error ((exit_code), 0, "%s `%s' larger than maximum long int",\ + (argument_type_string), (str)); \ + break; \ + } \ + } \ + while (0) + +#define STRTOL_FATAL_ERROR(str, argument_type_string, err) \ + _STRTOL_ERROR (2, str, argument_type_string, err) + +#define STRTOL_FAIL_WARN(str, argument_type_string, err) \ + _STRTOL_ERROR (0, str, argument_type_string, err) + +#endif /* _xstrtol_h_ */ diff --git a/xstrtoul.c b/xstrtoul.c new file mode 100644 index 0000000..8194c17 --- /dev/null +++ b/xstrtoul.c @@ -0,0 +1,2 @@ +#define STRING_TO_UNSIGNED 1 +#include "xstrtol.c" diff --git a/xstrtoul.h b/xstrtoul.h new file mode 100644 index 0000000..8251c57 --- /dev/null +++ b/xstrtoul.h @@ -0,0 +1,7 @@ +#ifndef _xstrtoul_h_ +#define _xstrtoul_h_ 1 + +#define STRING_TO_UNSIGNED 1 +#include "xstrtol.h" + +#endif /* _xstrtoul_h_ */ diff --git a/zglobal.h b/zglobal.h new file mode 100644 index 0000000..0f59dba --- /dev/null +++ b/zglobal.h @@ -0,0 +1,463 @@ +#ifndef ZMODEM_GLOBAL_H +#define ZMODEM_GLOBAL_H + +/* zglobal.h - prototypes etcetera for lrzsz + + Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc) + Copyright (C) 1994 Matt Porter + 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. +*/ + +#include "config.h" +#include <sys/types.h> + +#ifdef __GNUC__ +# define alloca __builtin_alloca +# define HAVE_ALLOCA 1 +#else +# if defined HAVE_ALLOCA_H || defined _LIBC +# include <alloca.h> +# else +# ifdef _AIX +#pragma alloca +# else +# ifndef alloca +# ifndef __GLIBC__ +char *alloca (); +# endif +# endif +# endif +# endif +#endif + +#ifndef __P +#if defined (__GNUC__) || (defined (__STDC__) && __STDC__) +#define __P(args) args +#else +#define __P(args) () +#endif /* GCC. */ +#endif /* Not __P. */ + +#ifdef __STDC__ +#include <stdarg.h> +#else +#include <varargs.h> +#endif + +#ifdef TIME_WITH_SYS_TIME +# include <sys/time.h> +# include <time.h> +# define INCLUDED_SYS_TIME +#else +# ifdef HAVE_SYS_TIME_H +# include <sys/time.h> +# define INCLUDED_SYS_TIME +# else +# include <time.h> +# endif +#endif +#ifdef SYS_TIME_WITHOUT_SYS_SELECT +# ifdef INCLUDED_SYS_TIME +# undef HAVE_SYS_SELECT_H +# endif +#endif + + +#ifdef HAVE_SYS_SELECT_H +# include <sys/select.h> +#endif +#ifdef __BEOS__ + /* BeOS 4.0: sys/select.h is almost completely #ifdefd out */ +#define HAVE_SOCKET_H +#ifdef HAVE_SOCKET_H +#include <socket.h> +#endif +#endif + +#if STDC_HEADERS +# include <string.h> +#else +# ifdef HAVE_STRINGS_H +# include <strings.h> +# endif +# ifndef HAVE_STRCHR +# define strchr index +# define strrchr rindex +# endif +char *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 + +#include <sys/stat.h> + +/* we need to decide whether readcheck is possible */ +#ifdef HAVE_FCNTL_H +# include <fcntl.h> +#endif +#ifdef HAVE_SYS_IOCTL_H +# include <sys/ioctl.h> +#endif +#ifdef HAVE_RDCHK +# define READCHECK +#else +# ifdef FIONREAD +# define READCHECK_FIONREAD +# define READCHECK +# else +# ifdef F_GETFL +# define READCHECK +# define READCHECK_READS +# define READCHECK_GETFL +# endif +# endif +#endif + +/* used to use #elif, but native braindead hpux 9.00 c compiler didn't + * understand it */ +#ifdef HAVE_TERMIOS_H +/* get rid of warnings on SCO ODT 3.2 */ +struct termios; +# include <termios.h> +# define USE_TERMIOS +#else +# if defined(HAVE_SYS_TERMIOS_H) +# include <sys/termios.h> +# define USE_TERMIOS +# else +# if defined(HAVE_TERMIO_H) +# include <termio.h> +# define USE_TERMIO +# else +# if defined(HAVE_SYS_TERMIO_H) +# include <sys/termio.h> +# define USE_TERMIO +# else +# if defined(HAVE_SGTTY_H) +# include <sgtty.h> +# define USE_SGTTY +# ifdef LLITOUT + extern long Locmode; /* Saved "local mode" for 4.x BSD "new driver" */ + extern long Locbit; /* Bit SUPPOSED to disable output translations */ +# endif +# else +# error neither termio.h nor sgtty.h found. Cannot continue. +# endif +# endif +# endif +# endif +#endif + +#ifdef USE_SGTTY +# ifdef TIOCSBRK +# define CANBREAK +# endif +#endif +#ifdef USE_TERMIO +# define CANBREAK +#endif + + + +/* Take care of NLS matters. */ +#if HAVE_LOCALE_H +# include <locale.h> +#endif +#if !HAVE_SETLOCALE +# define setlocale(Category, Locale) /* empty */ +#endif + +#if ENABLE_NLS +# include <libintl.h> +# define _(Text) gettext (Text) +#else +# define bindtextdomain(Domain, Directory) /* empty */ +# define textdomain(Domain) /* empty */ +# define _(Text) Text +#endif + +#ifndef ENABLE_SYSLOG +# undef HAVE_SYSLOG +#else +# ifdef HAVE_SYSLOG_H +# include <syslog.h> +# else +# if defined(HAVE_SYS_SYSLOG_H) +# include <sys/syslog.h> +# else +# undef HAVE_SYSLOG +# endif +# endif +#endif +#ifndef ENABLE_SYSLOG +# define openlog(name,pid,facility) /* void it */ +# define setlogmask(x) /* void it */ +#else +extern int enable_syslog; +#endif + +#if defined HAVE_UNISTD_H +# include <unistd.h> +#endif +/* The following is from pathmax.h. */ +/* Non-POSIX BSD systems might have gcc's limits.h, which doesn't define + PATH_MAX but might cause redefinition warnings when sys/param.h is + later included (as on MORE/BSD 4.3). */ +#if defined(_POSIX_VERSION) || (defined(HAVE_LIMITS_H) && !defined(__GNUC__)) +# include <limits.h> +#endif + +#ifndef _POSIX_PATH_MAX +# define _POSIX_PATH_MAX 255 +#endif + +#if !defined(PATH_MAX) && defined(_PC_PATH_MAX) +# define PATH_MAX (pathconf ("/", _PC_PATH_MAX) < 1 ? 1024 : pathconf ("/", _PC_PATH_MAX)) +#endif + +/* Don't include sys/param.h if it already has been. */ +#if defined(HAVE_SYS_PARAM_H) && !defined(PATH_MAX) && !defined(MAXPATHLEN) +# include <sys/param.h> +#endif + +#if !defined(PATH_MAX) && defined(MAXPATHLEN) +# define PATH_MAX MAXPATHLEN +#endif + +#if !defined(LONG_MAX) && defined(HAVE_LIMITS_H) +# include <limits.h> +#endif + +#ifndef PATH_MAX +# define PATH_MAX _POSIX_PATH_MAX +#endif + +#ifdef __GNUC__ + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 5) +# define LRZSZ_ATTRIB_SECTION(x) __attribute__((section(#x))) +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 4) +# define LRZSZ_ATTRIB_CONST __attribute__((__const__)) +#endif + + /* gcc.info sagt, noreturn wäre ab 2.5 verfügbar. HPUX-gcc 2.5.8 + * kann es noch nicht - what's this? + */ +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 5) +# define LRZSZ_ATTRIB_NORET __attribute__((__noreturn__)) +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 5) +# define LRZSZ_ATTRIB_PRINTF(formatnr,firstargnr) \ + __attribute__((__format__ (printf,formatnr,firstargnr))) +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ > 6) +#define LRZSZ_ATTRIB_UNUSED __attribute__((__unused__)) +#endif + +#if __GNUC__ > 2 || (__GNUC__ == 2 && __GNUC_MINOR__ >= 7) +# define LRZSZ_ATTRIB_REGPARM(n) \ + __attribute__((__regparm__ (n))) +#endif +#endif /* __GNUC__ */ +#ifndef LRZSZ_ATTRIB_REGPARM +#define LRZSZ_ATTRIB_REGPARM(n) +#endif +#ifndef LRZSZ_ATTRIB_UNUSED +#define LRZSZ_ATTRIB_UNUSED +#endif +#ifndef LRZSZ_ATTRIB_NORET +#define LRZSZ_ATTRIB_NORET +#endif +#ifndef LRZSZ_ATTRIB_CONST +#define LRZSZ_ATTRIB_CONST +#endif +#ifndef LRZSZ_ATTRIB_PRINTF +#define LRZSZ_ATTRIB_PRINTF(x,y) +#endif +#ifndef LRZSZ_ATTRIB_SECTION +#define LRZSZ_ATTRIB_SECTION(n) +#endif +#undef LRZSZ_ATTRIB_SECTION +#define LRZSZ_ATTRIB_SECTION(x) +#undef LRZSZ_ATTRIB_REGPARM +#define LRZSZ_ATTRIB_REGPARM(x) + + +#define OK 0 +#define FALSE 0 +#define TRUE 1 +#define ERROR (-1) + +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define ENQ 005 +#define CAN ('X'&037) +#define XOFF ('s'&037) +#define XON ('q'&037) +#define SOH 1 +#define STX 2 +#define EOT 4 +#define ACK 6 +#define NAK 025 +#define CPMEOF 032 +#define WANTCRC 0103 /* send C not NAK to get crc not checksum */ +#define WANTG 0107 /* Send G not NAK to get nonstop batch xmsn */ +#define TIMEOUT (-2) +#define RCDO (-3) +#define WCEOT (-10) + +#define RETRYMAX 10 + +#define UNIXFILE 0xF000 /* The S_IFMT file mask bit for stat */ + +#define DEFBYTL 2000000000L /* default rx file size */ + +enum zm_type_enum { + ZM_XMODEM, + ZM_YMODEM, + ZM_ZMODEM +}; + +struct zm_fileinfo { + char *fname; + time_t modtime; + mode_t mode; + size_t bytes_total; + size_t bytes_sent; + size_t bytes_received; + size_t bytes_skipped; /* crash recovery */ + int eof_seen; +}; + +#define R_BYTESLEFT(x) ((x)->bytes_total-(x)->bytes_received) + +extern enum zm_type_enum protocol; + +extern const char *program_name; /* the name by which we were called */ +extern int Verbose; +extern int errors; +extern int no_timeout; +extern int Zctlesc; /* Encode control characters */ +extern int under_rsh; + +RETSIGTYPE bibi __P ((int n)); + +#define sendline(c) putchar((c) & 0377) +#define xsendline(c) putchar(c) + +/* zreadline.c */ +extern char *readline_ptr; /* pointer for removing chars from linbuf */ +extern int readline_left; /* number of buffered chars left to read */ +#define READLINE_PF(timeout) \ + (--readline_left >= 0? (*readline_ptr++ & 0377) : readline_internal(timeout)) + +int readline_internal __P ((unsigned int timeout)); +void readline_purge __P ((void)); +void readline_setup __P ((int fd, size_t readnum, + size_t buffer_size)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); + + +/* rbsb.c */ +extern int Fromcu; +extern int Twostop; +#ifdef READCHECK_READS +extern unsigned char checked; +#endif +extern int iofd; +extern unsigned Baudrate; + +void zperr __P ((const char *fmt, ...)); +void zpfatal __P ((const char *fmt, ...)); +void vfile __P ((const char *format, ...)); +#define vchar(x) putc(x,stderr) +#define vstring(x) fputs(x,stderr) + +#ifdef __GNUC__ +#if __GNUC__ > 1 +#define vstringf(format,args...) fprintf(stderr,format, ##args) +#endif +#endif +#ifndef vstringf +void vstringf __P ((const char *format, ...)); +#endif +#define VPRINTF(level,format_args) do {if ((Verbose)>=(level)) \ + vstringf format_args ; } while(0) + +/* rbsb.c */ +int from_cu __P ((void)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); +int rdchk __P ((int fd)); +int io_mode __P ((int fd, int n)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); +void sendbrk __P ((int fd)); +#define flushmo() fflush(stdout) +void purgeline __P ((int fd)); +void canit __P ((int fd)); + + +/* crctab.c */ +extern unsigned short crctab[256]; +#define updcrc(cp, crc) ( crctab[((crc >> 8) & 255)] ^ (crc << 8) ^ cp) +extern long cr3tab[]; +#define UPDC32(b, c) (cr3tab[((int)c ^ b) & 0xff] ^ ((c >> 8) & 0x00FFFFFF)) + +/* zm.c */ +#include "zmodem.h" +extern unsigned int Rxtimeout; /* Tenths of seconds to wait for something */ +extern int bytes_per_error; /* generate one error around every x bytes */ + +/* Globals used by ZMODEM functions */ +extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ +extern int Rxtype; /* Type of header received */ +extern int Zrwindow; /* RX window size (controls garbage count) */ +/* extern int Rxcount; */ /* Count of data bytes received */ +extern char Rxhdr[4]; /* Received header */ +extern char Txhdr[4]; /* Transmitted header */ +extern long Txpos; /* Transmitted file position */ +extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern int Crc32; /* Display flag indicating 32 bit CRC being received */ +extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ + +extern void zsendline __P ((int c)); +extern void zsendline_init __P ((void)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); +void zsbhdr __P ((int type, char *hdr)); +void zshhdr __P ((int type, char *hdr)); +void zsdata __P ((const char *buf, size_t length, int frameend)); +void zsda32 __P ((const char *buf, size_t length, int frameend)); +int zrdata __P ((char *buf, int length, size_t *received)); +int zgethdr __P ((char *hdr, int eflag, size_t *)); +void stohdr __P ((size_t pos)) LRZSZ_ATTRIB_REGPARM(1); +long rclhdr __P ((char *hdr)) LRZSZ_ATTRIB_REGPARM(1); + +int tcp_server __P ((char *buf)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); +int tcp_connect __P ((char *buf)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); +int tcp_accept __P ((int d)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); + + +const char * protname __P ((void)) LRZSZ_ATTRIB_SECTION(lrzsz_rare); +void lsyslog __P ((int, const char *,...)); + + + + +#endif @@ -0,0 +1,982 @@ +/* + zm.c - zmodem protocol handling lowlevelstuff + Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc) + 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 +*/ +/* historical comment: -- uwe + * Z M . C + * ZMODEM protocol primitives + * 05-09-88 Chuck Forsberg Omen Technology Inc + * + * Entry point Functions: + * zsbhdr(type, hdr) send binary header + * zshhdr(type, hdr) send hex header + * zgethdr(hdr, eflag) receive header - binary or hex + * zsdata(buf, len, frameend) send data + * zrdata(buf, len, bytes_received) receive data + * stohdr(pos) store position data in Txhdr + * long rclhdr(hdr) recover position offset from header + */ + + +#include "zglobal.h" + +#include <stdio.h> + +unsigned int Rxtimeout = 100; /* Tenths of seconds to wait for something */ + +/* Globals used by ZMODEM functions */ +int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ +int Rxtype; /* Type of header received */ +char Rxhdr[4]; /* Received header */ +char Txhdr[4]; /* Transmitted header */ +long Txpos; /* Transmitted file position */ +int Txfcs32; /* TRUE means send binary frames with 32 bit FCS */ +int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +int Crc32; /* Display flag indicating 32 bit CRC being received */ +int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ + +static char lastsent; /* Last char we sent */ +int turbo_escape; +int bytes_per_error=0; + +static const char *frametypes[] = { + "Carrier Lost", /* -3 */ + "TIMEOUT", /* -2 */ + "ERROR", /* -1 */ +#define FTOFFSET 3 + "ZRQINIT", + "ZRINIT", + "ZSINIT", + "ZACK", + "ZFILE", + "ZSKIP", + "ZNAK", + "ZABORT", + "ZFIN", + "ZRPOS", + "ZDATA", + "ZEOF", + "ZFERR", + "ZCRC", + "ZCHALLENGE", + "ZCOMPL", + "ZCAN", + "ZFREECNT", + "ZCOMMAND", + "ZSTDERR", + "xxxxx" +#define FRTYPES 22 /* Total number of frame types in this array */ + /* not including psuedo negative entries */ +}; + +#define badcrc _("Bad CRC") +/* static char *badcrc = "Bad CRC"; */ +static inline int noxrd7 __P ((void)); +static inline int zdlread __P ((void)); +static int zdlread2 __P ((int)) LRZSZ_ATTRIB_REGPARM(1); +static inline int zgeth1 __P ((void)); +static void zputhex __P ((int c, char *pos)); +static inline int zgethex __P ((void)); +static int zrbhdr __P ((char *hdr)); +static int zrbhdr32 __P ((char *hdr)); +static int zrhhdr __P ((char *hdr)); +static char zsendline_tab[256]; +static int zrdat32 __P ((char *buf, int length, size_t *)); +static void zsbh32 __P ((char *hdr, int type)); +static inline void zsendline_s __P((const char *s, size_t count)); + +extern int zmodem_requested; + +#define sendline(c) putchar((c) & 0377) +#define xsendline(c) putchar(c) + +/* + * Read a character from the modem line with timeout. + * Eat parity, XON and XOFF characters. + */ +static inline int +noxrd7(void) +{ + register int c; + + for (;;) { + if ((c = READLINE_PF(Rxtimeout)) < 0) + return c; + switch (c &= 0177) { + case XON: + case XOFF: + continue; + default: + if (Zctlesc && !(c & 0140)) + continue; + case '\r': + case '\n': + case ZDLE: + return c; + } + } +} + +static inline int +zgeth1(void) +{ + register int c, n; + + if ((c = noxrd7()) < 0) + return c; + n = c - '0'; + if (n > 9) + n -= ('a' - ':'); + if (n & ~0xF) + return ERROR; + if ((c = noxrd7()) < 0) + return c; + c -= '0'; + if (c > 9) + c -= ('a' - ':'); + if (c & ~0xF) + return ERROR; + c += (n<<4); + return c; +} + +/* Decode two lower case hex digits into an 8 bit byte value */ +static inline int +zgethex(void) +{ + register int c; + + c = zgeth1(); + VPRINTF(9,("zgethex: %02X", c)); + return c; +} + +/* + * Read a byte, checking for ZMODEM escape encoding + * including CAN*5 which represents a quick abort + */ +static inline int +zdlread(void) +{ + int c; + /* Quick check for non control characters */ + if ((c = READLINE_PF(Rxtimeout)) & 0140) + return c; + return zdlread2(c); +} +/* no, i don't like gotos. -- uwe */ +static int +zdlread2(int c) +{ + goto jump_over; /* bad style */ + +again: + /* Quick check for non control characters */ + if ((c = READLINE_PF(Rxtimeout)) & 0140) + return c; +jump_over: + switch (c) { + case ZDLE: + break; + case XON: + case (XON|0200): + case XOFF: + case (XOFF|0200): + goto again; + default: + if (Zctlesc && !(c & 0140)) { + goto again; + } + return c; + } +again2: + if ((c = READLINE_PF(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0) + return c; + if (c == CAN && (c = READLINE_PF(Rxtimeout)) < 0) + return c; + switch (c) { + case CAN: + return GOTCAN; + case ZCRCE: + case ZCRCG: + case ZCRCQ: + case ZCRCW: + return (c | GOTOR); + case ZRUB0: + return 0177; + case ZRUB1: + return 0377; + case XON: + case (XON|0200): + case XOFF: + case (XOFF|0200): + goto again2; + default: + if (Zctlesc && ! (c & 0140)) { + goto again2; + } + if ((c & 0140) == 0100) + return (c ^ 0100); + break; + } + VPRINTF(2,(_("Bad escape sequence %x"), c)); + return ERROR; +} + + + +/* + * Send character c with ZMODEM escape sequence encoding. + * Escape XON, XOFF. Escape CR following @ (Telenet net escape) + */ +inline void +zsendline(int c) +{ + + switch(zsendline_tab[(unsigned) (c&=0377)]) + { + case 0: + xsendline(lastsent = c); + break; + case 1: + xsendline(ZDLE); + c ^= 0100; + xsendline(lastsent = c); + break; + case 2: + if ((lastsent & 0177) != '@') { + xsendline(lastsent = c); + } else { + xsendline(ZDLE); + c ^= 0100; + xsendline(lastsent = c); + } + break; + } +} + +static inline void +zsendline_s(const char *s, size_t count) +{ + const char *end=s+count; + while(s!=end) { + int last_esc=0; + const char *t=s; + while (t!=end) { + last_esc=zsendline_tab[(unsigned) ((*t) & 0377)]; + if (last_esc) + break; + t++; + } + if (t!=s) { + fwrite(s,(size_t)(t-s),1,stdout); + lastsent=t[-1]; + s=t; + } + if (last_esc) { + int c=*s; + switch(last_esc) { + case 0: + xsendline(lastsent = c); + break; + case 1: + xsendline(ZDLE); + c ^= 0100; + xsendline(lastsent = c); + break; + case 2: + if ((lastsent & 0177) != '@') { + xsendline(lastsent = c); + } else { + xsendline(ZDLE); + c ^= 0100; + xsendline(lastsent = c); + } + break; + } + s++; + } + } +} + + +/* Send ZMODEM binary header hdr of type type */ +void +zsbhdr(int type, char *hdr) +{ + register int n; + register unsigned short crc; + + VPRINTF(3,("zsbhdr: %s %lx", frametypes[type+FTOFFSET], rclhdr(hdr))); + if (type == ZDATA) + for (n = Znulls; --n >=0; ) + xsendline(0); + + xsendline(ZPAD); xsendline(ZDLE); + + Crc32t=Txfcs32; + if (Crc32t) + zsbh32(hdr, type); + else { + xsendline(ZBIN); zsendline(type); crc = updcrc(type, 0); + + for (n=4; --n >= 0; ++hdr) { + zsendline(*hdr); + crc = updcrc((0377& *hdr), crc); + } + crc = updcrc(0,updcrc(0,crc)); + zsendline(crc>>8); + zsendline(crc); + } + if (type != ZDATA) + flushmo(); +} + + +/* Send ZMODEM binary header hdr of type type */ +static void +zsbh32(char *hdr, int type) +{ + register int n; + register unsigned long crc; + + xsendline(ZBIN32); zsendline(type); + crc = 0xFFFFFFFFL; crc = UPDC32(type, crc); + + for (n=4; --n >= 0; ++hdr) { + crc = UPDC32((0377 & *hdr), crc); + zsendline(*hdr); + } + crc = ~crc; + for (n=4; --n >= 0;) { + zsendline((int)crc); + crc >>= 8; + } +} + +/* Send ZMODEM HEX header hdr of type type */ +void +zshhdr(int type, char *hdr) +{ + register int n; + register unsigned short crc; + char s[30]; + size_t len; + + VPRINTF(3,("zshhdr: %s %lx", frametypes[(type & 0x7f)+FTOFFSET], rclhdr(hdr))); + s[0]=ZPAD; + s[1]=ZPAD; + s[2]=ZDLE; + s[3]=ZHEX; + zputhex(type & 0x7f ,s+4); + len=6; + Crc32t = 0; + + crc = updcrc((type & 0x7f), 0); + for (n=4; --n >= 0; ++hdr) { + zputhex(*hdr,s+len); + len += 2; + crc = updcrc((0377 & *hdr), crc); + } + crc = updcrc(0,updcrc(0,crc)); + zputhex(crc>>8,s+len); + zputhex(crc,s+len+2); + len+=4; + + /* Make it printable on remote machine */ + s[len++]=015; + s[len++]=0212; + /* + * Uncork the remote in case a fake XOFF has stopped data flow + */ + if (type != ZFIN && type != ZACK) + { + s[len++]=021; + } + flushmo(); + write(1,s,len); +} + +/* + * Send binary array buf of length length, with ending ZDLE sequence frameend + */ +static const char *Zendnames[] = { "ZCRCE", "ZCRCG", "ZCRCQ", "ZCRCW"}; +void +zsdata(const char *buf, size_t length, int frameend) +{ + register unsigned short crc; + + VPRINTF(3,("zsdata: %lu %s", (unsigned long) length, + Zendnames[(frameend-ZCRCE)&3])); + crc = 0; + do { + zsendline(*buf); crc = updcrc((0377 & *buf), crc); + buf++; + } while (--length>0); + xsendline(ZDLE); xsendline(frameend); + crc = updcrc(frameend, crc); + + crc = updcrc(0,updcrc(0,crc)); + zsendline(crc>>8); zsendline(crc); + if (frameend == ZCRCW) { + xsendline(XON); flushmo(); + } +} + +void +zsda32(const char *buf, size_t length, int frameend) +{ + int c; + unsigned long crc; + int i; + VPRINTF(3,("zsdat32: %d %s", length, Zendnames[(frameend-ZCRCE)&3])); + + crc = 0xFFFFFFFFL; + zsendline_s(buf,length); + for (; length; length--) { + c = *buf & 0377; + crc = UPDC32(c, crc); + buf++; + } + xsendline(ZDLE); xsendline(frameend); + crc = UPDC32(frameend, crc); + + crc = ~crc; + for (i=4; --i >= 0;) { + c=(int) crc; + if (c & 0140) + xsendline(lastsent = c); + else + zsendline(c); + crc >>= 8; + } + if (frameend == ZCRCW) { + xsendline(XON); flushmo(); + } +} + +#if __GNUC__ < 2 || (__GNUC__ == 2 && __GNUC_MINOR__ <= 4) +# undef DEBUG_BLOCKSIZE +#endif + +#ifdef DEBUG_BLOCKSIZE +struct debug_blocksize { + int size; + long count; +}; +struct debug_blocksize blocksizes[]={ + {32,0}, + {64,0}, + {128,0}, + {256,0}, + {512,0}, + {1024,0}, + {2048,0}, + {4096,0}, + {8192,0}, + {0,0} +}; +static inline void +count_blk(int size) +{ + int i; + for (i=0;blocksizes[i].size;i++) { + if (blocksizes[i].size==size) { + blocksizes[i].count++; + return; + } + } + blocksizes[i].count++; +} + +static void printout_blocksizes(void) __attribute__((__destructor__)); +static void +printout_blocksizes(void) +{ + int i; + for (i=0;blocksizes[i].size;i++) { + if (blocksizes[i].count) { + lsyslog(LOG_DEBUG,"%4d byte: %ld blocks\n", + blocksizes[i].size,blocksizes[i].count); + } + } + if (blocksizes[i].count) { + lsyslog(LOG_DEBUG,"unk. byte: %ld blocks", + blocksizes[i].count); + } +} +#define COUNT_BLK(x) count_blk(x) +#else +#define COUNT_BLK(x) +#endif + +/* + * Receive array buf of max length with ending ZDLE sequence + * and CRC. Returns the ending character or error code. + * NB: On errors may store length+1 bytes! + */ +int +zrdata(char *buf, int length, size_t *bytes_received) +{ + register int c; + register unsigned short crc; + register char *end; + register int d; + + *bytes_received=0; + if (Rxframeind == ZBIN32) + return zrdat32(buf, length, bytes_received); + + crc = 0; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + { + d = c; + c &= 0377; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + zperr(badcrc); + return ERROR; + } + *bytes_received = length - (end - buf); + COUNT_BLK(*bytes_received); + VPRINTF(3,("zrdata: %lu %s", (unsigned long) (*bytes_received), + Zendnames[(d-GOTCRCE)&3])); + return d; + } + case GOTCAN: + zperr(_("Sender Canceled")); + return ZCAN; + case TIMEOUT: + zperr(_("TIMEOUT")); + return c; + default: + zperr(_("Bad data subpacket")); + return c; + } + } + *buf++ = c; + crc = updcrc(c, crc); + } + zperr(_("Data subpacket too long")); + return ERROR; +} + +static int +zrdat32(char *buf, int length, size_t *bytes_received) +{ + register int c; + register unsigned long crc; + register char *end; + register int d; + + crc = 0xFFFFFFFFL; end = buf + length; + while (buf <= end) { + if ((c = zdlread()) & ~0377) { +crcfoo: + switch (c) { + case GOTCRCE: + case GOTCRCG: + case GOTCRCQ: + case GOTCRCW: + d = c; + c &= 0377; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if ((c = zdlread()) & ~0377) + goto crcfoo; + crc = UPDC32(c, crc); + if (crc != 0xDEBB20E3) { + zperr(badcrc); + return ERROR; + } + *bytes_received = length - (end - buf); + COUNT_BLK(*bytes_received); + VPRINTF(3,("zrdat32: %lu %s", (unsigned long) *bytes_received, + Zendnames[(d-GOTCRCE)&3])); + return d; + case GOTCAN: + zperr(_("Sender Canceled")); + return ZCAN; + case TIMEOUT: + zperr(_("TIMEOUT")); + return c; + default: + zperr(_("Bad data subpacket")); + return c; + } + } + *buf++ = c; + crc = UPDC32(c, crc); + } + zperr(_("Data subpacket too long")); + return ERROR; +} + +/* + * Read a ZMODEM header to hdr, either binary or hex. + * eflag controls local display of non zmodem characters: + * 0: no display + * 1: display printing characters only + * 2: display all non ZMODEM characters + * On success, set Zmodem to 1, set Rxpos and return type of header. + * Otherwise return negative on error. + * Return ERROR instantly if ZCRCW sequence, for fast error recovery. + */ +int +zgethdr(char *hdr, int eflag, size_t *Rxpos) +{ + register int c, cancount; + unsigned int max_garbage; /* Max bytes before start of frame */ + size_t rxpos=0; /* keep gcc happy */ + + max_garbage = Zrwindow + Baudrate; + Rxframeind = Rxtype = 0; + +startover: + cancount = 5; +again: + /* Return immediate ERROR if ZCRCW sequence seen */ + switch (c = READLINE_PF(Rxtimeout)) { + case RCDO: + case TIMEOUT: + goto fifi; + case CAN: +gotcan: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + switch (c = READLINE_PF(1)) { + case TIMEOUT: + goto again; + case ZCRCW: + c = ERROR; + /* **** FALL THRU TO **** */ + case RCDO: + goto fifi; + default: + break; + case CAN: + if (--cancount <= 0) { + c = ZCAN; goto fifi; + } + goto again; + } + /* **** FALL THRU TO **** */ + default: +agn2: + if ( --max_garbage == 0) { + zperr(_("Garbage count exceeded")); + return(ERROR); + } + if (eflag && ((c &= 0177) & 0140) && Verbose) + vchar(c); + else if (eflag > 1 && Verbose) + vchar(c); + goto startover; + case ZPAD|0200: /* This is what we want. */ + case ZPAD: /* This is what we want. */ + break; + } + cancount = 5; +splat: + switch (c = noxrd7()) { + case ZPAD: + goto splat; + case RCDO: + case TIMEOUT: + goto fifi; + default: + goto agn2; + case ZDLE: /* This is what we want. */ + break; + } + + switch (c = noxrd7()) { + case RCDO: + case TIMEOUT: + goto fifi; + case ZBIN: + Rxframeind = ZBIN; Crc32 = FALSE; + c = zrbhdr(hdr); + break; + case ZBIN32: + Crc32 = Rxframeind = ZBIN32; + c = zrbhdr32(hdr); + break; + case ZHEX: + Rxframeind = ZHEX; Crc32 = FALSE; + c = zrhhdr(hdr); + break; + case CAN: + goto gotcan; + default: + goto agn2; + } + rxpos = hdr[ZP3] & 0377; + rxpos = (rxpos<<8) + (hdr[ZP2] & 0377); + rxpos = (rxpos<<8) + (hdr[ZP1] & 0377); + rxpos = (rxpos<<8) + (hdr[ZP0] & 0377); +fifi: + switch (c) { + case GOTCAN: + c = ZCAN; + /* **** FALL THRU TO **** */ + case ZNAK: + case ZCAN: + case ERROR: + case TIMEOUT: + case RCDO: + zperr(_("Got %s"), frametypes[c+FTOFFSET]); + /* **** FALL THRU TO **** */ + default: + if (c >= -3 && c <= FRTYPES) + VPRINTF(3,("zgethdr: %s %lx", frametypes[c+FTOFFSET], (unsigned long) rxpos)); + else + VPRINTF(3,("zgethdr: %d %lx", c, (unsigned long) rxpos)); + } + if (Rxpos) + *Rxpos=rxpos; + return c; +} + +/* Receive a binary style header (type and position) */ +static int +zrbhdr(char *hdr) +{ + register int c, n; + register unsigned short crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = updcrc(c, 0); + + for (n=4; --n >= 0; ++hdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + *hdr = c; + } + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + if ((c = zdlread()) & ~0377) + return c; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + zperr(badcrc); + return ERROR; + } + protocol = ZM_ZMODEM; + zmodem_requested=TRUE; + return Rxtype; +} + +/* Receive a binary style header (type and position) with 32 bit FCS */ +static int +zrbhdr32(char *hdr) +{ + register int c, n; + register unsigned long crc; + + if ((c = zdlread()) & ~0377) + return c; + Rxtype = c; + crc = 0xFFFFFFFFL; crc = UPDC32(c, crc); +#ifdef DEBUGZ + VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)i); +#endif + + for (n=4; --n >= 0; ++hdr) { + if ((c = zdlread()) & ~0377) + return c; + crc = UPDC32(c, crc); + *hdr = c; +#ifdef DEBUGZ + VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)); +#endif + } + for (n=4; --n >= 0;) { + if ((c = zdlread()) & ~0377) + return c; + crc = UPDC32(c, crc); +#ifdef DEBUGZ + VPRINTF(3,("zrbhdr32 c=%X crc=%lX", c, crc)); +#endif + } + if (crc != 0xDEBB20E3) { + zperr(badcrc); + return ERROR; + } + protocol = ZM_ZMODEM; + zmodem_requested=TRUE; + return Rxtype; +} + + +/* Receive a hex style header (type and position) */ +static int +zrhhdr(char *hdr) +{ + register int c; + register unsigned short crc; + register int n; + + if ((c = zgethex()) < 0) + return c; + Rxtype = c; + crc = updcrc(c, 0); + + for (n=4; --n >= 0; ++hdr) { + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + *hdr = c; + } + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + if ((c = zgethex()) < 0) + return c; + crc = updcrc(c, crc); + if (crc & 0xFFFF) { + zperr(badcrc); return ERROR; + } + switch ( c = READLINE_PF(1)) { + case 0215: + /* **** FALL THRU TO **** */ + case 015: + /* Throw away possible cr/lf */ + READLINE_PF(1); + break; + } + protocol = ZM_ZMODEM; + zmodem_requested=TRUE; + return Rxtype; +} + +/* Write a byte as two hex digits */ +static void +zputhex(int c, char *pos) +{ + static char digits[] = "0123456789abcdef"; + + VPRINTF(9,("zputhex: %02X", c)); + pos[0]=digits[(c&0xF0)>>4]; + pos[1]=digits[c&0x0F]; +} + +void +zsendline_init(void) +{ + int i; + for (i=0;i<256;i++) { + if (i & 0140) + zsendline_tab[i]=0; + else { + switch(i) + { + case ZDLE: + case XOFF: /* ^Q */ + case XON: /* ^S */ + case (XOFF | 0200): + case (XON | 0200): + zsendline_tab[i]=1; + break; + case 020: /* ^P */ + case 0220: + if (turbo_escape) + zsendline_tab[i]=0; + else + zsendline_tab[i]=1; + break; + case 015: + case 0215: + if (Zctlesc) + zsendline_tab[i]=1; + else if (!turbo_escape) + zsendline_tab[i]=2; + else + zsendline_tab[i]=0; + break; + default: + if (Zctlesc) + zsendline_tab[i]=1; + else + zsendline_tab[i]=0; + } + } + } +} + + + +/* Store pos in Txhdr */ +void +stohdr(size_t pos) +{ + long lpos=(long) pos; + Txhdr[ZP0] = lpos; + Txhdr[ZP1] = lpos>>8; + Txhdr[ZP2] = lpos>>16; + Txhdr[ZP3] = lpos>>24; +} + +/* Recover a long integer from a header */ +long +rclhdr(char *hdr) +{ + long l; + + l = (hdr[ZP3] & 0377); + l = (l << 8) | (hdr[ZP2] & 0377); + l = (l << 8) | (hdr[ZP1] & 0377); + l = (l << 8) | (hdr[ZP0] & 0377); + return l; +} + +/* End of zm.c */ diff --git a/zmodem.h b/zmodem.h new file mode 100644 index 0000000..01c9b2e --- /dev/null +++ b/zmodem.h @@ -0,0 +1,142 @@ +/* zmodem.h - ZMODEM protocol constants + + Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc) + 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. + + * 05-23-87 Chuck Forsberg Omen Technology Inc +*/ +#define ZPAD '*' /* 052 Padding character begins frames */ +#define ZDLE 030 /* Ctrl-X Zmodem escape - `ala BISYNC DLE */ +#define ZDLEE (ZDLE^0100) /* Escaped ZDLE as transmitted */ +#define ZBIN 'A' /* Binary frame indicator */ +#define ZHEX 'B' /* HEX frame indicator */ +#define ZBIN32 'C' /* Binary frame with 32 bit FCS */ + +/* Frame types (see array "frametypes" in zm.c) */ +#define ZRQINIT 0 /* Request receive init */ +#define ZRINIT 1 /* Receive init */ +#define ZSINIT 2 /* Send init sequence (optional) */ +#define ZACK 3 /* ACK to above */ +#define ZFILE 4 /* File name from sender */ +#define ZSKIP 5 /* To sender: skip this file */ +#define ZNAK 6 /* Last packet was garbled */ +#define ZABORT 7 /* Abort batch transfers */ +#define ZFIN 8 /* Finish session */ +#define ZRPOS 9 /* Resume data trans at this position */ +#define ZDATA 10 /* Data packet(s) follow */ +#define ZEOF 11 /* End of file */ +#define ZFERR 12 /* Fatal Read or Write error Detected */ +#define ZCRC 13 /* Request for file CRC and response */ +#define ZCHALLENGE 14 /* Receiver's Challenge */ +#define ZCOMPL 15 /* Request is complete */ +#define ZCAN 16 /* Other end canned session with CAN*5 */ +#define ZFREECNT 17 /* Request for free bytes on filesystem */ +#define ZCOMMAND 18 /* Command from sending program */ +#define ZSTDERR 19 /* Output to standard error, data follows */ + +/* ZDLE sequences */ +#define ZCRCE 'h' /* CRC next, frame ends, header packet follows */ +#define ZCRCG 'i' /* CRC next, frame continues nonstop */ +#define ZCRCQ 'j' /* CRC next, frame continues, ZACK expected */ +#define ZCRCW 'k' /* CRC next, ZACK expected, end of frame */ +#define ZRUB0 'l' /* Translate to rubout 0177 */ +#define ZRUB1 'm' /* Translate to rubout 0377 */ + +/* zdlread return values (internal) */ +/* -1 is general error, -2 is timeout */ +#define GOTOR 0400 +#define GOTCRCE (ZCRCE|GOTOR) /* ZDLE-ZCRCE received */ +#define GOTCRCG (ZCRCG|GOTOR) /* ZDLE-ZCRCG received */ +#define GOTCRCQ (ZCRCQ|GOTOR) /* ZDLE-ZCRCQ received */ +#define GOTCRCW (ZCRCW|GOTOR) /* ZDLE-ZCRCW received */ +#define GOTCAN (GOTOR|030) /* CAN*5 seen */ + +/* Byte positions within header array */ +#define ZF0 3 /* First flags byte */ +#define ZF1 2 +#define ZF2 1 +#define ZF3 0 +#define ZP0 0 /* Low order 8 bits of position */ +#define ZP1 1 +#define ZP2 2 +#define ZP3 3 /* High order 8 bits of file position */ + +/* Bit Masks for ZRINIT flags byte ZF0 */ +#define CANFDX 0x01 /* Rx can send and receive true FDX */ +#define CANOVIO 0x02 /* Rx can receive data during disk I/O */ +#define CANBRK 0x04 /* Rx can send a break signal */ +#define CANCRY 0x08 /* Receiver can decrypt */ +#define CANLZW 0x10 /* Receiver can uncompress */ +#define CANFC32 0x20 /* Receiver can use 32 bit Frame Check */ +#define ESCCTL 0x40 /* Receiver expects ctl chars to be escaped */ +#define ESC8 0x80 /* Receiver expects 8th bit to be escaped */ +/* Bit Masks for ZRINIT flags byze ZF1 */ +#define ZF1_CANVHDR 0x01 /* Variable headers OK, unused in lrzsz */ +#define ZF1_TIMESYNC 0x02 /* nonstandard, Receiver request timesync */ + +/* Parameters for ZSINIT frame */ +#define ZATTNLEN 32 /* Max length of attention string */ +/* Bit Masks for ZSINIT flags byte ZF0 */ +#define TESCCTL 0100 /* Transmitter expects ctl chars to be escaped */ +#define TESC8 0200 /* Transmitter expects 8th bit to be escaped */ + +/* Parameters for ZFILE frame */ +/* Conversion options one of these in ZF0 */ +#define ZCBIN 1 /* Binary transfer - inhibit conversion */ +#define ZCNL 2 /* Convert NL to local end of line convention */ +#define ZCRESUM 3 /* Resume interrupted file transfer */ +/* Management include options, one of these ored in ZF1 */ +#define ZF1_ZMSKNOLOC 0x80 /* Skip file if not present at rx */ +/* Management options, one of these ored in ZF1 */ +#define ZF1_ZMMASK 0x1f /* Mask for the choices below */ +#define ZF1_ZMNEWL 1 /* Transfer if source newer or longer */ +#define ZF1_ZMCRC 2 /* Transfer if different file CRC or length */ +#define ZF1_ZMAPND 3 /* Append contents to existing file (if any) */ +#define ZF1_ZMCLOB 4 /* Replace existing file */ +#define ZF1_ZMNEW 5 /* Transfer if source newer */ + /* Number 5 is alive ... */ +#define ZF1_ZMDIFF 6 /* Transfer if dates or lengths different */ +#define ZF1_ZMPROT 7 /* Protect destination file */ +#define ZF1_ZMCHNG 8 /* Change filename if destination exists */ + +/* Transport options, one of these in ZF2 */ +#define ZTLZW 1 /* Lempel-Ziv compression */ +#define ZTCRYPT 2 /* Encryption */ +#define ZTRLE 3 /* Run Length encoding */ +/* Extended options for ZF3, bit encoded */ +#define ZXSPARS 64 /* Encoding for sparse file operations */ + +/* Parameters for ZCOMMAND frame ZF0 (otherwise 0) */ +#define ZCACK1 1 /* Acknowledge, then do command */ + +/* Globals used by ZMODEM functions */ +#if 0 +extern int Rxframeind; /* ZBIN ZBIN32, or ZHEX type of frame received */ +extern int Rxtype; /* Type of header received */ +extern int Zrwindow; /* RX window size (controls garbage count) */ +extern char Rxhdr[4]; /* Received header */ +extern char Txhdr[4]; /* Transmitted header */ +extern long Txpos; /* Transmitted file position */ +extern int Txfcs32; /* TURE means send binary frames with 32 bit FCS */ +extern int Crc32t; /* Display flag indicating 32 bit CRC being sent */ +extern int Crc32; /* Display flag indicating 32 bit CRC being received */ +extern int Znulls; /* Number of nulls to send at beginning of ZDATA hdr */ +extern char Attn[ZATTNLEN+1]; /* Attention string rx sends to tx on err */ +#endif + +/* End of ZMODEM.H */ @@ -0,0 +1,113 @@ +/* + zperr.c - "stderr" output stuff + 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 Uwe Ohse +*/ +#include "zglobal.h" +#include <stdio.h> +#include <stdlib.h> +#include <errno.h> + +#ifdef __STDC__ +# define WAYTOGO +# include <stdarg.h> +# define VA_START(args, lastarg) va_start(args, lastarg) +#else +# include <varargs.h> +# define VA_START(args, lastarg) va_start(args) +#endif + +void +#ifdef WAYTOGO +zperr(const char *fmt, ...) +#else +zperr(fmt, va_alist) + const char *fmt; + va_dcl +#endif +{ + va_list ap; + + if (Verbose<=0) + return; + fprintf(stderr,_("Retry %d: "),errors); + VA_START(ap, fmt); + vfprintf(stderr,fmt, ap); + va_end(ap); + putc('\n',stderr); +} + +void +#ifdef WAYTOGO +zpfatal(const char *fmt, ...) +#else +zpfatal(fmt, va_alist) + const char *fmt; + va_dcl +#endif +{ + va_list ap; + int err=errno; + + if (Verbose<=0) + return; + fprintf(stderr,"%s: ",program_name); + VA_START(ap, fmt); + vfprintf(stderr,fmt, ap); + va_end(ap); + fprintf(stderr,": %s\n",strerror(err)); +} + +void +#ifdef WAYTOGO +vfile(const char *format, ...) +#else +vfile(format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list ap; + + if (Verbose < 3) + return; + VA_START(ap, format); + vfprintf(stderr,format, ap); + va_end(ap); + putc('\n',stderr); +} + +#ifndef vstringf +/* if using gcc this function is not needed */ +void +#ifdef WAYTOGO +vstringf(const char *format, ...) +#else +vstringf(format, va_alist) + const char *format; + va_dcl +#endif +{ + va_list ap; + + VA_START(ap, format); + vfprintf(stderr,format, ap); + va_end(ap); +} +#endif diff --git a/zreadline.c b/zreadline.c new file mode 100644 index 0000000..dd9736b --- /dev/null +++ b/zreadline.c @@ -0,0 +1,136 @@ +/* + zreadline.c - line reading stuff for lrzsz + Copyright (C) until 1998 Chuck Forsberg (OMEN Technology Inc) + Copyright (C) 1994 Matt Porter + 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 +*/ +/* once part of lrz.c, taken out to be useful to lsz.c too */ + +#include "zglobal.h" + +#include <stdlib.h> +#include <stdio.h> +#include <signal.h> +#include <ctype.h> +#include <errno.h> + +#include "error.h" + + +/* Ward Christensen / CP/M parameters - Don't change these! */ +#define TIMEOUT (-2) + +static size_t readline_readnum; +static int readline_fd; +static char *readline_buffer; +int readline_left=0; +char *readline_ptr; + +static RETSIGTYPE +zreadline_alarm_handler(int dummy) +{ + dummy++; /* doesn't need to do anything */ +} + +/* + * This version of readline is reasonably well suited for + * reading many characters. + * + * timeout is in tenths of seconds + */ +int +readline_internal(unsigned int timeout) +{ + + if (!no_timeout) + { + unsigned int n; + n = timeout/10; + if (n < 2 && timeout!=1) + n = 3; + else if (n==0) + n=1; + if (Verbose > 5) + vstringf("Calling read: alarm=%d Readnum=%d ", + n, readline_readnum); + signal(SIGALRM, zreadline_alarm_handler); + alarm(n); + } + else if (Verbose > 5) + vstringf("Calling read: Readnum=%d ", + readline_readnum); + + readline_ptr=readline_buffer; + readline_left=read(readline_fd, readline_ptr, readline_readnum); + if (!no_timeout) + alarm(0); + if (readline_left>0 && bytes_per_error) { + static long ct=0; + static int mod=1; + ct+=readline_left; + while (ct>bytes_per_error) { + readline_ptr[ct % bytes_per_error]^=mod; + ct-=bytes_per_error; + mod++; + if (mod==256) + mod=1; + } + } + if (Verbose > 5) { + vstringf("Read returned %d bytes\n", readline_left); + if (readline_left==-1) + vstringf("errno=%d:%s\n", errno,strerror(errno)); + if (Verbose > 9 && readline_left>0) { + int i,j; + j=readline_left > 48 ? 48 : readline_left; + vstring(" "); + for (i=0;i<j;i++) { + if (i%24==0 && i) + vstring("\n "); + vstringf("%02x ", readline_ptr[i] & 0377); + } + vstringf("\n"); + } + } + if (readline_left < 1) + return TIMEOUT; + --readline_left; + return (*readline_ptr++ & 0377); +} + + + +void +readline_setup(int fd, size_t readnum, size_t bufsize) +{ + readline_fd=fd; + readline_readnum=readnum; + readline_buffer=malloc(bufsize > readnum ? bufsize : readnum); + if (!readline_buffer) + error(1,0,_("out of memory")); +} + +void +readline_purge(void) +{ + readline_left=0; + return; +} + |