ckufio.c
资源名称:cku197.tar.Z [点击查看]
上传用户:dufan58
上传日期:2007-01-05
资源大小:3407k
文件大小:211k
源码类别:
通讯/手机编程
开发平台:
Windows_Unix
- /* C K U F I O -- Kermit file system support for UNIX, Aegis, and Plan 9 */
- #define CK_NONBLOCK /* See zoutdump() */
- #ifdef aegis
- char *ckzv = "Aegis File support, 7.0.156, 30 Dec 1999";
- #else
- #ifdef Plan9
- char *ckzv = "Plan 9 File support, 7.0.156, 30 Dec 1999";
- #else
- char *ckzv = "UNIX File support, 7.0.156, 30 Dec 1999";
- #endif /* Plan9 */
- #endif /* aegis */
- /*
- Author: Frank da Cruz <fdc@columbia.edu>,
- Columbia University Academic Information Systems, New York City,
- and others noted in the comments below. Note: CUCCA = Previous name of
- Columbia University Academic Information Systems.
- Copyright (C) 1985, 2000,
- Trustees of Columbia University in the City of New York.
- All rights reserved. See the C-Kermit COPYING.TXT file or the
- copyright text in the ckcmai.c module for disclaimer and permissions.
- */
- /*
- NOTE TO CONTRIBUTORS: This file, and all the other C-Kermit files, must be
- compatible with C preprocessors that support only #ifdef, #else, #endif,
- #define, and #undef. Please do not use #if, logical operators, or other
- preprocessor features in any of the portable C-Kermit modules. You can,
- of course, use these constructions in platform-specific modules where you
- know they are supported.
- */
- /* Include Files */
- #ifdef MINIX2
- #define _MINIX
- #endif /* MINIX2 */
- #include "ckcsym.h"
- #include "ckcdeb.h"
- #include "ckcasc.h"
- #ifndef NOCSETS
- #include "ckcxla.h"
- #endif /* NOCSETS */
- #ifdef OSF13
- #ifdef CK_ANSIC
- #ifdef _NO_PROTO
- #undef _NO_PROTO
- #endif /* _NO_PROTO */
- #endif /* CK_ANSIC */
- #endif /* OSF13 */
- #include <errno.h>
- #include <signal.h>
- #ifdef MINIX2
- #undef MINIX
- #undef CKSYSLOG
- #include <limits.h>
- #include <time.h>
- #define NOFILEH
- #endif /* MINIX2 */
- #ifdef MINIX
- #include <limits.h>
- #include <sys/types.h>
- #include <time.h>
- #else
- #ifdef POSIX
- #include <limits.h>
- #else
- #ifdef SVR3
- #include <limits.h>
- #endif /* SVR3 */
- #endif /* POSIX */
- #endif /* MINIX */
- /*
- Directory Separator macros, to allow this module to work with both UNIX and
- OS/2: Because of ambiguity with the command line editor escape character,
- the directory separator is currently left as / for OS/2 too, because the
- OS/2 kernel also accepts / as directory separator. But this is subject to
- change in future versions to conform to the normal OS/2 style.
- */
- #define DIRSEP '/'
- #define ISDIRSEP(c) ((c)=='/')
- #ifdef SDIRENT
- #define DIRENT
- #endif /* SDIRENT */
- #ifdef XNDIR
- #include <sys/ndir.h>
- #else /* !XNDIR */
- #ifdef NDIR
- #include <ndir.h>
- #else /* !NDIR, !XNDIR */
- #ifdef RTU
- #include "/usr/lib/ndir.h"
- #else /* !RTU, !NDIR, !XNDIR */
- #ifdef DIRENT
- #ifdef SDIRENT
- #include <sys/dirent.h>
- #else
- #include <dirent.h>
- #endif /* SDIRENT */
- #else
- #include <sys/dir.h>
- #endif /* DIRENT */
- #endif /* RTU */
- #endif /* NDIR */
- #endif /* XNDIR */
- #ifdef UNIX /* Pointer arg to wait() allowed */
- #define CK_CHILD /* Assume this is safe in all UNIX */
- #endif /* UNIX */
- extern int binary, recursive, stathack;
- #ifdef CK_CTRLZ
- extern int eofmethod;
- #endif /* CK_CTRLZ */
- #include <pwd.h> /* Password file for shell name */
- #ifdef CK_SRP
- #include <t_pwd.h> /* SRP Password file */
- #endif /* CK_SRP */
- #ifdef HPUX10_TRUSTED
- #include <hpsecurity.h>
- #include <prot.h>
- #endif /* HPUX10_TRUSTED */
- #ifdef POSIX
- #define UTIMEH
- #else
- #ifdef HPUX9
- #define UTIMEH
- #endif /* HPUX9 */
- #endif /* POSIX */
- #ifdef SYSUTIMEH /* <sys/utime.h> if requested, */
- #include <sys/utime.h> /* for extra fields required by */
- #else /* 88Open spec. */
- #ifdef UTIMEH /* or <utime.h> if requested */
- #include <utime.h> /* (SVR4, POSIX) */
- #define SYSUTIMEH /* Use this for both cases. */
- #endif /* UTIMEH */
- #endif /* SYSUTIMEH */
- #ifndef NOTIMESTAMP
- #ifdef POSIX
- #ifndef AS400
- #define TIMESTAMP
- #endif /* AS400 */
- #endif /* POSIX */
- #ifdef BSD44 /* BSD 4.4 */
- #ifndef TIMESTAMP
- #define TIMESTAMP /* Can do file dates */
- #endif /* TIMESTAMP */
- #include <sys/time.h>
- #include <sys/timeb.h>
- #else /* Not BSD44 */
- #ifdef BSD4 /* BSD 4.3 and below */
- #define TIMESTAMP /* Can do file dates */
- #include <time.h> /* Need this */
- #include <sys/timeb.h> /* Need this if really BSD */
- #else /* Not BSD 4.3 and below */
- #ifdef SVORPOSIX /* System V or POSIX */
- #ifndef TIMESTAMP
- #define TIMESTAMP
- #endif /* TIMESTAMP */
- #include <time.h>
- /* void tzset(); (the "void" type upsets some compilers) */
- #ifndef IRIX60
- #ifndef ultrix
- #ifndef CONVEX9
- /* ConvexOS 9.0, supposedly POSIX, has extern char *timezone(int,int) */
- #ifndef Plan9
- extern long timezone;
- #endif /* Plan9 */
- #endif /* CONVEX9 */
- #endif /* ultrix */
- #endif /* IRIX60 */
- #endif /* SVORPOSIX */
- #endif /* BSD4 */
- #endif /* BSD44 */
- #ifdef COHERENT
- #include <time.h>
- #endif /* COHERENT */
- /* Is `y' a leap year? */
- #define leap(y) (((y) % 4 == 0 && (y) % 100 != 0) || (y) % 400 == 0)
- /* Number of leap years from 1970 to `y' (not including `y' itself). */
- #define nleap(y) (((y) - 1969) / 4 - ((y) - 1901) / 100 + ((y) - 1601) / 400)
- #endif /* NOTIMESTAMP */
- #ifdef CIE
- #include <stat.h> /* File status */
- #else
- #include <sys/stat.h>
- #endif /* CIE */
- /* Macro to alleviate isdir() calls internal to this module */
- static struct stat STATBUF;
- #define xisdir(a) ((stat(a,&STATBUF)==-1)?0:(S_ISDIR(STATBUF.st_mode)?1:0))
- extern char uidbuf[];
- extern int xferlog;
- extern char * xferfile;
- static int iklogopen = 0;
- static time_t timenow;
- static char iksdmsg[CKMAXPATH+512];
- extern int local;
- extern int server, en_mkd, en_cwd;
- /*
- Functions (n is one of the predefined file numbers from ckcker.h):
- zopeni(n,name) -- Opens an existing file for input.
- zopeno(n,name,attr,fcb) -- Opens a new file for output.
- zclose(n) -- Closes a file.
- zchin(n,&c) -- Gets the next character from an input file.
- zsinl(n,&s,x) -- Read a line from file n, max len x, into address s.
- zsout(n,s) -- Write a null-terminated string to output file, buffered.
- zsoutl(n,s) -- Like zsout, but appends a line terminator.
- zsoutx(n,s,x) -- Write x characters to output file, unbuffered.
- zchout(n,c) -- Add a character to an output file, unbuffered.
- zchki(name) -- Check if named file exists and is readable, return size.
- zchko(name) -- Check if named file can be created.
- zchkspa(name,n) -- Check if n bytes available to create new file, name.
- znewn(name,s) -- Make a new unique file name based on the given name.
- zdelet(name) -- Delete the named file.
- zxpand(string) -- Expands the given wildcard string into a list of files.
- znext(string) -- Returns the next file from the list in "string".
- zxrewind() -- Rewind zxpand list.
- zxcmd(n,cmd) -- Execute the command in a lower fork on file number n.
- zclosf() -- Close input file associated with zxcmd()'s lower fork.
- zrtol(n1,n2) -- Convert remote filename into local form.
- zltor(n1,n2) -- Convert local filename into remote form.
- zchdir(dirnam) -- Change working directory.
- zhome() -- Return pointer to home directory name string.
- zkself() -- Kill self, log out own job.
- zsattr(struct zattr *) -- Return attributes for file which is being sent.
- zstime(f, struct zattr *, x) - Set file creation date from attribute packet.
- zrename(old, new) -- Rename a file.
- zcopy(source,destination) -- Copy a file.
- zmkdir(path) -- Create the directory path if possible
- zfnqfp(fname,len,fullpath) - Determine full path for file name.
- zgetfs(name) -- return file size regardless of accessibility
- zchkpid(pid) -- tell if PID is valid and active
- */
- /* Kermit-specific includes */
- /*
- Definitions here supersede those from system include files.
- ckcdeb.h is included above.
- */
- #include "ckcker.h" /* Kermit definitions */
- #include "ckucmd.h" /* For keyword tables */
- #include "ckuver.h" /* Version herald */
- char *ckzsys = HERALD;
- /*
- File access checking ... There are two calls to access() in this module.
- If this program is installed setuid or setgid on a Berkeley-based UNIX
- system that does NOT incorporate the saved-original-effective-uid/gid
- feature, then, when we have swapped the effective and original uid/gid,
- access() fails because it uses what it thinks are the REAL ids, but we have
- swapped them. This occurs on systems where ANYBSD is defined, NOSETREU
- is NOT defined, and SAVEDUID is NOT defined. So, in theory, we should take
- care of this situation like so:
- ifdef ANYBSD
- ifndef NOSETREU
- ifndef SAVEDUID
- define SW_ACC_ID
- endif
- endif
- endif
- But we can't test such a general scheme everywhere, so let's only do this
- when we know we have to...
- */
- #ifdef NEXT /* NeXTSTEP 1.0-3.0 */
- #define SW_ACC_ID
- #endif /* NEXT */
- /* Support for tilde-expansion in file and directory names */
- #ifdef POSIX
- #define NAMEENV "LOGNAME"
- #endif /* POSIX */
- #ifdef BSD4
- #define NAMEENV "USER"
- #endif /* BSD4 */
- #ifdef ATTSV
- #define NAMEENV "LOGNAME"
- #endif /* ATTSV */
- /* Berkeley Unix Version 4.x */
- /* 4.1bsd support from Charles E Brooks, EDN-VAX */
- #ifdef BSD4
- #ifdef MAXNAMLEN
- #define BSD42
- #endif /* MAXNAMLEN */
- #endif /* BSD4 */
- /* Definitions of some system commands */
- char *DELCMD = "rm -f "; /* For file deletion */
- char *CPYCMD = "cp "; /* For file copy */
- char *RENCMD = "mv "; /* For file rename */
- char *PWDCMD = "pwd "; /* For saying where I am */
- #ifdef COMMENT
- #ifdef HPUX10
- char *DIRCMD = "/usr/bin/ls -l "; /* For directory listing */
- char *DIRCM2 = "/usr/bin/ls -l "; /* For directory listing, no args */
- #else
- char *DIRCMD = "/bin/ls -l "; /* For directory listing */
- char *DIRCM2 = "/bin/ls -l "; /* For directory listing, no args */
- #endif /* HPUX10 */
- #else
- char *DIRCMD = "ls -l "; /* For directory listing */
- char *DIRCM2 = "ls -l "; /* For directory listing, no args */
- #endif /* COMMENT */
- char *TYPCMD = "cat "; /* For typing a file */
- #ifdef DGUX540
- char *MAILCMD = "mailx"; /* For sending mail */
- #else
- #ifdef UNIX
- char *MAILCMD = "Mail";
- #else
- char *MAILCMD = "";
- #endif /* UNIX */
- #endif /* DGUX40 */
- #ifdef UNIX
- #ifdef ANYBSD /* BSD uses lpr to spool */
- #ifdef DGUX540 /* And DG/UX */
- char * PRINTCMD = "lp";
- #else
- char * PRINTCMD = "lpr";
- #endif /* DGUX540 */
- #else /* Sys V uses lp */
- #ifdef TRS16 /* except for Tandy-16/6000... */
- char * PRINTCMD = "lpr";
- #else
- char * PRINTCMD = "lp";
- #endif /* TRS16 */
- #endif /* ANYBSD */
- #else /* Not UNIX */
- #define PRINTCMD ""
- #endif /* UNIX */
- #ifdef FT18 /* Fortune For:Pro 1.8 */
- #undef BSD4
- #endif /* FT18 */
- #ifdef BSD4
- char *SPACMD = "pwd ; df ."; /* Space in current directory */
- #else
- #ifdef FT18
- char *SPACMD = "pwd ; du ; df .";
- #else
- char *SPACMD = "df ";
- #endif /* FT18 */
- #endif /* BSD4 */
- char *SPACM2 = "df "; /* For space in specified directory */
- #ifdef FT18
- #define BSD4
- #endif /* FT18 */
- #ifdef BSD4
- char *WHOCMD = "finger ";
- #else
- char *WHOCMD = "who ";
- #endif /* BSD4 */
- /* More system-dependent includes, which depend on symbols defined */
- /* in the Kermit-specific includes. Oh what a tangled web we weave... */
- #ifdef COHERENT /* <sys/file.h> */
- #define NOFILEH
- #endif /* COHERENT */
- #ifdef MINIX
- #define NOFILEH
- #endif /* MINIX */
- #ifdef aegis
- #define NOFILEH
- #endif /* aegis */
- #ifdef unos
- #define NOFILEH
- #endif /* unos */
- #ifndef NOFILEH
- #include <sys/file.h>
- #endif /* NOFILEH */
- #ifndef is68k /* Whether to include <fcntl.h> */
- #ifndef BSD41 /* All but a couple UNIXes have it. */
- #ifndef FT18
- #ifndef COHERENT
- #include <fcntl.h>
- #endif /* COHERENT */
- #endif /* FT18 */
- #endif /* BSD41 */
- #endif /* not is68k */
- #ifdef COHERENT
- #ifdef _I386
- #include <fcntl.h>
- #else
- #include <sys/fcntl.h>
- #endif /* _I386 */
- #endif /* COHERENT */
- #ifdef IKSD
- extern int isguest;
- extern int inserver;
- extern char * homdir, * anonroot;
- #endif /* IKSD */
- #ifdef CK_LOGIN
- #define GUESTPASS 256
- static char guestpass[GUESTPASS] = { NUL, NUL }; /* Anonymous "password" */
- static int logged_in = 0; /* Set when user is logged in */
- int guest = 0; /* Anonymous user */
- static int askpasswd = 0; /* Have OK user, must ask for passwd */
- #endif /* CK_LOGIN */
- _PROTOTYP( VOID ignorsigs, (void) );
- _PROTOTYP( VOID restorsigs, (void) );
- /*
- Change argument to "(const char *)" if this causes trouble.
- Or... if it causes trouble, then maybe it was already declared
- in a header file after all, so you can remove this prototype.
- */
- #ifndef NDGPWNAM /* If not defined No Declare getpwnam... */
- #ifndef _POSIX_SOURCE
- #ifndef NEXT
- #ifndef SVR4
- /* POSIX <pwd.h> already gave prototypes for these. */
- #ifdef IRIX40
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- #ifdef IRIX51
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- #ifdef M_UNIX
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- #ifdef HPUX9
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- #ifdef HPUX10
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- #ifdef DCGPWNAM
- _PROTOTYP( struct passwd * getpwnam, (const char *) );
- #else
- _PROTOTYP( struct passwd * getpwnam, (char *) );
- #endif /* DCGPWNAM */
- #endif /* HPUX10 */
- #endif /* HPUX9 */
- #endif /* M_UNIX */
- #endif /* IRIX51 */
- #endif /* IRIX40 */
- #ifndef SUNOS4
- #ifndef HPUX9
- #ifndef HPUX10
- #ifndef _SCO_DS
- _PROTOTYP( struct passwd * getpwuid, (PWID_T) );
- #endif /* _SCO_DS */
- #endif /* HPUX10 */
- #endif /* HPUX9 */
- #endif /* SUNOS4 */
- _PROTOTYP( struct passwd * getpwent, (void) );
- #endif /* SVR4 */
- #endif /* NEXT */
- #endif /* _POSIX_SOURCE */
- #endif /* NDGPWNAM */
- #ifdef CK_SHADOW /* Shadow Passwords... */
- #include <shadow.h>
- #endif /* CK_SHADOW */
- #ifdef CK_PAM /* PAM... */
- #include <security/pam_appl.h>
- #ifndef PAM_SERVICE_TYPE /* Defines which PAM service we are */
- #define PAM_SERVICE_TYPE "kermit"
- #endif /* PAM_SERVICE_TYPE */
- int
- #ifdef CK_ANSIC
- pam_cb(int num_msg,
- const struct pam_message **msg,
- struct pam_response **resp,
- void *appdata_ptr
- )
- #else /* CK_ANSIC */
- pam_cb(num_msg, msg, resp, appdata_ptr)
- int num_msg;
- const struct pam_message **msg;
- struct pam_response **resp;
- void *appdata_ptr;
- #endif /* CK_ANSIC */
- {
- int i;
- debug(F111,"pam_cb","num_msg",num_msg);
- for (i = 0; i < num_msg; i++) {
- char message[PAM_MAX_MSG_SIZE];
- /* Issue prompt and get response */
- debug(F111,"pam_cb","Message",i);
- debug(F111,"pam_cb",msg[i]->msg,msg[i]->msg_style);
- if (msg[i]->msg_style == PAM_ERROR_MSG) {
- debug(F111,"pam_cb","PAM ERROR",0);
- fprintf(stdout,"%sn", msg[i]->msg);
- return(0);
- } else if (msg[i]->msg_style == PAM_TEXT_INFO) {
- debug(F111,"pam_cb","PAM TEXT INFO",0);
- fprintf(stdout,"%sn", msg[i]->msg);
- return(0);
- } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) {
- debug(F111,"pam_cb","Reading response, no echo",0);
- readpass(msg[i]->msg,message,PAM_MAX_MSG_SIZE);
- } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_ON) {
- debug(F111,"pam_cb","Reading response, with echo",0);
- readtext(msg[i]->msg,message,PAM_MAX_MSG_SIZE);
- } else {
- debug(F111,"pam_cb","unknown style",0);
- return(0);
- }
- /* Allocate space for this message's response structure */
- resp[i] = (struct pam_response *) malloc(sizeof (struct pam_response));
- if (!resp[i]) {
- int j;
- debug(F110,"pam_cb","malloc failure",0);
- for (j = 0; j < i; j++) {
- free(resp[j]->resp);
- free(resp[j]);
- }
- return(0);
- }
- /* Allocate a buffer for the response */
- resp[i]->resp = (char *) malloc((int)strlen(message) + 1);
- if (!resp[i]->resp) {
- int j;
- debug(F110,"pam_cb","malloc failure",0);
- for (j = 0; j < i; j++) {
- free(resp[j]->resp);
- free(resp[j]);
- }
- free(resp[i]);
- return(0);
- }
- /* Return the results back to PAM */
- strcpy(resp[i]->resp, message);
- resp[i]->resp_retcode = 0;
- }
- debug(F110,"pam_cb","Exiting",0);
- return(0);
- }
- #endif /* CK_PAM */
- /* Define macros for getting file type */
- #ifdef OXOS
- /*
- Olivetti X/OS 2.3 has S_ISREG and S_ISDIR defined
- incorrectly, so we force their redefinition.
- */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* OXOS */
- #ifdef UTSV /* Same deal for Amdahl UTSV */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* UTSV */
- #ifdef UNISYS52 /* And for UNISYS UTS V 5.2 */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* UNISYS52 */
- #ifdef ICLSVR3 /* And for old ICL versions */
- #undef S_ISREG
- #undef S_ISDIR
- #endif /* ICLSVR3 */
- #ifdef ISDIRBUG /* Also allow this from command line */
- #ifdef S_ISREG
- #undef S_ISREG
- #endif /* S_ISREG */
- #ifdef S_ISDIR
- #undef S_ISDIR
- #endif /* S_ISDIR */
- #endif /* ISDIRBUG */
- #ifndef _IFMT
- #ifdef S_IFMT
- #define _IFMT S_IFMT
- #else
- #define _IFMT 0170000
- #endif /* S_IFMT */
- #endif /* _IFMT */
- #ifndef S_ISREG
- #define S_ISREG(m) (((m) & S_IFMT) == S_IFREG)
- #endif /* S_ISREG */
- #ifndef S_ISDIR
- #define S_ISDIR(m) (((m) & S_IFMT) == S_IFDIR)
- #endif /* S_ISDIR */
- /* The following mainly for NeXTSTEP... */
- #ifndef S_IWUSR
- #define S_IWUSR 0000200
- #endif /* S_IWUSR */
- #ifndef S_IRGRP
- #define S_IRGRP 0000040
- #endif /* S_IRGRP */
- #ifndef S_IWGRP
- #define S_IWGRP 0000020
- #endif /* S_IWGRP */
- #ifndef S_IXGRP
- #define S_IXGRP 0000010
- #endif /* S_IXGRP */
- #ifndef S_IROTH
- #define S_IROTH 0000004
- #endif /* S_IROTH */
- #ifndef S_IWOTH
- #define S_IWOTH 0000002
- #endif /* S_IWOTH */
- #ifndef S_IXOTH
- #define S_IXOTH 0000001
- #endif /* S_IXOTH */
- /*
- Define maximum length for a file name if not already defined.
- NOTE: This applies to a path segment (directory or file name),
- not the entire path string, which can be CKMAXPATH bytes long.
- */
- #ifdef QNX
- #ifdef _MAX_FNAME
- #define MAXNAMLEN _MAX_FNAME
- #else
- #define MAXNAMLEN 48
- #endif /* _MAX_FNAME */
- #else
- #ifndef MAXNAMLEN
- #ifdef sun
- #define MAXNAMLEN 255
- #else
- #ifdef FILENAME_MAX
- #define MAXNAMLEN FILENAME_MAX
- #else
- #ifdef NAME_MAX
- #define MAXNAMLEN NAME_MAX
- #else
- #ifdef _POSIX_NAME_MAX
- #define MAXNAMLEN _POSIX_NAME_MAX
- #else
- #ifdef _D_NAME_MAX
- #define MAXNAMLEN _D_NAME_MAX
- #else
- #ifdef DIRSIZ
- #define MAXNAMLEN DIRSIZ
- #else
- #define MAXNAMLEN 14
- #endif /* DIRSIZ */
- #endif /* _D_NAME_MAX */
- #endif /* _POSIX_NAME_MAX */
- #endif /* NAME_MAX */
- #endif /* FILENAME_MAX */
- #endif /* sun */
- #endif /* MAXNAMLEN */
- #endif /* QNX */
- /* Longest pathname ... */
- /*
- Beware: MAXPATHLEN is one of UNIX's dirty little secrets. Where is it
- defined? Who knows... <param.h>, <mod.h>, <unistd.h>, <limits.h>, ...
- There is not necessarily even a definition for it anywhere, or it might have
- another name. If you get it wrong, bad things happen with getcwd() and/or
- getwd(). If you allocate a buffer that is too short, getwd() might write
- over memory and getcwd() will fail with ERANGE. The definitions of these
- functions (e.g. in SVID or POSIX.1) do not tell you how to determine the
- maximum path length in order to allocate a buffer that is the right size.
- */
- #ifdef BSD44
- #include <sys/param.h> /* For MAXPATHLEN */
- #endif /* BSD44 */
- #ifdef COHERENT
- #include <sys/param.h> /* for MAXPATHLEN, needed for -DDIRENT */
- #endif /* COHERENT */
- #ifdef MAXPATHLEN
- #ifdef MAXPATH
- #undef MAXPATH
- #endif /* MAXPATH */
- #define MAXPATH MAXPATHLEN
- #else
- #ifdef PATH_MAX
- #define MAXPATH PATH_MAX
- #else
- #ifdef _POSIX_PATH_MAX
- #define MAXPATH _POSIX_PATH_MAX
- #else
- #ifdef BSD42
- #define MAXPATH 1024
- #else
- #ifdef SVR4
- #define MAXPATH 1024
- #else
- #define MAXPATH 255
- #endif /* SVR4 */
- #endif /* BSD42 */
- #endif /* _POSIX_PATH_MAX */
- #endif /* PATH_MAX */
- #endif /* MAXPATHLEN */
- /* Maximum number of filenames for wildcard expansion */
- #ifndef MAXWLD /* (see ckcdeb.h) */
- #ifdef CK_SMALL
- #define MAXWLD 50
- #else
- #ifdef BIGBUFOK
- #define MAXWLD 102400
- #else
- #define MAXWLD 4096
- #endif /* BIGBUFOK */
- #endif /* CK_SMALL */
- #endif /* MAXWLD */
- #ifdef DCLFDOPEN
- /* fdopen() needs declaring because it's not declared in <stdio.h> */
- _PROTOTYP( FILE * fdopen, (int, char *) );
- #endif /* DCLFDOPEN */
- #ifdef DCLPOPEN
- /* popen() needs declaring because it's not declared in <stdio.h> */
- _PROTOTYP( FILE * popen, (char *, char *) );
- #endif /* DCLPOPEN */
- extern int nopush;
- /* More internal function prototypes */
- /*
- * The path structure is used to represent the name to match.
- * Each slash-separated segment of the name is kept in one
- * such structure, and they are linked together, to make
- * traversing the name easier.
- */
- struct path {
- char npart[MAXNAMLEN+4]; /* name part of path segment */
- struct path *fwd; /* forward ptr */
- };
- #ifndef NOPUSH
- _PROTOTYP( int shxpand, (char *, char *[], int ) );
- #endif /* NOPUSH */
- _PROTOTYP( static int fgen, (char *, char *[], int ) );
- _PROTOTYP( static VOID traverse, (struct path *, char *, char *) );
- _PROTOTYP( static VOID addresult, (char *, int) );
- #ifdef COMMENT
- /* Replaced by ckmatch() */
- _PROTOTYP( static int match, (char *, char *) );
- #endif /* COMMENT */
- _PROTOTYP( char * whoami, (void) );
- _PROTOTYP( UID_T real_uid, (void) );
- _PROTOTYP( static struct path *splitpath, (char *p) );
- _PROTOTYP( char * zdtstr, (time_t) );
- _PROTOTYP( time_t zstrdt, (char *, int) );
- /* Some systems define these symbols in include files, others don't... */
- #ifndef R_OK
- #define R_OK 4 /* For access */
- #endif /* R_OK */
- #ifndef W_OK
- #define W_OK 2
- #endif /* W_OK */
- #ifndef O_RDONLY
- #define O_RDONLY 000
- #endif /* O_RDONLY */
- /* syslog and wtmp items for Internet Kermit Service */
- extern char * clienthost; /* From ckcmai.c. */
- static char fullname[CKMAXPATH+1];
- static char tmp2[CKMAXPATH+1];
- extern int ckxlogging;
- #ifdef CKXPRINTF /* Our printf macro conflicts with */
- #undef printf /* use of "printf" in syslog.h */
- #endif /* CKXPRINTF */
- #ifdef CKSYSLOG
- #include <syslog.h>
- #endif /* CKSYSLOG */
- #ifdef CKXPRINTF
- #define printf ckxprintf
- #endif /* CKXPRINTF */
- int ckxanon = 1; /* Anonymous login ok */
- int ckxperms = 0040; /* Anonymous file permissions */
- int ckxpriv = 1; /* Priv'd login ok */
- #ifndef XFERFILE
- #define XFERFILE "/var/log/iksd.log"
- #endif /* XFERFILE */
- /* wtmp logging for IKSD... */
- #ifndef CKWTMP /* wtmp logging not selected */
- int ckxwtmp = 0; /* Know this at runtime */
- #else /* wtmp file details */
- int ckxwtmp = 1;
- #ifdef UTMPBUG /* Unfortunately... */
- /*
- Some versions of Linux have a <utmp.h> file that contains
- "enum utlogin { local, telnet, rlogin, screen, ... };" This clobbers
- any program that uses any of these words as variable names, function
- names, macro names, etc. (Other versions of Linux have this declaration
- within #if 0 ... #endif.) There is nothing we can do about this other
- than to not include the stupid file. But we need stuff from it, so...
- */
- #include <features.h>
- #include <sys/types.h>
- #define UT_LINESIZE 32
- #define UT_NAMESIZE 32
- #define UT_HOSTSIZE 256
- struct timeval {
- time_t tv_sec;
- time_t tv_usec;
- };
- struct exit_status {
- short int e_termination; /* Process termination status. */
- short int e_exit; /* Process exit status. */
- };
- struct utmp {
- short int ut_type; /* Type of login */
- pid_t ut_pid; /* Pid of login process */
- char ut_line[UT_LINESIZE]; /* NUL-terminated devicename of tty */
- char ut_id[4]; /* Inittab id */
- char ut_user[UT_NAMESIZE]; /* Username (not NUL terminated) */
- char ut_host[UT_HOSTSIZE]; /* Hostname for remote login */
- struct exit_status ut_exit; /* Exit status */
- long ut_session; /* Session ID, used for windowing */
- struct timeval ut_tv; /* Time entry was made */
- int32_t ut_addr_v6[4]; /* Internet address of remote host */
- char pad[20]; /* Reserved */
- };
- #define ut_time ut_tv.tv_sec /* Why should Linux be like anything else? */
- #define ut_name ut_user /* ... */
- extern void
- logwtmp __P ((__const char *__ut_line, __const char *__ut_name,
- __const char *__ut_host));
- #else /* Not UTMPBUG */
- #ifndef HAVEUTMPX /* Who has <utmpx.h> */
- #ifdef SOLARIS
- #define HAVEUTMPX
- #else
- #ifdef IRIX60
- #define HAVEUTMPX
- #else
- #ifdef CK_SCOV5
- #define HAVEUTMPX
- #else
- #ifdef HPUX100
- #define HAVEUTMPX
- #else
- #ifdef UNIXWARE
- #define HAVEUTMPX
- #endif /* UNIXWARE */
- #endif /* HPUX100 */
- #endif /* CK_SCOV5 */
- #endif /* IRIX60 */
- #endif /* SOLARIS */
- #endif /* HAVEUTMPX */
- #ifdef HAVEUTMPX
- #include <utmpx.h>
- #else
- #ifdef OSF50
- /* Because the time_t in the utmp struct is 64 bits but time() wants 32 */
- #define __V40_OBJ_COMPAT 1
- #endif /* OSF50 */
- #include <utmp.h>
- #ifdef OSF50
- #undef __V40_OBJ_COMPAT
- #endif /* OSF50 */
- #endif /* HAVEUTMPX */
- #endif /* UTMPBUG */
- #ifndef WTMPFILE
- #ifdef QNX
- #define WTMPFILE "/usr/adm/wtmp.1"
- #else
- #ifdef LINUX
- #define WTMPFILE "/var/log/wtmp"
- #else
- #define WTMPFILE "/usr/adm/wtmp"
- #endif /* QNX */
- #endif /* LINUX */
- #endif /* WTMPFILE */
- char * wtmpfile = NULL;
- static int wtmpfd = 0;
- static char cksysline[32] = { NUL, NUL };
- #ifndef HAVEUTHOST /* Does utmp include ut_host[]? */
- #ifdef HAVEUTMPX /* utmpx always does */
- #define HAVEUTHOST
- #else
- #ifdef LINUX /* Linux does */
- #define HAVEUTHOST
- #else
- #ifdef SUNOS4 /* SunOS does */
- #define HAVEUTHOST
- #else
- #ifdef AIX41 /* AIX 4.1 and later do */
- #define HAVEUTHOST
- #endif /* AIX41 */
- #endif /* SUNOS4 */
- #endif /* LINUX */
- #endif /* HAVEUTMPX */
- #endif /* HAVEUTHOST */
- #ifdef UW200
- PID_T _vfork() { /* To satisfy a library foulup */
- return(fork()); /* in Unixware 2.0.x */
- }
- #endif /* UW200 */
- VOID
- #ifdef CK_ANSIC
- logwtmp(const char * line, const char * name, const char * host)
- #else
- logwtmp(line, name, host) char *line, *name, *host;
- #endif /* CK_ANSIC */
- /* logwtmp */ {
- #ifdef HAVEUTMPX
- struct utmpx ut; /* Needed for ut_host[] */
- #else
- struct utmp ut;
- #endif /* HAVEUTMPX */
- struct stat buf;
- /* time_t time(); */
- if (!ckxwtmp)
- return;
- if (!wtmpfile)
- makestr(&wtmpfile,WTMPFILE);
- if (!line) line = "";
- if (!name) name = "";
- if (!host) host = "";
- if (!wtmpfd && (wtmpfd = open(wtmpfile, O_WRONLY|O_APPEND, 0)) < 0) {
- ckxwtmp = 0;
- debug(F110,"WTMP open failed",line,0);
- return;
- }
- if (!fstat(wtmpfd, &buf)) {
- ckstrncpy(ut.ut_line, line, sizeof(ut.ut_line));
- ckstrncpy(ut.ut_name, name, sizeof(ut.ut_name));
- #ifdef HAVEUTHOST
- /* Not portable */
- ckstrncpy(ut.ut_host, host, sizeof(ut.ut_host));
- #endif /* HAVEUTHOST */
- #ifdef HAVEUTMPX
- time(&ut.ut_tv.tv_sec);
- #else
- #ifdef LINUX
- /* In light of the following comment perhaps the previous line should */
- /* be "#ifndef COMMENT". */
- {
- /*
- * On 64-bit platforms sizeof(time_t) and sizeof(ut.ut_time)
- * are not the same and attempt to use an address of
- * ut.ut_time as an argument to time() call may cause
- * "unaligned access" trap.
- */
- time_t zz;
- time(&zz);
- ut.ut_time = zz;
- }
- #else
- time(&ut.ut_time);
- #endif /* LINUX */
- #endif /* HAVEUTMPX */
- if (write(wtmpfd, (char *)&ut, sizeof(struct utmp)) !=
- sizeof(struct utmp)) {
- #ifndef NOFTRUNCATE
- #ifndef COHERENT
- ftruncate(wtmpfd, buf.st_size); /* Error, undo any partial write */
- #else
- chsize(wtmpfd, buf.st_size); /* Error, undo any partial write */
- #endif /* COHERENT */
- #endif /* NOFTRUNCATE */
- debug(F110,"WTMP write error",line,0);
- } else {
- debug(F110,"WTMP record OK",line,0);
- return;
- }
- }
- }
- #endif /* CKWTMP */
- #ifdef CKSYSLOG
- /*
- C K S Y S L O G -- C-Kermit system logging function,
- For use by other modules.
- This module can, but doesn't have to, use it.
- Call with:
- n = SYSLG_xx values defined in ckcdeb.h
- s1, s2, s3: strings.
- */
- VOID
- cksyslog(n, m, s1, s2, s3) int n, m; char * s1, * s2, * s3; {
- int level;
- if (!ckxlogging) /* syslogging */
- return;
- if (!s1) s1 = ""; /* Fix null args */
- if (!s2) s2 = "";
- if (!s3) s3 = "";
- switch (n) { /* Translate Kermit level */
- case SYSLG_DB: /* to syslog level */
- level = LOG_DEBUG;
- break;
- default:
- level = m ? LOG_INFO : LOG_ERR;
- }
- debug(F110,"cksyslog s1",s1,0);
- debug(F110,"cksyslog s2",s2,0);
- debug(F110,"cksyslog s3",s3,0);
- errno = 0;
- syslog(level, "%s: %s %s", s1, s2, s3); /* Write syslog record */
- debug(F101,"cksyslog errno","",errno);
- }
- #endif /* CKSYSLOG */
- /* Declarations */
- int maxnam = MAXNAMLEN; /* Available to the outside */
- int maxpath = MAXPATH;
- int ck_znewn = -1;
- #ifdef UNIX
- char startupdir[MAXPATH+1];
- #endif /* UNIX */
- int pexitstat = -2; /* Process exit status */
- FILE *fp[ZNFILS] = { /* File pointers */
- NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL
- };
- /* Flags for each file indicating whether it was opened with popen() */
- int ispipe[ZNFILS] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- /* Buffers and pointers used in buffered file input and output. */
- #ifdef DYNAMIC
- extern char *zinbuffer, *zoutbuffer;
- #else
- extern char zinbuffer[], zoutbuffer[];
- #endif /* DYNAMIC */
- extern char *zinptr, *zoutptr;
- extern int zincnt, zoutcnt;
- extern int wildxpand;
- static long iflen = -1L; /* Input file length */
- static PID_T pid = 0; /* pid of child fork */
- static int fcount = 0; /* Number of files in wild group */
- static int nxpand = 0; /* Copy of fcount */
- static char nambuf[CKMAXPATH+4]; /* Buffer for a pathname */
- #ifndef NOFRILLS
- static char zmbuf[200]; /* For mail, remote print strings */
- #endif /* NOFRILLS */
- char **mtchs = NULL; /* Matches found for filename */
- char **mtchptr = NULL; /* Pointer to current match */
- /* Z K S E L F -- Kill Self: log out own job, if possible. */
- /* Note, should get current pid, but if your system doesn't have */
- /* getppid(), then just kill(0,9)... */
- #ifndef SVR3
- #ifndef POSIX
- #ifndef OSFPC
- /* Already declared in unistd.h for SVR3 and POSIX */
- #ifdef CK_ANSIC
- extern PID_T getppid(void);
- #else
- #ifndef PS2AIX10
- #ifndef COHERENT
- extern PID_T getppid();
- #endif /* COHERENT */
- #endif /* PS2AIX10 */
- #endif /* CK_ANSIC */
- #endif /* OSFPC */
- #endif /* POSIX */
- #endif /* SVR3 */
- int
- zkself() { /* For "bye", but no guarantee! */
- #ifdef PROVX1
- return(kill(0,9));
- #else
- #ifdef V7
- return(kill(0,9));
- #else
- #ifdef TOWER1
- return(kill(0,9));
- #else
- #ifdef FT18
- return(kill(0,9));
- #else
- #ifdef aegis
- return(kill(0,9));
- #else
- #ifdef COHERENT
- return(kill((PID_T)getpid(),1));
- #else
- #ifdef PID_T
- exit(kill((PID_T)getppid(),1));
- return(0);
- #else
- exit(kill(getppid(),1));
- return(0);
- #endif
- #endif
- #endif
- #endif
- #endif
- #endif
- #endif
- }
- static VOID
- getfullname(name) char * name; {
- char *p = (char *)fullname;
- int len = 0;
- fullname[0] = ' ';
- /* If necessary we could also chase down symlinks here... */
- #ifdef COMMENT
- /* This works but is incompatible with wuftpd */
- if (isguest && anonroot) {
- ckstrncpy(fullname,anonroot,CKMAXPATH);
- len = strlen(fullname);
- if (len > 0)
- if (fullname[len-1] == '/')
- len--;
- }
- p += len;
- #endif /* COMMENT */
- zfnqfp(name, CKMAXPATH - len, p);
- while (*p) {
- if (*p < '!') *p = '_';
- p++;
- }
- }
- /* D O I K L O G -- Open Kermit-specific ftp-like transfer log. */
- static VOID
- doiklog() {
- if (iklogopen) /* Already open? */
- return;
- if (xferlog) { /* Open iksd log if requested */
- if (!xferfile) /* If no pathname given */
- xferfile = XFERFILE; /* use this default */
- if (*xferfile) {
- xferlog = open(xferfile, O_WRONLY | O_APPEND | O_CREAT, 0660);
- debug(F101,"doiklog open","",xferlog);
- if (xferlog < 0) {
- #ifdef CKSYSLOG
- syslog(LOG_ERR, "xferlog open failure %s: %m", xferfile);
- #endif /* CKSYSLOG */
- debug(F101,"doiklog open errno","",errno);
- xferlog = 0;
- } else
- iklogopen = 1;
- } else
- xferlog = 0;
- #ifdef CKSYSLOG
- if (xferlog && ckxlogging)
- syslog(LOG_INFO, "xferlog: %s open ok", xferfile);
- #endif /* CKSYSLOG */
- }
- }
- /* Z O P E N I -- Open an existing file for input. */
- /* Returns 1 on success, 0 on failure */
- int
- zopeni(n,name) int n; char *name; {
- int x, y;
- debug(F111,"zopeni name",name,n);
- /* debug(F101,"zopeni fp","", (unsigned) fp[n]); */
- if (chkfn(n) != 0) return(0);
- zincnt = 0; /* Reset input buffer */
- if (n == ZSYSFN) { /* Input from a system function? */
- /*** Note, this function should not be called with ZSYSFN ***/
- /*** Always call zxcmd() directly, and give it the real file number ***/
- /*** you want to use. ***/
- debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
- *nambuf = ' '; /* No filename. */
- return(0); /* fail. */
- #ifdef COMMENT
- return(zxcmd(n,name)); /* Try to fork the command */
- #endif
- }
- if (n == ZSTDIO) { /* Standard input? */
- if (is_a_tty(0)) {
- fprintf(stderr,"Terminal input not allowed");
- debug(F110,"zopeni: attempts input from unredirected stdin","",0);
- return(0);
- }
- fp[ZIFILE] = stdin;
- ispipe[ZIFILE] = 0;
- return(1);
- }
- fp[n] = fopen(name,"r"); /* Real file, open it. */
- debug(F111,"zopeni fopen", name, fp[n]);
- #ifdef ZDEBUG
- printf("ZOPENI fp[%d]=%ldn",n,fp[n]);
- #endif /* ZDEBUG */
- ispipe[n] = 0;
- if (xferlog
- #ifdef CKSYSLOG
- || ckxsyslog >= SYSLG_FA && ckxlogging
- #endif /* CKSYSLOG */
- ) {
- getfullname(name);
- debug(F110,"zopeni fullname",fullname,0);
- }
- if (fp[n] == NULL) {
- #ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FA && ckxlogging)
- syslog(LOG_INFO, "file[%d] %s: open failed (%m)", n, fullname);
- perror(fullname);
- #else
- perror(name);
- #endif /* CKSYSLOG */
- return(0);
- } else {
- #ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FA && ckxlogging)
- syslog(LOG_INFO, "file[%d] %s: open read ok", n, fullname);
- #endif /* CKSYSLOG */
- clearerr(fp[n]);
- return(1);
- }
- }
- #ifdef QNX
- #define DONDELAY
- #else
- #ifdef O_NDELAY
- #define DONDELAY
- #endif /* O_NDELAY */
- #endif /* QNX */
- /* Z O P E N O -- Open a new file for output. */
- int
- zopeno(n,name,zz,fcb)
- /* zopeno */ int n; char *name; struct zattr *zz; struct filinfo *fcb; {
- char p[8];
- int append = 0;
- /* As of Version 5A, the attribute structure and the file information */
- /* structure are included in the arglist. */
- #ifdef DEBUG
- debug(F111,"zopeno",name,n);
- if (fcb) {
- debug(F101,"zopeno fcb disp","",fcb->dsp);
- debug(F101,"zopeno fcb type","",fcb->typ);
- debug(F101,"zopeno fcb char","",fcb->cs);
- } else {
- debug(F100,"zopeno fcb is NULL","",0);
- }
- #endif /* DEBUG */
- if (chkfn(n) != 0) /* Already open? */
- return(0); /* Nothing to do. */
- if ((n == ZCTERM) || (n == ZSTDIO)) { /* Terminal or standard output */
- fp[ZOFILE] = stdout;
- ispipe[ZOFILE] = 0;
- #ifdef COMMENT
- /* This seems right but it breaks client server ops */
- fp[n] = stdout;
- ispipe[n] = 0;
- #endif /* COMMENT */
- #ifdef DEBUG
- if (n != ZDFILE)
- debug(F101,"zopeno fp[n]=stdout","",fp[n]);
- #endif /* DEBUG */
- zoutcnt = 0;
- zoutptr = zoutbuffer;
- return(1);
- }
- /* A real file. Open it in desired mode (create or append). */
- strcpy(p,"w"); /* Assume write/create mode */
- if (fcb) { /* If called with an FCB... */
- if (fcb->dsp == XYFZ_A) { /* Does it say Append? */
- strcpy(p,"a"); /* Yes. */
- debug(F100,"zopeno append","",0);
- append = 1;
- }
- }
- if (xferlog
- #ifdef CKSYSLOG
- || ckxsyslog >= SYSLG_FC && ckxlogging
- #endif /* CKSYSLOG */
- ) {
- getfullname(name);
- debug(F110,"zopeno fullname",fullname,0);
- }
- debug(F110,"zopeno fopen arg",p,0);
- fp[n] = fopen(name,p); /* Try to open the file */
- ispipe[ZIFILE] = 0;
- #ifdef ZDEBUG
- printf("ZOPENO fp[%d]=%ldn",n,fp[n]);
- #endif /* ZDEBUG */
- if (fp[n] == NULL) { /* Failed */
- debug(F101,"zopeno failed errno","",errno);
- #ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FC && ckxlogging)
- syslog(LOG_INFO, "file[%d] %s: %s failed (%m)",
- n,
- fullname,
- append ? "append" : "create"
- );
- #endif /* CKSYSLOG */
- #ifdef COMMENT /* Let upper levels print message. */
- perror("Can't open output file");
- #endif /* COMMENT */
- } else { /* Succeeded */
- extern int zofbuffer, zofblock, zobufsize;
- debug(F101, "zopeno zobufsize", "", zobufsize);
- if (n == ZDFILE || n == ZTFILE) { /* If debug or transaction log */
- setbuf(fp[n],NULL); /* make it unbuffered. */
- #ifdef DONDELAY
- } else if (n == ZOFILE && !zofblock) { /* blocking or nonblocking */
- int flags;
- if ((flags = fcntl(fileno(fp[n]),F_GETFL,0)) > -1)
- fcntl(fileno(fp[n]),F_SETFL, flags |
- #ifdef QNX
- O_NONBLOCK
- #else
- O_NDELAY
- #endif /* QNX */
- );
- debug(F100,"zopeno ZOFILE nonblocking","",0);
- #endif /* DONDELAY */
- } else if (n == ZOFILE && !zofbuffer) { /* buffered or unbuffered */
- setbuf(fp[n],NULL);
- debug(F100,"zopeno ZOFILE unbuffered","",0);
- }
- #ifdef CK_LOGIN
- /* Enforce anonymous file-creation permission */
- if (isguest)
- if (n == ZWFILE || n == ZMFILE ||
- n == ZOFILE || n == ZDFILE ||
- n == ZTFILE || n == ZPFILE ||
- n == ZSFILE)
- chmod(name,ckxperms);
- #endif /* CK_LOGIN */
- #ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FC && ckxlogging)
- syslog(LOG_INFO, "file[%d] %s: %s ok",
- n,
- fullname,
- append ? "append" : "create"
- );
- #endif /* CKSYSLOG */
- debug(F100, "zopeno ok", "", 0);
- }
- zoutcnt = 0; /* (PWP) reset output buffer */
- zoutptr = zoutbuffer;
- return((fp[n] != NULL) ? 1 : 0);
- }
- /* Z C L O S E -- Close the given file. */
- /* Returns 0 if arg out of range, 1 if successful, -1 if close failed. */
- int
- zclose(n) int n; {
- int x = 0, x2 = 0;
- extern long ffc;
- debug(F101,"zclose","",n);
- if (chkfn(n) < 1) return(0); /* Check range of n */
- if ((n == ZOFILE) && (zoutcnt > 0)) /* (PWP) output leftovers */
- x2 = zoutdump();
- if (fp[ZSYSFN] || ispipe[n]) { /* If file is really pipe */
- #ifndef NOPUSH
- x = zclosf(n); /* do it specially */
- #else
- x = EOF;
- #endif /* NOPUSH */
- debug(F101,"zclose zclosf","",x);
- debug(F101,"zclose zclosf fp[n]","",fp[n]);
- } else {
- if ((fp[n] != stdout) && (fp[n] != stdin))
- x = fclose(fp[n]);
- fp[n] = NULL;
- #ifdef COMMENT
- if (n == ZCTERM || n == ZSTDIO) /* See zopeno() */
- if (fp[ZOFILE] == stdout)
- fp[ZOFILE] = NULL;
- #endif /* COMMENT */
- }
- iflen = -1L; /* Invalidate file length */
- if (x == EOF) { /* if we got a close error */
- debug(F101,"zclose fclose fails","",x);
- return(-1);
- } else if (x2 < 0) { /* or error flushing last buffer */
- debug(F101,"zclose error flushing last buffer","",x2);
- return(-1); /* then return an error */
- } else {
- /* Print log record compatible with wu-ftpd */
- if (xferlog && (n == ZIFILE || n == ZOFILE)) {
- char * s, *p;
- extern char ttname[];
- if (!iklogopen) (VOID) doiklog(); /* Open log if necessary */
- debug(F101,"zclose iklogopen","",iklogopen);
- if (iklogopen) {
- timenow = time(NULL);
- #ifdef CK_LOGIN
- if (logged_in)
- s = clienthost;
- else
- #endif /* CK_LOGIN */
- s = (char *)ttname;
- if (!s) s = "";
- if (!*s) s = "*";
- #ifdef CK_LOGIN
- if (logged_in) {
- p = guestpass;
- if (!*p) p = "*";
- } else
- #endif /* CK_LOGIN */
- p = whoami();
- sprintf(iksdmsg,
- "%.24s %d %s %ld %s %c %s %c %c %s %s %d %sn",
- ctime(&timenow), /* date/time */
- gtimer(), /* elapsed secs */
- s, /* peer name */
- ffc, /* byte count */
- fullname, /* full pathname of file */
- (binary ? 'b' : 'a'), /* binary or ascii */
- "_", /* options = none */
- n == ZIFILE ? 'o' : 'i', /* in/out */
- #ifdef CK_LOGIN
- (isguest ? 'a' : 'r'), /* User type */
- #else
- 'r',
- #endif /* CK_LOGIN */
- p, /* Username or guest passwd */
- #ifdef CK_LOGIN
- logged_in ? "iks" : "kermit", /* Record ID */
- #else
- "kermit",
- #endif /* CK_LOGIN */
- 0, /* User ID on client system unknown */
- "*" /* Ditto */
- );
- debug(F110,"zclose iksdmsg",iksdmsg,0);
- write(xferlog, iksdmsg, (int)strlen(iksdmsg));
- }
- }
- debug(F101,"zclose returns","",1);
- return(1);
- }
- }
- /* Z C H I N -- Get a character from the input file. */
- /* Returns -1 if EOF, 0 otherwise with character returned in argument */
- int
- zchin(n,c) int n; int *c; {
- int a, x;
- #ifdef IKSD
- /* I'm not sure how this would ever happen but... */
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- *c = coninc(0);
- if (*c < 0)
- return(-1);
- return(0);
- }
- #endif /* IKSD */
- /* (PWP) Just in case this gets called when it shouldn't. */
- if (n == ZIFILE) {
- x = zminchar();
- *c = x;
- return(x);
- }
- /* if (chkfn(n) < 1) return(-1); */
- a = getc(fp[n]);
- if (a == EOF) return(-1);
- #ifdef CK_CTRLZ
- /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
- if (!binary && a == 0x1A && eofmethod == XYEOF_Z)
- return(-1);
- #endif /* CK_CTRLZ */
- *c = (CHAR) a & 0377;
- return(0);
- }
- /* Z S I N L -- Read a line from a file */
- /*
- Writes the line into the address provided by the caller.
- n is the Kermit "channel number".
- Writing terminates when newline is encountered, newline is not copied.
- Writing also terminates upon EOF or if length x is exhausted.
- Returns 0 on success, -1 on EOF or error.
- */
- int
- zsinl(n,s,x) int n, x; char *s; {
- int a, z = 0; /* z is return code. */
- int count = 0;
- int len = 0;
- char *buf;
- extern CHAR feol; /* Line terminator */
- if (!s || chkfn(n) < 1) /* Make sure file is open, etc */
- return(-1);
- buf = s;
- s[0] = ' '; /* Don't return junk */
- a = -1; /* Current character, none yet. */
- while (x--) { /* Up to given length */
- int old = 0;
- if (feol) /* Previous character */
- old = a;
- if (zchin(n,&a) < 0) { /* Read a character from the file */
- debug(F101,"zsinl zchin fail","",count);
- if (count == 0)
- z = -1; /* EOF or other error */
- break;
- } else
- count++;
- if (feol) { /* Single-character line terminator */
- if (a == feol)
- break;
- } else { /* CRLF line terminator */
- if (a == ' 15') /* CR, get next character */
- continue;
- if (old == ' 15') { /* Previous character was CR */
- if (a == ' 12') { /* This one is LF, so we have a line */
- break;
- } else { /* Not LF, deposit CR */
- *s++ = ' 15';
- x--;
- len++;
- }
- }
- }
- *s = a; /* Deposit character */
- s++;
- len++;
- }
- *s = ' '; /* Terminate the string */
- debug(F111,"zsinl",buf,len);
- return(z);
- }
- /* Z X I N -- Read x bytes from a file */
- /*
- Reads x bytes (or less) from channel n and writes them
- to the address provided by the caller.
- Returns number of bytes read on success, 0 on EOF or error.
- */
- int
- zxin(n,s,x) int n, x; char *s; {
- #ifdef IKSD
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- int a, i;
- a = ttchk();
- if (a < 1) return(0);
- for (i = 0; i < a && i < x; i++)
- s[i] = coninc(0);
- return(i);
- }
- #endif /* IKSD */
- return(fread(s, sizeof (char), x, fp[n]));
- }
- /*
- Z I N F I L L -- Buffered file input.
- (re)fill the file input buffer with data. All file input
- should go through this routine, usually by calling the zminchar()
- macro defined in ckcker.h. Returns:
- Value 0..255 on success, the character that was read.
- -1 on end of file.
- -2 on any kind of error other than end of file.
- -3 timeout when reading from pipe (Kermit packet mode only).
- */
- int
- zinfill() {
- int x;
- extern int kactive, srvping;
- errno = 0;
- #ifdef ZDEBUG
- printf("ZINFILL fp[%d]=%ldn",ZIFILE,fp[ZIFILE]);
- #endif /* ZDEBUG */
- #ifdef IKSD
- if (inserver && !local && fp[ZIFILE] == stdin) {
- int a, i;
- a = ttchk();
- if (a < 0) return(-2);
- for (i = 0; i < a && i < INBUFSIZE; i++) {
- zinbuffer[i] = coninc(0);
- }
- zincnt = i;
- /* set pointer to beginning, (== &zinbuffer[0]) */
- zinptr = zinbuffer;
- if (zincnt == 0) return(-1);
- zincnt--; /* One less char in buffer */
- return((int)(*zinptr++) & 0377); /* because we return the first */
- }
- #endif /* IKSD */
- debug(F101,"zinfill kactive","",kactive);
- if (!(kactive && ispipe[ZIFILE])) {
- if (feof(fp[ZIFILE])) {
- debug(F100,"ZINFILL feof","",0);
- #ifdef ZDEBUG
- printf("ZINFILL EOFn");
- #endif /* ZDEBUG */
- return(-1);
- }
- }
- clearerr(fp[ZIFILE]);
- #ifdef SELECT
- /* Here we can call select() to get a timeout... */
- if (kactive && ispipe[ZIFILE]) {
- int secs, z = 0;
- #ifndef NOXFER
- if (srvping) {
- secs = 1;
- debug(F101,"zinfill calling ttwait","",secs);
- z = ttwait(fileno(fp[ZIFILE]),secs);
- debug(F101,"zinfill ttwait","",z);
- }
- #endif /* NOXFER */
- if (z == 0)
- return(-3);
- }
- #endif /* SELECT */
- /*
- Note: The following read MUST be nonblocking when reading from a pipe
- and we want timeouts to work. See zxcmd().
- */
- zincnt = fread(zinbuffer, sizeof (char), INBUFSIZE, fp[ZIFILE]);
- #ifdef COMMENT
- #ifdef DEBUG
- if (deblog) {
- debug(F011,"ZINFILL fread",zinbuffer,zincnt); /* Much too big */
- }
- #endif /* DEBUG */
- #else /* COMMENT */
- debug(F101,"ZINFILL fread","",zincnt); /* Just the size */
- #endif /* COMMENT */
- #ifdef ZDEBUG
- printf("FREAD=%dn",zincnt);
- #endif /* ZDEBUG */
- if (zincnt == 0) { /* Got nothing? */
- if (ferror(fp[ZIFILE])) {
- debug(F100,"ZINFILL ferror","",0);
- debug(F101,"ZINFILL errno","",errno);
- #ifdef ZDEBUG
- printf("ZINFILL errno=%dn",errno);
- #endif /* ZDEBUG */
- #ifdef EWOULDBLOCK
- return((errno == EWOULDBLOCK) ? -3 : -2);
- #else
- return(-2);
- #endif /* EWOULDBLOCK */
- }
- /* In case feof() didn't work just above -- sometimes it doesn't... */
- if (feof(fp[ZIFILE]) ) {
- debug(F100,"ZINFILL count 0 EOF return -1","",0);
- return (-1);
- } else {
- debug(F100,"ZINFILL count 0 not EOF return -2","",0);
- return(-2);
- }
- }
- zinptr = zinbuffer; /* set pointer to beginning, (== &zinbuffer[0]) */
- zincnt--; /* One less char in buffer */
- return((int)(*zinptr++) & 0377); /* because we return the first */
- }
- /* Z S O U T -- Write a string out to the given file, buffered. */
- int
- zsout(n,s) int n; char *s; {
- int rc = 0;
- rc = chkfn(n);
- if (rc < 1) return(-1); /* Keep this, prevents memory faults */
- if (!s) return(0); /* Null pointer, do nothing, succeed */
- if (!*s) return(0); /* empty string, ditto */
- #ifdef IKSD
- /*
- This happens with client-side Kermit server when a REMOTE command
- was sent from the server to the client and the server is supposed to
- display the text, but of course there is no place to display it
- since it is in remote mode executing Kermit protocol.
- */
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- #ifdef COMMENT
- return(ttol(s,((int)strlen(s)) < 0) ? -1 : 0);
- #else
- return(0);
- #endif /* COMMENT */
- }
- #endif /* IKSD */
- if (n == ZSFILE)
- return(write(fileno(fp[n]),s,(int)strlen(s)));
- rc = fputs(s,fp[n]) == EOF ? -1 : 0;
- if (n == ZWFILE)
- fflush(fp[n]);
- return(rc);
- }
- /* Z S O U T L -- Write string to file, with line terminator, buffered */
- int
- zsoutl(n,s) int n; char *s; {
- if (zsout(n,s) < 0)
- return(-1);
- #ifdef IKSD
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- #ifdef COMMENT
- return(ttoc(LF));
- #else
- return(0); /* See comments in zsout() */
- #endif /* COMMENT */
- }
- #endif /* IKSD */
- if (n == ZSFILE) /* Session log is unbuffered */
- return(write(fileno(fp[n]),"n",1));
- else if (fputs("n",fp[n]) == EOF)
- return(-1);
- if (n == ZDIFIL || n == ZWFILE) /* Flush connection log records */
- fflush(fp[n]);
- return(0);
- }
- /* Z S O U T X -- Write x characters to file, unbuffered. */
- int
- zsoutx(n,s,x) int n, x; char *s; {
- #ifdef IKSD
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- #ifdef COMMENT
- return(ttol(s,x)); /* See comments in zsout() */
- #else
- return(x);
- #endif /* COMMENT */
- }
- #endif /* IKSD */
- #ifdef COMMENT
- if (chkfn(n) < 1) return(-1);
- return(write(fp[n]->_file,s,x));
- #endif /* COMMENT */
- return(write(fileno(fp[n]),s,x) == x ? x : -1);
- }
- /* Z C H O U T -- Add a character to the given file. */
- /* Should return 0 or greater on success, -1 on failure (e.g. disk full) */
- int
- #ifdef CK_ANSIC
- zchout(register int n, char c)
- #else
- zchout(n,c) register int n; char c;
- #endif /* CK_ANSIC */
- /* zchout() */ {
- /* if (chkfn(n) < 1) return(-1); */
- #ifdef IKSD
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- #ifdef COMMENT
- return(ttoc(c));
- #else
- return(0); /* See comments in zsout() */
- #endif /* COMMENT */
- }
- #endif /* IKSD */
- if (n == ZSFILE) /* Use unbuffered for session log */
- return(write(fileno(fp[n]),&c,1) == 1 ? 0 : -1);
- /* Buffered for everything else */
- if (putc(c,fp[n]) == EOF) /* If true, maybe there was an error */
- return(ferror(fp[n])?-1:0); /* Check to make sure */
- else /* Otherwise... */
- return(0); /* There was no error. */
- }
- /* (PWP) buffered character output routine to speed up file IO */
- int
- zoutdump() {
- int x;
- char * zp;
- zoutptr = zoutbuffer; /* Reset buffer pointer in all cases */
- #ifdef DEBUG
- if (deblog)
- debug(F101,"zoutdump zoutcnt","",zoutcnt);
- #endif /* DEBUG */
- if (zoutcnt == 0) { /* Nothing to output */
- return(0);
- } else if (zoutcnt < 0) { /* Unexpected negative argument */
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* and fail. */
- }
- #ifdef IKSD
- if (inserver && !local && fp[ZOFILE] == stdout) {
- #ifdef COMMENT
- x = ttol(zoutbuffer,zoutcnt);
- #else
- x = 1; /* See comments in zsout() */
- #endif /* COMMENT */
- zoutcnt = 0;
- return(x > 0 ? 0 : -1);
- }
- #endif /* IKSD */
- /*
- Frank Prindle suggested that replacing this fwrite() by an fflush()
- followed by a write() would improve the efficiency, especially when
- writing to stdout. Subsequent tests showed a 5-fold improvement.
- */
- #ifdef COMMENT
- if (x = fwrite(zoutbuffer, 1, zoutcnt, fp[ZOFILE])) ...
- #endif /* COMMENT */
- #ifndef CK_NONBLOCK
- fflush(fp[ZOFILE]);
- #endif /* CK_NONBLOCK */
- zp = zoutbuffer;
- while (zoutcnt > 0) {
- if ((x = write(fileno(fp[ZOFILE]),zp,zoutcnt)) > -1) {
- #ifdef DEBUG
- if (deblog) /* Save a function call... */
- debug(F101,"zoutdump wrote","",x);
- #endif /* DEBUG */
- zoutcnt -= x; /* Adjust output buffer count */
- zp += x; /* and pointer */
- } else {
- #ifdef DEBUG
- if (deblog) {
- debug(F101,"zoutdump write error","",errno);
- debug(F101,"zoutdump write returns","",x);
- }
- #endif /* DEBUG */
- zoutcnt = 0; /* Reset output buffer count */
- return(-1); /* write() failed */
- }
- }
- return(0);
- }
- /* C H K F N -- Internal function to verify file number is ok */
- /*
- Returns:
- -1: File number n is out of range
- 0: n is in range, but file is not open
- 1: n in range and file is open
- */
- int
- chkfn(n) int n; {
- /* if (n != ZDFILE) debug(F101,"chkfn","",n); */
- if (n < 0 || n >= ZNFILS) {
- if (n != ZDFILE) debug(F101,"chkfn out of range","",n);
- return(-1);
- } else {
- /* if (n != ZDFILE) debug(F101,"chkfn fp[n]","",fp[n]); */
- return((fp[n] == NULL) ? 0 : 1);
- }
- }
- /* Z G E T F S -- Return file size regardless of accessibility */
- /*
- Used for directory listings, etc.
- Returns:
- The size of the file in bytes, 0 or greater, if the size can be learned.
- -1 if the file size can not be obtained.
- Also (and this is a hack just for UNIX):
- If the argument is the name of a symbolic link,
- the global variable issymlink is set to 1,
- and the global buffer linkname[] gets the link value.
- And it sets zgfs_dir to 1 if it's a directory, otherwise 0.
- This lets us avoid numerous redundant calls to stat().
- */
- int zgfs_link = 0;
- int zgfs_dir = 0;
- time_t zgfs_mtime = 0;
- unsigned int zgfs_mode = 0;
- #ifdef CKSYMLINK
- char linkname[CKMAXPATH+1];
- #ifndef _IFLNK
- #define _IFLNK 0120000
- #endif /* _IFLNK */
- #endif /* CKSYMLINK */
- long
- zgetfs(name) char *name; {
- struct stat buf;
- char fnam[CKMAXPATH+4];
- long size = -1L;
- int x;
- int needrlink = 0;
- char * s;
- #ifdef UNIX
- x = strlen(name);
- if (x == 9 && !strcmp(name,"/dev/null"))
- return(0);
- #endif /* UNIX */
- s = name;
- #ifdef DTILDE
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (!*s) s = name;
- }
- #endif /* DTILDE */
- x = ckstrncpy(fnam,s,CKMAXPATH);
- s = fnam;
- if (x > 0 && s[x-1] == '/')
- s[x-1] = ' ';
- zgfs_dir = 0; /* Assume it's not a directory */
- zgfs_link = 0; /* Assume it's not a symlink */
- zgfs_mtime = 0; /* No time yet */
- zgfs_mode = 0; /* No permission bits yet */
- #ifdef CKSYMLINK /* We're doing symlinks? */
- #ifdef USE_LSTAT /* OK to use lstat()? */
- x = lstat(s,&buf);
- debug(F101,"STAT","",1);
- if (x < 0) /* stat() failed */
- return(-1);
- if ( /* Now see if it's a symlink */
- #ifdef S_ISLNK
- S_ISLNK(buf.st_mode)
- #else
- #ifdef _IFLNK
- ((_IFMT & buf.st_mode) == _IFLNK)
- #endif /* _IFLNK */
- #endif /* S_ISLNK */
- ) {
- zgfs_link = 1; /* It's a symlink */
- linkname[0] = ' '; /* Get the name */
- x = readlink(s,linkname,CKMAXPATH);
- debug(F101,"zgetfs readlink",s,x);
- if (x > -1 && x < CKMAXPATH) { /* It's a link */
- linkname[x] = ' ';
- size = buf.st_size; /* Remember size of link */
- x = stat(s,&buf); /* Now stat the linked-to file */
- debug(F101,"STAT","",2);
- if (x < 0) /* so we can see if it's a directory */
- return(-1);
- } else {
- strcpy(linkname,"(lookup failed)");
- }
- }
- #else /* !USE_LSTAT */
- x = stat(s,&buf); /* No lstat(), use stat() instead */
- debug(F101,"STAT","",3);
- if (x < 0)
- return(-1);
- #endif /* USE_STAT */
- /* Do we need to call readlink()? */
- #ifdef NOLINKBITS
- /*
- lstat() does not work in SCO operating systems. From "man NS lstat":
- lstat obtains information about the file named by path. In the case of a
- symbolic link, lstat returns information about the link, and not the file
- named by the link. It is only used by the NFS automount daemon and should
- not be utilized by users.
- */
- needrlink = 1;
- debug(F101,"zgetfs forced needrlink","",needrlink);
- #else
- #ifdef S_ISLNK
- needrlink = S_ISLNK(buf.st_mode);
- debug(F101,"zgetfs S_ISLNK needrlink","",needrlink);
- #else
- #ifdef _IFLNK
- needrlink = (_IFMT & buf.st_mode) == _IFLNK;
- debug(F101,"zgetfs _IFLNK needrlink","",needrlink);
- #else
- needrlink = 1;
- debug(F101,"zgetfs default needrlink","",needrlink);
- #endif /* _IFLNK */
- #endif /* S_ISLNK */
- #endif /* NOLINKBITS */
- if (needrlink) {
- linkname[0] = ' ';
- errno = 0;
- x = readlink(s,linkname,CKMAXPATH);
- #ifdef DEBUG
- debug(F111,"zgetfs readlink",s,x);
- if (x < 0)
- debug(F101,"zgetfs readlink errno","",errno);
- else
- debug(F110,"zgetfs readlink result",linkname,0);
- #endif /* DEBUG */
- if (x > -1 && x < CKMAXPATH) {
- zgfs_link = 1;
- linkname[x] = ' ';
- }
- }
- #else /* !CKSYMLINK */
- x = stat(s,&buf); /* Just stat the file */
- debug(F101,"STAT","",4);
- if (x < 0) /* and get the size */
- return(-1);
- #endif /* CKSYMLINK */
- zgfs_mtime = buf.st_mtime;
- zgfs_mode = buf.st_mode;
- zgfs_dir = (S_ISDIR(buf.st_mode)) ? 1 : 0; /* Set "is directory" flag */
- return((size < 0L) ? buf.st_size : size); /* Return the size */
- }
- /* Z C H K I -- Check if input file exists and is readable */
- /*
- Returns:
- >= 0 if the file can be read (returns the size).
- -1 if file doesn't exist or can't be accessed,
- -2 if file exists but is not readable (e.g. a directory file).
- -3 if file exists but protected against read access.
- For Berkeley Unix, a file must be of type "regular" to be readable.
- Directory files, special files, and symbolic links are not readable.
- */
- long
- zchki(name) char *name; {
- struct stat buf;
- char * s;
- int x, itsadir = 0;
- extern int zchkid;
- if (!name)
- return(-1);
- x = strlen(name);
- if (x < 1)
- return(-1);
- s = name;
- #ifdef UNIX
- if (x == 9 && !strcmp(s,"/dev/null"))
- return(0);
- #endif /* UNIX */
- #ifdef DTILDE
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (!*s) s = name;
- }
- #endif /* DTILDE */
- x = stat(s,&buf);
- debug(F101,"STAT","",5);
- if (x < 0) {
- debug(F111,"zchki stat fails",s,errno);
- return(-1);
- }
- if (S_ISDIR (buf.st_mode))
- itsadir = 1;
- if (!(itsadir && zchkid)) { /* Unless this... */
- if (!S_ISREG (buf.st_mode) /* Must be regular file */
- #ifdef S_ISFIFO
- && !S_ISFIFO (buf.st_mode) /* or FIFO */
- #endif /* S_ISFIFO */
- ) {
- debug(F111,"zchki not regular file",s,x);
- return(-2);
- }
- }
- debug(F111,"zchki stat ok:",s,x);
- #ifdef SW_ACC_ID
- debug(F100,"zchki swapping ids for access()","",0);
- priv_on();
- #endif /* SW_ACC_ID */
- x = access(s,R_OK);
- #ifdef SW_ACC_ID
- priv_off();
- debug(F100,"zchki swapped ids restored","",0);
- #endif /* SW_ACC_ID */
- if (x < 0) { /* Is the file accessible? */
- debug(F111,"zchki access failed:",s,x); /* No */
- return(-3);
- } else {
- iflen = buf.st_size; /* Yes, remember size */
- ckstrncpy(nambuf,s,CKMAXPATH); /* and name globally. */
- debug(F111,"zchki access ok:",s,iflen);
- return((iflen > -1L) ? iflen : 0L);
- }
- }
- /* Z C H K O -- Check if output file can be created */
- /*
- Returns -1 if write permission for the file would be denied, 0 otherwise.
- NOTE: The design is flawed. There is no distinction among:
- . Can I overwrite an existing file?
- . Can I create a file (or directory) in an existing directory?
- . Can I create a file (or directory) and its parent(s)?
- */
- int
- zchko(name) char *name; {
- int i, x, itsadir = 0;
- char *s;
- extern int zchkod; /* Used by IF WRITEABLE */
- if (!name) return(-1); /* Watch out for null pointer. */
- x = (int)strlen(name); /* Get length of filename */
- debug(F111,"zchko",name,zchkod);
- #ifdef UNIX
- /*
- Writing to null device is OK.
- */
- if (x == 9 && !strcmp(name,"/dev/null"))
- return(0);
- #endif /* UNIX */
- s = name;
- #ifdef DTILDE
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (!*s) s = name;
- }
- #endif /* DTILDE */
- name = s;
- s = NULL;
- /*
- zchkod is a global flag meaning we're checking not to see if the directory
- file is writeable, but if it's OK to create files IN the directory.
- */
- if (!zchkod && isdir(name)) /* Directories are not writeable */
- return(-1);
- s = malloc(x+3); /* Must copy because we can't */
- if (!s) { /* write into our argument. */
- fprintf(stderr,"zchko: Malloc error 46n");
- return(-1);
- }
- strcpy(s,name);
- for (i = x; i > 0; i--) { /* Strip filename from right. */
- if (ISDIRSEP(s[i-1])) {
- itsadir = 1;
- break;
- }
- }
- debug(F101,"zchko i","",i);
- debug(F101,"zchko itsadir","",itsadir);
- #ifdef COMMENT
- /* X/OPEN XPG3-compliant systems fail if argument ends with "/"... */
- if (i == 0) /* If no path, use current directory */
- strcpy(s,"./");
- else /* Otherwise, use given one. */
- s[i] = ' ';
- #else
- #ifdef COMMENT
- /*
- The following does not work for "foo/bar" where the foo directory does
- not exist even though we could create it: access("foo/.") fails, but
- access("foo") works OK.
- */
- /* So now we use "path/." if path given, or "." if no path given. */
- s[i++] = '.'; /* Append "." to path. */
- s[i] = ' ';
- #else
- /* So NOW we strip path segments from the right as long as they don't */
- /* exist -- we only call access() for path segments that *do* exist.. */
- /* (But this isn't quite right either since now zchko(/foo/bar/baz/xxx) */
- /* succeeds when I have write access to foo and bar but baz doesn't exit.) */
- if (itsadir && i > 0) {
- s[i-1] = ' ';
- while (s[0] && !isdir(s)) {
- for (i = (int)strlen(s); i > 0; i--) {
- if (ISDIRSEP(s[i-1])) {
- s[i-1] = ' ';
- break;
- }
- }
- if (i == 0)
- s[0] = ' ';
- }
- } else {
- s[i++] = '.'; /* Append "." to path. */
- s[i] = ' ';
- }
- #endif /* COMMENT */
- #endif /* COMMENT */
- if (!s[0])
- strcpy(s,".");
- #ifdef SW_ACC_ID
- debug(F100,"zchko swapping ids for access()","",0);
- priv_on();
- #endif /* SW_ACC_ID */
- x = access(s,W_OK); /* Check access of path. */
- #ifdef SW_ACC_ID
- priv_off();
- debug(F100,"zchko swapped ids restored","",0);
- #endif /* SW_ACC_ID */
- if (x < 0)
- debug(F111,"zchko access failed:",s,errno);
- else
- debug(F111,"zchko access ok:",s,x);
- free(s); /* Free temporary storage */
- return((x < 0) ? -1 : 0); /* and return. */
- }
- /* Z D E L E T -- Delete the named file. */
- int
- zdelet(name) char *name; {
- int x;
- #ifdef CK_LOGIN
- if (isguest)
- x = -1;
- else
- #endif /* CK_LOGIN */
- x = unlink(name);
- debug(F110,"zdelet",name,0);
- #ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FC && ckxlogging) {
- fullname[0] = ' ';
- zfnqfp(name,CKMAXPATH,fullname);
- debug(F110,"zdelet fullname",fullname,0);
- if (x < 0)
- syslog(LOG_INFO, "file[] %s: delete failed (%m)", fullname);
- else
- syslog(LOG_INFO, "file[] %s: delete ok", fullname);
- }
- #endif /* CKSYSLOG */
- return(x);
- }
- /* Z R T O L -- Convert remote filename into local form */
- VOID
- zrtol(name,name2) char *name, *name2; {
- nzrtol(name,name2,1,0,CKMAXPATH);
- }
- VOID
- nzrtol(name,name2,fncnv,fnrpath,max)
- char *name, *name2; int fncnv, fnrpath, max;
- { /* nzrtol */
- char *s, *p;
- int flag = 0, n = 0;
- char fullname[CKMAXPATH+1];
- int devnull = 0;
- int acase = 0;
- if (!name2) return;
- if (!name) name = "";
- debug(F110,"nzrtol name",name,0);
- #ifdef DTILDE
- s = name;
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (*s) name = s;
- }
- #endif /* DTILDE */
- /* Handle the path -- we don't have to convert its format, since */
- /* the standard path format and our (UNIX) format are the same. */
- fullname[0] = NUL;
- devnull = !strcmp(name,"/dev/null");
- if (!devnull && fnrpath == PATH_OFF) { /* RECEIVE PATHNAMES OFF */
- zstrip(name,&p);
- strncpy(fullname,p,CKMAXPATH);
- } else if (!devnull && fnrpath == PATH_ABS) { /* REC PATHNAMES ABSOLUTE */
- strncpy(fullname,name,CKMAXPATH);
- } else if (!devnull && isabsolute(name)) { /* RECEIVE PATHNAMES RELATIVE */
- sprintf(fullname,".%s",name);
- } else { /* Ditto */
- ckstrncpy(fullname,name,CKMAXPATH);
- }
- fullname[CKMAXPATH] = NUL;
- debug(F110,"nzrtol fullname",fullname,0);
- #ifndef NOTRUNCATE
- /*
- The maximum length for any segment of a filename is MAXNAMLEN, defined
- above. On some platforms (at least QNX) if a segment exceeds this limit,
- the open fails with ENAMETOOLONG, so we must prevent it by truncating each
- overlong name segment to the maximum segment length before passing the
- name to open(). This must be done even when file names are literal, so as
- not to halt a file transfer unnecessarily.
- */
- {
- char buf[CKMAXPATH+1]; /* New temporary buffer on stack */
- char *p = fullname; /* Source and */
- char *s = buf; /* destination pointers */
- int i = 0, n = 0;
- debug(F101,"nzrtol sizing MAXNAMLEN","",MAXNAMLEN);
- while (*p && n < CKMAXPATH) { /* Copy name to new buffer */
- if (++i > MAXNAMLEN) { /* If this segment too long */
- while (*p && *p != '/') /* skip past the rest... */
- p++;
- i = 0; /* and reset counter. */
- } else if (*p == '/') { /* End of this segment. */
- i = 0; /* Reset counter. */
- }
- *s++ = *p++; /* Copy this character. */
- n++;
- }
- *s = NUL;
- ckstrncpy(fullname,buf,CKMAXPATH); /* Copy back to original buffer. */
- debug(F111,"nzrtol sizing",fullname,n);
- }
- #endif /* NOTRUNCATE */
- if (!fncnv || devnull) { /* Not converting */
- ckstrncpy(name2,fullname,max); /* We're done. */
- return;
- }
- name = fullname; /* Converting */
- p = name2;
- for (; *name != ' ' && n < maxnam; name++) {
- if (*name > SP) flag = 1; /* Strip leading blanks and controls */
- if (flag == 0 && *name < '!')
- continue;
- if (isupper(*name)) /* Check for mixed case */
- acase |= 1;
- else if (islower(*name))
- acase |= 2;
- *p++ = *name;
- n++;
- }
- *p-- = ' '; /* Terminate */
- while (*p < '!' && p > name2) /* Strip trailing blanks & controls */
- *p-- = ' ';
- if (*name2 == ' ') { /* Nothing left? */
- strcpy(name2,"NONAME"); /* do this... */
- } else if (acase == 1) { /* All uppercase? */
- p = name2; /* So convert all letters to lower */
- while (*p) {
- if (isupper(*p))
- *p = tolower(*p);
- p++;
- }
- }
- debug(F110,"nzrtol new name",name2,0);
- }
- /* Z S T R I P -- Strip device & directory name from file specification */
- /* Strip pathname from filename "name", return pointer to result in name2 */
- static char work[CKMAXPATH+1];
- VOID
- zstrip(name,name2) char *name, **name2; {
- char *cp, *pp;
- int n = 0;
- debug(F110,"zstrip before",name,0);
- if (!name) { *name2 = ""; return; }
- pp = work;
- #ifdef DTILDE
- /* Strip leading tilde */
- if (*name == '~') name++;
- debug(F110,"zstrip after tilde-stripping",name,0);
- #endif /* DTILDE */
- for (cp = name; *cp; cp++) {
- if (ISDIRSEP(*cp)) {
- pp = work;
- n = 0;
- } else {
- *pp++ = *cp;
- if (n++ >= CKMAXPATH)
- break;
- }
- }
- *pp = ' '; /* Terminate the string */
- *name2 = work;
- debug(F110,"zstrip after",*name2,0);
- }
- /* Z L T O R -- Local TO Remote */
- VOID
- zltor(name,name2) char *name, *name2; {
- nzltor(name,name2,1,0,CKMAXPATH);
- }
- /* N Z L T O R -- New Local TO Remote */
- VOID
- nzltor(name,name2,fncnv,fnspath,max)
- char *name, *name2; int fncnv, fnspath, max;
- { /* nzltor */
- char *cp, *pp;
- #ifdef COMMENT
- int dc = 0;
- #endif /* COMMENT */
- int n = 0;
- char *dotp = NULL;
- char *dirp = NULL;
- char fullname[CKMAXPATH+1];
- char *p;
- CHAR c;
- #ifndef NOCSETS
- extern int fcharset, /* tcharset, */ language;
- int langsv;
- _PROTOTYP ( CHAR (*sxo), (CHAR) ) = NULL; /* Translation functions */
- #ifdef CK_ANSIC
- extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])(CHAR);
- #else
- extern CHAR (*xls[MAXTCSETS+1][MAXFCSETS+1])();
- #endif /* CK_ANSIC */
- langsv = language;
- language = L_USASCII;
- #ifdef COMMENT
- /* Proper translation of filenames must be done elsewhere */
- n = tcharset ? tcharset : TC_USASCII;
- sxo = xls[n][fcharset];
- #else
- sxo = xls[TC_USASCII][fcharset];
- #endif /* COMMENT */
- #endif /* NOCSETS */
- debug(F110,"nzltor name",name,0);
- /* Handle pathname */
- fullname[0] = NUL;
- if (fnspath == PATH_OFF) { /* PATHNAMES OFF */
- zstrip(name,&p);
- ckstrncpy(fullname,p,CKMAXPATH);
- } else { /* PATHNAMES RELATIVE or ABSOLUTE */
- int x = 0;
- char * p = name;
- while (1) {
- if (!strncmp(p,"../",3))
- p += 3;
- else if (!strncmp(p,"./",2))
- p += 2;
- else
- break;
- }
- if (fnspath == PATH_ABS) { /* ABSOLUTE */
- zfnqfp(p,CKMAXPATH,fullname);
- } else { /* RELATIVE */
- ckstrncpy(fullname,p,CKMAXPATH);
- }
- }
- debug(F110,"nzltor fullname",fullname,0);
- if (!fncnv) { /* Not converting */
- ckstrncpy(name2,fullname,max); /* We're done. */
- #ifndef NOCSETS
- langsv = language;
- #endif /* NOCSETS */
- return;
- }
- name = fullname; /* Converting */
- #ifdef aegis
- char *namechars;
- int tilde = 0, bslash = 0;
- if ((namechars = getenv("NAMECHARS")) != NULL) {
- if (ckstrchr(namechars, '~' ) != NULL) tilde = '~';
- if (ckstrchr(namechars, '\') != NULL) bslash = '\';
- } else {
- tilde = '~';
- bslash = '\';
- }
- #endif /* aegis */
- pp = work; /* Output buffer */
- for (cp = name, n = 0; *cp && n < max; cp++,n++) { /* Convert name chars */
- c = *cp;
- #ifndef NOCSETS
- if (sxo) c = (*sxo)(c); /* Convert to ASCII */
- #endif /* NOCSETS */
- if (islower(c)) /* Uppercase letters */
- *pp++ = toupper(c); /* Change tilde to hyphen */
- else if (c == '~')
- *pp++ = '-';
- else if (c == '#') /* Change number sign to 'X' */
- *pp++ = 'X';
- else if (c == '*' || c == '?') /* Change wildcard chars to 'X' */
- *pp++ = 'X';
- else if (c == ' ') /* Change space to underscore */
- *pp++ = '_';
- else if (c < ' ') /* Change space and controls to 'X' */
- *pp++ = 'X';
- else if (c == '.') { /* Change dot to underscore */
- dotp = pp; /* Remember where we last did this */
- *pp++ = '_';
- } else {
- if (c == '/')
- dirp = pp;
- *pp++ = c;
- }
- }
- *pp = NUL; /* Tie it off. */
- #ifdef COMMENT
- if (dotp) *dotp = '.'; /* Restore last dot (if any) */
- #else
- if (dotp > dirp) *dotp = '.'; /* Restore last dot in file name */
- #endif /* COMMENT */
- cp = name2; /* If nothing before dot, */
- if (*work == '.') *cp++ = 'X'; /* insert 'X' */
- ckstrncpy(cp,work,max);
- #ifndef NOCSETS
- langsv = language;
- #endif /* NOCSETS */
- debug(F110,"nzltor name2",name2,0);
- }
- /* Z C H D I R -- Change directory */
- /*
- Call with:
- dirnam = pointer to name of directory to change to,
- which may be "" or NULL to indicate user's home directory.
- Returns:
- 0 on failure
- 1 on success
- */
- int
- zchdir(dirnam) char *dirnam; {
- char *hd, *sp, *p;
- #ifdef IKSDB
- _PROTOTYP (int slotdir,(char *,char *));
- #endif /* IKSDB */
- debug(F110,"zchdir",dirnam,0);
- if (!dirnam) dirnam = "";
- if (!*dirnam) /* If argument is null or empty, */
- dirnam = zhome(); /* use user's home directory. */
- sp = dirnam;
- debug(F110,"zchdir 2",dirnam,0);
- #ifdef DTILDE
- hd = tilde_expand(dirnam); /* Attempt to expand tilde */
- if (!hd) hd = "";
- if (*hd == ' ') hd = dirnam; /* in directory name. */
- #else
- hd = dirnam;
- #endif /* DTILDE */
- debug(F110,"zchdir 3",hd,0);
- #ifdef pdp11
- /* Just to save some space */
- return((chdir(hd) == 0) ? 1 : 0);
- #else
- if (chdir(hd) == 0) { /* Try to cd */
- #ifdef IKSDB
- if (inserver && ikdbopen)
- slotdir(isguest ? anonroot : "", zgtdir());
- #endif /* IKSDB */
- return(1);
- }
- return(0);
- #endif /* pdp11 */
- }
- int
- #ifdef CK_ANSIC
- zchkpid(unsigned long pid)
- #else
- zchkpid(pid) unsigned long pid;
- #endif /* CK_ANSIC */
- {
- return((kill((PID_T)pid,0) < 0) ? 0 : 1);
- }
- /* Z H O M E -- Return pointer to user's home directory */
- char *
- zhome() {
- #ifdef Plan9
- char *home = getenv("home");
- #else
- char *home = getenv("HOME");
- #endif /* Plan9 */
- return(home ? home : ".");
- }
- /* Z G T D I R -- Returns a pointer to the current directory */
- /*
- The "preferred" interface for getting the current directory in modern UNIX
- is getcwd() [POSIX 1003.1 5.2.2]. However, on certain platforms (such as
- SunOS), it is implemented by forking a shell, feeding it the pwd command,
- and returning the result, which is not only inefficient but also can result
- in stray messages to the terminal. In such cases -- as well as when
- getcwd() is not available at all -- getwd() can be used instead by defining
- USE_GETWD. However, note that getwd() provides no buffer-length argument
- and therefore no safeguard against memory leaks.
- */
- #ifndef USE_GETWD
- #ifdef BSD42
- #define USE_GETWD
- #else
- #ifdef SUNOS4
- #define USE_GETWD
- #endif /* SUNOS4 */
- #endif /* BSD42 */
- #endif /* USE_GETWD */
- #ifdef pdp11
- #define CWDBL 80 /* Save every byte we can... */
- #else
- #define CWDBL CKMAXPATH
- #endif /* pdp11 */
- static char cwdbuf[CWDBL+2];
- /*
- NOTE: The getcwd() prototypes are commented out on purpose. If you get
- compile-time warnings, search through your system's header files to see
- which one has the needed prototype, and #include it. Usually it is
- <unistd.h>. See the section for including <unistd.h> in ckcdeb.h and
- make any needed adjustments there (and report them).
- */
- char *
- zgtdir() {
- char * buf = cwdbuf;
- char * s;
- int x;
- #ifdef USE_GETWD
- extern char *getwd();
- s = getwd(buf);
- debug(F110,"zgtdir BSD4 getwd()",s,0);
- if (!s) s = "./";
- return(s);
- #else
- #ifdef BSD44
- #ifdef DCLGETCWD
- _PROTOTYP( char * getcwd, (char *, SIZE_T) );
- #endif /* DCLGETCWD */
- debug(F101,"zgtdir BSD44 CWDBL","",CWDBL);
- s = getcwd(buf,CWDBL);
- if (!s) s = "./";
- return(s);
- #else
- #ifdef MINIX2
- #ifdef DCLGETCWD
- _PROTOTYP( char * getcwd, (char *, SIZE_T) );
- #endif /* DCLGETCWD */
- debug(F101,"zgtdir MINIX2 CWDBL","",CWDBL);
- s = getcwd(buf,CWDBL);
- if (!s) s = "./";
- return(s);
- #else
- #ifdef SVORPOSIX
- #ifdef COMMENT
- /* This non-ANSI prototype can be fatal at runtime! (e.g. in SCO3.2v5.0.5). */
- /* Anyway it's already prototyped in some header file that we have included. */
- extern char *getcwd();
- #else
- #ifdef DCLGETCWD
- _PROTOTYP( char * getcwd, (char *, SIZE_T) );
- #endif /* DCLGETCWD */
- #endif /* COMMENT */
- debug(F101,"zgtdir SVORPOSIX CWDBL","",CWDBL);
- s = getcwd(buf,CWDBL);
- if (!s) s = "./";
- return(s);
- #else
- #ifdef COHERENT
- #ifdef _I386
- #ifdef DCLGETCWD
- extern char *getcwd();
- #endif /* DCLGETCWD */
- debug(F101,"zgtdir COHERENT _I386 CWDBL","",CWDBL);
- s = getcwd(buf,CWDBL);
- if (!s) s = "./";
- return(s);
- #else
- extern char *getwd();
- debug(F101,"zgtdir COHERENT CWDBL","",CWDBL);
- s = getwd(buf);
- if (!s) s = "./";
- return(s);
- #endif /* _I386 */
- #else
- #ifdef SUNOS4
- debug(F101,"zgtdir SUNOS CWDBL","",CWDBL);
- s = getcwd(buf,CWDBL);
- if (!s) s = "./";
- return(s);
- #else
- return("./");
- #endif /* SUNOS4 */
- #endif /* COHERENT */
- #endif /* SYSVORPOSIX */
- #endif /* MINIX2 */
- #endif /* BSD44 */
- #endif /* USE_GETWD */
- }
- /* Z X C M D -- Run a system command so its output can be read like a file */
- #ifndef NOPUSH
- int
- zxcmd(filnum,comand) int filnum; char *comand; {
- int out;
- int pipes[2];
- extern int kactive; /* From ckcpro.w and ckcmai.c */
- if (nopush) {
- debug(F100,"zxcmd fails: nopush","",0);
- return(-1);
- }
- debug(F111,"zxcmd",comand,filnum);
- if (chkfn(filnum) < 0) return(-1); /* Need a valid Kermit file number. */
- if (filnum == ZSTDIO || filnum == ZCTERM) /* But not one of these. */
- return(0);
- out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
- debug(F101,"zxcmd out",comand,out);
- /* Output to a command */
- if (out) { /* Need popen() to do this. */
- #ifdef NOPOPEN
- return(0); /* no popen(), fail. */
- #else
- /* Use popen() to run the command. */
- #ifdef _POSIX_SOURCE
- /* Strictly speaking, popen() is not available in POSIX.1 */
- #define DCLPOPEN
- #endif /* _POSIX_SOURCE */
- if (priv_chk() || ((fp[filnum] = popen(comand,"w")) == NULL)) {
- return(0);
- } else {
- #ifdef COMMENT
- /* I wonder what this is all about... */
- close(pipes[0]); /* Don't need the input side */
- fp[filnum] = fdopen(pipes[1],"w"); /* Open a stream for output. */
- fp[ZSYSFN] = fp[filnum]; /* Remember. */
- #endif /* COMMENT */
- ispipe[filnum] = 1;
- zoutcnt = 0; /* (PWP) reset input buffer */
- zoutptr = zoutbuffer;
- return(1);
- }
- #endif /* NOPOPEN */
- }
- /* Input from a command */
- #ifdef SNI541
- /* SINIX-L 5.41 does not like fdopen() */
- return(0);
- #else
- if (pipe(pipes) != 0) {
- debug(F100,"zxcmd pipe failure","",0);
- return(0); /* can't make pipe, fail */
- }
- /* Create a fork in which to run the named process */
- if ((
- #ifdef aegis
- pid = vfork() /* child */
- #else
- pid = fork() /* child */
- #endif /* aegis */
- ) == 0) {
- /* We're in the fork. */
- char *shpath, *shname, *shptr; /* Find user's preferred shell */
- #ifndef aegis
- struct passwd *p;
- char *defshell;
- #ifdef HPUX10 /* Default shell */
- defshell = "/usr/bin/sh";
- #else
- #ifdef Plan9
- defshell = "/bin/rc";
- #else
- defshell = "/bin/sh";
- #endif /* Plan9 */
- #endif /* HPUX10 */
- #endif /* aegis */
- if (priv_can()) exit(1); /* Turn off any privileges! */
- debug(F101,"zxcmd pid","",pid);
- close(pipes[0]); /* close input side of pipe */
- close(0); /* close stdin */
- if (open("/dev/null",0) < 0) return(0); /* replace input by null */
- #ifndef OXOS
- #ifndef SVORPOSIX
- dup2(pipes[1],1); /* BSD: replace stdout & stderr */
- dup2(pipes[1],2); /* by the pipe */
- #else
- close(1); /* AT&T: close stdout */
- if (dup(pipes[1]) != 1) /* Send stdout to the pipe */
- return(0);
- close(2); /* Send stderr to the pipe */
- if (dup(pipes[1]) != 2)
- return(0);
- #endif /* SVORPOSIX */
- #else /* OXOS */
- dup2(pipes[1],1);
- dup2(pipes[1],2);
- #endif /* OXOS */
- close(pipes[1]); /* Don't need this any more. */
- #ifdef aegis
- if ((shpath = getenv("SERVERSHELL")) == NULL)
- shpath = "/bin/sh";
- #else
- shpath = getenv("SHELL"); /* What shell? */
- if (shpath == NULL) {
- p = getpwuid( real_uid() ); /* Get login data */
- debug(F111,"zxcmd shpath","getpwuid()",p);
- if (p == (struct passwd *)NULL || !*(p->pw_shell))
- shpath = defshell;
- else shpath = p->pw_shell;
- }
- #endif /* aegis */
- shptr = shname = shpath;
- while (*shptr != ' ')
- if (*shptr++ == '/')
- shname = shptr;
- debug(F110,shpath,shname,0);
- restorsigs(); /* Restore ignored signals */
- execl(shpath,shname,"-c",comand,(char *)NULL); /* Execute the cmd */
- exit(0); /* just punt if it failed. */
- } else if (pid == (PID_T) -1) {
- debug(F100,"zxcmd fork failure","",0);
- return(0);
- }
- debug(F101,"zxcmd pid","",pid);
- close(pipes[1]); /* Don't need the output side */
- ispipe[filnum] = 1; /* Remember it's a pipe */
- fp[filnum] = fdopen(pipes[0],"r"); /* Open a stream for input. */
- #ifdef DONDELAY
- if (filnum == ZIFILE && kactive) { /* Make pipe reads nonblocking */
- int flags, x;
- if ((flags = fcntl(fileno(fp[filnum]),F_GETFL,0)) > -1) {
- debug(F101,"zxcmd fcntl 1 pipe flags","",flags);
- x = fcntl(fileno(fp[filnum]),F_SETFL, flags |
- #ifdef QNX
- O_NONBLOCK
- #else
- O_NDELAY
- #endif /* QNX */
- );
- debug(F101,"zxcmd fcntl 2 result","",x);
- }
- }
- #endif /* DONDELAY */
- #endif /* SNI541 */
- fp[ZSYSFN] = fp[filnum]; /* Remember. */
- zincnt = 0; /* (PWP) reset input buffer */
- zinptr = zinbuffer;
- return(1);
- } /* zxcmd */
- /* Z C L O S F - wait for the child fork to terminate and close the pipe. */
- /* Used internally by zclose - returns -1 on failure, 1 on success. */
- int
- zclosf(filnum) int filnum; {
- int wstat, out;
- int statusp;
- debug(F101,"zclosf filnum","",filnum);
- out = (filnum == ZIFILE || filnum == ZRFILE) ? 0 : 1 ;
- debug(F101,"zclosf out","",out);
- #ifndef NOPOPEN
- if (ispipe[filnum]
- /* In UNIX we use popen() only for output files */
- && out
- ) {
- int x;
- x = pclose(fp[filnum]);
- pexitstat = x >> 8;
- debug(F101,"zclosf pclose","",x);
- debug(F101,"zclosf pexitstat","",pexitstat);
- fp[filnum] = fp[ZSYSFN] = NULL;
- ispipe[filnum] = 0;
- return((x != 0) ? -1 : 1);
- }
- #endif /* NOPOPEN */
- debug(F101,"zclosf fp[filnum]","", fp[filnum]);
- debug(F101,"zclosf fp[ZSYSFN]","", fp[ZSYSFN]);
- if (pid != (PID_T) 0) {
- debug(F101,"zclosf killing pid","",pid);
- #ifdef Plan9
- kill(pid, SIGKILL);
- #else
- kill(pid,9);
- #endif /* Plan9 */
- #ifndef CK_CHILD
- /*
- This is the original code (before 20 April 1997) and has proven totally
- portable. But it does not give us the process's return code.
- */
- while ((wstat = wait((WAIT_T *)0)) != pid && wstat != -1) ;
- #else
- /* Here we try to get the return code. Let's hope this is portable too. */
- while ((wstat = wait(&statusp)) != pid && wstat != -1) ;
- pexitstat = (statusp & 0xff) ? statusp : statusp >> 8;
- debug(F101,"zclosf wait statusp","",statusp);
- debug(F101,"zclosf wait pexitstat","",pexitstat);
- #endif /* CK_CHILD */
- pid = 0;
- }
- fclose(fp[filnum]);
- fp[filnum] = fp[ZSYSFN] = NULL;
- ispipe[filnum] = 0;
- debug(F101,"zclosf fp[filnum]","",fp[filnum]);
- #ifdef CK_CHILD
- return(pexitstat == 0 ? 1 : -1);
- #else
- return(1);
- #endif /* CK_CHILD */
- }
- #else /* NOPUSH */
- int
- zxcmd(filnum,comand) int filnum; char *comand; {
- return(0);
- }
- int
- zclosf(filnum) int filnum; {
- return(EOF);
- }
- #endif /* NOPUSH */
- /* Z X P A N D -- Expand a wildcard string into an array of strings */
- /*
- As of C-Kermit 7.0, this API is obsolete, replaced by nzxpand(), and this
- function is only used internally. See nzxpand() below.
- Returns the number of files that match fnarg, with data structures set up
- so that first file (if any) will be returned by the next znext() call.
- Depends on external variable wildxpand: 0 means we expand wildcards
- internally, nonzero means we call the shell to do it.
- */
- static int xdironly = 0;
- static int xfilonly = 0;
- static int xmatchdot = 0;
- static int xrecursive = 0;
- static int xnobackup = 0;
- #ifndef pdp11
- static
- #endif /* pdp11 */
- int
- zxpand(fnarg) char *fnarg; {
- char fnbuf[CKMAXPATH+8];
- char * fn;
- char *p, *s;
- #ifdef DTILDE /* Built with tilde-expansion? */
- char *tnam;
- #endif /* DTILDE */
- int x;
- if (!fnarg) /* If no argument provided */
- return(0); /* Return zero files found */
- debug(F110,"zxpand entry",fnarg,0);
- debug(F101,"zxpand xdironly","",xdironly);
- debug(F101,"zxpand xfilonly","",xfilonly);
- #ifdef COMMENT
- /*
- This would have been perfect, except it makes us return fully qualified
- pathnames for all files.
- */
- zfnqfp(fnarg,CKMAXPATH,fnbuf);
- debug(F110,"zxpand zfnqfp",fnbuf,0);
- s = zgtdir();
- debug(F110,"zxpand zgtdir",s,0);
- p = fnbuf;
- while (*p && *s) /* Make it relative */
- if (*s++ != *p++)
- break;
- fn = (*s) ? fnbuf : p;
- debug(F110,"zxpand fn 0",fn,0);
- if (!*fn) {
- fn = fnbuf;
- fnbuf[0] = '*';
- fnbuf[1] = ' ';
- }
- debug(F110,"zxpand fn 0.5",fn,0);
- #else
- #ifdef DTILDE /* Built with tilde-expansion? */
- if (*fnarg == '~') { /* Starts with tilde? */
- tnam = tilde_expand(fnarg); /* Try to expand it. */
- ckstrncpy(fnbuf,tnam,CKMAXPATH);
- } else
- #endif /* DTILDE */
- ckstrncpy(fnbuf,fnarg,CKMAXPATH);
- fn = fnbuf; /* Point to what we'll work with */
- #endif /* COMMENT */
- debug(F110,"zxpand fn 1",fn,0);
- if (!*fn) /* But make sure something is there */
- return(0);
- p = fn + (int)strlen(fn) - 1;
- if (*p == '/') { /* If last char = / it must be a dir */
- strcat(fn, "*"); /* so append '*' */
- } else if (p > fn) { /* If ends in "/." */
- if (*(p-1) == '/' && *p == '.') /* change '.' to '*' */
- *p = '*';
- } else if (p == fn) { /* If it's '.' alone */
- if (*p == '.') /* change '.' to '*' */
- *p = '*';
- }
- debug(F110,"zxpand fn 2",fn,0);
- x = isdir(fn); /* Is it a directory? */
- debug(F111,"zxpand isdir 1",fn,x);
- if (x) { /* If so, make it into a wildcard */
- if ((x = strlen(fn)) > 0) {
- if (!ISDIRSEP(fn[x-1]))
- fn[x++] = DIRSEP;
- fn[x++] = '*';
- fn[x] = ' ';
- }
- }
- debug(F110,"zxpand fn 3",fn,0);
- #ifndef NOPUSH
- if (!nopush && wildxpand) /* Who is expanding wildcards? */
- fcount = (mtchs == NULL && /* Shell */
- (mtchs = (char **)malloc(MAXWLD * sizeof(*mtchs))) == NULL)
- ? 0
- : shxpand(fn,mtchs,MAXWLD);
- else
- #endif /* NOPUSH */
- fcount = (mtchs == NULL && /* Kermit */
- (mtchs = (char **)malloc(MAXWLD * sizeof(*mtchs))) == NULL)
- ? 0
- : fgen(fn,mtchs,MAXWLD); /* Look up the file. */
- mtchptr = mtchs; /* Save pointer for next. */
- nxpand = fcount;
- #ifdef DEBUG
- if (deblog) {
- if (fcount > 1)
- debug(F111,"zxpand ok",mtchs[0],fcount);
- else
- debug(F101,"zxpand fcount","",fcount);
- }
- #endif /* DEBUG */
- return(fcount);
- }
- /* N Z X P A N D -- Expland a file list, with options. */
- /*
- Call with:
- s = pointer to filename or pattern.
- flags = option bits:
- flags & ZX_FILONLY Match regular files
- flags & ZX_DIRONLY Match directories
- flags & ZX_RECURSE Descend through directory tree
- flags & ZX_MATCHDOT Match "dot files"
- flags & ZX_NOBACKUP Don't match "backup files"
- Returns the number of files that match s, with data structures set up
- so that first file (if any) will be returned by the next znext() call.
- */
- int
- nzxpand(s,flags) char * s; int flags; {
- int x;
- debug(F111,"nzxpand",s,flags);
- x = flags & (ZX_DIRONLY|ZX_FILONLY);
- xdironly = (x == ZX_DIRONLY);
- xfilonly = (x == ZX_FILONLY);
- if (xdironly && xfilonly) {
- xdironly = 0;
- xfilonly = 0;
- }
- xmatchdot = (flags & ZX_MATCHDOT);
- xrecursive = (flags & ZX_RECURSE);
- xnobackup = (flags & ZX_NOBACKUP);
- debug(F101,"nzxpand xdironly","",xdironly);
- debug(F101,"nzxpand xfilonly","",xfilonly);
- debug(F101,"nzxpand xmatchdot","",xmatchdot);
- debug(F101,"nzxpand xrecursive","",xrecursive);
- debug(F101,"nzxpand xnobackup","",xnobackup);
- x = zxpand(s);
- xdironly = 0;
- xfilonly = 0;
- xmatchdot = 0;
- xrecursive = 0;
- xnobackup = 0;
- return(x);
- }
- /* Z X R E W I N D -- Rewinds the zxpand() list */
- int
- zxrewind() {
- if (!mtchs) return(-1);
- fcount = nxpand;
- mtchptr = mtchs;
- return(nxpand);
- }
- /* Z N E X T -- Get name of next file from list created by zxpand(). */
- /*
- Returns >0 if there's another file, with its name copied into the arg string,
- or 0 if no more files in list.
- */
- int
- znext(fn) char *fn; {
- if (fcount-- > 0) {
- ckstrncpy(fn,*mtchptr++,CKMAXPATH);
- } else {
- fn[0] = ' ';
- }
- #ifndef COMMENT
- debug(F111,"znext",fn,fcount+1);
- return(fcount+1);
- #else
- debug(F111,"znext",fn,fcount); /* Return 0 if no filename to return */
- return(fcount);
- #endif /* COMMENT */
- }
- /* Z C H K S P A -- Check if there is enough space to store the file */
- /*
- Call with file specification f, size n in bytes.
- Returns -1 on error, 0 if not enough space, 1 if enough space.
- */
- int
- #ifdef CK_ANSIC
- zchkspa(char *f, long n)
- #else
- zchkspa(f,n) char *f; long n;
- #endif /* CK_ANSIC */
- /* zchkspa() */ {
- /* In UNIX there is no good (and portable) way. */
- return(1); /* Always say OK. */
- }
- #ifdef COMMENT /* (not used) */
- /* I S B A C K U P -- Tells if given file has a backup suffix */
- /*
- Returns:
- -1: Invalid argument
- 0: File does not have a backup suffix
- >0: Backup suffix number
- */
- int
- isbackup(fn) char * fn; { /* Get backup suffix number */
- int i, j, k, x, state, flag;
- if (!fn) /* Watch out for null pointers. */
- return(-1);
- if (!*fn) /* And empty names. */
- return(-1);
- flag = state = 0;
- for (i = (int)strlen(fn) - 1; (!flag && (i > 0)); i--) {
- switch (state) {
- case 0: /* State 0 - final char */
- if (fn[i] == '~') /* Is tilde */
- state = 1; /* Switch to next state */
- else /* Otherwise */
- flag = 1; /* Quit - no backup suffix. */
- break;
- case 1: /* State 1 - digits */
- if (fn[i] == '~' && fn[i-1] == '.') { /* Have suffix */
- return(atoi(&fn[i+1]));
- } else if (fn[i] >= '0' && fn[i] <= '9') { /* In number part */
- continue; /* Keep going */
- } else { /* Something else */
- flag = 1; /* Not a backup suffix - quit. */
- }
- break;
- }
- }
- return(0);
- }
- #endif /* COMMENT */
- /* Z N E W N -- Make a new name for the given file */
- /*
- Given the name, fn, of a file that already exists, this function builds a
- new name of the form "<oldname>.~<n>~", where <oldname> is argument name
- (fn), and <n> is a version number, one higher than any existing version
- number for that file, up to 99999. This format is consistent with that used
- by GNU EMACS. If the constructed name is too long for the system's maximum,
- enough characters are truncated from the end of <fn> to allow the version
- number to fit. If no free version numbers exist between 1 and 99999, a
- version number of "xxxx" is used. Returns a pointer to the new name in
- argument s.
- */
- #ifdef pdp11
- #define ZNEWNBL 63 /* Name buffer length */
- #define ZNEWNMD 3 /* Max digits for version number */
- #else
- #define ZNEWNBL CKMAXPATH
- #define ZNEWNMD 4
- #endif /* pdp11 */
- #define MAXBUDIGITS 5
- VOID
- znewn(fn,s) char *fn, **s; {
- static char buf[ZNEWNBL+12]; /* Buffer for new name */
- char * xp, * namepart = NULL; /* Pointer to filename part */
- struct zfnfp * fnfp; /* znfqfp() result struct pointer */
- int d = 0, t, fnlen, buflen;
- int n, i, k, x, flag, state;
- int max = MAXNAMLEN; /* Maximum name length */
- char * dname = NULL;
- *s = NULL; /* Initialize return value */
- if (!fn) fn = ""; /* Check filename argument */
- i = strlen(fn);
- /* If incoming file already has a backup suffix, remove it. */
- /* Then we'll tack a new on later, which will be the highest for this file. */
- if (i <= max && i > 0 && fn[i-1] == '~') {
- char * p;
- i--;
- debug(F111,"znewn suffix removal",fn,i);
- if (dname = (char *)malloc(i+1)) {
- strcpy(dname,fn);
- p = dname;
- for (flag = state = 0; (!flag && (i > 0)); i--) {
- switch (state) {
- case 0: /* State 0 - final char */
- if (p[i] == '~') /* Is tilde */
- state = 1; /* Switch to next state */
- else /* Otherwise */
- flag = 1; /* Quit - no backup suffix. */
- break;
- case 1: /* State 1 - digits */
- if (p[i] == '~' && p[i-1] == '.') { /* Have suffix */
- p[i-1] = NUL; /* Trim it */
- fn = dname;
- debug(F111,"znewn suffix removal 2",fn,i);
- flag = 1; /* done */
- } else if (p[i] >= '0' && p[i] <= '9') { /* Number part */
- continue; /* Keep going */
- } else { /* Something else */
- flag = 1; /* Not a backup suffix - quit. */
- }
- break;
- }
- }
- }
- }
- if ((fnlen = strlen(fn)) < 1) { /* Get length */
- if (dname) free(dname);
- return;
- }
- debug(F111,"znewn",fn,fnlen);
- debug(F101,"znewn max 1","",max);
- if (max < 14) max = 14; /* Make max reasonable for any UNIX */
- if (max > ZNEWNBL) max = ZNEWNBL;
- debug(F101,"znewn max 2","",max);
- if (fnfp = zfnqfp(fn, ZNEWNBL, buf)) { /* Get fully qualified name */
- namepart = fnfp->fname; /* Isolate the filename */
- k = strlen(fn); /* Length of name part */
- debug(F111,"znewn namepart",namepart,k);
- } else {
- if (dname) free(dname);
- return;
- }
- buflen = fnfp->len; /* Length of fully qualified name */
- debug(F111,"znewn len",buf,buflen);
- if (k + MAXBUDIGITS + 3 < max) { /* Backup name fits - no overflow */
- strcpy(buf+buflen,".~*~"); /* Make pattern for backup names */
- n = nzxpand(buf,ZX_FILONLY); /* Expand the pattern */
- debug(F111,"znewn A matches",buf,n);
- while (n-- > 0) { /* Find any existing name.~n~ files */
- xp = *mtchptr++; /* Point at matching name */
- t = atoi(xp+buflen+2); /* Get number */
- if (t > d) d = t; /* Save d = highest version number */
- }
- sprintf(buf+buflen,".~%d~",d+1); /* Yes, make "name.~<d+1>~" */
- debug(F110,"znewn A new name",buf,0);
- } else { /* Backup name would be too long */
- int xlen; /* So we have to eat back into it */
- int delta;
- char buf2[ZNEWNBL+12];
- delta = max - k;
- debug(F101,"znewn B delta","",delta);
- for (i = MAXBUDIGITS; i > 0; i--) { /* In this case the format of */
- strcpy(buf2,buf); /* the backup name depends on */
- xlen = buflen - i - 3 + delta; /* how many digits are in the */
- strcpy(buf2+xlen,".~*~"); /* the backup number... */
- n = nzxpand(buf2,ZX_FILONLY);
- debug(F111,"znewn B matches",buf2,n);
- if (n > 0)
- break;
- }
- while (n-- > 0) { /* Find any existing name.~n~ files */
- xp = *mtchptr++; /* Point at matching name */
- t = atoi(xp+xlen+2); /* Get number */
- if (t > d) d = t; /* Save d = highest version number */
- }
- if (d > 0) /* If the odometer turned over... */
- if ((d % 10) == 9) /* back up one space. */
- xlen--;
- sprintf(buf2+xlen,".~%d~",d+1); /* This just fits */
- strcpy(buf,buf2); /* (we could be more clever here...) */
- debug(F110,"znewn B new name",buf,0);
- }
- *s = buf; /* Point to new name */
- ck_znewn = d+1; /* Also make it available globally */
- if (dname) free(dname);
- return;
- }
- /* Z R E N A M E -- Rename a file */
- /*
- Call with old and new names.
- If new name is the name of a directory, the 'old' file is moved to
- that directory.
- Returns 0 on success, -1 on failure.
- */
- int
- zrename(old,new) char *old, *new; {
- char *p = NULL, *s = new;
- int x;
- debug(F110,"zrename old",old,0);
- debug(F110,"zrename new",s,0);
- #ifdef IKSD
- #ifdef CK_LOGIN
- if (inserver && isguest)
- return(-1);
- #endif /* CK_LOGIN */
- #endif /* IKSD */
- if (isdir(new)) {
- char *q = NULL;
- x = strlen(new);
- if (!(p = malloc(strlen(new) + strlen(old) + 2)))
- return(-1);
- strcpy(p,new); /* Directory part */
- if (!ISDIRSEP(*(new+x-1))) /* Separator, if needed */
- strcat(p,"/");
- zstrip(old,&q); /* Strip path part from old name */
- strcat(p,q); /* Concatenate to new directory */
- s = p;
- debug(F110,"zrename dir",s,0);
- } else debug(F110,"zrename no dir",s,0);
- #ifdef RENAME
- /*
- Atomic, preferred, uses a single system call, rename(), if available.
- OS/2 rename() returns nonzero, but not necessarily -1 (?), on failure.
- */
- x = rename(old,s);
- if (x) x = -1;
- #else /* !RENAME */
- /*
- This way has a window of vulnerability.
- */
- x = -1; /* Return code. */
- if (link(old,s) < 0) { /* Make a link with the new name. */
- debug(F111,"zrename link fails, errno",old,errno);
- } else if (unlink(old) < 0) { /* Unlink the old name. */
- debug(F111,"zrename unlink fails, errno",old,errno);
- } else
- x = 0;
- #endif /* RENAME */
- #ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FC && ckxlogging) {
- fullname[0] = ' ';
- zfnqfp(old,CKMAXPATH,fullname);
- tmp2[0] = ' ';
- zfnqfp(s,CKMAXPATH,tmp2);
- if (x)
- syslog(LOG_INFO,"file[] %s: rename to %s failed (%m)",fullname,tmp2);
- else
- syslog(LOG_INFO,"file[] %s: renamed to %s ok", fullname, tmp2);
- }
- #endif /* CKSYSLOG */
- if (p) free(p);
- return(x);
- }
- /* Z C O P Y -- Copy a single file. */
- /*
- Call with source and destination names.
- If destination is a directory, the source file is
- copied to that directory with its original name.
- Returns:
- 0 on success.
- <0 on failure:
- -2 = source file is not a regular file.
- -3 = source file not found.
- -4 = permission denied.
- -5 = source and destination are the same file.
- -6 = i/o error.
- -1 = other error.
- */
- int
- zcopy(source,destination) char *source, *destination; {
- char *src = source, *dst = destination; /* Local pointers to filenames */
- int x, y, rc; /* Workers */
- int in = -1, out = -1; /* i/o file descriptors */
- struct stat srcbuf; /* Source file info buffer */
- int perms; /* Output file permissions */
- char buf[1024]; /* File copying buffer */