135675Sbostic /*
266711Spendry * Copyright (c) 1988, 1993, 1994
361427Sbostic * The Regents of the University of California. All rights reserved.
435675Sbostic *
535675Sbostic * This code is derived from software written by Ken Arnold and
635675Sbostic * published in UNIX Review, Vol. 6, No. 8.
735675Sbostic *
842667Sbostic * %sccs.include.redist.c%
935675Sbostic *
1035675Sbostic */
1135675Sbostic
1235675Sbostic #ifndef lint
13*66725Spendry static char sccsid[] = "@(#)popen.c 8.3 (Berkeley) 04/06/94";
1435675Sbostic #endif /* not lint */
1535675Sbostic
1635676Sbostic #include <sys/types.h>
1736304Skarels #include <sys/wait.h>
1854526Sandrew
1966711Spendry #include <errno.h>
2066711Spendry #include <glob.h>
2146669Sbostic #include <signal.h>
2235675Sbostic #include <stdio.h>
2346669Sbostic #include <stdlib.h>
2446669Sbostic #include <string.h>
2566711Spendry #include <unistd.h>
2666711Spendry
2754526Sandrew #include "extern.h"
2835675Sbostic
2935676Sbostic /*
3066711Spendry * Special version of popen which avoids call to shell. This ensures noone
3135676Sbostic * may create a pipe to a hidden program as a side effect of a list or dir
3235676Sbostic * command.
3335676Sbostic */
3436304Skarels static int *pids;
3535675Sbostic static int fds;
3635675Sbostic
3735675Sbostic FILE *
ftpd_popen(program,type)3836276Sbostic ftpd_popen(program, type)
3935675Sbostic char *program, *type;
4035675Sbostic {
4166711Spendry char *cp;
4235675Sbostic FILE *iop;
4335676Sbostic int argc, gargc, pdes[2], pid;
4466711Spendry char **pop, *argv[100], *gargv[1000];
4535675Sbostic
4635675Sbostic if (*type != 'r' && *type != 'w' || type[1])
4766711Spendry return (NULL);
4835675Sbostic
4935675Sbostic if (!pids) {
5035675Sbostic if ((fds = getdtablesize()) <= 0)
5166711Spendry return (NULL);
5236304Skarels if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
5366711Spendry return (NULL);
5460086Sbostic memset(pids, 0, fds * sizeof(int));
5535675Sbostic }
5635675Sbostic if (pipe(pdes) < 0)
5766711Spendry return (NULL);
5835676Sbostic
5935676Sbostic /* break up string into pieces */
6035676Sbostic for (argc = 0, cp = program;; cp = NULL)
6135676Sbostic if (!(argv[argc++] = strtok(cp, " \t\n")))
6235676Sbostic break;
6335676Sbostic
6435676Sbostic /* glob each piece */
6535676Sbostic gargv[0] = argv[0];
6635676Sbostic for (gargc = argc = 1; argv[argc]; argc++) {
6766711Spendry glob_t gl;
68*66725Spendry int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
6966711Spendry
7066711Spendry memset(&gl, 0, sizeof(gl));
7166711Spendry if (glob(argv[argc], flags, NULL, &gl))
7266711Spendry gargv[gargc++] = strdup(argv[argc]);
7366711Spendry else
7466711Spendry for (pop = gl.gl_pathv; *pop; pop++)
7566711Spendry gargv[gargc++] = strdup(*pop);
7666711Spendry globfree(&gl);
7735676Sbostic }
7835676Sbostic gargv[gargc] = NULL;
7935676Sbostic
8035676Sbostic iop = NULL;
8135675Sbostic switch(pid = vfork()) {
8235675Sbostic case -1: /* error */
8335675Sbostic (void)close(pdes[0]);
8435675Sbostic (void)close(pdes[1]);
8536434Sbostic goto pfree;
8635675Sbostic /* NOTREACHED */
8735675Sbostic case 0: /* child */
8835675Sbostic if (*type == 'r') {
8966711Spendry if (pdes[1] != STDOUT_FILENO) {
9066711Spendry dup2(pdes[1], STDOUT_FILENO);
9135675Sbostic (void)close(pdes[1]);
9235675Sbostic }
9366711Spendry dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
9435675Sbostic (void)close(pdes[0]);
9535675Sbostic } else {
9666711Spendry if (pdes[0] != STDIN_FILENO) {
9766711Spendry dup2(pdes[0], STDIN_FILENO);
9835675Sbostic (void)close(pdes[0]);
9935675Sbostic }
10035675Sbostic (void)close(pdes[1]);
10135675Sbostic }
10235676Sbostic execv(gargv[0], gargv);
10335676Sbostic _exit(1);
10435675Sbostic }
10535675Sbostic /* parent; assume fdopen can't fail... */
10635675Sbostic if (*type == 'r') {
10735675Sbostic iop = fdopen(pdes[0], type);
10835675Sbostic (void)close(pdes[1]);
10935675Sbostic } else {
11035675Sbostic iop = fdopen(pdes[1], type);
11135675Sbostic (void)close(pdes[0]);
11235675Sbostic }
11335675Sbostic pids[fileno(iop)] = pid;
11435676Sbostic
11566711Spendry pfree: for (argc = 1; gargv[argc] != NULL; argc++)
11666711Spendry free(gargv[argc]);
11766711Spendry
11866711Spendry return (iop);
11935675Sbostic }
12035675Sbostic
12154526Sandrew int
ftpd_pclose(iop)12236304Skarels ftpd_pclose(iop)
12335675Sbostic FILE *iop;
12435675Sbostic {
12566711Spendry int fdes, omask, status;
12666711Spendry pid_t pid;
12735675Sbostic
12835675Sbostic /*
12935675Sbostic * pclose returns -1 if stream is not associated with a
13035675Sbostic * `popened' command, or, if already `pclosed'.
13135675Sbostic */
13236304Skarels if (pids == 0 || pids[fdes = fileno(iop)] == 0)
13366711Spendry return (-1);
13435675Sbostic (void)fclose(iop);
13535675Sbostic omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
13666711Spendry while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
13766711Spendry continue;
13835675Sbostic (void)sigsetmask(omask);
13935675Sbostic pids[fdes] = 0;
14066711Spendry if (pid < 0)
14166711Spendry return (pid);
14266711Spendry if (WIFEXITED(status))
14366711Spendry return (WEXITSTATUS(status));
14466711Spendry return (1);
14535675Sbostic }
146