perl 3.0 patch #22 patch #19, continued
[p5sagit/p5-mst-13.2.git] / doio.c
diff --git a/doio.c b/doio.c
index c0ba205..88c0f4c 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1,4 +1,4 @@
-/* $Header: doio.c,v 3.0 89/10/18 15:10:54 lwall Locked $
+/* $Header: doio.c,v 3.0.1.9 90/08/09 02:56:19 lwall Locked $
  *
  *    Copyright (c) 1989, Larry Wall
  *
@@ -6,6 +6,54 @@
  *    as specified in the README file that comes with the perl 3.0 kit.
  *
  * $Log:       doio.c,v $
+ * Revision 3.0.1.9  90/08/09  02:56:19  lwall
+ * patch19: various MSDOS and OS/2 patches folded in
+ * patch19: prints now check error status better
+ * patch19: printing a list with null elements only printed front of list
+ * patch19: on machines with vfork child would allocate memory in parent
+ * patch19: getsockname and getpeername gave bogus warning on error
+ * patch19: MACH doesn't have seekdir or telldir
+ * 
+ * Revision 3.0.1.8  90/03/27  15:44:02  lwall
+ * patch16: MSDOS support
+ * patch16: support for machines that can't cast negative floats to unsigned ints
+ * patch16: system() can lose arguments passed to shell scripts on SysV machines
+ * 
+ * Revision 3.0.1.7  90/03/14  12:26:24  lwall
+ * patch15: commands involving execs could cause malloc arena corruption
+ * 
+ * Revision 3.0.1.6  90/03/12  16:30:07  lwall
+ * patch13: system 'FOO=bar command' didn't invoke sh as it should
+ * 
+ * Revision 3.0.1.5  90/02/28  17:01:36  lwall
+ * patch9: open(FOO,"$filename\0") will now protect trailing spaces in filename
+ * patch9: removed obsolete checks to avoid opening block devices
+ * patch9: removed references to acusec and modusec that some utime.h's have
+ * patch9: added pipe function
+ * 
+ * Revision 3.0.1.4  89/12/21  19:55:10  lwall
+ * patch7: select now works on big-endian machines
+ * patch7: errno may now be a macro with an lvalue
+ * patch7: ANSI strerror() is now supported
+ * patch7: Configure now detects DG/UX thingies like [sg]etpgrp2 and utime.h
+ * 
+ * Revision 3.0.1.3  89/11/17  15:13:06  lwall
+ * patch5: some systems have symlink() but not lstat()
+ * patch5: some systems have dirent.h but not readdir()
+ * 
+ * Revision 3.0.1.2  89/11/11  04:25:51  lwall
+ * patch2: orthogonalized the file modes some so we can have <& +<& etc.
+ * patch2: do_open() now detects sockets passed to process from parent
+ * patch2: fd's above 2 are now closed on exec
+ * patch2: csh code can now use csh from other than /bin
+ * patch2: getsockopt, get{sock,peer}name didn't define result properly
+ * patch2: warn("shutdown") was replicated
+ * patch2: gethostbyname was misdeclared
+ * patch2: telldir() is sometimes a macro
+ * 
+ * Revision 3.0.1.1  89/10/26  23:10:05  lwall
+ * patch1: Configure now checks for BSD shadow passwords
+ * 
  * Revision 3.0  89/10/18  15:10:54  lwall
  * 3.0 baseline
  * 
 #include <netdb.h>
 #endif
 
-#include <errno.h>
 #ifdef I_PWD
 #include <pwd.h>
 #endif
 #ifdef I_GRP
 #include <grp.h>
 #endif
-
-extern int errno;
+#ifdef I_UTIME
+#include <utime.h>
+#endif
+#ifdef I_FCNTL
+#include <fcntl.h>
+#endif
 
 bool
-do_open(stab,name)
+do_open(stab,name,len)
 STAB *stab;
 register char *name;
+int len;
 {
     FILE *fp;
-    int len = strlen(name);
     register STIO *stio = stab_io(stab);
     char *myname = savestr(name);
     int result;
@@ -86,61 +137,65 @@ register char *name;
        fp = mypopen(name,"w");
        writing = 1;
     }
-    else if (*name == '>' && name[1] == '>') {
-#ifdef TAINT
-       taintproper("Insecure dependency in open");
-#endif
-       mode[0] = stio->type = 'a';
-       for (name += 2; isspace(*name); name++) ;
-       fp = fopen(name, mode);
-       writing = 1;
-    }
-    else if (*name == '>' && name[1] == '&') {
-#ifdef TAINT
-       taintproper("Insecure dependency in open");
-#endif
-       for (name += 2; isspace(*name); name++) ;
-       if (isdigit(*name))
-           fd = atoi(name);
-       else {
-           stab = stabent(name,FALSE);
-           if (stab_io(stab) && stab_io(stab)->ifp) {
-               fd = fileno(stab_io(stab)->ifp);
-               stio->type = stab_io(stab)->type;
-           }
-           else
-               fd = -1;
-       }
-       fp = fdopen(dup(fd),stio->type == 'a' ? "a" :
-         (stio->type == '<' ? "r" : "w") );
-       writing = 1;
-    }
     else if (*name == '>') {
 #ifdef TAINT
        taintproper("Insecure dependency in open");
 #endif
-       for (name++; isspace(*name); name++) ;
-       if (strEQ(name,"-")) {
-           fp = stdout;
-           stio->type = '-';
+       name++;
+       if (*name == '>') {
+           mode[0] = stio->type = 'a';
+           name++;
        }
-       else  {
+       else
            mode[0] = 'w';
-           fp = fopen(name,mode);
-       }
        writing = 1;
+       if (*name == '&') {
+         duplicity:
+           name++;
+           while (isspace(*name))
+               name++;
+           if (isdigit(*name))
+               fd = atoi(name);
+           else {
+               stab = stabent(name,FALSE);
+               if (!stab || !stab_io(stab))
+                   return FALSE;
+               if (stab_io(stab) && stab_io(stab)->ifp) {
+                   fd = fileno(stab_io(stab)->ifp);
+                   if (stab_io(stab)->type == 's')
+                       stio->type = 's';
+               }
+               else
+                   fd = -1;
+           }
+           fp = fdopen(dup(fd),mode);
+       }
+       else {
+           while (isspace(*name))
+               name++;
+           if (strEQ(name,"-")) {
+               fp = stdout;
+               stio->type = '-';
+           }
+           else  {
+               fp = fopen(name,mode);
+           }
+       }
     }
     else {
        if (*name == '<') {
-           for (name++; isspace(*name); name++) ;
+           mode[0] = 'r';
+           name++;
+           while (isspace(*name))
+               name++;
+           if (*name == '&')
+               goto duplicity;
            if (strEQ(name,"-")) {
                fp = stdin;
                stio->type = '-';
            }
-           else  {
-               mode[0] = 'r';
+           else
                fp = fopen(name,mode);
-           }
        }
        else if (name[len-1] == '|') {
 #ifdef TAINT
@@ -174,21 +229,24 @@ register char *name;
            (void)fclose(fp);
            return FALSE;
        }
-       if ((statbuf.st_mode & S_IFMT) != S_IFREG &&
+       result = (statbuf.st_mode & S_IFMT);
 #ifdef S_IFSOCK
-           (statbuf.st_mode & S_IFMT) != S_IFSOCK &&
-#endif
-#ifdef S_IFFIFO
-           (statbuf.st_mode & S_IFMT) != S_IFFIFO &&
+       if (result == S_IFSOCK || result == 0)
+           stio->type = 's';   /* in case a socket was passed in to us */
 #endif
