eliminate local version of glob (cf ftp)
[unix-history] / usr / src / libexec / ftpd / popen.c
index 5fd5fa7..1f5a0bc 100644 (file)
 /*
 /*
- * Copyright (c) 1988 The Regents of the University of California.
- * All rights reserved.
+ * Copyright (c) 1988, 1993, 1994
+ *     The Regents of the University of California.  All rights reserved.
  *
  * This code is derived from software written by Ken Arnold and
  * published in UNIX Review, Vol. 6, No. 8.
  *
  *
  * This code is derived from software written by Ken Arnold and
  * published in UNIX Review, Vol. 6, No. 8.
  *
- * Redistribution and use in source and binary forms are permitted
- * provided that the above copyright notice and this paragraph are
- * duplicated in all such forms and that any documentation,
- * advertising materials, and other materials related to such
- * distribution and use acknowledge that the software was developed
- * by the University of California, Berkeley.  The name of the
- * University may not be used to endorse or promote products derived
- * from this software without specific prior written permission.
- * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
- * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
- * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
+ * %sccs.include.redist.c%
  *
  *
- * static char sccsid[] = "@(#)popen.c 5.7 (Berkeley) 9/1/88";
  */
 
 #ifndef lint
  */
 
 #ifndef lint
-static char sccsid[] = "@(#)popen.c    5.1 (Berkeley) %G%";
+static char sccsid[] = "@(#)popen.c    8.2 (Berkeley) %G%";
 #endif /* not lint */
 
 #endif /* not lint */
 
-#include <sys/param.h>
-#include <sys/signal.h>
+#include <sys/types.h>
 #include <sys/wait.h>
 #include <sys/wait.h>
+
+#include <errno.h>
+#include <glob.h>
+#include <signal.h>
 #include <stdio.h>
 #include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "extern.h"
 
 
-static uid_t *pids;
+/*
+ * Special version of popen which avoids call to shell.  This ensures noone
+ * may create a pipe to a hidden program as a side effect of a list or dir
+ * command.
+ */
+static int *pids;
 static int fds;
 
 FILE *
 static int fds;
 
 FILE *
-popen(program, type)
+ftpd_popen(program, type)
        char *program, *type;
 {
        char *program, *type;
 {
+       char *cp;
        FILE *iop;
        FILE *iop;
-       int pdes[2], pid;
-       char *malloc();
+       int argc, gargc, pdes[2], pid;
+       char **pop, *argv[100], *gargv[1000];
 
        if (*type != 'r' && *type != 'w' || type[1])
 
        if (*type != 'r' && *type != 'w' || type[1])
-               return(NULL);
+               return (NULL);
 
        if (!pids) {
                if ((fds = getdtablesize()) <= 0)
 
        if (!pids) {
                if ((fds = getdtablesize()) <= 0)
-                       return(NULL);
-               if (!(pids =
-                   (uid_t *)malloc((u_int)(fds * sizeof(uid_t)))))
-                       return(NULL);
-               bzero(pids, fds * sizeof(uid_t));
+                       return (NULL);
+               if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
+                       return (NULL);
+               memset(pids, 0, fds * sizeof(int));
        }
        if (pipe(pdes) < 0)
        }
        if (pipe(pdes) < 0)
-               return(NULL);
+               return (NULL);
+
+       /* break up string into pieces */
+       for (argc = 0, cp = program;; cp = NULL)
+               if (!(argv[argc++] = strtok(cp, " \t\n")))
+                       break;
+
+       /* glob each piece */
+       gargv[0] = argv[0];
+       for (gargc = argc = 1; argv[argc]; argc++) {
+               glob_t gl;
+               int flags = GLOB_BRACE|GLOB_QUOTE|GLOB_TILDE;
+
+               memset(&gl, 0, sizeof(gl));
+               if (glob(argv[argc], flags, NULL, &gl))
+                       gargv[gargc++] = strdup(argv[argc]);
+               else
+                       for (pop = gl.gl_pathv; *pop; pop++)
+                               gargv[gargc++] = strdup(*pop);
+               globfree(&gl);
+       }
+       gargv[gargc] = NULL;
+
+       iop = NULL;
        switch(pid = vfork()) {
        case -1:                        /* error */
                (void)close(pdes[0]);
                (void)close(pdes[1]);
        switch(pid = vfork()) {
        case -1:                        /* error */
                (void)close(pdes[0]);
                (void)close(pdes[1]);
-               return(NULL);
+               goto pfree;
                /* NOTREACHED */
        case 0:                         /* child */
                if (*type == 'r') {
                /* NOTREACHED */
        case 0:                         /* child */
                if (*type == 'r') {
-                       if (pdes[1] != 1) {
-                               dup2(pdes[1], 1);
+                       if (pdes[1] != STDOUT_FILENO) {
+                               dup2(pdes[1], STDOUT_FILENO);
                                (void)close(pdes[1]);
                        }
                                (void)close(pdes[1]);
                        }
+                       dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
                        (void)close(pdes[0]);
                } else {
                        (void)close(pdes[0]);
                } else {
-                       if (pdes[0] != 0) {
-                               dup2(pdes[0], 0);
+                       if (pdes[0] != STDIN_FILENO) {
+                               dup2(pdes[0], STDIN_FILENO);
                                (void)close(pdes[0]);
                        }
                        (void)close(pdes[1]);
                }
                                (void)close(pdes[0]);
                        }
                        (void)close(pdes[1]);
                }
-               execl("/bin/sh", "sh", "-c", program, NULL);
-               _exit(127);
-               /* NOTREACHED */
+               execv(gargv[0], gargv);
+               _exit(1);
        }
        /* parent; assume fdopen can't fail...  */
        if (*type == 'r') {
        }
        /* parent; assume fdopen can't fail...  */
        if (*type == 'r') {
@@ -86,28 +111,35 @@ popen(program, type)
                (void)close(pdes[0]);
        }
        pids[fileno(iop)] = pid;
                (void)close(pdes[0]);
        }
        pids[fileno(iop)] = pid;
-       return(iop);
+
+pfree: for (argc = 1; gargv[argc] != NULL; argc++)
+               free(gargv[argc]);
+
+       return (iop);
 }
 
 }
 
-pclose(iop)
+int
+ftpd_pclose(iop)
        FILE *iop;
 {
        FILE *iop;
 {
-       register int fdes;
-       long omask;
-       int stat_loc;
-       pid_t waitpid();
+       int fdes, omask, status;
+       pid_t pid;
 
        /*
         * pclose returns -1 if stream is not associated with a
         * `popened' command, or, if already `pclosed'.
         */
 
        /*
         * pclose returns -1 if stream is not associated with a
         * `popened' command, or, if already `pclosed'.
         */
-       if (pids[fdes = fileno(iop)] == 0)
-               return(-1);
+       if (pids == 0 || pids[fdes = fileno(iop)] == 0)
+               return (-1);
        (void)fclose(iop);
        omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
        (void)fclose(iop);
        omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
-       stat_loc = waitpid(pids[fdes], &stat_loc, 0) == -1 ?
-           -1 : WEXITSTATUS(stat_loc);
+       while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
+               continue;
        (void)sigsetmask(omask);
        pids[fdes] = 0;
        (void)sigsetmask(omask);
        pids[fdes] = 0;
-       return(stat_loc);
+       if (pid < 0)
+               return (pid);
+       if (WIFEXITED(status))
+               return (WEXITSTATUS(status));
+       return (1);
 }
 }