+++ /dev/null
-/* 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, 8.0.200, 4 Mar 2004";
-#else
-#ifdef Plan9
-char *ckzv = "Plan 9 File support, 8.0.200, 4 Mar 2004";
-#else
-char *ckzv = "UNIX File support, 8.0.200, 4 Mar 2004";
-#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, 2004,
- 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 COMMENT
-/* This causes trouble in C-Kermit 8.0. I don't remember the original */
-/* reason for this being here but it must have been needed at the time... */
-#ifdef OSF13
-#ifdef CK_ANSIC
-#ifdef _NO_PROTO
-#undef _NO_PROTO
-#endif /* _NO_PROTO */
-#endif /* CK_ANSIC */
-#endif /* OSF13 */
-#endif /* COMMENT */
-
-#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.
-*/
-#ifndef DIRSEP
-#define DIRSEP '/'
-#endif /* DIRSEP */
-#ifndef ISDIRSEP
-#define ISDIRSEP(c) ((c)=='/')
-#endif /* ISDIRSEP */
-
-#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 COMMENT
-/* Moved to ckcdeb.h */
-#ifdef POSIX
-#define UTIMEH
-#else
-#ifdef HPUX9
-#define UTIMEH
-#endif /* HPUX9 */
-#endif /* POSIX */
-#endif /* COMMENT */
-
-#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) */
-#ifndef BSD44
-#ifndef V7
-/* Not sure why this is here. What it implies is that the code bracketed
- by SYSUTIMEH is valid on all platforms on which we support time
- functionality. But we know that is not true because the BSD44 and V7
- platforms do not support sys/utime.h and the data structures which
- are defined in them. Now this worked before because prior to today's
- changes the UTIMEH definition for BSD44 and V7 did not take place
- until after SYSUTIMEH was defined. It also would not have been a
- problem if the ordering of all the time blocks was consistent. All but
- one of the blocks were BSD44, V7, SYSUTIMEH, <OTHER>. That one case
- is where this problem was triggered.
-*/
-#define SYSUTIMEH /* Use this for both cases. */
-#endif /* V7 */
-#endif /* BSD44 */
-#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;
-int iklogopen = 0;
-static time_t timenow;
-
-#define IKSDMSGLEN CKMAXPATH+512
-
-static char iksdmsg[IKSDMSGLEN];
-
-extern int local;
-
-extern int server, en_mkd, en_cwd, en_del;
-
-/*
- 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"
-#else
-#ifdef BSD4
-#define NAMEENV "USER"
-#else
-#ifdef ATTSV
-#define NAMEENV "LOGNAME"
-#endif /* ATTSV */
-#endif /* BSD4 */
-#endif /* POSIX */
-
-/* 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 HPUX
-char *MAILCMD = "mailx"; /* For sending mail */
-#else
-#ifdef DGUX540
-char *MAILCMD = "mailx";
-#else
-#ifdef UNIX
-#ifdef CK_MAILCMD
-char *MAILCMD = CK_MAILCMD; /* CFLAGS override */
-#else
-char *MAILCMD = "Mail"; /* Default */
-#endif /* CK_MAILCMD */
-#else
-char *MAILCMD = "";
-#endif /* UNIX */
-#endif /* HPUX */
-#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 /* is68k */
-
-#ifdef COHERENT
-#ifdef _I386
-#include <fcntl.h>
-#else
-#include <sys/fcntl.h>
-#endif /* _I386 */
-#endif /* COHERENT */
-
-extern int inserver; /* I am IKSD */
-int guest = 0; /* Anonymous user */
-
-#ifdef IKSD
-extern int isguest;
-extern char * 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 */
-static int askpasswd = 0; /* Have OK user, must ask for passwd */
-#endif /* CK_LOGIN */
-
-#ifdef CKROOT
-static char ckroot[CKMAXPATH+1] = { NUL, NUL };
-static int ckrootset = 0;
-int ckrooterr = 0;
-#endif /* CKROOT */
-
-_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 */
-
-#ifdef SOLARIS
-#define PAM_CONST
-#else /* SOLARIS */
-#define PAM_CONST CONST
-#endif
-
-static char * pam_pw = NULL;
-
-int
-#ifdef CK_ANSIC
-pam_cb(int num_msg,
- PAM_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;
- PAM_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,"%s\n", msg[i]->msg);
- return(0);
- } else if (msg[i]->msg_style == PAM_TEXT_INFO) {
- debug(F111,"pam_cb","PAM TEXT INFO",0);
- fprintf(stdout,"%s\n", msg[i]->msg);
- return(0);
- } else if (msg[i]->msg_style == PAM_PROMPT_ECHO_OFF) {
- debug(F111,"pam_cb","Reading response, no echo",0);
- /* Ugly hack. We check to see if a password has been pushed */
- /* into zvpasswd(). This would be true if the password was */
- /* received by REMOTE LOGIN. */
- if (pam_pw) {
- ckstrncpy(message,pam_pw,PAM_MAX_MSG_SIZE);
- } else
- readpass((char *)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((char *)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); /* safe (prechecked) */
- 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 */
-
-#ifdef COMMENT
-/* As of 2001-11-03 this is handled in ckcdeb.h */
-/* 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 */
-#endif /* COMMENT */
-
-#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
-/* Already defined in ckcdeb.h so the following is superfluous. */
-/* Don't expect changing them to have any effect. */
-#ifdef CK_SMALL
-#define MAXWLD 50
-#else
-#ifdef BIGBUFOK
-#define MAXWLD 102400
-#else
-#define MAXWLD 8192
-#endif /* BIGBUFOK */
-#endif /* CK_SMALL */
-#endif /* MAXWLD */
-
-static int maxnames = MAXWLD;
-
-/* Define the size of the string space for filename expansion. */
-
-#ifndef DYNAMIC
-#ifdef PROVX1
-#define SSPACE 500
-#else
-#ifdef BSD29
-#define SSPACE 500
-#else
-#ifdef pdp11
-#define SSPACE 500
-#else
-#ifdef aegis
-#define SSPACE 10000 /* Size of string-generating buffer */
-#else /* Default static buffer size */
-#ifdef BIGBUFOK
-#define SSPACE 65000 /* Size of string-generating buffer */
-#else
-#define SSPACE 2000 /* size of string-generating buffer */
-#endif /* BIGBUFOK */
-#endif /* aegis */
-#endif /* pdp11 */
-#endif /* BSD29 */
-#endif /* PROVX1 */
-static char sspace[SSPACE]; /* Buffer for generating filenames */
-#else /* is DYNAMIC */
-#ifdef BIGBUFOK
-#define SSPACE 500000
-#else
-#define SSPACE 10000
-#endif /* BIGBUFOK */
-char *sspace = (char *)0;
-#endif /* DYNAMIC */
-static int ssplen = SSPACE; /* Length of string space buffer */
-
-#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 X_OK
-#define X_OK 1
-#endif /* X_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
-#ifdef RTAIX
-#include <sys/syslog.h>
-#else /* RTAIX */
-#include <syslog.h>
-#endif /* RTAIX */
-#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
-#define ZMBUFLEN 200
-static char zmbuf[ZMBUFLEN]; /* 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] = '\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. */
-
-VOID /* Called in ckcmai.c */
-doiklog() {
- if (iklogopen) /* Already open? */
- return;
- if (xferlog) { /* Open iksd log if requested */
- if (!xferfile) /* If no pathname given */
- makestr(&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;
-
- debug(F111,"zopeni",name,n);
- if ((x = chkfn(n)) != 0) {
- debug(F111,"zopeni chkfn",ckitoa(n),x);
- return(0);
- }
- zincnt = 0; /* Reset input buffer */
- if (n == ZSYSFN) { /* Input from a system function? */
-#ifdef COMMENT
-/*** Note, this function should not be called with ZSYSFN ***/
-/*** Always call zxcmd() directly, and give it the real file number ***/
-/*** you want to use. ***/
- return(zxcmd(n,name)); /* Try to fork the command */
-#else
- debug(F110,"zopeni called with ZSYSFN, failing!",name,0);
- *nambuf = '\0'; /* No filename. */
- return(0); /* fail. */
-#endif /* COMMENT */
- }
- 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);
- }
-#ifdef CKROOT
- debug(F111,"zopeni setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(name)) {
- debug(F110,"zopeni setroot violation",name,0);
- return(0);
- }
-#endif /* CKROOT */
- fp[n] = fopen(name,"r"); /* Real file, open it. */
- debug(F111,"zopeni fopen", name, fp[n]);
-#ifdef ZDEBUG
- printf("ZOPENI fp[%d]=%ld\n",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
-#endif /* CKSYSLOG */
- perror(name);
- 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. */
-
-/*ARGSUSED*/ /* zz not used */
-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). */
-
-#ifdef CKROOT
- debug(F111,"zopeno setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(name)) {
- debug(F110,"zopeno setroot violation",name,0);
- return(0);
- }
-#endif /* CKROOT */
-
- ckstrncpy(p,"w",8); /* Assume write/create mode */
- if (fcb) { /* If called with an FCB... */
- if (fcb->dsp == XYFZ_A) { /* Does it say Append? */
- ckstrncpy(p,"a",8); /* 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]=%ld\n",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 file number","",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) {
- int len;
- char * fnam;
-
- 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();
-
- len = 24 + 12 + (int)strlen(s) + 16
- + (int)strlen(fullname) + 1 + 1 + 1 + 1
- + (int)strlen(p) + 6 + 2 + 12;
- fnam = fullname;
- if (!*fnam) fnam = "(pipe)";
-
- if (len > IKSDMSGLEN)
- sprintf(iksdmsg, /* SAFE */
- "%.24s [BUFFER WOULD OVERFLOW]\n",ctime(&timenow));
- else
- sprintf(iksdmsg, /* SAFE */
- "%.24s %d %s %ld %s %c %s %c %c %s %s %d %s\n",
- ctime(&timenow), /* date/time */
- gtimer(), /* elapsed secs */
- s, /* peer name */
- ffc, /* byte count */
- fnam, /* 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;
-
-#ifdef IKSD
- if (inserver && !local && (n == ZCTERM || n == ZSTDIO)) {
- a = coninc(0);
- if (*c < 0)
- return(-1);
- } else
-#endif /* IKSD */
- /* (PWP) Just in case this gets called when it shouldn't. */
- if (n == ZIFILE) {
- a = zminchar(); /* Note: this catches Ctrl-Z */
- if (a < 0) /* (See zinfill()...) */
- return(-1);
- } else {
- 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] = '\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 == '\015') /* CR, get next character */
- continue;
- if (old == '\015') { /* Previous character was CR */
- if (a == '\012') { /* This one is LF, so we have a line */
- break;
- } else { /* Not LF, deposit CR */
- *s++ = '\015';
- x--;
- len++;
- }
- }
- }
- *s = a; /* Deposit character */
- s++;
- len++;
- }
- *s = '\0'; /* Terminate the string */
- debug(F011,"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() {
- extern int kactive, srvping;
- errno = 0;
-
-#ifdef ZDEBUG
- printf("ZINFILL fp[%d]=%ld\n",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 EOF\n");
-#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 */
-
-#ifdef DEBUG
- if (deblog) {
- int i;
- debug(F101,"ZINFILL INBUFSIZE","",INBUFSIZE);
-#ifdef USE_MEMCPY
- memset(zinbuffer, 0xFF, INBUFSIZE);
-#else
- for (i = 0; i < INBUFSIZE; i++) {
- zinbuffer[i] = 0xFF;
-#ifdef COMMENT /* Too much! */
- debug(F101,"ZINFILL zinbuffer[i]","",i);
-#endif /* COMMENT */
- }
-#endif /* USE_MEMCPY */
- ckstrncpy(zinbuffer,"zinbuffer is a valid buffer",INBUFSIZE);
- debug(F111,"ZINFILL about to call fread",zinbuffer,zinbuffer);
- }
-#endif /* DEBUG */
-
-/*
- 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]);
- debug(F101,"ZINFILL fread","",zincnt); /* Just the size */
-#ifdef ZDEBUG
- printf("FREAD=%d\n",zincnt);
-#endif /* ZDEBUG */
-#ifdef CK_CTRLZ
- /* If SET FILE EOF CTRL-Z, first Ctrl-Z marks EOF */
- if (zincnt > 0 && !binary && eofmethod == XYEOF_Z) {
- register int i;
- for (i = 0; i < zincnt; i++) {
- if (zinbuffer[i] == SUB) {
- zincnt = i; /* Stop at first Ctrl-Z */
- if (i == 0)
- return(-1);
- break;
- }
- }
- }
-#endif /* CK_CTRLZ */
-
- if (zincnt == 0) { /* Got nothing? */
- if (ferror(fp[ZIFILE])) {
- debug(F100,"ZINFILL ferror","",0);
- debug(F101,"ZINFILL errno","",errno);
-#ifdef ZDEBUG
- printf("ZINFILL errno=%d\n",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;
-
- if (!name) name = "";
- if (!*name) return(-1);
-
-#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;
- debug(F111,"zgetfs fnam",s,x);
- if (x > 0 && s[x-1] == '/')
- s[x-1] = '\0';
-
- 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] = '\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] = '\0';
- 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 {
- ckstrncpy(linkname,"(lookup failed)",CKMAXPATH);
- }
- }
-#else /* !USE_LSTAT */
- x = stat(s,&buf); /* No lstat(), use stat() instead */
- debug(F101,"STAT","",3);
- if (x < 0)
- return(-1);
-#endif /* USE_LSTAT */
-
- /* 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] = '\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] = '\0';
- }
- }
-#else /* !CKSYMLINK */
- x = stat(s,&buf); /* Just stat the file */
- debug(F111,"zgetfs stat",s,x);
- 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 */
- debug(F111,"zgetfs size",s,size);
- debug(F111,"zgetfs st_size",s,buf.st_size);
- 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, diractive, matchfifo;
-
- 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);
- if (x == 8 && !strcmp(s,"/dev/tty"))
- return(0);
-#endif /* UNIX */
-
-#ifdef DTILDE
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (!*s) s = name;
- }
-#endif /* DTILDE */
-
-#ifdef CKROOT
- debug(F111,"zchki setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(name)) {
- debug(F110,"zchki setroot violation",name,0);
- return(-1);
- }
-#endif /* CKROOT */
-
- 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
- && (!matchfifo || !S_ISFIFO (buf.st_mode)) /* or FIFO */
-#endif /* S_ISFIFO */
- ) {
- debug(F111,"zchki not regular file (or fifo)",s,matchfifo);
- return(-2);
- }
- }
- debug(F111,"zchki stat ok:",s,x);
-
- if (diractive) { /* If listing don't check access */
- x = 1;
- } else {
-#ifdef SW_ACC_ID
- debug(F100,"zchki swapping ids for access()","",0);
- priv_on();
-#endif /* SW_ACC_ID */
- if ((x = access(s,R_OK)) < 0)
- x = access(s,X_OK); /* For RUN-class commands */
-#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;
- char * oname;
- extern int zchkod; /* Used by IF WRITEABLE */
-
- debug(F110,"zchko entry",name,0);
-
- if (!name) return(-1); /* Watch out for null pointer. */
-
- oname = name;
-
-#ifdef CKROOT
- debug(F111,"zchko setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(name)) {
- debug(F110,"zchko setroot violation",name,0);
- errno = EACCES;
- return(-1);
- }
-#endif /* CKROOT */
-
- x = (int)strlen(name); /* Get length of filename */
- debug(F111,"zchko len",name,x);
- debug(F111,"zchko zchkod",name,zchkod);
-
-#ifdef UNIX
-/*
- Writing to null device is OK.
-*/
- if (x == 9 && !strcmp(name,"/dev/null"))
- return(0);
- if (x == 8 && !strcmp(name,"/dev/tty"))
- return(0);
-#endif /* UNIX */
-
- s = name;
-#ifdef DTILDE
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (!*s) s = name;
- x = strlen(s);
- }
-#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 46\n");
- return(-1);
- }
- ckstrncpy(s,name,x+3);
-
- 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] = '\0';
-#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] = '\0';
-#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] = '\0';
- while (s[0] && !isdir(s)) {
- for (i = (int)strlen(s); i > 0; i--) {
- if (ISDIRSEP(s[i-1])) {
- s[i-1] = '\0';
- break;
- }
- }
- if (i == 0)
- s[0] = '\0';
- }
- } else {
- s[i++] = '.'; /* Append "." to path. */
- s[i] = '\0';
- }
-#endif /* COMMENT */
-#endif /* COMMENT */
-
- if (!s[0])
- ckstrncpy(s,".",x+3);
-
-#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. */
-
-/* Returns: -1 on error, 0 on success */
-
-int
-zdelet(name) char *name; {
- int x;
-#ifdef CK_LOGIN
- if (isguest)
- return(-1);
-#endif /* CK_LOGIN */
-
-#ifdef CKROOT
- debug(F111,"zdelet setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(name)) {
- debug(F110,"zdelet setroot violation",name,0);
- return(-1);
- }
-#endif /* CKROOT */
-
- x = unlink(name);
- debug(F111,"zdelet",name,x);
-#ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FC && ckxlogging) {
- fullname[0] = '\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(F111,"nzrtol name",name,fncnv);
-
-#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 */
- ckmakmsg(fullname,CKMAXPATH,".",name,NULL,NULL);
- } 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 != '\0' && n < maxnam; name++) {
- if (*name > SP) flag = 1; /* Strip leading blanks and controls */
- if (flag == 0 && *name < '!')
- continue;
- if (fncnv > 0) {
- if (*name == SP) {
- *p++ = '_';
- n++;
- continue;
- }
- if (isupper(*name)) /* Check for mixed case */
- acase |= 1;
- else if (islower(*name))
- acase |= 2;
- }
- *p++ = *name;
- n++;
- }
- *p-- = '\0'; /* Terminate */
- while (*p < '!' && p > name2) /* Strip trailing blanks & controls */
- *p-- = '\0';
-
- if (*name2 == '\0') { /* Nothing left? */
- ckstrncpy(name2,"NONAME",max); /* 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 = '\0'; /* 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 */
-
-/*
- fncnv = 0 for no conversion, > 0 for regular conversion, < 0 for minimal.
-*/
-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 */
- 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 (fncnv > 0 && islower(c)) /* Uppercase letters */
- *pp++ = toupper(c); /* Change tilde to hyphen */
- else if (c == '~')
- *pp++ = '-';
- else if (fncnv > 0 && 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 controls to 'X' */
- *pp++ = 'X';
- else if (fncnv > 0 && 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
- language = langsv;
-#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;
-#ifdef IKSDB
- _PROTOTYP (int slotdir,(char *,char *));
-#endif /* IKSDB */
-#ifndef NOSPL
- extern struct mtab *mactab; /* Main macro table */
- extern int nmac; /* Number of macros */
-#endif /* NOSPL */
-
- 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 == '\0') hd = dirnam; /* in directory name. */
-#else
- hd = dirnam;
-#endif /* DTILDE */
- debug(F110,"zchdir 3",hd,0);
-
-#ifdef CKROOT
- debug(F111,"zchdir setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(hd)) {
- debug(F110,"zchdir setroot violation",hd,0);
- return(0);
- }
-#endif /* CKROOT */
-
-#ifdef pdp11
- /* Just to save some space */
- return((chdir(hd) == 0) ? 1 : 0);
-#else
- if (chdir(hd) == 0) { /* Try to cd */
-#ifdef IKSDB
-#ifdef CK_LOGIN
- if (inserver && ikdbopen)
- slotdir(isguest ? anonroot : "", zgtdir());
-#endif /* CK_LOGIN */
-#endif /* IKSDB */
-
-#ifndef NOSPL
- if (nmac) { /* Any macros defined? */
- int k; /* Yes */
- static int on_cd = 0;
- if (!on_cd) {
- on_cd = 1;
- k = mlook(mactab,"on_cd",nmac); /* Look this up */
- if (k >= 0) { /* If found, */
- if (dodo(k,zgtdir(),0) > -1) /* set it up, */
- parser(1); /* and execute it */
- }
- on_cd = 0;
- }
- }
-#endif /* NOSPL */
- return(1);
- }
- return(0);
-#endif /* pdp11 */
-}
-
-int
-#ifdef CK_ANSIC
-zchkpid(unsigned long xpid)
-#else
-zchkpid(xpid) unsigned long xpid;
-#endif /* CK_ANSIC */
-{
- return((kill((PID_T)xpid,0) < 0) ? 0 : 1);
-}
-
-
-/* Z H O M E -- Return pointer to user's home directory */
-
-static char * zhomdir = NULL;
-
-char *
-zhome() {
- char * home;
-
-#ifdef CKROOT
- if (ckrootset)
- return((char *)ckroot);
-#endif /* CKROOT */
-
-#ifdef Plan9
- home = getenv("home");
-#else
- home = getenv("HOME");
-#endif /* Plan9 */
- makestr(&zhomdir,home);
- return(home ? zhomdir : ".");
-}
-
-/* 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;
-
-#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. */
- ckstrncpy(fullname,"(pipe)",CKMAXPATH);
-#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 */
-
- debug(F110,"zxcmd out",comand,0);
-
- if (priv_chk()) {
- debug(F100,"zxcmd priv_chk failed","",0);
- return(0);
- }
- errno = 0;
- fp[filnum] = popen(comand,"w");
- debug(F111,"zxcmd popen",fp[filnum] ? "OK" : "Failed", errno);
- if (fp[filnum] == NULL)
- return(0);
-#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 output stream. */
- 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 != '\0')
- 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
-#ifdef SELECT
- 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 /* SELECT */
-#endif /* DONDELAY */
-#endif /* SNI541 */
- fp[ZSYSFN] = fp[filnum]; /* Remember. */
- zincnt = 0; /* (PWP) reset input buffer */
- zinptr = zinbuffer;
- fullname[0] = '\0';
- 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;
-static int xnolinks = 0;
-
-static char *freeptr = NULL, **resptr = NULL; /* Copies of caller's args */
-static int remlen; /* Remaining space in caller's array */
-static int numfnd = 0; /* Number of matches found */
-
-#define MINSPACE 1024
-
-static int
-initspace(resarry,len) char * resarry[]; int len; {
-#ifdef DYNAMIC
- if (len < MINSPACE) len = MINSPACE;
- if (!sspace) { /* Need to allocate string space? */
- while (len >= MINSPACE) {
- if ((sspace = malloc(len+2))) { /* Got it. */
- debug(F101,"fgen string space","",len);
- break;
- }
- len = (len / 2) + (len / 4); /* Didn't, reduce by 3/4 */
- }
- if (len <= MINSPACE) { /* Did we get it? */
- fprintf(stderr,"fgen can't malloc string space\n");
- return(-1);
- }
- ssplen = len;
- }
-#endif /* DYNAMIC */
-
- freeptr = sspace; /* This is where matches are copied. */
- resptr = resarry; /* Static copies of these so */
- remlen = len; /* recursive calls can alter them. */
- debug(F101,"initspace ssplen","",ssplen);
- return(0);
-}
-
-/*
- Z S E T F I L -- Query or change the size of file list buffers.
-
- fc = 1: Change current string space to n, return new size.
- fc = 2: Return current string space size.
- fc = 3: Change current maxnames to n, return new maxnames.
- fc = 4: Return current maxnames.
- Returns < 0 on error.
-*/
-int
-zsetfil(n, fc) int n, fc; {
-#ifdef DYNAMIC
- switch (fc) {
- case 1: /* Stringspace */
- if (sspace) {
- free(sspace);
- sspace = NULL;
- }
- if (initspace(mtchs,n) < 0)
- return(-1);
- case 2: /* Fall thru deliberately */
- return(ssplen);
- case 3: /* Listsize */
- if (mtchs) {
- free((char *)mtchs);
- mtchs = NULL;
- }
- mtchs = (char **)malloc(n * sizeof(char *));
- if (!mtchs)
- return(-1);
- maxnames = n;
- case 4: /* Fall thru deliberately */
- return(maxnames);
- }
-#endif /* DYNAMIC */
- return(-1);
-}
-
-
-
-#ifndef NONZXPAND
-#ifndef pdp11
-static
-#endif /* pdp11 */
-#endif /* NONZXPAND */
-int
-zxpand(fnarg) char *fnarg; {
- extern int diractive;
- char fnbuf[CKMAXPATH+8], * fn, * p;
-
-#ifdef DTILDE /* Built with tilde-expansion? */
- char *tnam;
-#endif /* DTILDE */
- int x;
- int haveonedir = 0;
-
- if (!fnarg) { /* If no argument provided */
- nxpand = fcount = 0;
- return(0); /* Return zero files found */
- }
- debug(F110,"zxpand entry",fnarg,0);
- debug(F101,"zxpand xdironly","",xdironly);
- debug(F101,"zxpand xfilonly","",xfilonly);
-
- if (!*fnarg) { /* If no argument provided */
- nxpand = fcount = 0;
- return(0); /* Return zero files found */
- }
-
-#ifdef CKROOT
- debug(F111,"zxpand setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(fnarg)) {
- debug(F110,"zxpand setroot violation",fnarg,0);
- nxpand = fcount = 0;
- return(0);
- }
-#endif /* CKROOT */
-
-#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] = '\0';
- }
- 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 */
- if (!xfilonly && !iswild(p)) haveonedir++;
- ckstrncat(fn, "*", CKMAXPATH+8); /* 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 (!xfilonly && !iswild(p))
- haveonedir++;
- if ((x = strlen(fn)) > 0) {
- if (!ISDIRSEP(fn[x-1]))
- fn[x++] = DIRSEP;
- fn[x++] = '*';
- fn[x] = '\0';
- }
- }
- debug(F111,"zxpand fn 3",fn,haveonedir);
-/*
- The following allows us to parse a single directory name without opening
- the directory and looking at its contents. The diractive flag is a horrible
- hack (especially since DIR /NORECURSIVE turns it off), but otherwise we'd
- have to change the API.
-*/
- if (!diractive && haveonedir) {
-#ifdef COMMENT
- fcount = (mtchs == NULL &&
- (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
- ? 0 : 1;
-#else
- fcount = 0;
- if (!mtchs) {
- mtchs = (char **)malloc(maxnames * sizeof(*mtchs));
- if (mtchs)
- fcount = 1;
- if (!fcount)
- return(nxpand = fcount);
- }
-#endif /* COMMENT */
- debug(F110,"zxpand haveonedir A1",fnarg,0);
- initspace(mtchs,ssplen);
- addresult(fnarg,1);
- if (numfnd < 0) return(-1);
- mtchptr = mtchs; /* Save pointer for next. */
- debug(F110,"zxpand haveonedir A2",*mtchptr,0);
- return(nxpand = fcount);
- }
-
-#ifndef NOPUSH
- if (!nopush && wildxpand) /* Who is expanding wildcards? */
- fcount = (mtchs == NULL && /* Shell */
- (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
- ? 0
- : shxpand(fn,mtchs,maxnames);
- else
-#endif /* NOPUSH */
- fcount = (mtchs == NULL && /* Kermit */
- (mtchs = (char **)malloc(maxnames * sizeof(*mtchs))) == NULL)
- ? 0
- : fgen(fn,mtchs,maxnames); /* Look up the file. */
-
- if (fcount == 0 && haveonedir) {
- fcount = 1;
- debug(F110,"zxpand haveonedir B",fnarg,0);
- addresult(fnarg,1);
- if (numfnd < 0) return(-1);
- }
- 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);
-}
-
-#ifndef NONZXPAND
-/* N Z X P A N D -- Expand 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"
- flags & ZX_NOLINKS Don't follow symlinks.
-
- 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; {
- char * p;
- 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);
- debug(F111,"nzxpand xmatchdot 1",s,xmatchdot);
- /* If xmatchdot not set by caller but pattern implies it, set it anyway */
- if (!xmatchdot && ((p = ckstrchr(s,'.')))) {
- if (p == s && p[1] != '/') {
- xmatchdot = 1;
- debug(F111,"nzxpand xmatchdot 2",s,xmatchdot);
- } else if (p > s) {
- xmatchdot = (*(p-1) == ',') || (*(p-1) == '{') || (*(p-1) == '/');
- debug(F111,"nzxpand xmatchdot 3",s,xmatchdot);
- }
- }
- xrecursive = (flags & ZX_RECURSE);
- xnobackup = (flags & ZX_NOBACKUP);
- xnolinks = (flags & ZX_NOLINKS);
-
-#ifdef DEBUG
- if (deblog) {
- 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);
- debug(F101,"nzxpand xnolinks","",xnolinks);
- }
-#endif /* DEBUG */
-
- x = zxpand(s);
- if (x > 1)
- sh_sort(mtchs,NULL,x,0,0,1); /* Alphabetize the list */
- xdironly = 0;
- xfilonly = 0;
- xmatchdot = 0;
- xrecursive = 0;
- xnobackup = 0;
- xnolinks = 0;
- return(x);
-}
-#endif /* NONZXPAND */
-
-#ifndef NOZXREWIND
-/* Z X R E W I N D -- Rewinds the zxpand() list */
-
-int
-zxrewind() {
- /* if (!mtchs) return(-1); */
- fcount = nxpand;
- mtchptr = mtchs;
- return(nxpand);
-}
-#endif /* NOZXREWIND */
-
-/* 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] = '\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.
-*/
-/*ARGSUSED*/
-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
-
-static char znewbuf[ZNEWNBL+12];
-
-VOID
-znewn(fn,s) char *fn, **s; {
- char * buf; /* Pointer to 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, flag, state;
- int max = MAXNAMLEN; /* Maximum name length */
- char * dname = NULL;
-
- buf = znewbuf;
- *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))) {
- ckstrncpy(dname,fn,i+1);
- 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 */
- /* Make pattern for backup names */
- ckstrncpy(buf+buflen,".~*~",ZNEWNBL+12-buflen);
- 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 newname",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 */
- ckstrncpy(buf2,buf,ZNEWNBL+12); /* the backup name depends on */
- xlen = buflen - i - 3 + delta; /* how many digits are in the */
- ckstrncpy(buf2+xlen,".~*~",ZNEWNBL+12-xlen); /* 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 */
- ckstrncpy(buf,buf2,ZNEWNBL+12); /* (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, *s;
- int x;
-
- if (!old) old = "";
- if (!new) new = "";
- debug(F110,"zrename old",old,0);
- debug(F110,"zrename new",new,0);
- if (!*old) return(-1);
- if (!*new) return(-1);
-
-#ifdef IKSD
-#ifdef CK_LOGIN
- if (inserver && isguest)
- return(-1);
-#endif /* CK_LOGIN */
-#endif /* IKSD */
-
-#ifdef CKROOT
- debug(F111,"zrename setroot",ckroot,ckrootset);
- if (ckrootset) {
- if (!zinroot(old)) {
- debug(F110,"zrename old: setroot violation",old,0);
- return(-1);
- }
- if (!zinroot(new)) {
- debug(F110,"zrename new: setroot violation",new,0);
- return(-1);
- }
- }
-#endif /* CKROOT */
-
- p = NULL;
- s = new;
-
- if (isdir(new)) {
- char *q = NULL;
- x = strlen(new);
- if (!(p = malloc(strlen(new) + strlen(old) + 2)))
- return(-1);
- strcpy(p,new); /* (safe) Directory part */
- if (!ISDIRSEP(*(new+x-1))) /* Separator, if needed */
- strcat(p,"/"); /* (safe) */
- zstrip(old,&q); /* Strip path part from old name */
- strcat(p,q); /* cat to new directory (safe) */
- s = p;
- debug(F110,"zrename dir",s,0);
- }
-#ifdef DEBUG
- else debug(F110,"zrename no dir",s,0);
-#endif /* DEBUG */
-
-#ifdef IKSD
- if (inserver && (!ENABLED(en_del))) {
- if (zchki(s) > -1) /* Destination file exists? */
- return(-1);
- }
-#endif /* IKSD */
-
- x = -1; /* Return code. */
-#ifdef RENAME
-/* Atomic, preferred, uses a single system call, rename(), if available. */
- x = rename(old,s);
- debug(F111,"zrename rename()",old,x);
- if (x) x = -1;
-#endif /* RENAME */
-
- /* If rename() failed or not available try link()/unlink() */
-
- if (x < 0) {
- if (zchko(old) > -1) { /* Requires write access to orignal */
- x = link(old,s);
- debug(F111,"zrename link()",old,x);
- if (x > -1) { /* Make a link with the new name. */
- x = unlink(old);
- debug(F111,"zrename unlink()",old,x);
- }
- /* If link/unlink failed copy and delete */
- if (x < 0) {
- x = zcopy(old,s);
- debug(F111,"zrename zcopy()",old,x);
- if (x > -1) {
- x = zdelet(old);
- debug(F111,"zrename zdelet()",old,x);
- }
- }
- }
- }
- fullname[0] = '\0'; /* Clear this out for next time. */
-
-#ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_FC && ckxlogging) {
- zfnqfp(old,CKMAXPATH,fullname);
- tmp2[0] = '\0';
- zfnqfp(s,CKMAXPATH,tmp2);
- if (x > -1)
- syslog(LOG_INFO,"file[] %s: renamed to %s ok", fullname, tmp2);
- else
- syslog(LOG_INFO,"file[] %s: rename to %s failed (%m)",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, *dst; /* 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 */
-
- if (!source) source = "";
- if (!destination) destination = "";
-
- debug(F110,"zcopy src arg",source,0);
- debug(F110,"zcopy dst arg",destination,0);
-
- if (!*source) return(-1);
- if (!*destination) return(-1);
-
-#ifdef IKSD
-#ifdef CK_LOGIN
- if (inserver && isguest)
- return(-4);
-#endif /* CK_LOGIN */
-#endif /* IKSD */
-
-#ifdef CKROOT
- debug(F111,"zcopy setroot",ckroot,ckrootset);
- if (ckrootset) {
- if (!zinroot(source)) {
- debug(F110,"zcopy source: setroot violation",source,0);
- return(-1);
- }
- if (!zinroot(destination)) {
- debug(F110,"zcopy destination: setroot violation",destination,0);
- return(-1);
- }
- }
-#endif /* CKROOT */
-
- src = source;
- dst = destination;
-
- if (stat(src,&srcbuf) == 0) { /* Get source file info */
- struct stat dstbuf; /* Destination file info buffer */
- debug(F101,"STAT","",6);
- if (stat(dst,&dstbuf) == 0) {
- debug(F101,"STAT","",7);
- if (srcbuf.st_dev == dstbuf.st_dev)
- if (srcbuf.st_ino == dstbuf.st_ino) {
- debug(F100,"zcopy files identical: stat()","",0);
- return(-5);
- }
- }
- } else { /* stat() failed... */
- debug(F101,"STAT","",8);
- debug(F111,"source file not found",src,errno);
- return(-3);
- }
- fullname[0] = '\0'; /* Get full pathnames */
- if (zfnqfp(source,CKMAXPATH,fullname))
- src = fullname;
- debug(F110,"zcopy src",src,0);
- tmp2[0] = '\0';
- if (zfnqfp(destination,CKMAXPATH,tmp2))
- dst = tmp2;
- debug(F110,"zcopy dst 1",dst,0);
- if (!strcmp(src,dst)) { /* Src and dst are same file? */
- debug(F100,"zcopy files identical: strcmp()","",0); /* This... */
- return(-5); /* should not happen. */
- }
- if (isdir(src)) { /* Source file is a directory? */
- debug(F110,"zcopy source is directory",src,0);
- return(-2); /* Fail */
- }
- if (isdir(dst)) { /* Destination is a directory? */
- char *q = NULL; /* Yes, add filename to it. */
- x = strlen(dst);
- if (x < 1) return(-1);
- if (!ISDIRSEP(*(dst+x-1))) { /* Add separator if needed */
- tmp2[x++] = '/';
- tmp2[x] = '\0';
- }
- debug(F111,"zcopy dst 2",dst,x);
- zstrip(src,&q); /* Strip path part from old name */
- ckstrncpy(tmp2+x,q,CKMAXPATH-x); /* Concatenate it to new name */
- }
- debug(F110,"zcopy dst 3",dst,0);
-
-#ifdef IKSD
- if (inserver && (!ENABLED(en_del))) {
- if (zchki(dst) > -1) /* Destination file exists? */
- return(-4);
- }
-#endif /* IKSD */
-
- perms = umask(0); /* Get user's umask */
- umask(perms); /* Put it back! */
- perms ^= 0777; /* Flip the bits */
- perms &= 0666; /* Zero execute bits from umask */
- perms |= (srcbuf.st_mode & 0111); /* OR in source file's execute bits */
- rc = -1; /* Default return code */
- errno = 0; /* Reset errno */
- in = open(src, O_RDONLY, 0); /* Open source file */
- debug(F111,"zcopy open source",src,in);
- if (in > -1) { /* If open... */
- /* Open destination file */
-#ifdef O_TRUNC
- out = open(dst, O_WRONLY|O_CREAT|O_TRUNC, perms);
-#else
- out = open(dst, O_WRONLY|O_CREAT, perms);
-#endif /* O_TRUNC */
- debug(F111,"zcopy open dest",dst,out);
- if (out > -1) { /* If open... */
- while ((x = read(in,buf,1024)) > 0) { /* Copy in 1K blocks */
- y = write(out,buf,x);
- if (y < 0) { /* On write failure */
- x = -1;
- rc = -6; /* Indicate i/o error */
- break;
- }
- }
- debug(F101,"zcopy final read","",x);
- debug(F101,"zcopy errno","",errno);
- rc = (x == 0) ? 0 : -6; /* In case of read failure */
- }
- }
- if (in > -1) close(in); /* Close files */
- if (out > -1) close(out);
- if (rc == -1) { /* Set return code */
- switch (errno) {
- case ENOENT: rc = -3; break;
- case EACCES: rc = -4; break;
- case EIO: rc = -6;
- }
- }
-
-#ifdef CKSYSLOG
- if (rc > -1 && ckxsyslog >= SYSLG_FC && ckxlogging) {
- if (rc)
- syslog(LOG_INFO,"file[] %s: copy to %s failed (%m)", fullname, tmp2);
- else
- syslog(LOG_INFO,"file[] %s: copy to %s ok", fullname, tmp2);
- }
-#endif /* CKSYSLOG */
-
- return(rc);
-}
-
-/* Z S A T T R */
-/*
- Fills in a Kermit file attribute structure for the file which is to be sent.
- Returns 0 on success with the structure filled in, or -1 on failure.
- If any string member is null, then it should be ignored.
- If any numeric member is -1, then it should be ignored.
-*/
-#ifdef CK_PERMS
-
-#ifdef CK_GPERMS
-#undef CK_GPERMS
-#endif /* CK_GPERMS */
-
-#ifdef UNIX
-#ifndef S_IRUSR
-#define S_IRUSR 0400
-#endif /* S_IRUSR */
-#ifndef S_IWUSR
-#define S_IXUSR 0200
-#endif /* S_IWUSR */
-#ifndef S_IXUSR
-#define S_IXUSR 0100
-#endif /* S_IXUSR */
-#endif /* UNIX */
-
-#ifdef S_IRUSR
-#ifdef S_IWUSR
-#ifdef S_IXUSR
-#define CK_GPERMS
-#endif /* S_IXUSR */
-#endif /* S_IWUSR */
-#endif /* S_IRUSR */
-
-static char gperms[2];
-
-#endif /* CK_GPERMS */
-
-static char lperms[24];
-
-#ifdef CK_PERMS
-static char xlperms[24];
-
-/* Z S E T P E R M -- Set permissions of a file */
-
-int
-zsetperm(f,code) char * f; int code; {
- int x;
-#ifdef CK_SCO32V4
- mode_t mask;
-#else
- int mask;
-#endif /* CK_SCO32V4 */
- mask = code;
- if (inserver && guest) {
- debug(F110,"zsetperm guest",f,0);
- return(0);
- }
- x = chmod(f,mask);
- if (x < 0) {
- debug(F111,"zsetperm error",f,errno);
- return(0);
- }
- debug(F111,"zsetperm ok",f,mask);
- return(1);
-}
-
-/* Z G P E R M -- Get permissions of a file as an octal string */
-
-char *
-zgperm(f) char *f; {
- extern int diractive;
- int x; char *s = (char *)xlperms;
- struct stat buf;
- debug(F110,"zgperm",f,0);
- if (!f) return("----------");
- if (!*f) return("----------");
-
-#ifdef CKROOT
- debug(F111,"zgperm setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(f)) {
- debug(F110,"zgperm setroot violation",f,0);
- return("----------");
- }
-#endif /* CKROOT */
-
-#ifdef USE_LSTAT
- if (diractive)
- x = lstat(f,&buf);
- else
-#endif /* USE_LSTAT */
- x = stat(f,&buf);
- debug(F101,"STAT","",9);
- if (x < 0)
- return("----------");
- sprintf(s,"%o",buf.st_mode);
- debug(F110,"zgperm",s,0);
- return(s);
-}
-
-/* Like zgperm() but returns permissions in "ls -l" string format */
-
-static char xsperms[24];
-
-char *
-ziperm(f) char * f; {
- extern int diractive;
- int x; char *s = (char *)xsperms;
- struct stat buf;
- unsigned int perms = 0;
-
- debug(F110,"ziperm",f,0);
-
- if (!f) return(NULL);
- if (!*f) return(NULL);
-
- if (diractive && zgfs_mode != 0) {
- perms = zgfs_mode; /* zgetfs() already got them */
- } else {
-#ifdef USE_LSTAT
- if (diractive)
- x = lstat(f,&buf);
- else
-#endif /* USE_LSTAT */
- x = stat(f,&buf);
- debug(F101,"STAT","",10);
- if (x < 0)
- return("----------");
- perms = buf.st_mode;
- }
- switch (perms & S_IFMT) {
- case S_IFDIR:
- *s++ = 'd';
- break;
- case S_IFCHR: /* Character special */
- *s++ = 'c';
- break;
- case S_IFBLK: /* Block special */
- *s++ = 'b';
- break;
- case S_IFREG: /* Regular */
- *s++ = '-';
- break;
-#ifdef S_IFLNK
- case S_IFLNK: /* Symbolic link */
- *s++ = 'l';
- break;
-#endif /* S_IFLNK */
-#ifdef S_IFSOCK
- case S_IFSOCK: /* Socket */
- *s++ = 's';
- break;
-#endif /* S_IFSOCK */
-#ifdef S_IFIFO
-#ifndef Plan9
-#ifndef COHERENT
- case S_IFIFO: /* FIFO */
- *s++ = 'p';
- break;
-#endif /* COHERENT */
-#endif /* Plan9 */
-#endif /* S_IFIFO */
-#ifdef S_IFWHT
- case S_IFWHT: /* Whiteout */
- *s++ = 'w';
- break;
-#endif /* S_IFWHT */
- default: /* Unknown */
- *s++ = '?';
- break;
- }
- if (perms & S_IRUSR) /* Owner's permissions */
- *s++ = 'r';
- else
- *s++ = '-';
- if (perms & S_IWUSR)
- *s++ = 'w';
- else
- *s++ = '-';
- switch (perms & (S_IXUSR | S_ISUID)) {
- case 0:
- *s++ = '-';
- break;
- case S_IXUSR:
- *s++ = 'x';
- break;
- case S_ISUID:
- *s++ = 'S';
- break;
- case S_IXUSR | S_ISUID:
- *s++ = 's';
- break;
- }
- if (perms & S_IRGRP) /* Group permissions */
- *s++ = 'r';
- else
- *s++ = '-';
- if (perms & S_IWGRP)
- *s++ = 'w';
- else
- *s++ = '-';
- switch (perms & (S_IXGRP | S_ISGID)) {
- case 0:
- *s++ = '-';
- break;
- case S_IXGRP:
- *s++ = 'x';
- break;
- case S_ISGID:
- *s++ = 'S';
- break;
- case S_IXGRP | S_ISGID:
- *s++ = 's';
- break;
- }
- if (perms & S_IROTH) /* World permissions */
- *s++ = 'r';
- else
- *s++ = '-';
- if (perms & S_IWOTH)
- *s++ = 'w';
- else
- *s++ = '-';
- switch (
-#ifdef Plan9
- perms & (S_IXOTH)
-#else
- perms & (S_IXOTH | S_ISVTX)
-#endif
- ) {
- case 0:
- *s++ = '-';
- break;
- case S_IXOTH:
- *s++ = 'x';
- break;
-#ifndef Plan9
- case S_ISVTX:
- *s++ = 'T';
- break;
- case S_IXOTH | S_ISVTX:
- *s++ = 't';
- break;
-#endif /* Plan9 */
- }
- *s = '\0';
- debug(F110,"ziperm",xsperms,0);
- return((char *)xsperms);
-}
-
-#else
-
-char *
-zgperm(f) char *f; {
- return("----------");
-}
-char *
-ziperms(f) char *f; {
- return("----------");
-}
-#endif /* CK_PERMS */
-
-int
-zsattr(xx) struct zattr *xx; {
- long k; int x;
- struct stat buf;
-
- k = iflen % 1024L; /* File length in K */
- if (k != 0L) k = 1L;
- xx->lengthk = (iflen / 1024L) + k;
- xx->type.len = 0; /* File type can't be filled in here */
- xx->type.val = "";
- if (*nambuf) {
- xx->date.val = zfcdat(nambuf); /* File creation date */
- xx->date.len = (int)strlen(xx->date.val);
- } else {
- xx->date.len = 0;
- xx->date.val = "";
- }
- xx->creator.len = 0; /* File creator */
- xx->creator.val = "";
- xx->account.len = 0; /* File account */
- xx->account.val = "";
- xx->area.len = 0; /* File area */
- xx->area.val = "";
- xx->password.len = 0; /* Area password */
- xx->password.val = "";
- xx->blksize = -1L; /* File blocksize */
- xx->xaccess.len = 0; /* File access */
- xx->xaccess.val = "";
- xx->encoding.len = 0; /* Transfer syntax */
- xx->encoding.val = 0;
- xx->disp.len = 0; /* Disposition upon arrival */
- xx->disp.val = "";
- xx->lprotect.len = 0; /* Local protection */
- xx->lprotect.val = "";
- xx->gprotect.len = 0; /* Generic protection */
- xx->gprotect.val = "";
- x = -1;
- if (*nambuf) x = stat(nambuf,&buf);
- debug(F101,"STAT","",11);
- if (x >= 0) {
- debug(F111,"zsattr buf.st_mode & 0777",nambuf,buf.st_mode & 0777);
- /* UNIX filemode as an octal string without filetype bits */
- sprintf(lperms,"%o",buf.st_mode & 0777);
- xx->lprotect.len = (int)strlen(lperms);
- xx->lprotect.val = (char *)lperms;
- x = 0;
-#ifdef CK_GPERMS
- /* Generic permissions only if we have stat.h symbols defined */
- if (buf.st_mode & S_IRUSR) x |= 1; /* Read */
- if (buf.st_mode & S_IWUSR) x |= (2+16); /* Write and Delete */
- if (buf.st_mode & S_IXUSR) x |= 4; /* Execute */
- gperms[0] = tochar(x);
- gperms[1] = NUL;
- xx->gprotect.len = 1;
- xx->gprotect.val = (char *)gperms;
-#endif /* CK_GPERMS */
- }
- debug(F111,"zsattr lperms",xx->lprotect.val,xx->lprotect.len);
- debug(F111,"zsattr gperms",xx->gprotect.val,xx->gprotect.len);
- xx->systemid.val = "U1"; /* U1 = UNIX */
- xx->systemid.len = 2; /* System ID */
- xx->recfm.len = 0; /* Record format */
- xx->recfm.val = "";
- xx->sysparam.len = 0; /* System-dependent parameters */
- xx->sysparam.val = "";
- xx->length = iflen; /* Length */
- return(0);
-}
-
-/* Z F C D A T -- Get file creation date */
-/*
- Call with pointer to filename.
- On success, returns pointer to modification date in yyyymmdd hh:mm:ss format.
- On failure, returns pointer to null string.
-*/
-static char datbuf[40];
-
-char *
-#ifdef CK_ANSIC
-zdtstr(time_t timearg)
-#else
-zdtstr(timearg) time_t timearg;
-#endif /* CK_ANSIC */
-/* zdtstr */ {
-#ifndef TIMESTAMP
- return("");
-#else
- struct tm * time_stamp;
- struct tm * localtime();
- int yy, ss;
-
- debug(F101,"zdtstr timearg","",timearg);
- if (timearg < 0)
- return("");
- time_stamp = localtime(&(timearg));
- if (!time_stamp) {
- debug(F100,"localtime returns null","",0);
- return("");
- }
-/*
- We assume that tm_year is ALWAYS years since 1900.
- Any platform where this is not the case will have problems
- starting in 2000.
-*/
- yy = time_stamp->tm_year; /* Year - 1900 */
- debug(F101,"zdtstr tm_year","",time_stamp->tm_year);
- if (yy > 1000) {
- debug(F101,"zstrdt YEAR-2000 ALERT 1: localtime year","",yy);
- }
- yy += 1900;
- debug(F101,"zdatstr year","",yy);
-
- if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
- return("");
- if (time_stamp->tm_mday < 0 || time_stamp->tm_mday > 31)
- return("");
- if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 23)
- return("");
- if (time_stamp->tm_min < 0 || time_stamp->tm_min > 59)
- return("");
- ss = time_stamp->tm_sec; /* Seconds */
- if (ss < 0 || ss > 59) /* Some systems give a BIG number */
- ss = 0;
- sprintf(datbuf,
-#ifdef pdp11
-/* For some reason, 2.1x BSD sprintf gets the last field wrong. */
- "%04d%02d%02d %02d:%02d:00",
-#else
- "%04d%02d%02d %02d:%02d:%02d",
-#endif /* pdp11 */
- yy,
- time_stamp->tm_mon + 1,
- time_stamp->tm_mday,
- time_stamp->tm_hour,
- time_stamp->tm_min
-#ifndef pdp11
- , ss
-#endif /* pdp11 */
- );
- yy = (int)strlen(datbuf);
- debug(F111,"zdatstr",datbuf,yy);
- if (yy > 17) datbuf[17] = '\0';
- return(datbuf);
-#endif /* TIMESTAMP */
-}
-
-char *
-zfcdat(name) char *name; {
-#ifdef TIMESTAMP
- struct stat buffer;
- extern int diractive;
- unsigned int mtime;
- int x;
- char * s;
-
- if (!name)
- return("");
- s = name;
- if (!*s)
- return("");
-
-#ifdef CKROOT
- debug(F111,"zfcdat setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(name)) {
- debug(F110,"zfcdat setroot violation",name,0);
- return("");
- }
-#endif /* CKROOT */
-
-#ifdef DTILDE
- if (*s == '~') {
- s = tilde_expand(s);
- if (!s) s = "";
- if (!*s) s = name;
- }
-#endif /* DTILDE */
-
- datbuf[0] = '\0';
- x = 0;
- debug(F111,"zfcdat",s,diractive);
-
- if (diractive && zgfs_mtime) {
- mtime = zgfs_mtime;
- } else {
-#ifdef USE_LSTAT
- if (diractive) {
- x = lstat(s,&buffer);
- debug(F101,"STAT","",12);
- debug(F101,"zfcdat lstat","",x);
- } else {
-#endif /* USE_LSTAT */
- x = stat(s,&buffer);
- debug(F101,"STAT","",13);
- debug(F101,"zfcdat stat","",x);
-#ifdef USE_LSTAT
- }
-#endif /* USE_LSTAT */
- if (x != 0) {
-#ifdef USE_LSTAT
- debug(F111,"zfcdat stat failed",s,errno);
-#else
- debug(F111,"zfcdat lstat failed",s,errno);
-#endif /* USE_LSTAT */
- return("");
- }
- debug(F101,"zfcdat buffer.st_mtime","",buffer.st_mtime);
- mtime = buffer.st_mtime;
- }
- return(zdtstr(mtime));
-#else
- return("");
-#endif /* TIMESTAMP */
-}
-
-#ifndef NOTIMESTAMP
-
-/* Z S T R D T -- Converts local date string to internal representation */
-/*
- In our case (UNIX) this is seconds since midnite 1 Jan 1970 UTC,
- suitable for comparison with UNIX file dates. As far as I know, there is
- no library or system call -- at least nothing reasonably portable -- to
- convert local time to UTC.
-*/
-time_t
-zstrdt(date,len) char * date; int len; {
-#ifdef M_UNIX
-/*
- SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
- ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
- dependence on the XPG4 supplement presence. So always use
- what the system header file supplies in ODT 3.0...
-*/
-#ifndef ODT30
-#ifndef _SCO_DS
- extern void ftime(); /* extern void ftime(struct timeb *) */
-#endif /* _SCO_DS */
-#endif /* ODT30 */
-#else
-#ifndef M_XENIX
- extern int ftime();
-#endif /* M_XENIX */
-#endif /* M_UNIX */
- extern struct tm * localtime();
-
- /* And this should have been declared always through a header file */
-#ifdef HPUX10
- time_t tmx;
- long days;
-#else
-#ifdef BSD44
- time_t tmx;
- long days;
-#else
- long tmx, days;
-#endif /* BSD44 */
-#endif /* HPUX10 */
- int i, n, isleapyear;
- /* J F M A M J J A S O N D */
- /* 31 28 31 30 31 30 31 31 30 31 30 31 */
- static
- int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
- char s[5];
- struct tm *time_stamp;
-
-#ifdef BSD44
- struct timeval tp[2];
- long xtimezone = 0L;
-#else
-#ifdef V7
- struct utimbuf {
- time_t timep[2]; /* New access and modificaton time */
- } tp;
- char *tz;
- long timezone; /* In case timezone not defined in .h file */
-#else
-#ifdef SYSUTIMEH
- struct utimbuf tp;
-#else
- struct utimbuf {
- time_t atime;
- time_t mtime;
- } tp;
-#endif /* SYSUTIMEH */
-#endif /* V7 */
-#endif /* BSD44 */
-
-#ifdef ANYBSD
- long timezone = 0L;
- static struct timeb tbp;
-#endif /* ANYBSD */
-
-#ifdef BEBOX
- long timezone = 0L;
-#endif /* BEBOX */
-
- debug(F111,"zstrdt",date,len);
-
- if ((len == 0)
- || (len != 17)
- || (date[8] != ' ')
- || (date[11] != ':')
- || (date[14] != ':') ) {
- debug(F111,"Bad creation date ",date,len);
- return(-1);
- }
- debug(F111,"zstrdt date check 1",date,len);
- for(i = 0; i < 8; i++) {
- if (!isdigit(date[i])) {
- debug(F111,"Bad creation date ",date,len);
- return(-1);
- }
- }
- debug(F111,"zstrdt date check 2",date,len);
- i++;
-
- for (; i < 16; i += 3) {
- if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
- debug(F111,"Bad creation date ",date,len);
- return(-1);
- }
- }
- debug(F111,"zstrdt date check 3",date,len);
-
-
-#ifdef COMMENT /* was BSD44 */
-/*
- man gettimeofday on BSDI 3.1 says:
- "The timezone field is no longer used; timezone information is stored out-
- side the kernel. See ctime(3) for more information." So this chunk of
- code is effectively a no-op, at least in BSDI 3.x.
-*/
- {
- int x;
- struct timezone tzp;
- x = gettimeofday(NULL, &tzp);
- debug(F101,"zstrdt BSD44 gettimeofday","",x);
- if (x > -1)
- xtimezone = tzp.tz_minuteswest * 60L;
- else
- xtimezone = 0L;
- debug(F101,"zstrdt BSD44 timezone","",xtimezone);
- }
-#else
-#ifdef ANYBSD
- debug(F100,"zstrdt BSD calling ftime","",0);
- ftime(&tbp);
- debug(F100,"zstrdt BSD back from ftime","",0);
- timezone = tbp.timezone * 60L;
- debug(F101,"zstrdt BSD timezone","",timezone);
-#else
-#ifdef SVORPOSIX
- tzset(); /* Set timezone */
-#else
-#ifdef V7
- if ((tz = getenv("TZ")) == NULL)
- timezone = 0; /* UTC/GMT */
- else
- timezone = atoi(&tz[3]); /* Set 'timezone'. */
- timezone *= 60L;
-#endif /* V7 */
-#endif /* SVORPOSIX */
-#endif /* ANYBSD */
-#endif /* COMMENT (was BSD44) */
-
- debug(F100,"zstrdt so far so good","",0);
-
- s[4] = '\0';
- for (i = 0; i < 4; i++) /* Fix the year */
- s[i] = date[i];
-
- n = atoi(s);
- debug(F111,"zstrdt year",s,n);
- if (n < 1970) {
- debug(F100,"zstrdt fails - year","",n);
- return(-1);
- }
-
-/* Previous year's leap days. This won't work after year 2100. */
-
- isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
- days = (long) (n - 1970) * 365;
- days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
-
- s[2] = '\0';
-
- for (i = 4; i < 16; i += 2) {
- s[0] = date[i];
- s[1] = date[i + 1];
- n = atoi(s);
- switch (i) {
- case 4: /* MM: month */
- if ((n < 1 ) || ( n > 12)) {
- debug(F111,"zstrdt 4 bad date ",date,len);
- return(-1);
- }
- days += monthdays [n];
- if (isleapyear && n > 2)
- ++days;
- continue;
-
- case 6: /* DD: day */
- if ((n < 1 ) || ( n > 31)) {
- debug(F111,"zstrdt 6 bad date ",date,len);
- return(-1);
- }
- tmx = (days + n - 1) * 24L * 60L * 60L;
- i++; /* Skip the space */
- continue;
-
- case 9: /* hh: hour */
- if ((n < 0 ) || ( n > 23)) {
- debug(F111,"zstrdt 9 bad date ",date,len);
- return(-1);
- }
- tmx += n * 60L * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 12: /* mm: minute */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"zstrdt 12 bad date ",date,len);
- return(-1);
- }
-#ifdef COMMENT /* (was BSD44) */ /* Correct for time zone */
- tmx += xtimezone;
- debug(F101,"zstrdt BSD44 tmx","",tmx);
-#else
-#ifdef ANYBSD
- tmx += timezone;
-#else
-#ifndef CONVEX9 /* Don't yet know how to do this here */
-#ifdef ultrix
- tmx += (long) timezone;
-#else
-#ifdef Plan9
- {
- extern time_t tzoffset;
- tmx += tzoffset;
- }
-#else
-#ifndef BSD44
- tmx += timezone;
-#endif /* BSD44 */
-#endif /* Plan9 */
-#endif /* ultrix */
-#endif /* CONVEX9 */
-#endif /* ANYBSD */
-#endif /* COMMENT (was BSD44) */
- tmx += n * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 15: /* ss: second */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"zstrdt 15 bad date ",date,len);
- return(-1);
- }
- tmx += n;
- }
- time_stamp = localtime(&tmx);
- debug(F101,"zstrdt tmx 1","",tmx);
- if (!time_stamp)
- return(-1);
-#ifdef COMMENT
- /* Why was this here? */
- time_stamp = localtime(&tmx);
- debug(F101,"zstrdt tmx 2","",tmx);
-#endif /* COMMENT */
-#ifdef BSD44
- { /* New to 7.0 - Works in at at least BSDI 3.1 and FreeBSD 2.2.7 */
- long zz;
- zz = time_stamp->tm_gmtoff; /* Seconds away from Zero Meridian */
- debug(F101,"zstrdt BSD44 tm_gmtoff","",zz);
- tmx -= zz;
- debug(F101,"zstrdt BSD44 tmx 3 (GMT)","",tmx);
- }
-#else
- /*
- Daylight Savings Time adjustment.
- Do this everywhere BUT in BSD44 because in BSD44,
- tm_gmtoff also includes the DST adjustment.
- */
- if (time_stamp->tm_isdst) {
- tmx -= 60L * 60L;
- debug(F101,"zstrdt tmx 3 (DST)","",tmx);
- }
-#endif /* BSD44 */
- n = time_stamp->tm_year;
- if (n < 300) {
- n += 1900;
- }
- }
- return(tmx);
-}
-
-
-#ifdef ZLOCALTIME
-/* Z L O C A L T I M E -- GMT/UTC time string to local time string */
-
-/*
- Call with: "yyyymmdd hh:mm:ss" GMT/UTC date-time.
- Returns: "yyyymmdd hh:mm:ss" local date-time on success, NULL on failure.
-*/
-static char zltimbuf[64];
-
-char *
-zlocaltime(gmtstring) char * gmtstring; {
-#ifdef M_UNIX
-/*
- SCO UNIX 3.2v2.0 and ODT 2.0 lack prototypes for ftime().
- ODT 3.0 (3.2v4.2 OS) has a prototype, which may vary in
- dependence on the XPG4 supplement presence. So always use
- what the system header file supplies in ODT 3.0...
-*/
-#ifndef ODT30
-#ifndef _SCO_DS
- extern void ftime(); /* extern void ftime(struct timeb *) */
-#endif /* _SCO_DS */
-#endif /* ODT30 */
-#else
-#ifndef M_XENIX
- extern int ftime();
-#endif /* M_XENIX */
-#endif /* M_UNIX */
- extern struct tm * localtime();
-
- /* And this should have been declared always through a header file */
-#ifdef HPUX10
- time_t tmx;
- long days;
-#else
-#ifdef BSD44
- time_t tmx;
- long days;
-#else
- long tmx, days;
-#endif /* BSD44 */
-#endif /* HPUX10 */
- int i, n, x, isleapyear;
- /* J F M A M J J A S O N D */
- /* 31 28 31 30 31 30 31 31 30 31 30 31 */
- static
- int monthdays [13] = { 0,0,31,59,90,120,151,181,212,243,273,304,334 };
- char s[5];
- struct tm *time_stamp;
-
-#ifdef BSD44
- struct timeval tp[2];
-#else
-#ifdef V7
- struct utimbuf {
- time_t timep[2]; /* New access and modificaton time */
- } tp;
-#else
-#ifdef SYSUTIMEH
- struct utimbuf tp;
-#else
- struct utimbuf {
- time_t atime;
- time_t mtime;
- } tp;
-#endif /* SYSUTIMEH */
-#endif /* V7 */
-#endif /* BSD44 */
-
-#ifdef ANYBSD
- static struct timeb tbp;
-#endif /* ANYBSD */
-
- char * date = gmtstring;
- int len;
-
- len = strlen(date);
- debug(F111,"zlocaltime",date,len);
-
- if ((len == 0)
- || (len != 17)
- || (date[8] != ' ')
- || (date[11] != ':')
- || (date[14] != ':') ) {
- debug(F111,"Bad creation date ",date,len);
- return(NULL);
- }
- debug(F111,"zlocaltime date check 1",date,len);
- for(i = 0; i < 8; i++) {
- if (!isdigit(date[i])) {
- debug(F111,"Bad creation date ",date,len);
- return(NULL);
- }
- }
- debug(F111,"zlocaltime date check 2",date,len);
- i++;
-
- for (; i < 16; i += 3) {
- if ((!isdigit(date[i])) || (!isdigit(date[i + 1]))) {
- debug(F111,"Bad creation date ",date,len);
- return(NULL);
- }
- }
- debug(F111,"zlocaltime date check 3",date,len);
-
- debug(F100,"zlocaltime so far so good","",0);
-
- s[4] = '\0';
- for (i = 0; i < 4; i++) /* Fix the year */
- s[i] = date[i];
-
- n = atoi(s);
- debug(F111,"zlocaltime year",s,n);
- if (n < 1970) {
- debug(F100,"zlocaltime fails - year","",n);
- return(NULL);
- }
-
-/* Previous year's leap days. This won't work after year 2100. */
-
- isleapyear = (( n % 4 == 0 && n % 100 !=0) || n % 400 == 0);
- days = (long) (n - 1970) * 365;
- days += (n - 1968 - 1) / 4 - (n - 1900 - 1) / 100 + (n - 1600 - 1) / 400;
-
- s[2] = '\0';
-
- for (i = 4; i < 16; i += 2) {
- s[0] = date[i];
- s[1] = date[i + 1];
- n = atoi(s);
- switch (i) {
- case 4: /* MM: month */
- if ((n < 1 ) || ( n > 12)) {
- debug(F111,"zlocaltime 4 bad date ",date,len);
- return(NULL);
- }
- days += monthdays [n];
- if (isleapyear && n > 2)
- ++days;
- continue;
-
- case 6: /* DD: day */
- if ((n < 1 ) || ( n > 31)) {
- debug(F111,"zlocaltime 6 bad date ",date,len);
- return(NULL);
- }
- tmx = (days + n - 1) * 24L * 60L * 60L;
- i++; /* Skip the space */
- continue;
-
- case 9: /* hh: hour */
- if ((n < 0 ) || ( n > 23)) {
- debug(F111,"zlocaltime 9 bad date ",date,len);
- return(NULL);
- }
- tmx += n * 60L * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 12: /* mm: minute */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"zlocaltime 12 bad date ",date,len);
- return(NULL);
- }
- tmx += n * 60L;
- i++; /* Skip the colon */
- continue;
-
- case 15: /* ss: second */
- if ((n < 0 ) || ( n > 59)) {
- debug(F111,"zlocaltime 15 bad date ",date,len);
- return(NULL);
- }
- tmx += n;
- }
-
-/*
- At this point tmx is the time_t representation of the argument date-time
- string without any timezone or DST adjustments. Therefore it should be
- the same as the time_t representation of the GMT/UTC time. Now we should
- be able to feed it to localtime() and have it converted to a struct tm
- representing the local time equivalent of the given UTC time.
-*/
- time_stamp = localtime(&tmx);
- if (!time_stamp)
- return(NULL);
- }
-
-/* Now we simply reformat the struct tm to a string */
-
- x = time_stamp->tm_year;
- if (time_stamp->tm_year < 70 || time_stamp->tm_year > 8099)
- return(NULL);
- if (time_stamp->tm_mon < 0 || time_stamp->tm_mon > 11)
- return(NULL);
- if (time_stamp->tm_mday < 1 || time_stamp->tm_mday > 31)
- return(NULL);
- if (time_stamp->tm_hour < 0 || time_stamp->tm_hour > 24)
- return(NULL);
- if (time_stamp->tm_min < 0 || time_stamp->tm_min > 60)
- return(NULL);
- if (time_stamp->tm_sec < 0 || time_stamp->tm_sec > 60)
- return(NULL);
- sprintf(zltimbuf,"%04d%02d%02d %02d:%02d:%02d",
- time_stamp->tm_year + 1900,
- time_stamp->tm_mon + 1,
- time_stamp->tm_mday,
- time_stamp->tm_hour,
- time_stamp->tm_min,
- time_stamp->tm_sec
- );
- return((char *)zltimbuf);
-}
-#endif /* ZLOCALTIME */
-#endif /* NOTIMESTAMP */
-
-/* Z S T I M E -- Set modification date/time+permissions for incoming file */
-/*
- Call with:
- f = pointer to name of existing file.
- yy = pointer to a Kermit file attribute structure in which yy->date.val
- is a date of the form yyyymmdd hh:mm:ss, e.g. 19900208 13:00:00.
- yy->lprotect.val & yy->gprotect.val are permission/protection values.
- x = is a function code: 0 means to set the file's attributes as given.
- 1 means compare the date in struct yy with the file creation date.
- Returns:
- -1 on any kind of error.
- 0 if x is 0 and the attributes were set successfully.
- 0 if x is 1 and date from attribute structure <= file creation date.
- 1 if x is 1 and date from attribute structure > file creation date.
-*/
-int
-zstime(f,yy,x)
- char *f; struct zattr *yy; int x;
-/* zstime */ {
- int r = -1; /* Return code */
-#ifdef CK_PERMS
- int setperms = 0;
-#endif /* CK_PERMS */
- int setdate = 0;
-
-/* It is ifdef'd TIMESTAMP because it might not work on V7. bk@kullmar.se. */
-
-#ifdef TIMESTAMP
-#ifdef BSD44
- extern int utimes();
-#else
- extern int utime();
-#endif /* BSD44 */
-
- struct stat sb;
-
-/* At least, the declarations for int functions are not needed anyway */
-
-#ifdef BSD44
- struct timeval tp[2];
- long xtimezone;
-#else
-#ifdef V7
- struct utimbuf {
- time_t timep[2]; /* New access and modificaton time */
- } tp;
- char *tz;
- long timezone; /* In case not defined in .h file */
-#else
-#ifdef SYSUTIMEH
- struct utimbuf tp;
-#else
- struct utimbuf {
- time_t atime;
- time_t mtime;
- } tp;
-#endif /* SYSUTIMEH */
-#endif /* V7 */
-#endif /* BSD44 */
-
- long tm = 0L;
-
- if (!f) f = "";
- if (!*f) return(-1);
- if (!yy) return(-1);
-
- debug(F110,"zstime",f,0);
- debug(F111,"zstime date",yy->date.val,yy->date.len);
-
-#ifdef CKROOT
- debug(F111,"zstime setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(f)) {
- debug(F110,"zstime setroot violation",f,0);
- return(0);
- }
-#endif /* CKROOT */
-
- if (yy->date.len == 0) { /* No date in struct */
- if (yy->lprotect.len != 0) { /* So go do permissions */
- goto zsperms;
- } else {
- debug(F100,"zstime: nothing to do","",0);
- return(0);
- }
- }
- if ((tm = zstrdt(yy->date.val,yy->date.len)) < 0) {
- debug(F101,"zstime: zstrdt fails","",0);
- return(-1);
- }
- debug(F101,"zstime: tm","",tm);
- debug(F111,"zstime: A-pkt date ok ",yy->date.val,yy->date.len);
-
- if (stat(f,&sb)) { /* Get the time for the file */
- debug(F101,"STAT","",14);
- debug(F111,"zstime: Can't stat file:",f,errno);
- return(-1);
- }
- debug(F101,"STAT","",15);
- setdate = 1;
-
- zsperms:
-#ifdef CK_PERMS
- {
- int i, x = 0, xx, flag = 0;
- char * s;
-#ifdef DEBUG
- char obuf[24];
- if (deblog) {
- debug(F111,"zstime lperms",yy->lprotect.val,yy->lprotect.len);
- debug(F111,"zstime gperms",yy->gprotect.val,yy->gprotect.len);
- debug(F110,"zstime system id",yy->systemid.val,0);
- sprintf(obuf,"%o",sb.st_mode);
- debug(F110,"zstime file perms before",obuf,0);
- }
-#endif /* DEBUG */
-
-#ifdef CK_LOGIN
- debug(F101,"zstime isguest","",isguest);
- debug(F101,"zstime ckxperms","",ckxperms);
- if (isguest) {
-#ifdef COMMENT
- /* Clear owner permissions */
- sb.st_mode &= (unsigned) 0177077; /* (16 bits) */
-#else
- /* Set permissions from ckxperms variable */
- sb.st_mode = ckxperms;
-#endif /* COMMENT */
- debug(F101,"zstime isguest sb.st_mode","",sb.st_mode);
-#ifdef COMMENT
- /* We already set them in zopeno() */
- setperms = 1;
-#endif /* COMMENT */
- flag = 0;
- } else
-#endif /* CK_LOGIN */
- if ((yy->lprotect.len > 0 && /* Have local-format permissions */
- yy->systemid.len > 0 && /* from A-packet... */
-#ifdef UNIX
- !strcmp(yy->systemid.val,"U1") /* AND you are same as me */
-#else
- 0
-#endif /* UNIX */
- ) || (yy->lprotect.len < 0) /* OR by inheritance from old file */
- ) {
- flag = 1;
- s = yy->lprotect.val; /* UNIX filemode */
- xx = yy->lprotect.len;
- if (xx < 0) /* len < 0 means inheritance */
- xx = 0 - xx;
- for (i = 0; i < xx; i++) { /* Decode octal string */
- if (*s <= '7' && *s >= '0') {
- x = 8 * x + (int)(*s) - '0';
- } else {
- flag = 0;
- break;
- }
- s++;
- }
-#ifdef DEBUG
- sprintf(obuf,"%o",x);
- debug(F110,"zstime octal lperm",obuf,0);
-#endif /* DEBUG */
- } else if (!flag && yy->gprotect.len > 0) {
- int g;
-#ifdef CK_SCO32V4
- mode_t mask;
-#else
- int mask;
-#endif /* CK_SCO32V4 */
- mask = umask(0); /* Get umask */
- debug(F101,"zstime mask 1","",mask);
- umask(mask); /* Put it back */
- mask ^= 0777; /* Flip the bits */
- debug(F101,"zstime mask 2","",mask);
- g = xunchar(*(yy->gprotect.val)); /* Decode generic protection */
- debug(F101,"zstime gprotect","",g);
-#ifdef S_IRUSR
- debug(F100,"zstime S_IRUSR","",0);
- if (g & 1) x |= S_IRUSR; /* Read permission */
- flag = 1;
-#endif /* S_IRUSR */
-#ifdef S_IWUSR
- debug(F100,"zstime S_IWUSR","",0);
- if (g & 2) x |= S_IWUSR; /* Write permission */
- if (g & 16) x |= S_IWUSR; /* Delete permission */
- flag = 1;
-#endif /* S_IWUSR */
-#ifdef S_IXUSR
- debug(F100,"zstime S_IXUSR","",0);
- if (g & 4) /* Has execute permission bit */
- x |= S_IXUSR;
- else /* Doesn't have it */
- mask &= 0666; /* so also clear it out of mask */
- flag = 1;
-#endif /* S_IXUSR */
- debug(F101,"zstime mask x","",x);
- x |= mask;
- debug(F101,"zstime mask x|mask","",x);
- }
- debug(F101,"zstime flag","",flag);
- if (flag) {
-#ifdef S_IFMT
- debug(F101,"zstime S_IFMT x","",x);
- sb.st_mode = (sb.st_mode & S_IFMT) | x;
- setperms = 1;
-#else
-#ifdef _IFMT
- debug(F101,"zstime _IFMT x","",x);
- sb.st_mode = (sb.st_mode & _IFMT) | x;
- setperms = 1;
-#endif /* _IFMT */
-#endif /* S_IFMT */
- }
-#ifdef DEBUG
- sprintf(obuf,"%04o",sb.st_mode);
- debug(F111,"zstime file perms after",obuf,setperms);
-#endif /* DEBUG */
- }
-#endif /* CK_PERMS */
-
- debug(F101,"zstime: sb.st_atime","",sb.st_atime);
-
-#ifdef BSD44
- tp[0].tv_sec = sb.st_atime; /* Access time first */
- tp[1].tv_sec = tm; /* Update time second */
- debug(F100,"zstime: BSD44 modtime","",0);
-#else
-#ifdef V7
- tp.timep[0] = tm; /* Set modif. time to creation date */
- tp.timep[1] = sb.st_atime; /* Don't change the access time */
- debug(F100,"zstime: V7 modtime","",0);
-#else
-#ifdef SYSUTIMEH
- tp.modtime = tm; /* Set modif. time to creation date */
- tp.actime = sb.st_atime; /* Don't change the access time */
- debug(F100,"zstime: SYSUTIMEH modtime","",0);
-#else
- tp.mtime = tm; /* Set modif. time to creation date */
- tp.atime = sb.st_atime; /* Don't change the access time */
- debug(F100,"zstime: default modtime","",0);
-#endif /* SYSUTIMEH */
-#endif /* V7 */
-#endif /* BSD44 */
-
- switch (x) { /* Execute desired function */
- case 0: /* Set the creation date of the file */
-#ifdef CK_PERMS /* And permissions */
-/*
- NOTE: If we are inheriting permissions from a previous file, and the
- previous file was a directory, this would turn the new file into a directory
- too, but it's not, so we try to unset the right bit. Luckily, this code
- will probably never be executed since the upper level modules do not allow
- reception of a file that has the same name as a directory.
-
- NOTE 2: We change the permissions *before* we change the modification time,
- otherwise changing the permissions would set the mod time to the present
- time.
-*/
- {
- int x;
- debug(F101,"zstime setperms","",setperms);
- if (S_ISDIR(sb.st_mode)) {
- debug(F101,"zstime DIRECTORY bit on","",sb.st_mode);
- sb.st_mode ^= 0040000;
- debug(F101,"zstime DIRECTORY bit off","",sb.st_mode);
- }
- if (setperms) {
- x = chmod(f,sb.st_mode);
- debug(F101,"zstime chmod","",x);
- }
- }
- if (x < 0) return(-1);
-#endif /* CK_PERMS */
-
- if (!setdate) /* We don't have a date */
- return(0); /* so skip the following... */
-
- if (
-#ifdef BSD44
- utimes(f,tp)
-#else
- utime(f,&tp)
-#endif /* BSD44 */
- ) { /* Fix modification time */
- debug(F111,"zstime 0: can't set modtime for file",f,errno);
- r = -1;
- } else {
- /* Including the modtime here is not portable */
- debug(F110,"zstime 0: modtime set for file",f,0);
- r = 0;
- }
- break;
-
- case 1: /* Compare the dates */
-/*
- This was st_atime, which was wrong. We want the file-data modification
- time, st_mtime.
-*/
- debug(F111,"zstime 1: compare",f,sb.st_mtime);
- debug(F111,"zstime 1: compare","packet",tm);
-
- r = (sb.st_mtime < tm) ? 0 : 1;
- break;
-
- default: /* Error */
- r = -1;
- }
-#endif /* TIMESTAMP */
- return(r);
-}
-
-/* Find initialization file. */
-
-#ifdef NOTUSED
-int
-zkermini() {
-/* nothing here for Unix. This function added for benefit of VMS Kermit. */
- return(0);
-}
-#endif /* NOTUSED */
-
-#ifndef UNIX
-/* Historical -- not used in Unix any more (2001-11-03) */
-#ifndef NOFRILLS
-int
-zmail(p,f) char *p; char *f; { /* Send file f as mail to address p */
-/*
- Returns 0 on success
- 2 if mail delivered but temp file can't be deleted
- -2 if mail can't be delivered
- -1 on file access error
- The UNIX version always returns 0 because it can't get a good return
- code from zsyscmd.
-*/
- int n;
-
-#ifdef CK_LOGIN
- if (isguest)
- return(-2);
-#endif /* CK_LOGIN */
-
- if (!f) f = "";
- if (!*f) return(-1);
-
-#ifdef CKROOT
- debug(F111,"zmail setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(f)) {
- debug(F110,"zmail setroot violation",f,0);
- return(-1);
- }
-#endif /* CKROOT */
-
-#ifdef BSD4
-/* The idea is to use /usr/ucb/mail, rather than regular mail, so that */
-/* a subject line can be included with -s. Since we can't depend on the */
-/* user's path, we use the convention that /usr/ucb/Mail = /usr/ucb/mail */
-/* and even if Mail has been moved to somewhere else, this should still */
-/* find it... The search could be made more reliable by actually using */
-/* access() to see if /usr/ucb/Mail exists. */
-
- n = strlen(f);
- n = n + n + 15 + (int)strlen(p);
-
- if (n > ZMBUFLEN)
- return(-2);
-
-#ifdef DGUX540
- sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
-#else
- sprintf(zmbuf,"Mail -s %c%s%c %s < %s", '"', f, '"', p, f);
-#endif /* DGUX540 */
- zsyscmd(zmbuf);
-#else
-#ifdef SVORPOSIX
-#ifndef OXOS
- sprintf(zmbuf,"mail %s < %s", p, f);
-#else /* OXOS */
- sprintf(zmbuf,"mailx -s %c%s%c %s < %s", '"', f, '"', p, f);
-#endif /* OXOS */
- zsyscmd(zmbuf);
-#else
- *zmbuf = '\0';
-#endif
-#endif
- return(0);
-}
-#endif /* NOFRILLS */
-#endif /* UNIX */
-
-#ifndef NOFRILLS
-int
-zprint(p,f) char *p; char *f; { /* Print file f with options p */
- extern char * printername; /* From ckuus3.c */
- extern int printpipe;
- int n;
-
-#ifdef CK_LOGIN
- if (isguest)
- return(-2);
-#endif /* CK_LOGIN */
-
- if (!f) f = "";
- if (!*f) return(-1);
-
-#ifdef CKROOT
- debug(F111,"zprint setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(f)) {
- debug(F110,"zprint setroot violation",f,0);
- return(-1);
- }
-#endif /* CKROOT */
-
- debug(F110,"zprint file",f,0);
- debug(F110,"zprint flags",p,0);
- debug(F110,"zprint printername",printername,0);
- debug(F101,"zprint printpipe","",printpipe);
-
-#ifdef UNIX
-/*
- Note use of standard input redirection. In some systems, lp[r] runs
- setuid to lp (or ...?), so if user has sent a file into a directory
- that lp does not have read access to, it can't be printed unless it is
- fed to lp[r] as standard input.
-*/
- if (printpipe && printername) {
- n = 8 + (int)strlen(f) + (int)strlen(printername);
- if (n > ZMBUFLEN)
- return(-2);
- sprintf(zmbuf,"cat %s | %s", f, printername);
- } else if (printername) {
- n = 8 + (int)strlen(f) + (int)strlen(printername);
- if (n > ZMBUFLEN)
- return(-2);
- sprintf(zmbuf,"cat %s >> %s", f, printername);
- } else {
- n = 4 + (int)strlen(PRINTCMD) + (int)strlen(p) + (int)strlen(f);
- if (n > ZMBUFLEN)
- return(-2);
- sprintf(zmbuf,"%s %s < %s", PRINTCMD, p, f);
- }
- debug(F110,"zprint command",zmbuf,0);
- zsyscmd(zmbuf);
-#else /* Not UNIX */
- *zmbuf = '\0';
-#endif /* UNIX */
- return(0);
-}
-#endif /* NOFRILLS */
-
-/* Wildcard expansion functions... */
-
-static char scratch[MAXPATH+4]; /* Used by both methods */
-
-static int oldmtchs = 0; /* Let shell (ls) expand them. */
-#ifdef COMMENT
-static char *lscmd = "/bin/ls -d"; /* Command to use. */
-#else
-static char *lscmd = "echo"; /* Command to use. */
-#endif /* COMMENT */
-
-#ifndef NOPUSH
-int
-shxpand(pat,namlst,len) char *pat, *namlst[]; int len; {
- char *fgbuf = NULL; /* Buffer for forming ls command */
- char *p, *q; /* Workers */
-
- int i, x, retcode, itsadir;
- char c;
-
- x = (int)strlen(pat) + (int)strlen(lscmd) + 3; /* Length of ls command */
- for (i = 0; i < oldmtchs; i++) { /* Free previous file list */
- if (namlst[i] ) { /* If memory is allocated */
- free(namlst[i]); /* Free the memory */
- namlst[i] = NULL ; /* Remember no memory is allocated */
- }
- }
- oldmtchs = 0 ; /* Remember there are no matches */
- fgbuf = malloc(x); /* Get buffer for command */
- if (!fgbuf) return(-1); /* Fail if cannot */
- ckmakmsg(fgbuf,x,lscmd," ",pat,NULL); /* Form the command */
- zxcmd(ZIFILE,fgbuf); /* Start the command */
- i = 0; /* File counter */
- p = scratch; /* Point to scratch area */
- retcode = -1; /* Assume failure */
- while ((x = zminchar()) != -1) { /* Read characters from command */
- c = (char) x;
- if (c == ' ' || c == '\n') { /* Got newline or space? */
- *p = '\0'; /* Yes, terminate string */
- p = scratch; /* Point back to beginning */
- if (zchki(p) == -1) /* Does file exist? */
- continue; /* No, continue */
- itsadir = isdir(p); /* Yes, is it a directory? */
- if (xdironly && !itsadir) /* Want only dirs but this isn't */
- continue; /* so skip. */
- if (xfilonly && itsadir) /* It's a dir but want only files */
- continue; /* so skip. */
- x = (int)strlen(p); /* Keep - get length of name */
- q = malloc(x+1); /* Allocate space for it */
- if (!q) goto shxfin; /* Fail if space can't be obtained */
- strcpy(q,scratch); /* (safe) Copy name to space */
- namlst[i++] = q; /* Copy pointer to name into array */
- if (i >= len) goto shxfin; /* Fail if too many */
- } else { /* Regular character */
- *p++ = c; /* Copy it into scratch area */
- }
- }
- retcode = i; /* Return number of matching files */
-shxfin: /* Common exit point */
- free(fgbuf); /* Free command buffer */
- fgbuf = NULL;
- zclosf(ZIFILE); /* Delete the command fork. */
- oldmtchs = i; /* Remember how many files */
- return(retcode);
-}
-#endif /* NOPUSH */
-
-/*
- Directory-reading functions for UNIX originally written for C-Kermit 4.0
- by Jeff Damens, CUCCA, 1984.
-*/
-static char * xpat = NULL; /* Global copy of fgen() pattern */
-static char * xpatlast = NULL; /* Rightmost segment of pattern*/
-static int xpatslash = 0; /* Slash count in pattern */
-static int xpatwild = 0; /* Original pattern is wild */
-static int xleafwild = 0; /* Last segment of pattern is wild */
-static int xpatabsolute = 0;
-
-#ifdef aegis
-static char bslash;
-#endif /* aegis */
-
-
-/* S P L I T P A T H */
-
-/*
- Splits the slash-separated portions of the argument string into
- a list of path structures. Returns the head of the list. The
- structures are allocated by malloc, so they must be freed.
- Splitpath is used internally by the filename generator.
-
- Input:
- A path string.
-
- Returns:
- A linked list of the slash-separated segments of the input.
-*/
-static struct path *
-splitpath(p) char *p; {
- struct path *head,*cur,*prv;
- int i;
-
- debug(F111,"splitpath",p,xrecursive);
- head = prv = NULL;
-
- if (!p) return(NULL);
- if (!*p) return(NULL);
-
- if (!strcmp(p,"**")) { /* Fix this */
- p = "*";
- }
- if (ISDIRSEP(*p)) p++; /* Skip leading slash if any */
-
- /* Make linked list of path segments from pattern */
-
- while (*p) {
- cur = (struct path *) malloc(sizeof (struct path));
- debug(F101,"splitpath malloc","",cur);
- if (cur == NULL) {
- debug(F100,"splitpath malloc failure","",0);
- prv -> fwd = NULL;
- return((struct path *)NULL);
- }
- cur -> fwd = NULL;
- if (head == NULL) /* First, make list head */
- head = cur;
- else /* Not first, link into chain */
- prv -> fwd = cur;
- prv = cur; /* Link from previous to this one */
-
-#ifdef aegis
- /* treat backslash as "../" */
- if (bslash && *p == bslash) {
- strcpy(cur->npart, ".."); /* safe */
- ++p;
- } else {
- for (i=0; i < MAXNAMLEN && *p && *p != '/' && *p != bslash; i++)
- cur -> npart[i] = *p++;
- cur -> npart[i] = '\0'; /* end this segment */
- if (i >= MAXNAMLEN)
- while (*p && *p != '/' && *p != bslash)
- p++;
- }
- if (*p == '/') p++;
-#else
- /* General case (UNIX) */
- for (i = 0; i < MAXNAMLEN && !ISDIRSEP(*p) && *p != '\0'; i++) {
- cur -> npart[i] = *p++;
- }
-
- cur -> npart[i] = '\0'; /* End this path segment */
- if (i >= MAXNAMLEN)
- while (!ISDIRSEP(*p) && *p != '\0') p++;
- if (ISDIRSEP(*p))
- p++;
-
-#endif /* aegis */
- }
- if (prv) {
- makestr(&xpatlast,prv -> npart);
- debug(F110,"splitpath xpatlast",xpatlast,0);
- }
-#ifdef DEBUG
- /* Show original path list */
- if (deblog) {
- for (i = 0, cur = head; cur; i++) {
- debug(F111,"SPLITPATH",cur -> npart, i);
- cur = cur -> fwd;
- }
- }
-#endif /* DEBUG */
- return(head);
-}
-
-/* F G E N -- Generate File List */
-
-/*
- File name generator. It is passed a string, possibly containing wildcards,
- and an array of character pointers. It finds all the matching filenames and
- stores pointers to them in the array. The returned strings are allocated
- from a static buffer local to this module (so the caller doesn't have to
- worry about deallocating them); this means that successive calls to fgen
- will wipe out the results of previous calls.
-
- Input:
- A wildcard string, an array to write names to, the length of the array.
-
- Returns:
- The number of matches.
- The array is filled with filenames that matched the pattern.
- If there wasn't enough room in the array, -1 is returned.
-
- Originally by: Jeff Damens, CUCCA, 1984. Many changes since then.
-*/
-static int
-fgen(pat,resarry,len) char *pat,*resarry[]; int len; {
- struct path *head;
- char *sptr, *s;
- int n;
-
-#ifdef aegis
- char *namechars;
- int tilde = 0, bquote = 0;
-
- if ((namechars = getenv("NAMECHARS")) != NULL) {
- if (ckstrchr(namechars, '~' ) != NULL) tilde = '~';
- if (ckstrchr(namechars, '\\') != NULL) bslash = '\\';
- if (ckstrchr(namechars, '`' ) != NULL) bquote = '`';
- } else {
- tilde = '~'; bslash = '\\'; bquote = '`';
- }
- sptr = scratch;
-
- /* copy "`node_data", etc. anchors */
- if (bquote && *pat == bquote)
- while (*pat && *pat != '/' && *pat != bslash)
- *sptr++ = *pat++;
- else if (tilde && *pat == tilde)
- *sptr++ = *pat++;
- while (*pat == '/')
- *sptr++ = *pat++;
- if (sptr == scratch) {
- strcpy(scratch,"./"); /* safe */
- sptr = scratch+2;
- }
- if (!(head = splitpath(pat))) return(-1);
-
-#else /* not aegis */
-
- debug(F111,"fgen pat",pat,len);
- debug(F110,"fgen current directory",zgtdir(),0);
- debug(F101,"fgen stathack","",stathack);
-
- scratch[0] = '\0';
- xpatwild = 0;
- xleafwild = 0;
- xpatabsolute = 0;
-
- if (!(head = splitpath(pat))) /* Make the path segment list */
- return(-1);
-
- sptr = scratch;
-
-#ifdef COMMENT
- if (strncmp(pat,"./",2) && strncmp(pat,"../",3)) {
-#endif /* COMMENT */
- if (!ISDIRSEP(*pat)) /* If name is not absolute */
- *sptr++ = '.'; /* put "./" in front. */
- *sptr++ = DIRSEP;
-#ifdef COMMENT
- }
-#endif /* COMMENT */
- *sptr = '\0';
-#endif /* aegis */
-
- makestr(&xpat,pat); /* Save copy of original pattern */
- debug(F110,"fgen scratch",scratch,0);
-
- for (n = 0, s = xpat; *s; s++) /* How many slashes in the pattern */
- if (*s == DIRSEP) /* since these are fences for */
- n++; /* pattern matching */
- xpatslash = n;
- debug(F101,"fgen xpatslash","",xpatslash);
-
- numfnd = 0; /* None found yet */
-
- if (initspace(resarry,ssplen) < 0)
- return(-1);
-
- xpatwild = iswild(xpat); /* Original pattern is wild? */
- xpatabsolute = isabsolute(xpat);
- xleafwild = iswild(xpatlast);
-
- debug(F111,"fgen xpat",xpat,xpatwild);
- debug(F111,"fgen xpatlast",xpatlast,xleafwild);
- debug(F101,"fgen xpatabsolute","",xpatabsolute);
-
- traverse(head,scratch,sptr); /* Go walk the directory tree. */
- while (head != NULL) { /* Done - free path segment list. */
- struct path *next = head -> fwd;
- free((char *)head);
- head = next;
- }
- debug(F101,"fgen","",numfnd);
- return(numfnd); /* Return the number of matches */
-}
-
-/* Define LONGFN (long file names) automatically for BSD 2.9 and 4.2 */
-/* LONGFN can also be defined on the cc command line. */
-
-#ifdef BSD29
-#ifndef LONGFN
-#define LONGFN
-#endif
-#endif
-
-#ifdef BSD42
-#ifndef LONGFN
-#define LONGFN
-#endif
-#endif
-
-/*
- T R A V E R S E -- Traverse a directory tree.
-
- Walks the directory tree looking for matches to its arguments.
- The algorithm is, briefly:
-
- If the current pattern segment contains no wildcards, that
- segment is added to what we already have. If the name so far
- exists, we call ourselves recursively with the next segment
- in the pattern string; otherwise, we just return.
-
- If the current pattern segment contains wildcards, we open the name
- we've accumulated so far (assuming it is really a directory), then read
- each filename in it, and, if it matches the wildcard pattern segment, add
- that filename to what we have so far and call ourselves recursively on
- the next segment.
-
- Finally, when no more pattern segments remain, we add what's accumulated
- so far to the result array and increment the number of matches.
-
- Inputs:
- A pattern path list (as generated by splitpath), a string pointer that
- points to what we've traversed so far (this can be initialized to "/"
- to start the search at the root directory, or to "./" to start the
- search at the current directory), and a string pointer to the end of
- the string in the previous argument, plus the global "recursive",
- "xmatchdot", and "xdironly" flags.
-
- Returns: void, with:
- mtchs[] containing the array of filename string pointers, and:
- numfnd containing the number of filenames.
-
- Although it might be poor practice, the mtchs[] array is revealed to the
- outside in case it needs it; for example, to be sorted prior to use.
- (It is poor practice because not all platforms implement file lists the
- same way; some don't use an array at all.)
-
- Note that addresult() acts as a second-level filter; due to selection
- criteria outside of the pattern, it might decline to add files that
- this routine asks it to, e.g. because we are collecting only directory
- names but not the names of regular files.
-
- WARNING: In the course of C-Kermit 7.0 development, this routine became
- ridiculously complex, in order to meet approximately sixty specific
- requirements. DON'T EVEN THINK ABOUT MODIFYING THIS ROUTINE! Trust me;
- it is not possible to fix anything in it without breaking something else.
- This routine badly needs a total redesign and rewrite. Note: There may
- be some good applications for realpath() and/or scandir() and/or fts_blah()
- here, on platforms where they are available.
-*/
-static VOID
-traverse(pl,sofar,endcur) struct path *pl; char *sofar, *endcur; {
-
-/* Appropriate declarations for directory routines and structures */
-/* #define OPENDIR means to use opendir(), readdir(), closedir() */
-/* If OPENDIR not defined, we use open(), read(), close() */
-
-#ifdef DIRENT /* New way, <dirent.h> */
-#define OPENDIR
- DIR *fd, *opendir();
- struct dirent *dirbuf;
- struct dirent *readdir();
-#else /* !DIRENT */
-#ifdef LONGFN /* Old way, <dir.h> with opendir() */
-#define OPENDIR
- DIR *fd, *opendir();
- struct direct *dirbuf;
-#else /* !LONGFN */
- int fd; /* Old way, <dir.h> with open() */
- struct direct dir_entry;
- struct direct *dirbuf = &dir_entry;
-#endif /* LONGFN */
-#endif /* DIRENT */
- int mopts = 0; /* ckmatch() opts */
- int depth = 0; /* Directory tree depth */
-
- char nambuf[MAXNAMLEN+4]; /* Buffer for a filename */
- int itsadir = 0, segisdir = 0, itswild = 0, mresult, n, x /* , y */ ;
- struct stat statbuf; /* For file info. */
-
- debug(F101,"STAT","",16);
- if (pl == NULL) { /* End of path-segment list */
- *--endcur = '\0'; /* Terminate string, overwrite trailing slash */
- debug(F110,"traverse add: end of path segment",sofar,0);
- addresult(sofar,-1);
- return;
- }
- if (stathack) {
- /* This speeds up the search a lot and we still get good results */
- /* but it breaks the tagging of directory names done in addresult */
- if (xrecursive || xfilonly || xdironly || xpatslash) {
- itsadir = xisdir(sofar);
- debug(F101,"STAT","",17);
- } else
- itsadir = (strncmp(sofar,"./",2) == 0);
- } else {
- itsadir = xisdir(sofar);
- debug(F101,"STAT","",18);
- }
- debug(F111,"traverse entry sofar",sofar,itsadir);
-
-#ifdef CKSYMLINK /* We're doing symlinks? */
-#ifdef USE_LSTAT /* OK to use lstat()? */
- if (itsadir && xnolinks) { /* If not following symlinks */
- int x;
- struct stat buf;
- x = lstat(sofar,&buf);
- debug(F111,"traverse lstat 1",sofar,x);
- if (x > -1 &&
-#ifdef S_ISLNK
- S_ISLNK(buf.st_mode)
-#else
-#ifdef _IFLNK
- ((_IFMT & buf.st_mode) == _IFLNK)
-#endif /* _IFLNK */
-#endif /* S_ISLNK */
- )
- itsadir = 0;
- }
-#endif /* USE_LSTAT */
-#endif /* CKSYMLINK */
-
- if (!xmatchdot && xpatlast[0] == '.')
- xmatchdot = 1;
- if (!xmatchdot && xpat[0] == '.' && xpat[1] != '/' && xpat[1] != '.')
- xmatchdot = 1;
-
- /* ckmatch() options */
-
- if (xmatchdot) mopts |= 1; /* Match dot */
- if (!xrecursive) mopts |= 2; /* Dirsep is fence */
-
- debug(F111,"traverse entry xpat",xpat,xpatslash);
- debug(F111,"traverse entry xpatlast",xpatlast,xmatchdot);
- debug(F110,"traverse entry pl -> npart",pl -> npart,0);
-
-#ifdef RECURSIVE
- if (xrecursive > 0 && !itsadir) {
- char * s; /* Recursive descent and this is a regular file */
- *--endcur = '\0'; /* Terminate string, overwrite trailing slash */
-
- /* Find the nth slash from the right and match from there... */
- /* (n == the number of slashes in the original pattern - see fgen) */
- if (*sofar == '/') {
- debug(F110,"traverse xpatslash absolute",sofar,0);
- s = sofar;
- } else {
- debug(F111,"traverse xpatslash relative",sofar,xpatslash);
- for (s = endcur - 1, n = 0; s >= sofar; s--) {
- if (*s == '/') {
- if (++n >= xpatslash) {
- s++;
- break;
- }
- }
- }
- }
-#ifndef NOSKIPMATCH
- /* This speeds things up a bit. */
- /* If it causes trouble define NOSKIPMATCH and rebuild. */
- if (xpat[0] == '*' && !xpat[1])
- x = xmatchdot ? 1 : (s[0] != '.');
- else
-#endif /* NOSKIPMATCH */
- x = ckmatch(xpat, s, 1, mopts); /* Match with original pattern */
- debug(F111,"traverse xpatslash ckmatch",s,x);
- if (x > 0) {
- debug(F110,"traverse add: recursive, match, && !isdir",sofar,0);
- addresult(sofar,itsadir);
- }
- return;
- }
-#endif /* RECURSIVE */
-
- debug(F111,"traverse sofar 2",sofar,0);
-
- segisdir = ((pl -> fwd) == NULL) ? 0 : 1;
- itswild = iswild(pl -> npart);
-
- debug(F111,"traverse segisdir",sofar,segisdir);
- debug(F111,"traverse itswild ",pl -> npart,itswild);
-
-#ifdef RECURSIVE
- if (xrecursive > 0) { /* If recursing and... */
- if (segisdir && itswild) /* this is a dir and npart is wild */
- goto blah; /* or... */
- else if (!xpatabsolute && !xpatwild) /* search object is nonwild */
- goto blah; /* then go recurse */
- }
-#endif /* RECURSIVE */
-
- if (!itswild) { /* This path segment not wild? */
-#ifdef COMMENT
- strcpy(endcur,pl -> npart); /* (safe) Append next part. */
- endcur += (int)strlen(pl -> npart); /* Advance end pointer */
-#else
-/*
- strcpy() does not account for quoted metacharacters.
- We must remove the quotes before doing the stat().
-*/
- {
- int quote = 0;
- char c, * s;
- s = pl -> npart;
- while ((c = *s++)) {
- if (!quote) {
- if (c == CMDQ) {
- quote = 1;
- continue;
- }
- }
- *endcur++ = c;
- quote = 0;
- }
- }
-#endif /* COMMENT */
- *endcur = '\0'; /* End new current string. */
-
- if (stat(sofar,&statbuf) == 0) { /* If this piece exists... */
- debug(F110,"traverse exists",sofar,0);
- *endcur++ = DIRSEP; /* add slash to end */
- *endcur = '\0'; /* and end the string again. */
- traverse(pl -> fwd, sofar, endcur);
- }
-#ifdef DEBUG
- else debug(F110,"traverse not found", sofar, 0);
-#endif /* DEBUG */
- return;
- }
-
- *endcur = '\0'; /* End current string */
- debug(F111,"traverse sofar 3",sofar,0);
-
- if (!itsadir)
- return;
-
- /* Search is recursive or ... */
- /* path segment contains wildcards, have to open and search directory. */
-
- blah:
-
- debug(F110,"traverse opening directory", sofar, 0);
-
-#ifdef OPENDIR
- debug(F110,"traverse opendir()",sofar,0);
- if ((fd = opendir(sofar)) == NULL) { /* Can't open, fail. */
- debug(F101,"traverse opendir() failed","",errno);
- return;
- }
- while ((dirbuf = readdir(fd)))
-#else /* !OPENDIR */
- debug(F110,"traverse directory open()",sofar,0);
- if ((fd = open(sofar,O_RDONLY)) < 0) {
- debug(F101,"traverse directory open() failed","",errno);
- return;
- }
- while (read(fd, (char *)dirbuf, sizeof dir_entry))
-#endif /* OPENDIR */
- { /* Read each entry in this directory */
- int exists;
- char *eos, *s;
- exists = 0;
-
- /* On some platforms, the read[dir]() can return deleted files, */
- /* e.g. HP-UX 5.00. There is no point in grinding through this */
- /* routine when the file doesn't exist... */
-
- if ( /* There actually is an inode... */
-#ifdef BSD42
- dirbuf->d_ino != -1
-#else
-#ifdef unos
- dirbuf->d_ino != -1
-#else
-#ifdef QNX
- dirbuf->d_stat.st_ino != 0
-#else
-#ifdef SOLARIS
- dirbuf->d_ino != 0
-#else
-#ifdef sun
- dirbuf->d_fileno != 0
-#else
-#ifdef bsdi
- dirbuf->d_fileno != 0
-#else
-#ifdef __386BSD__
- dirbuf->d_fileno != 0
-#else
-#ifdef __FreeBSD__
- dirbuf->d_fileno != 0
-#else
-#ifdef ultrix
- dirbuf->gd_ino != 0
-#else
-#ifdef Plan9
- 1
-#else
- dirbuf->d_ino != 0
-#endif /* Plan9 */
-#endif /* ultrix */
-#endif /* __FreeBSD__ */
-#endif /* __386BSD__ */
-#endif /* bsdi */
-#endif /* sun */
-#endif /* SOLARIS */
-#endif /* QNX */
-#endif /* unos */
-#endif /* BSD42 */
- )
- exists = 1;
- if (!exists)
- continue;
-
- ckstrncpy(nambuf, /* Copy the name */
- dirbuf->d_name,
- MAXNAMLEN
- );
- if (nambuf[0] == '.') {
- if (!nambuf[1] || (nambuf[1] == '.' && !nambuf[2])) {
- debug(F110,"traverse skipping",nambuf,0);
- continue; /* skip "." and ".." */
- }
- }
- s = nambuf; /* Copy name to end of sofar */
- eos = endcur;
- while ((*eos = *s)) {
- s++;
- eos++;
- }
-/*
- Now we check the file for (a) whether it is a directory, and (b) whether
- its name matches our pattern. If it is a directory, and if we have been
- told to build a recursive list, then we must descend regardless of whether
- it matches the pattern. If it is not a directory and it does not match
- our pattern, we skip it. Note: sofar is the full pathname, nambuf is
- the name only.
-*/
- /* Do this first to save pointless function calls */
- if (nambuf[0] == '.' && !xmatchdot) /* Dir name starts with '.' */
- continue;
- if (stathack) {
- if (xrecursive || xfilonly || xdironly || xpatslash) {
- itsadir = xisdir(sofar); /* See if it's a directory */
- debug(F101,"STAT","",19);
- } else {
- itsadir = 0;
- }
- } else {
- itsadir = xisdir(sofar);
- debug(F101,"STAT","",20);
- }
-
-#ifdef CKSYMLINK
-#ifdef USE_LSTAT
- if (itsadir && xnolinks) { /* If not following symlinks */
- int x;
- struct stat buf;
- x = lstat(sofar,&buf);
- debug(F111,"traverse lstat 2",sofar,x);
- if (x > -1 &&
-#ifdef S_ISLNK
- S_ISLNK(buf.st_mode)
-#else
-#ifdef _IFLNK
- ((_IFMT & buf.st_mode) == _IFLNK)
-#endif /* _IFLNK */
-#endif /* S_ISLNK */
- )
- itsadir = 0;
- }
-#endif /* USE_LSTAT */
-#endif /* CKSYMLINK */
-
-#ifdef RECURSIVE
- if (xrecursive > 0 && itsadir &&
- (xpatlast[0] == '*') && !xpatlast[1]
- ) {
- debug(F110,
- "traverse add: recursive && isdir && segisdir or match",
- sofar,
- segisdir
- );
- addresult(sofar,itsadir);
- if (numfnd < 0) return;
- }
-#endif /* RECURSIVE */
-
- debug(F111,"traverse mresult xpat",xpat,xrecursive);
- debug(F111,"traverse mresult pl -> npart",
- pl -> npart,
- ((pl -> fwd) ? 9999 : 0)
- );
- debug(F111,"traverse mresult sofar segisdir",sofar,segisdir);
- debug(F111,"traverse mresult sofar itsadir",sofar,itsadir);
- debug(F101,"traverse mresult xmatchdot","",xmatchdot);
-/*
- Match the path so far with the pattern after stripping any leading "./"
- from either or both. The pattern chosen is the full original pattern if
- the match candidate (sofar) is not a directory, or else just the name part
- (pl->npart) if it is.
-*/
- {
- char * s1; /* The pattern */
- char * s2 = sofar; /* The path so far */
- char * s3; /* Worker */
- int opts; /* Match options */
-
- s1 = itsadir ? pl->npart : xpat;
-
-#ifndef COMMENT
- /* I can't explain this but it unbreaks "cd blah/sub<Esc>" */
- if (itsadir && !xrecursive && xpatslash > 0 &&
- segisdir == 0 && itswild) {
- s1 = xpat;
- debug(F110,"traverse mresult s1 kludge",s1,0);
- }
-#endif /* COMMENT */
-
- if (xrecursive && xpatslash == 0)
- s2 = nambuf;
- while ((s1[0] == '.') && (s1[1] == '/')) /* Strip "./" */
- s1 += 2;
- while ((s2[0] == '.') && (s2[1] == '/')) /* Ditto */
- s2 += 2;
- opts = mopts; /* Match options */
- if (itsadir) /* Current segment is a directory */
- opts = mopts & 1; /* No fences */
- s3 = s2; /* Get segment depth */
- depth = 0;
- while (*s3) { if (*s3++ == '/') depth++; }
-#ifndef NOSKIPMATCH
- /* This speeds things up a bit. */
- /* If it causes trouble define NOSKIPMATCH and rebuild. */
- if (depth == 0 && (s1[0] == '*') && !s1[1])
- mresult = xmatchdot ? 1 : (s2[0] != '.');
- else
-#endif /* NOSKIPMATCH */
- mresult = ckmatch(s1,s2,1,opts); /* Match */
- }
-#ifdef DEBUG
- if (deblog) {
- debug(F111,"traverse mresult depth",sofar,depth);
- debug(F101,"traverse mresult xpatslash","",xpatslash);
- debug(F111,"traverse mresult nambuf",nambuf,mresult);
- debug(F111,"traverse mresult itswild",pl -> npart,itswild);
- debug(F111,"traverse mresult segisdir",pl -> npart,segisdir);
- }
-#endif /* DEBUG */
- if (mresult || /* If match succeeded */
- xrecursive || /* Or search is recursive */
- depth < xpatslash /* Or not deep enough to match... */
- ) {
- if ( /* If it's not a directory... */
-/*
- The problem here is that segisdir is apparently not set appropriately.
- If I leave in the !segisdir test, then "dir /recursive blah" (where blah is
- a directory name) misses some regular files because sometimes segisdir
- is set and sometimes it's not. But if I comment it out, then
- "dir <star>/<star>.txt lists every file in * and does not even open up the
- subdirectories. However, "dir /rec <star>/<star>.txt" works right.
-*/
-#ifdef COMMENT
- mresult && (!itsadir && !segisdir)
-#else
- mresult && /* Matched */
- !itsadir && /* sofar is not a directory */
- ((!xrecursive && !segisdir) || xrecursive)
-#endif /* COMMENT */
- ) {
- debug(F110,
- "traverse add: match && !itsadir",sofar,0);
- addresult(sofar,itsadir);
- if (numfnd < 0) return;
- } else if (itsadir && (xrecursive || mresult)) {
- struct path * xx = NULL;
- *eos++ = DIRSEP; /* Add directory separator */
- *eos = '\0'; /* to end of segment */
-#ifdef RECURSIVE
- /* Copy previous pattern segment to this new directory */
-
- if (xrecursive > 0 && !(pl -> fwd)) {
- xx = (struct path *) malloc(sizeof (struct path));
- pl -> fwd = xx;
- if (xx) {
- xx -> fwd = NULL;
- strcpy(xx -> npart, pl -> npart); /* safe */
- }
- }
-#endif /* RECURSIVE */
- traverse(pl -> fwd, sofar, eos); /* Traverse new directory */
- }
- }
- }
-#ifdef OPENDIR
- closedir(fd);
-#else /* !OPENDIR */
- close(fd);
-#endif /* OPENDIR */
-}
-
-/*
- * addresult:
- * Adds a result string to the result array. Increments the number
- * of matches found, copies the found string into our string
- * buffer, and puts a pointer to the buffer into the caller's result
- * array. Our free buffer pointer is updated. If there is no
- * more room in the caller's array, the number of matches is set to -1.
- * Input: a result string.
- * Returns: nothing.
- */
-static VOID
-addresult(str,itsadir) char *str; int itsadir; {
- int len;
-
- if (!freeptr) {
- debug(F100,"addresult string space not init'd","",0);
- initspace(mtchs,ssplen);
- }
- if (!str) str = "";
- debug(F111,"addresult",str,itsadir);
- if (!*str)
- return;
-
- if (itsadir < 0) {
- itsadir = xisdir(str);
- }
- if ((xdironly && !itsadir) || (xfilonly && itsadir)) {
- debug(F111,"addresult skip",str,itsadir);
- return;
- }
- while (str[0] == '.' && ISDIRSEP(str[1])) /* Strip all "./" from front */
- str += 2;
- if (--remlen < 0) { /* Elements left in array of names */
- debug(F111,"addresult ARRAY FULL",str,numfnd);
- numfnd = -1;
- return;
- }
- len = (int)strlen(str); /* Space this will use */
- debug(F111,"addresult len",str,len);
-
- if (len < 1)
- return;
-
- if ((freeptr + len + itsadir + 1) > (sspace + ssplen)) {
- debug(F111,"addresult OUT OF SPACE",str,numfnd);
-#ifdef DYNAMIC
- printf(
-"?String space %d exhausted - use SET FILE STRINGSPACE to increase\n",ssplen);
-#else
- printf("?String space %d exhausted\n",ssplen);
-#endif /* DYNAMIC */
- numfnd = -1; /* Do not record if not enough space */
- return;
- }
- strcpy(freeptr,str); /* safe */
-
- /* Tag directory names by putting '/' at the end */
-
- if (itsadir && (freeptr[len-1] == '/')) {
- freeptr[len++] = DIRSEP;
- freeptr[len] = '\0';
- }
- if (numfnd >= maxnames) {
-#ifdef DYNAMIC
- printf(
-"?Too many files (%d max) - use SET FILE LISTSIZE to increase\n",maxnames);
-#else
- printf("?Too many files - %d max\n",maxnames);
-#endif /* DYNAMIC */
- numfnd = -1;
- return;
- }
- str = freeptr;
- *resptr++ = freeptr;
- freeptr += (len + 1);
- numfnd++;
- debug(F111,"addresult ADD",str,numfnd);
-}
-
-#ifdef COMMENT
-/*
- * match(pattern,string):
- * pattern matcher. Takes a string and a pattern possibly containing
- * the wildcard characters '*' and '?'. Returns true if the pattern
- * matches the string, false otherwise.
- * Orignally by: Jeff Damens, CUCCA, 1984
- * No longer used as of C-Kermit 7.0, now we use ckmatch() instead (ckclib.c).
- *
- * Input: a string and a wildcard pattern.
- * Returns: 1 if match, 0 if no match.
- */
-static int
-match(pattern, string) char *pattern, *string; {
- char *psave = NULL, *ssave = NULL; /* Backup pointers for failure */
- int q = 0; /* Quote flag */
-
- if (*string == '.' && *pattern != '.' && !xmatchdot) {
- debug(F110,"match skip",string,0);
- return(0);
- }
- while (1) {
- for (; *pattern == *string; pattern++,string++) /* Skip first */
- if (*string == '\0') return(1); /* End of strings, succeed */
-
- if (*pattern == '\\' && q == 0) { /* Watch out for quoted */
- q = 1; /* metacharacters */
- pattern++; /* advance past quote */
- if (*pattern != *string) return(0);
- continue;
- } else q = 0;
-
- if (q) {
- return(0);
- } else {
- if (*string != '\0' && *pattern == '?') {
- pattern++; /* '?', let it match */
- string++;
- } else if (*pattern == '*') { /* '*' ... */
- psave = ++pattern; /* remember where we saw it */
- ssave = string; /* let it match 0 chars */
- } else if (ssave != NULL && *ssave != '\0') { /* if not at end */
- /* ...have seen a star */
- string = ++ssave; /* skip 1 char from string */
- pattern = psave; /* and back up pattern */
- } else return(0); /* otherwise just fail */
- }
- }
-}
-#endif /* COMMENT */
-
-/*
- The following two functions are for expanding tilde in filenames
- Contributed by Howie Kaye, CUCCA, developed for CCMD package.
-*/
-
-/* W H O A M I -- Get user's username. */
-
-/*
- 1) Get real uid
- 2) See if the $USER environment variable is set ($LOGNAME on AT&T)
- 3) If $USER's uid is the same as ruid, realname is $USER
- 4) Otherwise get logged in user's name
- 5) If that name has the same uid as the real uid realname is loginname
- 6) Otherwise, get a name for ruid from /etc/passwd
-*/
-char *
-whoami() {
-#ifdef DTILDE
-#ifdef pdp11
-#define WHOLEN 100
-#else
-#define WHOLEN 257
-#endif /* pdp11 */
- static char realname[UIDBUFLEN+1]; /* user's name */
- static int ruid = -1; /* user's real uid */
- char loginname[UIDBUFLEN+1], envname[256]; /* temp storage */
- char *c;
- struct passwd *p;
- _PROTOTYP(extern char * getlogin, (void) );
-
- if (ruid != -1)
- return(realname);
-
- ruid = real_uid(); /* get our uid */
-
- /* how about $USER or $LOGNAME? */
- if ((c = getenv(NAMEENV)) != NULL) { /* check the env variable */
- ckstrncpy(envname, c, 255);
- if ((p = getpwnam(envname)) != NULL) {
- if (p->pw_uid == ruid) { /* get passwd entry for envname */
- ckstrncpy(realname, envname, UIDBUFLEN); /* uid's are same */
- return(realname);
- }
- }
- }
-
- /* can we use loginname() ? */
-
- if ((c = getlogin()) != NULL) { /* name from utmp file */
- ckstrncpy (loginname, c, UIDBUFLEN);
- if ((p = getpwnam(loginname)) != NULL) /* get passwd entry */
- if (p->pw_uid == ruid) /* for loginname */
- ckstrncpy(realname, envname, UIDBUFLEN); /* if uid's are same */
- }
-
- /* Use first name we get for ruid */
-
- if ((p = getpwuid(ruid)) == NULL) { /* name for uid */
- realname[0] = '\0'; /* no user name */
- ruid = -1;
- return(NULL);
- }
- ckstrncpy(realname, p->pw_name, UIDBUFLEN);
- return(realname);
-#else
- return(NULL);
-#endif /* DTILDE */
-}
-
-/* T I L D E _ E X P A N D -- expand ~user to the user's home directory. */
-
-char *
-tilde_expand(dirname) char *dirname; {
-#ifdef DTILDE
-#ifdef pdp11
-#define BUFLEN 100
-#else
-#define BUFLEN 257
-#endif /* pdp11 */
- struct passwd *user;
- static char olddir[BUFLEN+1];
- static char oldrealdir[BUFLEN+1];
- static char temp[BUFLEN+1];
- int i, j;
-
- debug(F111,"tilde_expand",dirname,dirname[0]);
-
- if (dirname[0] != '~') /* Not a tilde...return param */
- return(dirname);
- if (!strcmp(olddir,dirname)) { /* Same as last time */
- return(oldrealdir); /* so return old answer. */
- } else {
- j = (int)strlen(dirname);
- for (i = 0; i < j; i++) /* find username part of string */
- if (!ISDIRSEP(dirname[i]))
- temp[i] = dirname[i];
- else break;
- temp[i] = '\0'; /* tie off with a NULL */
- if (i == 1) { /* if just a "~" */
-#ifdef IKSD
- if (inserver)
- user = getpwnam(uidbuf); /* Get info on current user */
- else
-#endif /* IKSD */
- {
- char * p = whoami();
- if (p)
- user = getpwnam(p);
- else
- user = NULL;
- }
- } else {
- user = getpwnam(&temp[1]); /* otherwise on the specified user */
- }
- }
- if (user != NULL) { /* valid user? */
- ckstrncpy(olddir, dirname, BUFLEN); /* remember the directory */
- ckstrncpy(oldrealdir,user->pw_dir, BUFLEN); /* and home directory */
- ckstrncat(oldrealdir,&dirname[i], BUFLEN);
- oldrealdir[BUFLEN] = '\0';
- return(oldrealdir);
- } else { /* invalid? */
- ckstrncpy(olddir, dirname, BUFLEN); /* remember for next time */
- ckstrncpy(oldrealdir, dirname, BUFLEN);
- return(oldrealdir);
- }
-#else
- return(NULL);
-#endif /* DTILDE */
-}
-
-/*
- Functions for executing system commands.
- zsyscmd() executes the system command in the normal, default way for
- the system. In UNIX, it does what system() does. Thus, its results
- are always predictable.
- zshcmd() executes the command using the user's preferred shell.
-*/
-int
-zsyscmd(s) char *s; {
-#ifdef aegis
- if (nopush) return(-1);
- if (!priv_chk()) return(system(s));
-#else
- PID_T shpid;
-#ifdef COMMENT
-/* This doesn't work... */
- WAIT_T status;
-#else
- int status;
-#endif /* COMMENT */
-
- if (nopush) return(-1);
- if ((shpid = fork())) {
- if (shpid < (PID_T)0) return(-1); /* Parent */
- while (shpid != (PID_T) wait(&status))
- ;
- return(status);
- }
- if (priv_can()) { /* Child: cancel any priv's */
- printf("?Privilege cancellation failure\n");
- _exit(255);
- }
- restorsigs(); /* Restore ignored signals */
-#ifdef HPUX10
- execl("/usr/bin/sh","sh","-c",s,NULL);
- perror("/usr/bin/sh");
-#else
-#ifdef Plan9
- execl("/bin/rc", "rc", "-c", s, NULL);
- perror("/bin/rc");
-#else
- execl("/bin/sh","sh","-c",s,NULL);
- perror("/bin/sh");
-#endif /* Plan9 */
-#endif /* HPUX10 */
- _exit(255);
- return(0); /* Shut up ANSI compilers. */
-#endif /* aegis */
-}
-
-
-/* Z _ E X E C -- Overlay ourselves with another program */
-
-#ifndef NOZEXEC
-#ifdef HPUX5
-#define NOZEXEC
-#else
-#ifdef ATT7300
-#define NOZEXEC
-#endif /* ATT7300 */
-#endif /* HPUX5 */
-#endif /* NOZEXEC */
-
-VOID
-z_exec(p,s,t) char * p, ** s; int t; { /* Overlay ourselves with "p s..." */
-#ifdef NOZEXEC
- printf("EXEC /REDIRECT NOT IMPLEMENTED IN THIS VERSION OF C-KERMIT\n");
- debug(F110,"z_exec NOT IMPLEMENTED",p,0);
-#else
- int x;
- extern int ttyfd;
- debug(F110,"z_exec command",p,0);
- debug(F110,"z_exec arg 0",s[0],0);
- debug(F110,"z_exec arg 1",s[1],0);
- debug(F101,"z_exec t","",t);
- errno = 0;
- if (t) {
- if (ttyfd > 2) {
- dup2(ttyfd, 0);
- dup2(ttyfd, 1);
- /* dup2(ttyfd, 2); */
- close(ttyfd);
- }
- }
- restorsigs(); /* Restore ignored signals */
- x = execvp(p,s);
- if (x < 0) debug(F101,"z_exec errno","",errno);
-#endif /* NOZEXEC */
-}
-
-/*
- Z S H C M D -- Execute a shell command (or program thru the shell).
-
- Original UNIX code by H. Fischer; copyright rights assigned to Columbia U.
- Adapted to use getpwuid to find login shell because many systems do not
- have SHELL in environment, and to use direct calling of shell rather
- than intermediate system() call. -- H. Fischer (1985); many changes since
- then. Call with s pointing to command to execute. Returns:
- -1 on failure to start the command (can't find, can't fork, can't run).
- 1 if command ran and gave an exit status of 0.
- 0 if command ran and gave a nonzero exit status.
- with pexitstatus containing the command's exit status.
-*/
-int
-zshcmd(s) char *s; {
- PID_T pid;
-
-#ifdef NOPUSH
- return(0);
-#else
- if (nopush) return(-1);
- debug(F110,"zshcmd command",s,0);
-
-#ifdef aegis
- if ((pid = vfork()) == 0) { /* Make child quickly */
- char *shpath, *shname, *shptr; /* For finding desired shell */
-
- if (priv_can()) exit(1); /* Turn off privs. */
- if ((shpath = getenv("SHELL")) == NULL) shpath = "/com/sh";
-
-#else /* All Unix systems */
- if ((pid = fork()) == 0) { /* Make child */
- char *shpath, *shname, *shptr; /* For finding desired shell */
- struct passwd *p;
-#ifdef HPUX10 /* Default */
- char *defshell = "/usr/bin/sh";
-#else
-#ifdef Plan9
- char *defshell = "/bin/rc";
-#else
- char *defshell = "/bin/sh";
-#endif /* Plan9 */
-#endif /* HPUX10 */
- if (priv_can()) exit(1); /* Turn off privs. */
-#ifdef COMMENT
-/* Old way always used /etc/passwd shell */
- p = getpwuid(real_uid()); /* Get login data */
- if (p == (struct passwd *) NULL || !*(p->pw_shell))
- shpath = defshell;
- else
- shpath = p->pw_shell;
-#else
-/* New way lets user override with SHELL variable, but does not rely on it. */
-/* This allows user to specify a different shell. */
- shpath = getenv("SHELL"); /* What shell? */
- debug(F110,"zshcmd SHELL",shpath,0);
- if (shpath == NULL) {
- p = getpwuid( real_uid() ); /* Get login data */
- if (p == (struct passwd *)NULL || !*(p->pw_shell))
- shpath = defshell;
- else shpath = p->pw_shell;
- debug(F110,"zshcmd shpath",shpath,0);
- }
-#endif /* COMMENT */
-#endif /* aegis */
- shptr = shname = shpath;
- while (*shptr != '\0')
- if (*shptr++ == DIRSEP)
- shname = shptr;
- restorsigs(); /* Restore ignored signals */
- debug(F110,"zshcmd shname",shname,0);
- if (s == NULL || *s == '\0') { /* Interactive shell requested? */
- execl(shpath,shname,"-i",NULL); /* Yes, do that */
- } else { /* Otherwise, */
- execl(shpath,shname,"-c",s,NULL); /* exec the given command */
- } /* If execl() failed, */
- exit(BAD_EXIT); /* return bad return code. */
-
- } else { /* Parent */
-
- int wstat; /* ... must wait for child */
-#ifdef CK_CHILD
- int child; /* Child's exit status */
-#endif /* CK_CHILD */
- SIGTYP (*istat)(), (*qstat)();
-
- if (pid == (PID_T) -1) return(-1); /* fork() failed? */
-
- istat = signal(SIGINT,SIG_IGN); /* Let the fork handle keyboard */
- qstat = signal(SIGQUIT,SIG_IGN); /* interrupts itself... */
-
-#ifdef CK_CHILD
- while (((wstat = wait(&child)) != pid) && (wstat != -1))
-#else
- while (((wstat = wait((WAIT_T *)0)) != pid) && (wstat != -1))
-#endif /* CK_CHILD */
- ; /* Wait for fork */
- signal(SIGINT,istat); /* Restore interrupts */
- signal(SIGQUIT,qstat);
-#ifdef CK_CHILD
- pexitstat = (child & 0xff) ? child : child >> 8;
- debug(F101,"zshcmd exit status","",pexitstat);
- return(child == 0 ? 1 : 0); /* Return child's status */
-#endif /* CK_CHILD */
- }
- return(1);
-#endif /* NOPUSH */
-}
-
-/* I S W I L D -- Check if filespec is "wild" */
-
-/*
- Returns:
- 0 if argument is empty or is the name of a single file;
- 1 if it contains wildcard characters.
- Note: must match the algorithm used by match(), hence no [a-z], etc.
-*/
-int
-iswild(filespec) char *filespec; {
- char c, *p, *f; int x;
- int quo = 0;
- if (!filespec)
- return(0);
- f = filespec;
- if (wildxpand) { /* Shell handles wildcarding */
- if ((x = nzxpand(filespec,0)) > 1)
- return(1);
- if (x == 0) return(0); /* File does not exist */
- p = malloc(MAXNAMLEN + 20);
- znext(p);
- x = (strcmp(filespec,p) != 0);
- free(p);
- p = NULL;
- return(x);
- } else { /* We do it ourselves */
- while ((c = *filespec++) != '\0') {
- if (c == '\\' && quo == 0) {
- quo = 1;
- continue;
- }
- if (!quo && (c == '*' || c == '?'
-#ifdef CKREGEX
-#ifndef VMS
- || c == '['
-#endif /* VMS */
- || c == '{'
-#endif /* CKREGEX */
- )) {
- debug(F111,"iswild",f,1);
- return(1);
- }
- quo = 0;
- }
- debug(F111,"iswild",f,0);
- return(0);
- }
-}
-
-/*
- I S D I R -- Is a Directory.
-
- Tell if string pointer s is the name of an existing directory. Returns 1 if
- directory, 0 if not a directory.
-
- The following no longer applies:
-
- If the file is a symlink, we return 1 if
- it is a directory OR if it is a link to a directory and the "xrecursive" flag
- is NOT set. This is to allow parsing a link to a directory as if it were a
- directory (e.g. in the CD or IF DIRECTORY command) but still prevent
- recursive traversal from visiting the same directory twice.
-*/
-
-#ifdef ISDIRCACHE
-/* This turns out to be unsafe and gives little benefit anyway. */
-/* See notes 28 Sep 2003. Thus ISDIRCACHE is not defined. */
-
-static char prevpath[CKMAXPATH+4] = { '\0', '\0' };
-static int prevstat = -1;
-int
-clrdircache() {
- debug(F100,"CLEAR ISDIR CACHE","",0);
- prevstat = -1;
- prevpath[0] = NUL;
-}
-#endif /* ISDIRCACHE */
-
-int
-isdir(s) char *s; {
- int x, needrlink = 0, islink = 0;
- struct stat statbuf;
- char fnam[CKMAXPATH+4];
-
- if (!s) return(0);
- if (!*s) return(0);
-
-#ifdef ISDIRCACHE
- if (prevstat > -1) {
- if (s[0] == prevpath[0]) {
- if (!strcmp(s,prevpath)) {
- debug(F111,"isdir cache hit",s,prevstat);
- return(prevstat);
- }
- }
- }
-#endif /* ISDIRCACHE */
-
-#ifdef CKSYMLINK
-#ifdef COMMENT
-/*
- The following over-clever bit has been commented out because it presumes
- to know when a symlink might be redundant, which it can't possibly know.
- Using plain old stat() gives Kermit the same results as ls and ls -R, which
- is just fine: no surprises.
-*/
-#ifdef USE_LSTAT
- if (xrecursive) {
- x = lstat(s,&statbuf);
- debug(F111,"isdir lstat",s,x);
- } else {
-#endif /* USE_LSTAT */
- x = stat(s,&statbuf);
- debug(F111,"isdir stat",s,x);
-#ifdef USE_LSTAT
- }
-#endif /* USE_LSTAT */
-#else
- x = stat(s,&statbuf);
- debug(F111,"isdir stat",s,x);
-#endif /* COMMENT */
- if (x == -1) {
- debug(F101,"isdir errno","",errno);
- return(0);
- }
- islink = 0;
- if (xrecursive) {
-#ifdef NOLINKBITS
- needrlink = 1;
-#else
-#ifdef S_ISLNK
- islink = S_ISLNK(statbuf.st_mode);
- debug(F101,"isdir S_ISLNK islink","",islink);
-#else
-#ifdef _IFLNK
- islink = (_IFMT & statbuf.st_mode) == _IFLNK;
- debug(F101,"isdir _IFLNK islink","",islink);
-#endif /* _IFLNK */
-#endif /* S_ISLNK */
-#endif /* NOLINKBITS */
- if (needrlink) {
- if (readlink(s,fnam,CKMAXPATH) > -1)
- islink = 1;
- }
- }
-#else
- x = stat(s,&statbuf);
- if (x == -1) {
- debug(F101,"isdir errno","",errno);
- return(0);
- }
- debug(F111,"isdir stat",s,x);
-#endif /* CKSYMLINK */
- debug(F101,"isdir islink","",islink);
- debug(F101,"isdir statbuf.st_mode","",statbuf.st_mode);
- x = islink ? 0 : (S_ISDIR (statbuf.st_mode) ? 1 : 0);
-#ifdef ISDIRCACHE
- prevstat = x;
- ckstrncpy(prevpath,s,CKMAXPATH+1);
-#endif /* ISDIRCACHE */
- return(x);
-}
-
-#ifdef CK_MKDIR
-/* Some systems don't have mkdir(), e.g. Tandy Xenix 3.2.. */
-
-/* Z M K D I R -- Create directory(s) if necessary */
-/*
- Call with:
- A pointer to a file specification that might contain directory
- information. The filename is expected to be included.
- If the file specification does not include any directory separators,
- then it is assumed to be a plain file.
- If one or more directories are included in the file specification,
- this routine tries to create them if they don't already exist.
- Returns:
- 0 or greater on success, i.e. the number of directories created.
- -1 on failure to create the directory
-*/
-int
-zmkdir(path) char *path; {
- char *xp, *tp, c;
- int x, count = 0;
-
- if (!path) path = "";
- if (!*path) return(-1);
-
-#ifdef CKROOT
- debug(F111,"zmkdir setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(path)) {
- debug(F110,"zmkdir setroot violation",path,0);
- return(-1);
- }
-#endif /* CKROOT */
-
- x = strlen(path);
- debug(F111,"zmkdir",path,x);
- if (x < 1 || x > MAXPATH) /* Check length */
- return(-1);
- if (!(tp = malloc(x+1))) /* Make a temporary copy */
- return(-1);
- strcpy(tp,path); /* safe (prechecked) */
-#ifdef DTILDE
- if (*tp == '~') { /* Starts with tilde? */
- xp = tilde_expand(tp); /* Attempt to expand tilde */
- if (!xp) xp = "";
- if (*xp) {
- char *zp;
- debug(F110,"zmkdir tilde_expand",xp,0);
- if (!(zp = malloc(strlen(xp) + 1))) { /* Make a place for it */
- free(tp);
- tp = NULL;
- return(-1);
- }
- free(tp); /* Free previous buffer */
- tp = zp; /* Point to new one */
- strcpy(tp,xp); /* Copy expanded name to new buffer */
- }
- }
-#endif /* DTILDE */
- debug(F110,"zmkdir tp after tilde_expansion",tp,0);
- xp = tp;
- if (ISDIRSEP(*xp)) /* Don't create root directory! */
- xp++;
-
- /* Go thru filespec from left to right... */
-
- for (; *xp; xp++) { /* Create parts that don't exist */
- if (!ISDIRSEP(*xp)) /* Find next directory separator */
- continue;
- c = *xp; /* Got one. */
- *xp = NUL; /* Make this the end of the string. */
- if (!isdir(tp)) { /* This directory exists already? */
-#ifdef CK_LOGIN
- if (isguest) /* Not allowed for guests */
- return(-1);
-#ifndef NOXFER
- /* Nor if MKDIR and/or CD are disabled */
- else
-#endif /* CK_LOGIN */
- if ((server
-#ifdef IKSD
- || inserver
-#endif /* IKSD */
- ) && (!ENABLED(en_mkd) || !ENABLED(en_cwd)))
- return(-1);
-#endif /* IKSD */
-
- debug(F110,"zmkdir making",tp,0);
- x = /* No, try to create it */
-#ifdef NOMKDIR
- -1 /* Systems without mkdir() */
-#else
- mkdir(tp,0777) /* UNIX */
-#endif /* NOMKDIR */
- ;
- if (x < 0) {
- debug(F101,"zmkdir failed, errno","",errno);
- free(tp); /* Free temporary buffer. */
- tp = NULL;
- return(-1); /* Return failure code. */
- } else
- count++;
- }
- *xp = c; /* Replace the separator. */
- }
- free(tp); /* Free temporary buffer. */
- return(count); /* Return success code. */
-}
-#endif /* CK_MKDIR */
-
-int
-zrmdir(path) char *path; {
-#ifdef CK_LOGIN
- if (isguest)
- return(-1);
-#endif /* CK_LOGIN */
-
- if (!path) path = "";
- if (!*path) return(-1);
-
-#ifdef CKROOT
- debug(F111,"zrmdir setroot",ckroot,ckrootset);
- if (ckrootset) if (!zinroot(path)) {
- debug(F110,"zrmdir setroot violation",path,0);
- return(-1);
- }
-#endif /* CKROOT */
-
-#ifndef NOMKDIR
- return(rmdir(path));
-#else
- return(-1);
-#endif /* NOMKDIR */
-}
-
-/* Z F S E E K -- Position input file pointer */
-/*
- Call with:
- Long int, 0-based, indicating desired position.
- Returns:
- 0 on success.
- -1 on failure.
-*/
-#ifndef NORESEND
-int
-#ifdef CK_ANSIC
-zfseek(long pos)
-#else
-zfseek(pos) long pos;
-#endif /* CK_ANSIC */
-/* zfseek */ {
- zincnt = -1; /* Must empty the input buffer */
- debug(F101,"zfseek","",pos);
- return(fseek(fp[ZIFILE], pos, 0)?-1:0);
-}
-#endif /* NORESEND */
-
-/* Z F N Q F P -- Convert filename to fully qualified absolute pathname */
-
-static struct zfnfp fnfp = { 0, NULL, NULL };
-
-struct zfnfp *
-zfnqfp(fname, buflen, buf) char * fname; int buflen; char * buf; {
- char * s;
- int len;
-#ifdef MAXPATHLEN
- char zfntmp[MAXPATHLEN+4];
-#else
- char zfntmp[CKMAXPATH+4];
-#endif /* MAXPATHLEN */
-
- char sb[32], * tmp;
- int i = 0, j = 0, k = 0, x = 0, y = 0;
- int itsadir = 0;
-
- s = fname;
- if (!s)
- return(NULL);
- if (!*s)
- return(NULL);
- if (!buf)
- return(NULL);
-
- /* Initialize the data structure */
-
- fnfp.len = ckstrncpy(buf,fname,buflen);
- fnfp.fpath = buf;
- fnfp.fname = NULL;
- len = buflen;
- debug(F111,"zfnqfp fname",fname,len);
-
-#ifdef DTILDE
- if (*s == '~') { /* Starts with tilde? */
- char * xp;
- xp = tilde_expand(s); /* Attempt to expand tilde */
- debug(F110,"zfnqfp xp",xp,0); /* (realpath() doesn't do this) */
- if (!xp) xp = "";
- if (*xp)
- s = xp;
- }
-#endif /* DTILDE */
-
-#ifdef CKREALPATH
-
-/* N.B.: The realpath() result buffer MUST be MAXPATHLEN bytes long */
-/* otherwise we write over memory. */
-
- if (!realpath(s,zfntmp)) {
- debug(F111,"zfnqfp realpath fails",s,errno);
-#ifdef COMMENT
- if (errno != ENOENT)
- return(NULL);
-#else
- /* If realpath() fails use the do-it-yourself method */
- /* 16 Jan 2002 */
- goto norealpath;
-#endif /* COMMENT */
- }
- len = strlen(zfntmp);
- if (len > buflen) {
- debug(F111,"zfnqfp result too long",ckitoa(buflen),len);
- return(NULL);
- } else {
- ckstrncpy(buf,zfntmp,buflen);
- }
- if (buf[len-1] != '/') {
- if ((itsadir = isdir(buf)) && len < (buflen - 1)) {
- buf[len++] = '/';
- buf[len] = NUL;
- }
- }
- fnfp.len = len;
- fnfp.fpath = buf;
- debug(F110,"zfnqfp realpath path",fnfp.fpath,0);
- tmp = buf + fnfp.len - 1;
- if (!itsadir) {
- while (tmp >= buf) {
- if (*tmp == '/') {
- fnfp.fname = tmp + 1;
- debug(F110,"zfnqfp realpath name",fnfp.fname,0);
- break;
- }
- tmp--;
- }
- }
- return(&fnfp);
-
-#endif /* CKREALPATH */
-
- norealpath:
-
- tmp = zfntmp;
- while (*s) { /* Remove leading "./" (0 or more) */
- debug(F110,"zfnqfp while *s",s,0);
- if (*s == '.' && *(s+1) == '/') {
- s += 2;
- while (*s == '/') s++;
- } else
- break;
- }
- if (!*s) return(NULL);
- if (*s == '/') { /* Pathname is absolute */
- ckstrncpy(buf,s,len);
- x = strlen(buf);
- y = 0;
- } else { /* Pathname is relative */
- char * p;
- if (p = zgtdir()) { /* So get current directory */
- debug(F110,"zfnqfp zgtdir",p,0);
- x = ckstrncpy(buf,p,len);
- buf[x++] = '/';
- debug(F110,"zfnqfp buf 1",buf,0);
- len -= x; /* How much room left in buffer */
- if ((y = (int)strlen(s)) > len) /* If enough room... */
- return(NULL);
- ckstrncpy(buf+x,s,len); /* ... append the filename */
- debug(F110,"zfnqfp buf 2",buf,0);
- } else {
- return(NULL);
- }
- }
-
- /* Buf now holds full path but maybe containing some . or .. tricks */
-
- j = x + y; /* Length of what's in buf */
- len = j;
- debug(F101,"zfnqfp len","",len);
-
- /* Catch dangling "/." or "/.." */
- if ((j > 1 && buf[j-1] == '.' && buf[j-2] == '/') ||
- (j > 2 && buf[j-1] == '.' && buf[j-2] == '.' && buf[j-3] == '/')) {
- if (j < buflen - 2) {
- buf[j] = '/';
- buf[j+1] = NUL;
- }
- }
- j = -1; /* j = position of rightmost "/" */
- i = 0; /* i = destination index */
- tmp[i] = NUL; /* destination is temporary buffer */
-
- for (x = 0; x < len; x++) { /* x = source index */
- if (buf[x] == '/') {
- for (k = 0; k < 4; k++) {
- sb[k] = buf[x+k];
- sb[k+1] = '\0';
- if (!sb[k]) break;
- }
- if (!strncmp(sb,"/./",3)) { /* Eliminate "./" in "/./" */
- x += 1;
- continue;
- } else if (!strncmp(sb,"//",2)) { /* Change "//" to "/" */
- continue;
- } else if (!strncmp(sb,"/../",4)) { /* ".." in path */
- for (k = i - 1; k >= 0; k--) { /* Back up one level */
- if (tmp[k] == '/') {
- i = k;
- tmp[i] = NUL;
- break;
- }
- }
- x += 2;
- continue;
- }
- }
- if (i >= (buflen - 1)) {
- debug(F111,"zfnqfp overflow",tmp,i);
- return(NULL);
- }
- tmp[i++] = buf[x]; /* Regular character, copy */
- tmp[i] = NUL;
- if (buf[x] == '/') /* Remember rightmost "/" */
- j = i;
- }
- ckstrncpy(buf,tmp,buflen-1); /* Copy the result back */
-
- buf[buflen-1] = NUL;
- if (!buf[0]) { /* If empty, say root */
- buf[0] = '/';
- buf[2] = NUL;
- j = 0;
- i = 1;
- }
- if ((itsadir = isdir(buf))) {
- if (buf[i-1] != '/' && i < (buflen - 1)) {
- buf[i++] = '/';
- buf[i] = NUL;
- }
- }
- if (!itsadir && (j > -1)) { /* Set pointer to basename */
- fnfp.fname = (char *)(buf + j);
- fnfp.fpath = (char *)buf;
- fnfp.len = i;
- debug(F111,"zfnqfp path",fnfp.fpath,i);
- debug(F110,"zfnqfp name",fnfp.fname,0);
- return(&fnfp);
- }
- return(NULL);
-}
-
-/* Z C M P F N -- Compare two filenames */
-
-/* Returns 1 if the two names refer to the same existing file, 0 otherwise. */
-
-int
-zcmpfn(s1,s2) char * s1, * s2; {
- char buf1[CKMAXPATH+1];
- char buf2[CKMAXPATH+1];
-
-#ifdef USE_LSTAT
- char linkname[CKMAXPATH+1];
- struct stat buf;
-#endif /* USE_LSTAT */
- int x, rc = 0;
-
- if (!s1) s1 = "";
- if (!s2) s2 = "";
- if (!*s1 || !*s2) return(0);
-
-#ifdef CKSYMLINK /* We're doing symlinks? */
-#ifdef USE_LSTAT /* OK to use lstat()? */
- x = lstat(s1,&buf);
- if (x > -1 && /* 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 */
- ) {
- linkname[0] = '\0'; /* Get the name */
- x = readlink(s1,linkname,CKMAXPATH);
- if (x > -1 && x < CKMAXPATH) { /* It's a link */
- linkname[x] = '\0';
- s1 = linkname;
- }
- }
-#endif /* USE_LSTAT */
-#endif /* CKSYMLINK */
-
- if (zfnqfp(s1,CKMAXPATH,buf1)) { /* Convert to full pathname */
-
-#ifdef CKSYMLINK /* Same deal for second name... */
-#ifdef USE_LSTAT
- x = lstat(s2,&buf);
- if (x > -1 &&
-#ifdef S_ISLNK
- S_ISLNK(buf.st_mode)
-#else
-#ifdef _IFLNK
- ((_IFMT & buf.st_mode) == _IFLNK)
-#endif /* _IFLNK */
-#endif /* S_ISLNK */
- ) {
- linkname[0] = '\0';
- x = readlink(s2,linkname,CKMAXPATH);
- if (x > -1 && x < CKMAXPATH) {
- linkname[x] = '\0';
- s2 = linkname;
- }
- }
-#endif /* USE_LSTAT */
-#endif /* CKSYMLINK */
- if (zfnqfp(s2,CKMAXPATH,buf2)) {
- debug(F110,"zcmpfn s1",buf1,0);
- debug(F110,"zcmpfn s2",buf2,0);
- if (!strncmp(buf1,buf2,CKMAXPATH))
- rc = 1;
- }
- }
- debug(F101,"zcmpfn result","",rc);
- return(rc);
-}
-
-#ifdef CKROOT
-
-/* User-mode chroot() implementation */
-
-int
-zsetroot(s) char * s; { /* Sets the root */
- char buf[CKMAXPATH+1];
- if (!s) return(-1);
- if (!*s) return(-1);
- debug(F110,"zsetroot",s,0);
- if (!isdir(s)) return(-2);
- if (!zfnqfp(s,CKMAXPATH,buf)) /* Get full, real path */
- return(-3);
- if (access(buf,R_OK) < 0) { /* Check access */
- debug(F110,"zsetroot access denied",buf,0);
- return(-4);
- }
- s = buf;
- if (ckrootset) { /* If root already set */
- if (!zinroot(s)) { /* make sure new root is in it */
- debug(F110,"zsetroot new root not in root",ckroot,0);
- return(-5);
- }
- }
- if (zchdir(buf) < 1) return(-4); /* Change directory to new root */
- ckrootset = ckstrncpy(ckroot,buf,CKMAXPATH); /* Now set the new root */
- if (ckroot[ckrootset-1] != '/') {
- ckroot[ckrootset++] = '/';
- ckroot[ckrootset] = '\0';
- }
- debug(F111,"zsetroot rootset",ckroot,ckrootset);
- ckrooterr = 0; /* Reset error flag */
- return(1);
-}
-
-char *
-zgetroot() { /* Returns the root */
- if (!ckrootset)
- return(NULL);
- return((char *)ckroot);
-}
-
-int
-zinroot(s) char * s; { /* Checks if file s is in the root */
- int x, n;
- struct zfnfp * f = NULL;
- char buf[CKMAXPATH+2];
-
- debug(F111,"zinroot setroot",ckroot,ckrootset);
- ckrooterr = 0; /* Reset global error flag */
- if (!ckrootset) /* Root not set */
- return(1); /* so it's ok - no need to check */
- if (!(f = zfnqfp(s,CKMAXPATH,buf))) /* Get full and real pathname */
- return(0); /* Fail if we can't */
- n = f->len; /* Length of full pathname */
- debug(F111,"zinroot n",buf,n);
- if (n < (ckrootset - 1) || n > CKMAXPATH) { /* Bad length */
- ckrooterr = 1; /* Fail */
- return(0);
- }
- if (isdir(buf) && buf[n-1] != '/') { /* If it's a directory name */
- buf[n++] = '/'; /* make sure it ends with '/' */
- buf[n] = '\0';
- }
- x = strncmp(buf,ckroot,ckrootset); /* Compare, case-sensitive */
- debug(F111,"zinroot checked",buf,x);
- if (x == 0) /* OK */
- return(1);
- ckrooterr = 1; /* Not OK */
- return(0);
-}
-#endif /* CKROOT */
-
-#ifdef CK_LOGIN
-/*
- The following code provides support for user login and logout
- including anonymous accounts. If this feature is to be supported
- outside of UNIX, it should be spread out among the ck?fio.c modules...
-*/
-#ifndef _PATH_BSHELL
-#define _PATH_BSHELL "/usr/bin/bash"
-#endif /* _PATH_BSHELL */
-#ifndef _PATH_FTPUSERS
-#define _PATH_FTPUSERS "/etc/ftpusers"
-#endif /* _PATH_FTPUSERS */
-
-/*
- * Helper function for sgetpwnam().
- */
-char *
-sgetsave(s) char *s; {
- char *new = malloc((unsigned) strlen(s) + 1);
- if (new == NULL) {
- printf("?Local resource failure: malloc\n");
- exit(1);
- /* NOTREACHED */
- }
- (void) strcpy(new, s); /* safe */
- return (new);
-}
-
-/*
- * Save the result of getpwnam(). Used for USER command, since
- * the data returned must not be clobbered by any other command
- * (e.g., globbing).
- */
-struct passwd *
-sgetpwnam(name) char *name; {
- static struct passwd save;
- register struct passwd *p;
-#ifdef CK_SHADOW
- register struct spwd *sp;
-#endif /* CK_SHADOW */
- char *sgetsave();
-
-#ifdef HPUX10_TRUSTED
- struct pr_passwd *pr;
-#endif /* HPUX10_TRUSTED */
-
-#ifdef CK_SHADOW
- sp = getspnam(name);
- debug(F111,"sgetpwnam","getspnam()",sp);
- if (sp == NULL)
- return (NULL);
-#endif /* CK_SHADOW */
-
-#ifdef HPUX10_TRUSTED
- if ((pr = getprpwnam(name)) == NULL)
- return(NULL);
-#endif /* HPUX10_TRUSTED */
-
- p = getpwnam(name);
- debug(F111,"sgetpwnam","getpwnam()",p);
- if (p == NULL)
- return(NULL);
- if (save.pw_name) {
- free(save.pw_name);
- free(save.pw_passwd);
- free(save.pw_gecos);
- free(save.pw_dir);
- free(save.pw_shell);
- }
- save = *p;
- save.pw_name = sgetsave(p->pw_name);
-#ifdef CK_SHADOW
- save.pw_passwd = sgetsave(sp->sp_pwdp);
-#else /* CK_SHADOW */
-#ifdef HPUX10_TRUSTED
- if (pr->uflg.fg_encrypt && pr->ufld.fd_encrypt && *pr->ufld.fd_encrypt)
- save.pw_passwd = sgetsave(pr->ufld.fd_encrypt);
- else
- save.pw_passwd = sgetsave("");
-#else /* HPUX10_TRUSTED */
- save.pw_passwd = sgetsave(p->pw_passwd);
-#endif /* HPUX10_TRUSTED */
-#endif /* CK_SHADOW */
- save.pw_gecos = sgetsave(p->pw_gecos);
- save.pw_dir = sgetsave(p->pw_dir);
- save.pw_shell = sgetsave(p->pw_shell);
- return(&save);
-}
-
-#define CKXLOGBSIZ 256
-
-struct passwd * pw = NULL;
-char * home = NULL; /* Home directory pointer for glob */
-#ifdef CMASK
-#undef CMASK
-#endif /* CMASK */
-
-#define CMASK 027
-
-int defumask = CMASK; /* Default umask value */
-
-/* Z V U S E R -- Verify user, Returns 1 if user OK, 0 otherwise. */
-
-/* Sets global passwd pointer pw if named account exists and is acceptable;
- * sets askpasswd if a PASS command is expected. If logged in previously,
- * need to reset state. If name is "ftp" or "anonymous", the name is not in
- * _PATH_FTPUSERS, and ftp account exists, set guest and pw, then just return.
- * If account doesn't exist, ask for passwd anyway. Otherwise, check user
- * requesting login privileges. Disallow anyone who does not have a standard
- * shell as returned by getusershell(). Disallow anyone mentioned in the file
- * _PATH_FTPUSERS to allow people such as root and uucp to be avoided.
- */
-_PROTOTYP(static int checkuser, (char *) );
-
-char zvuname[64] = { NUL, NUL };
-char zvhome[CKMAXPATH+1] = { NUL, NUL };
-#define ZENVUSER 70
-#define ZENVHOME CKMAXPATH+12
-#define ZENVLOGNAME 74
-static char zenvuser[ZENVUSER];
-static char zenvhome[ZENVHOME];
-static char zenvlogname[ZENVLOGNAME];
-
-#ifdef CK_PAM
-static char pam_data[500];
-struct pam_conv pam_conv = {pam_cb, pam_data}; /* PAM structure */
-struct pam_handle * pamh = NULL; /* PAM reference handle */
-#endif /* CK_PAM */
-
-int
-zvuser(name) char *name; {
- register char *cp = NULL;
- int x;
- char *shell;
-#ifdef GETUSERSHELL
- char *getusershell();
-#endif /* GETUSERSHELL */
-
-#ifdef CK_PAM
- int pam_status;
- const char * reply = NULL;
-#endif /* CK_PAM */
-
- debug(F111,"user",name,logged_in);
-
- if (!name) name = "";
- zvuname[0] = NUL;
-
- debug(F101,"zvuser ckxsyslog","",ckxsyslog);
-
-#ifdef CKSYSLOG
- debug(F100,"zvuser CKSYSLOG defined","",0);
-#endif /* CKSYSLOG */
-
- if (logged_in) /* Should not be called if logged in */
- return(0);
-
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: user %s",name
- );
- }
-#endif /* CKSYSLOG */
-
- guest = 0; /* Assume not guest */
- askpasswd = 0;
-
- if (strcmp(name, "ftp") == 0 || strcmp(name, "anonymous") == 0) {
- debug(F101,"zvuser anonymous ckxanon","",ckxanon);
- if (!ckxanon) { /* Anonymous login not allowed */
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: anonymous login not allowed: %s",
- clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- }
- if (checkuser("ftp") || checkuser("anonymous")) {
- debug(F100,"zvuser anon forbidden by ftpusers file","",0);
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: anonymous login forbidden by ftpusers file: %s",
- clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- } else if ((pw = sgetpwnam("ftp")) != NULL) {
- debug(F100,"zvuser anon sgetpwnam(ftp) OK","",0);
- guest = 1;
- askpasswd = 1;
- ckstrncpy(zvuname,"anonymous",64);
- return(1);
- } else {
- debug(F100,"zvuser anon sgetpwnam(ftp) FAILED","",0);
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: anonymous getpwnam(ftp) failed: %s",
- clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- }
- }
- pw = sgetpwnam(name);
- if (pw) {
-/*
- Of course some UNIX platforms (like AIX) don't have getusershell().
- In that case we can't check if the user's account has been "turned off"
- or somesuch, e.g. by setting their shell to "/etc/nologin" or somesuch,
- which runs (usually just printing a message and exiting), but which is
- not listed in /etc/shells. For that matter, if getusershell() is not
- available, then probably neither is /etc/shells.
-*/
- debug(F100,"zvuser sgetpwnam ok","",0);
- shell = pw->pw_shell;
- if (!shell) shell = "";
- if (!*shell)
- shell = _PATH_BSHELL;
- debug(F110,"zvuser shell",shell,0);
-#ifdef GETUSERSHELL
- while ((cp = getusershell()) != NULL) {
- debug(F110,"zvuser getusershell",cp,0);
- if (strcmp(cp, shell) == 0)
- break;
- }
- debug(F100,"zvuser endusershell 1","",0);
- endusershell();
- debug(F100,"zvuser endusershell 2","",0);
-#else /* GETUSERSHELL */
- cp = ""; /* Do not refuse if we cannot check */
-#endif /* GETUSERSHELL */
- x = checkuser(name);
- debug(F101,"zvuser checkuser","",x);
- if (cp == NULL) {
- debug(F100,"zvuser refused 1","",0);
- pw = (struct passwd *) NULL;
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: invalid shell %s for %s %s",shell, name,
- clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- } else if (x) {
- debug(F100,"zvuser refused 2","",0);
- pw = (struct passwd *) NULL;
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: %s login forbidden by ftpusers file: %s",
- name, clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- } else {
- x = 0;
-#ifdef CK_PAM
- /* Get PAM authentication details */
- debug(F110,"zvuser","calling pam_start",0);
- if ((pam_status =
- pam_start(PAM_SERVICE_TYPE,name,&pam_conv,&pamh))
- != PAM_SUCCESS) {
- reply = pam_strerror(NULL, pam_status);
- debug(F110,"zvuser PAM failure",reply,0);
- printf("%s\n",reply);
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: %s refused by PAM \"%s\": %s",
- name,reply,
- clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- }
-#endif /* CK_PAM */
- askpasswd = 1;
- ckstrncpy(zvuname,name,64);
- return(1);
- }
- } else {
- x = 0;
- debug(F100,"zvuser sgetpwnam NULL","",0);
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: getpwnam(%s) failed: %s",name,
- clienthost ? clienthost : "(unknown host)"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- }
-
-#ifdef FTP_KERBEROS
- if (auth_type && strcmp(auth_type, "KERBEROS_V4") == 0) {
-#ifdef COMMENT
- /* Why sprintf and then printf? */
- /* Also, what is kerb_ok? And is the test on it right? */
- char buf[CKXLOGBSIZ];
- sprintf(buf, "Kerberos user %s%s%s@%s is%s authorized as %s%s",
- kdata.pname, *kdata.pinst ? "." : "",
- kdata.pinst, kdata.prealm,
- (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not",
- name, kerb_ok ? "" : "; Password required.");
- printf("%s", buf);
-#else
- printf("Kerberos user %s%s%s@%s is%s authorized as %s%s",
- kdata.pname, *kdata.pinst ? "." : "",
- kdata.pinst, kdata.prealm,
- (kerb_ok = kuserok(&kdata,name) == 0) ? "" : " not",
- name, kerb_ok ? "" : "; Password required.");
-#endif /* COMMENT */
- if (kerb_ok) return(1);
- } else
- return(0);
-#endif /* FTP_KERBEROS */
-}
-
-/* Check if the given user is in the forbidden-user file */
-
-static int
-checkuser(name) char *name; {
- extern char * userfile;
- FILE *fd;
- int i;
- char line[CKXLOGBSIZ+1];
-
- if (!name)
- name = "";
- i = strlen(name);
- debug(F111,"checkuser name",name,i);
- if (!*name)
- return(1);
-
- fd = fopen(userfile ? userfile : _PATH_FTPUSERS, "r");
- debug(F111,"checkuser userfile",userfile,fd);
- if (fd) {
- line[0] = '\0';
- while (fgets(line, sizeof(line), fd)) {
- debug(F110,"checkuser line",line,0);
- if (line[0] <= '#')
- continue;
- if (strncmp(line, name, i) == 0) {
- debug(F110,"checkuser REFUSED",name,0);
- return(1);
- }
- line[0] = '\0';
- }
- (VOID) fclose(fd);
- }
- debug(F110,"checkuser OK",name,0);
- return(0);
-}
-
-/* Z V L O G O U T -- Log out from Internet Kermit Service */
-
-VOID
-zvlogout() {
-#ifdef COMMENT
- /* This could be dangerous */
- if (setuid((UID_T)0) < 0) {
- debug(F100,"zvlogout setuid FAILED","",0);
- goto bad;
- }
- debug(F100,"zvlogout setuid OK","",0);
-#endif /* COMMENT */
-#ifdef CKSYSLOG
- if (ckxsyslog >= SYSLG_LI && ckxlogging) {
- cksyslog(SYSLG_LI, 1, "logout",(char *) uidbuf, clienthost);
- }
-#endif /* CKSYSLOG */
-#ifdef CKWTMP
- debug(F110,"WTMP logout",cksysline,logged_in);
- if (logged_in)
- logwtmp(cksysline, "", "");
-#endif /* CKWTMP */
- pw = NULL;
- logged_in = 0;
- guest = 0;
- isguest = 0;
-}
-
-#ifdef FTP_KERBEROS
-kpass(name, p) char *name, *p; {
- char instance[INST_SZ];
- char realm[REALM_SZ];
- char tkt_file[20];
- KTEXT_ST ticket;
- AUTH_DAT authdata;
- unsigned long faddr;
- struct hostent *hp;
-
- if (krb_get_lrealm(realm, 1) != KSUCCESS)
- return(0);
-
- ckstrncpy(tkt_file, TKT_ROOT, 20);
- ckstrncat(tkt_file, "_ftpdXXXXXX", 20);
- krb_set_tkt_string(mktemp(tkt_file));
-
- (VOID) ckstrncpy(instance, krb_get_phost(hostname), sizeof(instance));
-
- if ((hp = gethostbyname(instance)) == NULL)
- return(0);
-
-#ifdef HADDRLIST
- hp = ck_copyhostent(hp); /* safe copy that won't change */
-#endif /* HADDRLIST */
- bcopy((char *)hp->h_addr, (char *) &faddr, sizeof(faddr));
-
- if (krb_get_pw_in_tkt(name, "", realm, "krbtgt", realm, 1, p) ||
- krb_mk_req(&ticket, "rcmd", instance, realm, 33) ||
- krb_rd_req(&ticket, "rcmd", instance, faddr, &authdata, "") ||
- kuserok(&authdata, name)) {
- dest_tkt();
- return(0);
- }
- dest_tkt();
- return(1);
-}
-#endif /* FTP_KERBEROS */
-
-VOID
-zsyslog() {
-#ifdef CKSYSLOG
- if (ckxsyslog && !ckxlogging) {
-#ifdef LOG_DAEMON
- openlog(inserver ? "iksd" : "ckermit", LOG_PID, LOG_DAEMON);
-#else
- openlog(inserver ? "iksd" : "ckermit", LOG_PID);
-#endif /* LOG_DAEMON */
- ckxlogging = 1;
- debug(F100,"zsyslog syslog opened","",0);
- }
-#endif /* CKSYSLOG */
-}
-
-/* Z V P A S S -- Verify password; returns 1 if OK, 0 otherwise */
-
-#ifndef AUTH_USER
-#define AUTH_USER 3
-#endif /* AUTH_USER */
-#ifndef AUTH_VALID
-#define AUTH_VALID 4
-#endif /* AUTH_VALID */
-
-int
-zvpass(p) char *p; {
- char *xpasswd, *salt;
- char * dir = NULL;
-#ifdef CK_PAM
- int pam_status;
- const char * reply = NULL;
-#endif /* CK_PAM */
-
- if (logged_in || askpasswd == 0) {
- return(0);
- }
- debug(F111,"zvpass",p ? (guest ? p : "xxxxxx") : "(null)",guest);
- if (!p) p = "";
- askpasswd = 0;
- if (guest && !*p) { /* Guests must specify a password */
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: anonymous guests must specify a password"
- );
- }
-#endif /* CKSYSLOG */
- return(0);
- }
- if (!guest
-#ifdef CK_AUTHENTICATION
- && ck_tn_auth_valid() != AUTH_VALID
-#endif /* CK_AUTHENTICATION */
- ) { /* "ftp" is only account allowed no password */
-#ifdef CK_PAM
- debug(F110,"zvpass","calling pam_set_item(AUTHTOK)",0);
- if ((pam_status = pam_set_item(pamh,PAM_AUTHTOK,p)) != PAM_SUCCESS) {
- reply = pam_strerror(pamh, pam_status);
- debug(F110,"zvpass PAM failure",reply,0);
- /* if no password given treat as non-fatal error */
- /* pam will prompt for password in pam_authenticate() */
- if (!p) {
- printf("%s\n",reply);
- pam_end(pamh, 0);
- debug(F100,"zvpass denied","",0);
- pw = NULL;
- zvuname[0] = NUL;
- return(0);
- }
- }
- debug(F110,"zvpass","calling pam_authenticate",0);
- if (*p)
- pam_pw = p;
- if ((pam_status = pam_authenticate(pamh, 0)) != PAM_SUCCESS) {
- reply = pam_strerror(pamh, pam_status);
- debug(F110,"zvpass PAM failure",reply,0);
- printf("%s\n",reply);
- pam_end(pamh, 0);
- debug(F100,"zvpass denied","",0);
- pam_pw = NULL;
- pw = NULL;
- zvuname[0] = NUL;
- return(0);
- }
- pam_pw = NULL;
- debug(F110,"zvpass","calling pam_acct_mgmt",0);
- if ((pam_status = pam_acct_mgmt(pamh, 0)) != PAM_SUCCESS) {
- reply = pam_strerror(pamh, pam_status);
- debug(F110,"zvpass PAM failure",reply,0);
- printf("%s\n",reply);
- pam_end(pamh, 0);
- debug(F100,"zvpass denied","",0);
- pw = NULL;
- zvuname[0] = NUL;
- return(0);
- }
- debug(F110,"zvpass","PAM validates OK",0);
- pam_end(pamh,0);
-#else /* CK_PAM */
- if (pw == NULL)
- salt = "xx";
- else
- salt = pw->pw_passwd;
-
-#ifdef HPUX10_TRUSTED
- xpasswd = bigcrypt(p, salt);
-#else
-/*
- On 64-bit platforms this can give "cast to pointer from integer of
- different size" warning, but I'm not sure what the effect is at runtime,
- or what to do about it.
- */
- xpasswd = (char *)crypt(p, salt);
-#endif /* HPUX10_TRUSTED */
-
- if (
-#ifdef FTP_KERBEROS
- /* null pw_passwd ok if Kerberos password ok */
- pw == NULL ||
- ((*pw->pw_passwd != '\0' ||
- strcmp(xpasswd, pw->pw_passwd))
- && !kpass(pw->pw_name, p))
-#else
-#ifdef CK_SRP
- /* check with tpasswd first if there */
- pw == NULL || *pw->pw_passwd == '\0' ||
- t_verifypw (pw->pw_name, p) == 0 ||
- (t_verifypw (pw->pw_name, p) < 0 &&
- strcmp (xpasswd, pw->pw_passwd))
-#else /* CK_SRP */
- /* The strcmp does not catch null passwords! */
- (pw == NULL) || (*pw->pw_passwd == '\0') ||
- strcmp(xpasswd, pw->pw_passwd)
-#endif /* CK_SRP */
-#endif /* FTP_KERBEROS */
- ) {
- debug(F100,"zvpass denied","",0);
- pw = NULL;
- zvuname[0] = NUL;
- return(0);
- }
-#endif /* CK_PAM */
- }
-
- (VOID) setgid((GID_T)pw->pw_gid); /* Set group ID */
-
-#ifndef NOINITGROUPS
- (VOID) initgroups(pw->pw_name, pw->pw_gid);
-#endif /* NOINITGROUPS */
-
- logged_in = 1;
- dir = pw->pw_dir;
-
-#ifdef CKWTMP
- /* Open wtmp before chroot */
- if (ckxwtmp) {
- sprintf(cksysline,"iks_%04x", getpid()); /* safe */
- logwtmp(cksysline, pw->pw_name,
- clienthost ? clienthost : "(unknown host)"
- );
- debug(F110,"WTMP login",cksysline,logged_in);
- }
-#endif /* CKWTMP */
-/*
- For anonymous users, we chroot to user ftp's home directory unless
- started with --anonroot:xxx, in which case we chroot to xxx. We must
- immediately chdir() to the same directory we chroot() to or else the
- old current directory remains accessible as "." outside the new root.
-*/
- if (guest) {
- if (anonroot) /* Non-default anonymous root */
- dir = anonroot;
- else
- makestr(&anonroot,dir);
- errno = 0;
- debug(F110,"zvpass anon chroot",dir,0);
- if (chroot(dir) < 0) {
- debug(F111,"zvpass anon chroot FAILED",dir,errno);
- goto bad;
- }
- errno = 0;
- if (chdir("/") < 0) {
- debug(F111,"zvpass anon chdir FAILED",dir,errno);
- goto bad;
- }
- debug(F110,"zvpass anon chroot/chdir OK",dir,0);
- } else if (chdir(dir) < 0) { /* Not guest */
-#ifdef COMMENT
- if (chdir("/") < 0) {
- debug(F110,"Non-guest chdir FAILED",dir,0);
- goto bad;
- } else
- printf("?No directory! Logging in with home=/\n");
-#else
- debug(F110,"zvpass non-guest chdir FAILED",dir,0);
- goto bad; /* Be conservative at first */
-#endif /* COMMENT */
- }
- debug(F110,"zvpass non-guest chdir OK",dir,0);
- if (setuid((UID_T)pw->pw_uid) < 0) {
- debug(F101,"zvpass setuid FAILED","",pw->pw_uid);
- goto bad;
- }
- debug(F101,"zvpass setuid OK","",pw->pw_uid);
-
- guestpass[0] = '\0';
- if (guest) {
- extern int fncact;
- isguest = 1;
- fncact = XYFX_R; /* FILE COLLISION = RENAME */
- debug(F110,"GUEST fncact=R",p,0);
- lset(guestpass,"anonymous:",10,32);
- ckstrncpy(&guestpass[10],p,GUESTPASS-10);
- home = "/";
- printf("Anonymous login.\r\n");
-
-#ifdef SETPROCTITLE
- /* proctitle declared where? Obviously this code is never compiled. */
- sprintf(proctitle, "%s: anonymous/%.*s",
- clienthost ? clienthost : "(unk)",
- sizeof(proctitle) - sizeof(clienthost) -
- sizeof(": anonymous/"), p);
- setproctitle(proctitle);
-#endif /* SETPROCTITLE */
-
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging) {
- syslog(LOG_INFO,
- "login: anonymous %s %s",
- clienthost ? clienthost : "(unknown host)",
- p
- );
- }
-#endif /* CKSYSLOG */
-
- } else { /* Real user */
- isguest = 0;
- home = dir;
- ckstrncpy(guestpass,zvuname,GUESTPASS);
-
- printf("User %s logged in.\r\n", pw->pw_name);
-#ifdef SETPROCTITLE
- /* not used */
- sprintf(proctitle, "%s: %s",
- clienthost ? clienthost : "(unk)",
- pw->pw_name
- );
- setproctitle(proctitle);
-#endif /* SETPROCTITLE */
-
-#ifdef CKSYSLOG
- if (ckxsyslog && ckxlogging)
- syslog(LOG_INFO, "login: %s %s",
- pw->pw_name,
- clienthost ? clienthost : "(unknown host)"
- );
-#endif /* CKSYSLOG */
- }
- ckstrncpy(zvhome,home,CKMAXPATH); /* Set environment variables */
-#ifndef NOPUTENV
-
- ckmakmsg(zenvuser,ZENVUSER,"USER=",zvuname,NULL,NULL);
- putenv((char *)zenvuser);
- ckmakmsg(zenvlogname,ZENVLOGNAME,"LOGNAME=",zvuname,NULL,NULL);
- putenv((char *)zenvlogname);
- ckmakmsg(zenvhome,ZENVHOME,"HOME=",zvhome,NULL,NULL);
- putenv((char *)zenvhome);
-#endif /* NOPUTENV */
- /* homdir = (char *)zvhome; */
- ckstrncpy((char *)uidbuf,(char *)zvuname,64);
- (VOID) umask(defumask);
-#ifdef IKSDB
- if (ikdbopen) {
- char * p2;
- int k;
- extern char dbrec[];
- extern unsigned long myflags;
- extern unsigned int mydbslot;
- extern struct iksdbfld dbfld[];
-#ifdef CK_AUTHENTICATION
- extern unsigned long myamode, myatype;
-#endif /* CK_AUTHENTICATION */
- myflags |= DBF_LOGGED;
-#ifdef DEBUG
- if (deblog) {
- debug(F101,"zvpass guest","",guest);
- debug(F111,"zvpass zvuname",zvuname,0);
- debug(F110,"zvpass guestpass",guestpass,0);
- debug(F110,"zvpass dir",dir,0);
- debug(F110,"zvpass home",home,0);
- debug(F110,"zvpass anonroot",anonroot,0);
- }
-#endif /* DEBUG */
- p2 = guest ? guestpass : zvuname;
- if (guest) {
- p2 = (char *)guestpass;
- myflags &= ~DBF_USER;
- } else {
- p2 = (char *)zvuname;
- myflags |= DBF_USER;
- }
- k = strlen(p2);
- strncpy(&dbrec[DB_ULEN],ulongtohex((unsigned long)k,4),4);
- lset(&dbrec[dbfld[db_USER].off],p2,1024,32);
- strncpy(&dbrec[DB_FLAGS],ulongtohex(myflags,4),4);
-#ifdef CK_AUTHENTICATION
- myamode = ck_tn_auth_valid();
- strncpy(&dbrec[DB_AMODE],ulongtohex(myamode,4),4);
- myatype = ck_tn_authenticated();
- strncpy(&dbrec[DB_ATYPE],ulongtohex(myatype,4),4);
-#endif /* CK_AUTHENTICATION */
- if (guest) {
- p2 = dir;
- } else {
- p2 = zgtdir();
- if (!p2) p2 = "";
- if (!*p2) p2 = home;
- }
- strncpy(&dbrec[DB_DLEN],
- ulongtohex((unsigned long)strlen(p2),4),
- 4
- );
- lset(&dbrec[dbfld[db_DIR].off],p2,1024,32);
- updslot(mydbslot);
- }
-#endif /* IKSDB */
- return(1);
-
-bad: /* Common failure exit */
- zvuname[0] = NUL;
- zvlogout();
- return(0);
-}
-#endif /* CK_LOGIN */
-
-/* Buggy Xenix 2.3.4 cc needs this line after the endif */