-           (statbuf.st_mode & S_IFMT) != S_IFCHR) {
-           (void)fclose(fp);
-           return FALSE;
-       }
     }
+#if defined(FCNTL) && defined(F_SETFD)
+    fd = fileno(fp);
+    if (fd >= 3)
+       fcntl(fd,F_SETFD,1);
+#endif
     stio->ifp = fp;
-    if (writing)
-       stio->ofp = fp;
+    if (writing) {
+       if (stio->type != 's')
+           stio->ofp = fp;
+       else
+           stio->ofp = fdopen(fileno(fp),"w");
+    }
     return TRUE;
 }
 
@@ -205,7 +263,7 @@ register STAB *stab;
        str_sset(stab_val(stab),str);
        STABSET(stab_val(stab));
        oldname = str_get(stab_val(stab));
-       if (do_open(stab,oldname)) {
+       if (do_open(stab,oldname,stab_val(stab)->str_cur)) {
            if (inplace) {
 #ifdef TAINT
                taintproper("Insecure dependency in inplace open");
@@ -214,9 +272,20 @@ register STAB *stab;
                fileuid = statbuf.st_uid;
                filegid = statbuf.st_gid;
                if (*inplace) {
+#ifdef SUFFIX
+                   add_suffix(str,inplace);
+#else
                    str_cat(str,inplace);
+#endif
 #ifdef RENAME
+#ifndef MSDOS
+                   (void)rename(oldname,str->str_ptr);
+#else
+                   do_close(stab,FALSE);
+                   (void)unlink(str->str_ptr);
                    (void)rename(oldname,str->str_ptr);
+                   do_open(stab,str->str_ptr,stab_val(stab)->str_cur);
+#endif /* MSDOS */
 #else
                    (void)UNLINK(str->str_ptr);
                    (void)link(oldname,str->str_ptr);
@@ -224,13 +293,17 @@ register STAB *stab;
 #endif
                }
                else {
+#ifndef MSDOS
                    (void)UNLINK(oldname);
+#else
+                   fatal("Can't do inplace edit without backup");
+#endif
                }
 
                str_nset(str,">",1);
                str_cat(str,oldname);
                errno = 0;              /* in case sprintf set errno */
-               if (!do_open(argvoutstab,str->str_ptr))
+               if (!do_open(argvoutstab,str->str_ptr,str->str_cur))
                    fatal("Can't do inplace edit");
                defoutstab = argvoutstab;
 #ifdef FCHMOD
@@ -241,8 +314,10 @@ register STAB *stab;
 #ifdef FCHOWN
                (void)fchown(fileno(stab_io(argvoutstab)->ifp),fileuid,filegid);
 #else
+#ifdef CHOWN
                (void)chown(oldname,fileuid,filegid);
 #endif
+#endif
            }
            str_free(str);
            return stab_io(stab)->ifp;
@@ -258,6 +333,51 @@ register STAB *stab;
     return Nullfp;
 }
 
+#ifdef PIPE
+void
+do_pipe(str, rstab, wstab)
+STR *str;
+STAB *rstab;
+STAB *wstab;
+{
+    register STIO *rstio;
+    register STIO *wstio;
+    int fd[2];
+
+    if (!rstab)
+       goto badexit;
+    if (!wstab)
+       goto badexit;
+
+    rstio = stab_io(rstab);
+    wstio = stab_io(wstab);
+
+    if (!rstio)
+       rstio = stab_io(rstab) = stio_new();
+    else if (rstio->ifp)
+       do_close(rstab,FALSE);
+    if (!wstio)
+       wstio = stab_io(wstab) = stio_new();
+    else if (wstio->ifp)
+       do_close(wstab,FALSE);
+
+    if (pipe(fd) < 0)
+       goto badexit;
+    rstio->ifp = fdopen(fd[0], "r");
+    wstio->ofp = fdopen(fd[1], "w");
+    wstio->ifp = wstio->ofp;
+    rstio->type = '<';
+    wstio->type = '>';
+
+    str_sset(str,&str_yes);
+    return;
+
+badexit:
+    str_sset(str,&str_undef);
+    return;
+}
+#endif
+
 bool
 do_close(stab,explicit)
 STAB *stab;
@@ -276,7 +396,7 @@ bool explicit;
        if (stio->type == '|') {
            status = mypclose(stio->ifp);
            retval = (status >= 0);
-           statusvalue = (unsigned)status & 0xffff;
+           statusvalue = (unsigned short)status & 0xffff;
        }
        else if (stio->type == '-')
            retval = TRUE;
@@ -416,7 +536,7 @@ STR *argstr;
        retval = 256;                   /* otherwise guess at what's safe */
 #endif
        if (argstr->str_cur < retval) {
-           str_grow(argstr,retval+1);
+           Str_Grow(argstr,retval+1);
            argstr->str_cur = retval;
        }
 
@@ -475,7 +595,7 @@ int *arglast;
     else {
        str_sset(statname,ary->ary_array[sp]);
        statstab = Nullstab;
-#ifdef SYMLINK
+#ifdef LSTAT
        if (arg->arg_type == O_LSTAT)
            i = lstat(str_get(statname),&statcache);
        else
@@ -538,6 +658,64 @@ int *arglast;
 }
 
 int
+do_truncate(str,arg,gimme,arglast)
+STR *str;
+register ARG *arg;
+int gimme;
+int *arglast;
+{
+    register ARRAY *ary = stack;
+    register int sp = arglast[0] + 1;
+    off_t len = (off_t)str_gnum(ary->ary_array[sp+1]);
+    int result = 1;
+    STAB *tmpstab;
+
+#if defined(TRUNCATE) || defined(CHSIZE) || defined(F_FREESP)
+#ifdef TRUNCATE
+    if ((arg[1].arg_type & A_MASK) == A_WORD) {
+       tmpstab = arg[1].arg_ptr.arg_stab;
+       if (!stab_io(tmpstab) ||
+         ftruncate(fileno(stab_io(tmpstab)->ifp), len) < 0)
+           result = 0;
+    }
+    else if (truncate(str_get(ary->ary_array[sp]), len) < 0)
+       result = 0;
+#else
+#ifndef CHSIZE
+#define chsize(f,l) fcntl(f,F_FREESP,l)
+#endif
+    if ((arg[1].arg_type & A_MASK) == A_WORD) {
+       tmpstab = arg[1].arg_ptr.arg_stab;
+       if (!stab_io(tmpstab) ||
+         chsize(fileno(stab_io(tmpstab)->ifp), len) < 0)
+           result = 0;
+    }
+    else {
+       int tmpfd;
+
+       if ((tmpfd = open(str_get(ary->ary_array[sp]), 0)) < 0)
+           result = 0;
+       else {
+           if (chsize(tmpfd, len) < 0)
+               result = 0;
+           close(tmpfd);
+       }
+    }
+#endif
+
+    if (result)
+       str_sset(str,&str_yes);
+    else
+       str_sset(str,&str_undef);
+    STABSET(str);
+    ary->ary_array[sp] = str;
+    return sp;
+#else
+    fatal("truncate not implemented");
+#endif
+}
+
+int
 looks_like_number(str)
 STR *str;
 {
@@ -593,11 +771,13 @@ FILE *fp;
        return FALSE;
     }
     if (!str)
-       return FALSE;
+       return TRUE;
     if (ofmt &&
       ((str->str_nok && str->str_u.str_nval != 0.0)
-       || (looks_like_number(str) && str_gnum(str) != 0.0) ) )
+       || (looks_like_number(str) && str_gnum(str) != 0.0) ) ) {
        fprintf(fp, ofmt, str->str_u.str_nval);
+       return !ferror(fp);
+    }
     else {
        tmps = str_get(str);
        if (*tmps == 'S' && tmps[1] == 't' && tmps[2] == 'a' && tmps[3] == 'b'
@@ -606,7 +786,7 @@ FILE *fp;
            str = ((STAB*)str)->str_magic;
            putc('*',fp);
        }
-       if (str->str_cur && fwrite(tmps,1,str->str_cur,fp) == 0)
+       if (str->str_cur && (fwrite(tmps,1,str->str_cur,fp) == 0 || ferror(fp)))
            return FALSE;
     }
     return TRUE;
