xref: /csrg-svn/libexec/ftpd/popen.c (revision 66725)
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