xref: /csrg-svn/libexec/ftpd/popen.c (revision 35676)
135675Sbostic /*
235675Sbostic  * Copyright (c) 1988 The Regents of the University of California.
335675Sbostic  * 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  *
835675Sbostic  * Redistribution and use in source and binary forms are permitted
935675Sbostic  * provided that the above copyright notice and this paragraph are
1035675Sbostic  * duplicated in all such forms and that any documentation,
1135675Sbostic  * advertising materials, and other materials related to such
1235675Sbostic  * distribution and use acknowledge that the software was developed
1335675Sbostic  * by the University of California, Berkeley.  The name of the
1435675Sbostic  * University may not be used to endorse or promote products derived
1535675Sbostic  * from this software without specific prior written permission.
1635675Sbostic  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
1735675Sbostic  * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
1835675Sbostic  * WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
1935675Sbostic  *
2035675Sbostic  * static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 9/1/88";
2135675Sbostic  */
2235675Sbostic 
2335675Sbostic #ifndef lint
24*35676Sbostic static char sccsid[] = "@(#)popen.c	5.2 (Berkeley) 09/22/88";
2535675Sbostic #endif /* not lint */
2635675Sbostic 
27*35676Sbostic #include <sys/types.h>
2835675Sbostic #include <sys/signal.h>
2935675Sbostic #include <stdio.h>
3035675Sbostic 
31*35676Sbostic /*
32*35676Sbostic  * Special version of popen which avoids call to shell.  This insures noone
33*35676Sbostic  * may create a pipe to a hidden program as a side effect of a list or dir
34*35676Sbostic  * command.
35*35676Sbostic  */
3635675Sbostic static uid_t *pids;
3735675Sbostic static int fds;
3835675Sbostic 
3935675Sbostic FILE *
4035675Sbostic popen(program, type)
4135675Sbostic 	char *program, *type;
4235675Sbostic {
43*35676Sbostic 	register char *cp;
4435675Sbostic 	FILE *iop;
45*35676Sbostic 	int argc, gargc, pdes[2], pid;
46*35676Sbostic 	char **pop, *argv[100], *gargv[1000], *vv[2];
47*35676Sbostic 	extern char **glob(), **copyblk(), *strtok();
4835675Sbostic 
4935675Sbostic 	if (*type != 'r' && *type != 'w' || type[1])
5035675Sbostic 		return(NULL);
5135675Sbostic 
5235675Sbostic 	if (!pids) {
5335675Sbostic 		if ((fds = getdtablesize()) <= 0)
5435675Sbostic 			return(NULL);
5535675Sbostic 		if (!(pids =
5635675Sbostic 		    (uid_t *)malloc((u_int)(fds * sizeof(uid_t)))))
5735675Sbostic 			return(NULL);
5835675Sbostic 		bzero(pids, fds * sizeof(uid_t));
5935675Sbostic 	}
6035675Sbostic 	if (pipe(pdes) < 0)
6135675Sbostic 		return(NULL);
62*35676Sbostic 
63*35676Sbostic 	/* break up string into pieces */
64*35676Sbostic 	for (argc = 0, cp = program;; cp = NULL)
65*35676Sbostic 		if (!(argv[argc++] = strtok(cp, " \t\n")))
66*35676Sbostic 			break;
67*35676Sbostic 
68*35676Sbostic 	/* glob each piece */
69*35676Sbostic 	gargv[0] = argv[0];
70*35676Sbostic 	for (gargc = argc = 1; argv[argc]; argc++) {
71*35676Sbostic 		if (!(pop = glob(argv[argc]))) {	/* globbing failed */
72*35676Sbostic 			vv[0] = argv[argc];
73*35676Sbostic 			vv[1] = NULL;
74*35676Sbostic 			pop = copyblk(vv);
75*35676Sbostic 		}
76*35676Sbostic 		argv[argc] = (char *)pop;		/* save to free later */
77*35676Sbostic 		while (*pop && gargc < 1000)
78*35676Sbostic 			gargv[gargc++] = *pop++;
79*35676Sbostic 	}
80*35676Sbostic 	gargv[gargc] = NULL;
81*35676Sbostic 
82*35676Sbostic 	iop = NULL;
8335675Sbostic 	switch(pid = vfork()) {
8435675Sbostic 	case -1:			/* error */
8535675Sbostic 		(void)close(pdes[0]);
8635675Sbostic 		(void)close(pdes[1]);
87*35676Sbostic 		goto free;
8835675Sbostic 		/* NOTREACHED */
8935675Sbostic 	case 0:				/* child */
9035675Sbostic 		if (*type == 'r') {
9135675Sbostic 			if (pdes[1] != 1) {
9235675Sbostic 				dup2(pdes[1], 1);
9335675Sbostic 				(void)close(pdes[1]);
9435675Sbostic 			}
9535675Sbostic 			(void)close(pdes[0]);
9635675Sbostic 		} else {
9735675Sbostic 			if (pdes[0] != 0) {
9835675Sbostic 				dup2(pdes[0], 0);
9935675Sbostic 				(void)close(pdes[0]);
10035675Sbostic 			}
10135675Sbostic 			(void)close(pdes[1]);
10235675Sbostic 		}
103*35676Sbostic 		execv(gargv[0], gargv);
104*35676Sbostic 		_exit(1);
10535675Sbostic 	}
10635675Sbostic 	/* parent; assume fdopen can't fail...  */
10735675Sbostic 	if (*type == 'r') {
10835675Sbostic 		iop = fdopen(pdes[0], type);
10935675Sbostic 		(void)close(pdes[1]);
11035675Sbostic 	} else {
11135675Sbostic 		iop = fdopen(pdes[1], type);
11235675Sbostic 		(void)close(pdes[0]);
11335675Sbostic 	}
11435675Sbostic 	pids[fileno(iop)] = pid;
115*35676Sbostic 
116*35676Sbostic free:	for (argc = 1; argv[argc] != NULL; argc++)
117*35676Sbostic 		blkfree((char **)argv[argc]);
11835675Sbostic 	return(iop);
11935675Sbostic }
12035675Sbostic 
12135675Sbostic pclose(iop)
12235675Sbostic 	FILE *iop;
12335675Sbostic {
12435675Sbostic 	register int fdes;
12535675Sbostic 	long omask;
126*35676Sbostic 	int pid, stat_loc;
127*35676Sbostic 	u_int waitpid();
12835675Sbostic 
12935675Sbostic 	/*
13035675Sbostic 	 * pclose returns -1 if stream is not associated with a
13135675Sbostic 	 * `popened' command, or, if already `pclosed'.
13235675Sbostic 	 */
13335675Sbostic 	if (pids[fdes = fileno(iop)] == 0)
13435675Sbostic 		return(-1);
13535675Sbostic 	(void)fclose(iop);
13635675Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
137*35676Sbostic 	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1);
13835675Sbostic 	(void)sigsetmask(omask);
13935675Sbostic 	pids[fdes] = 0;
14035675Sbostic 	return(stat_loc);
14135675Sbostic }
142