xref: /csrg-svn/libexec/ftpd/popen.c (revision 66711)
135675Sbostic /*
2*66711Spendry  * 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*66711Spendry static char sccsid[] = "@(#)popen.c	8.2 (Berkeley) 04/04/94";
1435675Sbostic #endif /* not lint */
1535675Sbostic 
1635676Sbostic #include <sys/types.h>
1736304Skarels #include <sys/wait.h>
1854526Sandrew 
19*66711Spendry #include <errno.h>
20*66711Spendry #include <glob.h>
2146669Sbostic #include <signal.h>
2235675Sbostic #include <stdio.h>
2346669Sbostic #include <stdlib.h>
2446669Sbostic #include <string.h>
25*66711Spendry #include <unistd.h>
26*66711Spendry 
2754526Sandrew #include "extern.h"
2835675Sbostic 
2935676Sbostic /*
30*66711Spendry  * 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 *
3836276Sbostic ftpd_popen(program, type)
3935675Sbostic 	char *program, *type;
4035675Sbostic {
41*66711Spendry 	char *cp;
4235675Sbostic 	FILE *iop;
4335676Sbostic 	int argc, gargc, pdes[2], pid;
44*66711Spendry 	char **pop, *argv[100], *gargv[1000];
4535675Sbostic 
4635675Sbostic 	if (*type != 'r' && *type != 'w' || type[1])
47*66711Spendry 		return (NULL);
4835675Sbostic 
4935675Sbostic 	if (!pids) {
5035675Sbostic 		if ((fds = getdtablesize()) <= 0)
51*66711Spendry 			return (NULL);
5236304Skarels 		if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
53*66711Spendry 			return (NULL);
5460086Sbostic 		memset(pids, 0, fds * sizeof(int));
5535675Sbostic 	}
5635675Sbostic 	if (pipe(pdes) < 0)
57*66711Spendry 		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++) {
67*66711Spendry 		glob_t gl;
68*66711Spendry 		int flags = GLOB_BRACE|GLOB_QUOTE|GLOB_TILDE;
69*66711Spendry 
70*66711Spendry 		memset(&gl, 0, sizeof(gl));
71*66711Spendry 		if (glob(argv[argc], flags, NULL, &gl))
72*66711Spendry 			gargv[gargc++] = strdup(argv[argc]);
73*66711Spendry 		else
74*66711Spendry 			for (pop = gl.gl_pathv; *pop; pop++)
75*66711Spendry 				gargv[gargc++] = strdup(*pop);
76*66711Spendry 		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') {
89*66711Spendry 			if (pdes[1] != STDOUT_FILENO) {
90*66711Spendry 				dup2(pdes[1], STDOUT_FILENO);
9135675Sbostic 				(void)close(pdes[1]);
9235675Sbostic 			}
93*66711Spendry 			dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
9435675Sbostic 			(void)close(pdes[0]);
9535675Sbostic 		} else {
96*66711Spendry 			if (pdes[0] != STDIN_FILENO) {
97*66711Spendry 				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 
115*66711Spendry pfree:	for (argc = 1; gargv[argc] != NULL; argc++)
116*66711Spendry 		free(gargv[argc]);
117*66711Spendry 
118*66711Spendry 	return (iop);
11935675Sbostic }
12035675Sbostic 
12154526Sandrew int
12236304Skarels ftpd_pclose(iop)
12335675Sbostic 	FILE *iop;
12435675Sbostic {
125*66711Spendry 	int fdes, omask, status;
126*66711Spendry 	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)
133*66711Spendry 		return (-1);
13435675Sbostic 	(void)fclose(iop);
13535675Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
136*66711Spendry 	while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
137*66711Spendry 		continue;
13835675Sbostic 	(void)sigsetmask(omask);
13935675Sbostic 	pids[fdes] = 0;
140*66711Spendry 	if (pid < 0)
141*66711Spendry 		return (pid);
142*66711Spendry 	if (WIFEXITED(status))
143*66711Spendry 		return (WEXITSTATUS(status));
144*66711Spendry 	return (1);
14535675Sbostic }
146