perl 3.0 patch #15 (combined patch)
[p5sagit/p5-mst-13.2.git] / doio.c
diff --git a/doio.c b/doio.c
index a50d18f..e19a6f2 100644 (file)
--- a/doio.c
+++ b/doio.c
@@ -1,4 +1,4 @@
-/* $Header: doio.c,v 3.0.1.1 89/10/26 23:10:05 lwall Locked $
+/* $Header: doio.c,v 3.0.1.7 90/03/14 12:26:24 lwall Locked $
  *
  *    Copyright (c) 1989, Larry Wall
  *
@@ -6,6 +6,38 @@
  *    as specified in the README file that comes with the perl 3.0 kit.
  *
  * $Log:       doio.c,v $
+ * 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
  * 
 #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
 
 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;
@@ -89,61 +121,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
@@ -177,21 +213,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;
 }
 
@@ -208,7 +247,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");
@@ -233,7 +272,7 @@ register STAB *stab;
                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
@@ -261,6 +300,49 @@ register STAB *stab;
     return Nullfp;
 }
 
+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;
+}
+
 bool
 do_close(stab,explicit)
 STAB *stab;
@@ -478,7 +560,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
@@ -823,9 +905,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");
@@ -841,15 +924,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]) {
@@ -1102,6 +1189,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;
@@ -1117,7 +1205,7 @@ int *arglast;
 
 nuts:
     if (dowarn)
-       warn("shutdown() on closed fd");
+       warn("[gs]etsockopt() on closed fd");
     st[sp] = &str_undef;
     return sp;
 
@@ -1143,6 +1231,7 @@ 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:
@@ -1159,7 +1248,7 @@ int *arglast;
 
 nuts:
     if (dowarn)
-       warn("shutdown() on closed fd");
+       warn("get{sock,peer}name() on closed fd");
     st[sp] = &str_undef;
     return sp;
 
@@ -1175,7 +1264,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();
@@ -1435,20 +1524,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';
                }
            }
@@ -1457,6 +1578,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) {
@@ -1470,12 +1601,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);
@@ -1681,13 +1831,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;
 
@@ -1854,7 +2006,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 ||
@@ -1873,13 +2025,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;