@@ -637,7 +817,7 @@ int *arglast;
        retval = (items <= 0);
        for (; items > 0; items--,st++) {
            if (retval && ofslen) {
-               if (fwrite(ofs, 1, ofslen, fp) == 0) {
+               if (fwrite(ofs, 1, ofslen, fp) == 0 || ferror(fp)) {
                    retval = FALSE;
                    break;
                }
@@ -646,7 +826,7 @@ int *arglast;
                break;
        }
        if (retval && orslen)
-           if (fwrite(ors, 1, orslen, fp) == 0)
+           if (fwrite(ors, 1, orslen, fp) == 0 || ferror(fp))
                retval = FALSE;
     }
     return retval;
@@ -804,13 +984,28 @@ int *arglast;
     return FALSE;
 }
 
+static char **Argv = Null(char **);
+static char *Cmd = Nullch;
+
+int
+do_execfree()
+{
+    if (Argv) {
+       Safefree(Argv);
+       Argv = Null(char **);
+    }
+    if (Cmd) {
+       Safefree(Cmd);
+       Cmd = Nullch;
+    }
+}
+
 bool
 do_exec(cmd)
 char *cmd;
 {
     register char **a;
     register char *s;
-    char **argv;
     char flags[10];
 
 #ifdef TAINT
@@ -820,9 +1015,10 @@ char *cmd;
 
     /* save an extra exec if possible */
 
-    if (csh > 0 && strnEQ(cmd,"/bin/csh -c",11)) {
+#ifdef CSH
+    if (strnEQ(cmd,cshname,cshlen) && strnEQ(cmd+cshlen," -c",3)) {
        strcpy(flags,"-c");
-       s = cmd+11;
+       s = cmd+cshlen+3;
        if (*s == 'f') {
            s++;
            strcat(flags,"f");
@@ -838,15 +1034,19 @@ char *cmd;
                *--s = '\0';
            if (s[-1] == '\'') {
                *--s = '\0';
-               execl("/bin/csh","csh", flags,ncmd,(char*)0);
+               execl(cshname,"csh", flags,ncmd,(char*)0);
                *s = '\'';
                return FALSE;
            }
        }
     }
+#endif /* CSH */
 
     /* see if there are shell metacharacters in it */
 
+    for (s = cmd; *s && isalpha(*s); s++) ;    /* catch VAR=val gizmo */
+    if (*s == '=')
+       goto doshell;
     for (s = cmd; *s; s++) {
        if (*s != ' ' && !isalpha(*s) && index("$&*(){}[]'\";\\|?<>~`\n",*s)) {
            if (*s == '\n' && !s[1]) {
@@ -858,10 +1058,10 @@ char *cmd;
            return FALSE;
        }
     }
-    New(402,argv, (s - cmd) / 2 + 2, char*);
-
-    a = argv;
-    for (s = cmd; *s;) {
+    New(402,Argv, (s - cmd) / 2 + 2, char*);
+    Cmd = nsavestr(cmd, s-cmd);
+    a = Argv;
+    for (s = Cmd; *s;) {
        while (*s && isspace(*s)) s++;
        if (*s)
            *(a++) = s;
@@ -870,12 +1070,14 @@ char *cmd;
            *s++ = '\0';
     }
     *a = Nullch;
-    if (argv[0]) {
-       execvp(argv[0],argv);
-       if (errno == ENOEXEC)           /* for system V NIH syndrome */
+    if (Argv[0]) {
+       execvp(Argv[0],Argv);
+       if (errno == ENOEXEC) {         /* for system V NIH syndrome */
+           do_execfree();
            goto doshell;
+       }
     }
-    Safefree(argv);
+    do_execfree();
     return FALSE;
 }
 
@@ -1099,6 +1301,7 @@ int *arglast;
     case O_GSOCKOPT:
        st[sp] = str_2static(str_new(257));
        st[sp]->str_cur = 256;
+       st[sp]->str_pok = 1;
        if (getsockopt(fd, lvl, optname, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
            goto nuts;
        break;
@@ -1114,7 +1317,7 @@ int *arglast;
 
 nuts:
     if (dowarn)
-       warn("shutdown() on closed fd");
+       warn("[gs]etsockopt() on closed fd");
     st[sp] = &str_undef;
     return sp;
 
@@ -1140,15 +1343,16 @@ int *arglast;
 
     st[sp] = str_2static(str_new(257));
     st[sp]->str_cur = 256;
+    st[sp]->str_pok = 1;
     fd = fileno(stio->ifp);
     switch (optype) {
     case O_GETSOCKNAME:
        if (getsockname(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
-           goto nuts;
+           goto nuts2;
        break;
     case O_GETPEERNAME:
        if (getpeername(fd, st[sp]->str_ptr, &st[sp]->str_cur) < 0)
-           goto nuts;
+           goto nuts2;
        break;
     }
     
@@ -1156,7 +1360,8 @@ int *arglast;
 
 nuts:
     if (dowarn)
-       warn("shutdown() on closed fd");
+       warn("get{sock,peer}name() on closed fd");
+nuts2:
     st[sp] = &str_undef;
     return sp;
 
@@ -1172,7 +1377,7 @@ int *arglast;
     register int sp = arglast[0];
     register char **elem;
     register STR *str;
-    struct hostent *gethostbynam();
+    struct hostent *gethostbyname();
     struct hostent *gethostbyaddr();
 #ifdef GETHOSTENT
     struct hostent *gethostent();
@@ -1416,6 +1621,9 @@ int *arglast;
     return sp;
 }
 
+#endif /* SOCKET */
+
+#ifdef SELECT
 int
 do_select(gimme,arglast)
 int gimme;
@@ -1432,20 +1640,52 @@ int *arglast;
     int nfound;
     struct timeval timebuf;
     struct timeval *tbuf = &timebuf;
+    int growsize;
+#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
+    int masksize;
+    int offset;
+    char *fd_sets[4];
+    int k;
+
+#if BYTEORDER & 0xf0000
+#define ORDERBYTE (0x88888888 - BYTEORDER)
+#else
+#define ORDERBYTE (0x4444 - BYTEORDER)
+#endif
+
+#endif
 
     for (i = 1; i <= 3; i++) {
-       j = st[sp+i]->str_len;
+       j = st[sp+i]->str_cur;
        if (maxlen < j)
            maxlen = j;
     }
+
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
+    growsize = maxlen;         /* little endians can use vecs directly */
+#else
+#ifdef NFDBITS
+
+#ifndef NBBY
+#define NBBY 8
+#endif
+
+    masksize = NFDBITS / NBBY;
+#else
+    masksize = sizeof(long);   /* documented int, everyone seems to use long */
+#endif
+    growsize = maxlen + (masksize - (maxlen % masksize));
+    Zero(&fd_sets[0], 4, char*);
+#endif
+
     for (i = 1; i <= 3; i++) {
        str = st[sp+i];
        j = str->str_len;
-       if (j < maxlen) {
+       if (j < growsize) {
            if (str->str_pok) {
-               str_grow(str,maxlen);
+               Str_Grow(str,growsize);
                s = str_get(str) + j;
-               while (++j <= maxlen) {
+               while (++j <= growsize) {
                    *s++ = '\0';
                }
            }
@@ -1454,6 +1694,16 @@ int *arglast;
                str->str_ptr = Nullch;
            }
        }
+#if BYTEORDER != 0x1234 && BYTEORDER != 0x12345678
+       s = str->str_ptr;
+       if (s) {
+           New(403, fd_sets[i], growsize, char);
+           for (offset = 0; offset < growsize; offset += masksize) {
+               for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
+                   fd_sets[i][j+offset] = s[(k % masksize) + offset];
+           }
+       }
+#endif
     }
     str = st[sp+4];
     if (str->str_nok || str->str_pok) {
@@ -1467,12 +1717,31 @@ int *arglast;
     else
        tbuf = Null(struct timeval*);
 
+#if BYTEORDER == 0x1234 || BYTEORDER == 0x12345678
     nfound = select(
        maxlen * 8,
        st[sp+1]->str_ptr,
        st[sp+2]->str_ptr,
        st[sp+3]->str_ptr,
        tbuf);
+#else
+    nfound = select(
+       maxlen * 8,
+       fd_sets[1],
+       fd_sets[2],
+       fd_sets[3],
+       tbuf);
+    for (i = 1; i <= 3; i++) {
+       if (fd_sets[i]) {
+           str = st[sp+i];
+           s = str->str_ptr;
+           for (offset = 0; offset < growsize; offset += masksize) {
+               for (j = 0, k=ORDERBYTE; j < masksize; j++, (k >>= 4))
+                   s[(k % masksize) + offset] = fd_sets[i][j+offset];
+           }
+       }
+    }
+#endif
 
     st[++sp] = str_static(&str_no);
     str_numset(st[sp], (double)nfound);
@@ -1484,7 +1753,9 @@ int *arglast;
     }
     return sp;
 }
+#endif /* SELECT */
 
+#ifdef SOCKET
 int
 do_spair(stab1, stab2, arglast)
 STAB *stab1;
@@ -1544,13 +1815,11 @@ int *arglast;
 #ifdef I_PWD
     register ARRAY *ary = stack;
     register int sp = arglast[0];
-    register char **elem;
     register STR *str;
     struct passwd *getpwnam();
     struct passwd *getpwuid();
     struct passwd *getpwent();
     struct passwd *pwent;
-    unsigned long len;
 
     if (gimme != G_ARRAY) {
        astore(ary, ++sp, str_static(&str_undef));
@@ -1580,6 +1849,9 @@ int *arglast;
        (void)astore(ary, ++sp, str = str_static(&str_no));
        str_numset(str, (double)pwent->pw_gid);
        (void)astore(ary, ++sp, str = str_static(&str_no));
+#ifdef PWCHANGE
+       str_numset(str, (double)pwent->pw_change);
+#else
 #ifdef PWQUOTA
        str_numset(str, (double)pwent->pw_quota);
 #else
@@ -1587,14 +1859,23 @@ int *arglast;
        str_set(str, pwent->pw_age);
 #endif
 #endif
+#endif
        (void)astore(ary, ++sp, str = str_static(&str_no));
+#ifdef PWCLASS
+       str_set(str,pwent->pw_class);
+#else
        str_set(str, pwent->pw_comment);
+#endif
        (void)astore(ary, ++sp, str = str_static(&str_no));
        str_set(str, pwent->pw_gecos);
        (void)astore(ary, ++sp, str = str_static(&str_no));
        str_set(str, pwent->pw_dir);
        (void)astore(ary, ++sp, str = str_static(&str_no));
        str_set(str, pwent->pw_shell);
+#ifdef PWEXPIRE
+       (void)astore(ary, ++sp, str = str_static(&str_no));
+       str_numset(str, (double)pwent->pw_expire);
+#endif
     }
 
     return sp;
@@ -1618,7 +1899,6 @@ int *arglast;
     struct group *getgrgid();
     struct group *getgrent();
     struct group *grent;
-    unsigned long len;
 
     if (gimme != G_ARRAY) {
        astore(ary, ++sp, str_static(&str_undef));
@@ -1666,13 +1946,15 @@ STAB *stab;
 int gimme;
 int *arglast;
 {
-#ifdef DIRENT
+#if defined(DIRENT) && defined(READDIR)
     register ARRAY *ary = stack;
     register STR **st = ary->ary_array;
     register int sp = arglast[1];
     register STIO *stio;
     long along;
+#ifndef telldir
     long telldir();
+#endif
     struct DIRENT *readdir();
     register struct DIRENT *dp;
 
@@ -1714,6 +1996,11 @@ int *arglast;
 #endif
        }
        break;
+#if MACH
+    case O_TELLDIR:
+    case O_SEEKDIR:
+        goto nope;
+#else
     case O_TELLDIR:
        st[sp] = str_static(&str_undef);
        str_numset(st[sp], (double)telldir(stio->dirp));
@@ -1723,6 +2010,7 @@ int *arglast;
        along = (long)str_gnum(st[sp+1]);
        (void)seekdir(stio->dirp,along);
        break;
+#endif
     case O_REWINDDIR:
        st[sp] = str_static(&str_undef);
        (void)rewinddir(stio->dirp);
@@ -1777,6 +2065,7 @@ int *arglast;
            }
        }
        break;
+#ifdef CHOWN
     case O_CHOWN:
 #ifdef TAINT
        taintproper("Insecure dependency in chown");
@@ -1792,6 +2081,8 @@ int *arglast;
            }
        }
        break;
+#endif
+#ifdef KILL
     case O_KILL:
 #ifdef TAINT
        taintproper("Insecure dependency in kill");
@@ -1827,6 +2118,7 @@ int *arglast;
            }
        }
        break;
+#endif
     case O_UNLINK:
 #ifdef TAINT
        taintproper("Insecure dependency in unlink");
@@ -1839,7 +2131,7 @@ int *arglast;
                    tot--;
            }
            else {      /* don't let root wipe out directories without -U */
-#ifdef SYMLINK
+#ifdef LSTAT
                if (lstat(s,&statbuf) < 0 ||
 #else
                if (stat(s,&statbuf) < 0 ||
@@ -1858,13 +2150,18 @@ int *arglast;
        taintproper("Insecure dependency in utime");
 #endif
        if (items > 2) {
+#ifdef I_UTIME
+           struct utimbuf utbuf;
+#else
            struct {
-               long    atime,
-                       mtime;
+               long    actime;
+               long    modtime;
            } utbuf;
+#endif
 
-           utbuf.atime = (long)str_gnum(st[++sp]);    /* time accessed */
-           utbuf.mtime = (long)str_gnum(st[++sp]);    /* time modified */
+           Zero(&utbuf, sizeof utbuf, char);
+           utbuf.actime = (long)str_gnum(st[++sp]);    /* time accessed */
+           utbuf.modtime = (long)str_gnum(st[++sp]);    /* time modified */
            items -= 2;
 #ifndef lint
            tot = items;