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 3884035..88c0f4c 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1,4 +1,4 @@
-/* $Header: doio.c,v 3.0.1.3 89/11/17 15:13:06 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,37 @@
  *    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()
 #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;
@@ -196,21 +230,6 @@ register char *name;
            return FALSE;
        }
        result = (statbuf.st_mode & S_IFMT);
-       if (result != S_IFREG &&
-#ifdef S_IFSOCK
-           result != S_IFSOCK &&
-#endif
-#ifdef S_IFFIFO
-           result != S_IFFIFO &&
-#endif
-#ifdef S_IFIFO
-           result != S_IFIFO &&
-#endif
-           result != 0 &&              /* socket? */
-           result != S_IFCHR) {
-           (void)fclose(fp);
-           return FALSE;
-       }
 #ifdef S_IFSOCK
        if (result == S_IFSOCK || result == 0)
            stio->type = 's';   /* in case a socket was passed in to us */
@@ -244,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");
@@ -253,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);
@@ -263,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
@@ -280,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;
@@ -297,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;
@@ -315,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;
@@ -455,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;
        }
 
@@ -577,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;
 {
@@ -632,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'
@@ -645,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;
@@ -676,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;
                }
@@ -685,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;
@@ -843,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
@@ -888,6 +1044,9 @@ char *cmd;
 
     /* 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]) {
@@ -899,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;
@@ -911,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;
 }
 
@@ -1187,11 +1348,11 @@ int *arglast;
     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;
     }
     
@@ -1200,6 +1361,7 @@ int *arglast;
 nuts:
     if (dowarn)
        warn("get{sock,peer}name() on closed fd");
+nuts2:
     st[sp] = &str_undef;
     return sp;
 
@@ -1459,6 +1621,9 @@ int *arglast;
     return sp;
 }
 
+#endif /* SOCKET */
+
+#ifdef SELECT
 int
 do_select(gimme,arglast)
 int gimme;
@@ -1475,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';
                }
            }
@@ -1497,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) {
@@ -1510,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);
@@ -1527,7 +1753,9 @@ int *arglast;
     }
     return sp;
 }
+#endif /* SELECT */
 
+#ifdef SOCKET
 int
 do_spair(stab1, stab2, arglast)
 STAB *stab1;
@@ -1587,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));
@@ -1673,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));
@@ -1771,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));
@@ -1780,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);
@@ -1834,6 +2065,7 @@ int *arglast;
            }
        }
        break;
+#ifdef CHOWN
     case O_CHOWN:
 #ifdef TAINT
        taintproper("Insecure dependency in chown");
@@ -1849,6 +2081,8 @@ int *arglast;
            }
        }
        break;
+#endif
+#ifdef KILL
     case O_KILL:
 #ifdef TAINT
        taintproper("Insecure dependency in kill");
@@ -1884,6 +2118,7 @@ int *arglast;
            }
        }
        break;
+#endif
     case O_UNLINK:
 #ifdef TAINT
        taintproper("Insecure dependency in unlink");
@@ -1915,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;