xref: /csrg-svn/libexec/ftpd/popen.c (revision 60086)
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  *
842667Sbostic  * %sccs.include.redist.c%
935675Sbostic  *
1035675Sbostic  */
1135675Sbostic 
1235675Sbostic #ifndef lint
13*60086Sbostic static char sccsid[] = "@(#)popen.c	5.11 (Berkeley) 05/17/93";
1435675Sbostic #endif /* not lint */
1535675Sbostic 
1635676Sbostic #include <sys/types.h>
1736304Skarels #include <sys/wait.h>
1854526Sandrew 
1946669Sbostic #include <signal.h>
2046669Sbostic #include <unistd.h>
2135675Sbostic #include <stdio.h>
2246669Sbostic #include <stdlib.h>
2346669Sbostic #include <string.h>
2454526Sandrew #include "extern.h"
2535675Sbostic 
2635676Sbostic /*
2735676Sbostic  * Special version of popen which avoids call to shell.  This insures noone
2835676Sbostic  * may create a pipe to a hidden program as a side effect of a list or dir
2935676Sbostic  * command.
3035676Sbostic  */
3136304Skarels static int *pids;
3235675Sbostic static int fds;
3335675Sbostic 
3435675Sbostic FILE *
3536276Sbostic ftpd_popen(program, type)
3635675Sbostic 	char *program, *type;
3735675Sbostic {
3835676Sbostic 	register char *cp;
3935675Sbostic 	FILE *iop;
4035676Sbostic 	int argc, gargc, pdes[2], pid;
4135676Sbostic 	char **pop, *argv[100], *gargv[1000], *vv[2];
4235675Sbostic 
4335675Sbostic 	if (*type != 'r' && *type != 'w' || type[1])
4435675Sbostic 		return(NULL);
4535675Sbostic 
4635675Sbostic 	if (!pids) {
4735675Sbostic 		if ((fds = getdtablesize()) <= 0)
4835675Sbostic 			return(NULL);
4936304Skarels 		if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
5035675Sbostic 			return(NULL);
51*60086Sbostic 		memset(pids, 0, fds * sizeof(int));
5235675Sbostic 	}
5335675Sbostic 	if (pipe(pdes) < 0)
5435675Sbostic 		return(NULL);
5535676Sbostic 
5635676Sbostic 	/* break up string into pieces */
5735676Sbostic 	for (argc = 0, cp = program;; cp = NULL)
5835676Sbostic 		if (!(argv[argc++] = strtok(cp, " \t\n")))
5935676Sbostic 			break;
6035676Sbostic 
6135676Sbostic 	/* glob each piece */
6235676Sbostic 	gargv[0] = argv[0];
6335676Sbostic 	for (gargc = argc = 1; argv[argc]; argc++) {
6446669Sbostic 		if (!(pop = ftpglob(argv[argc]))) {	/* globbing failed */
6535676Sbostic 			vv[0] = argv[argc];
6635676Sbostic 			vv[1] = NULL;
6735676Sbostic 			pop = copyblk(vv);
6835676Sbostic 		}
6935676Sbostic 		argv[argc] = (char *)pop;		/* save to free later */
7035676Sbostic 		while (*pop && gargc < 1000)
7135676Sbostic 			gargv[gargc++] = *pop++;
7235676Sbostic 	}
7335676Sbostic 	gargv[gargc] = NULL;
7435676Sbostic 
7535676Sbostic 	iop = NULL;
7635675Sbostic 	switch(pid = vfork()) {
7735675Sbostic 	case -1:			/* error */
7835675Sbostic 		(void)close(pdes[0]);
7935675Sbostic 		(void)close(pdes[1]);
8036434Sbostic 		goto pfree;
8135675Sbostic 		/* NOTREACHED */
8235675Sbostic 	case 0:				/* child */
8335675Sbostic 		if (*type == 'r') {
8435675Sbostic 			if (pdes[1] != 1) {
8535675Sbostic 				dup2(pdes[1], 1);
8636445Sbostic 				dup2(pdes[1], 2);	/* stderr, too! */
8735675Sbostic 				(void)close(pdes[1]);
8835675Sbostic 			}
8935675Sbostic 			(void)close(pdes[0]);
9035675Sbostic 		} else {
9135675Sbostic 			if (pdes[0] != 0) {
9235675Sbostic 				dup2(pdes[0], 0);
9335675Sbostic 				(void)close(pdes[0]);
9435675Sbostic 			}
9535675Sbostic 			(void)close(pdes[1]);
9635675Sbostic 		}
9735676Sbostic 		execv(gargv[0], gargv);
9835676Sbostic 		_exit(1);
9935675Sbostic 	}
10035675Sbostic 	/* parent; assume fdopen can't fail...  */
10135675Sbostic 	if (*type == 'r') {
10235675Sbostic 		iop = fdopen(pdes[0], type);
10335675Sbostic 		(void)close(pdes[1]);
10435675Sbostic 	} else {
10535675Sbostic 		iop = fdopen(pdes[1], type);
10635675Sbostic 		(void)close(pdes[0]);
10735675Sbostic 	}
10835675Sbostic 	pids[fileno(iop)] = pid;
10935676Sbostic 
11036434Sbostic pfree:	for (argc = 1; argv[argc] != NULL; argc++) {
11135676Sbostic 		blkfree((char **)argv[argc]);
11236434Sbostic 		free((char *)argv[argc]);
11336434Sbostic 	}
11435675Sbostic 	return(iop);
11535675Sbostic }
11635675Sbostic 
11754526Sandrew int
11836304Skarels ftpd_pclose(iop)
11935675Sbostic 	FILE *iop;
12035675Sbostic {
12135675Sbostic 	register int fdes;
12236304Skarels 	int omask;
12336304Skarels 	union wait stat_loc;
12436304Skarels 	int pid;
12535675Sbostic 
12635675Sbostic 	/*
12735675Sbostic 	 * pclose returns -1 if stream is not associated with a
12835675Sbostic 	 * `popened' command, or, if already `pclosed'.
12935675Sbostic 	 */
13036304Skarels 	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
13135675Sbostic 		return(-1);
13235675Sbostic 	(void)fclose(iop);
13335675Sbostic 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
13446669Sbostic 	while ((pid = wait((int *)&stat_loc)) != pids[fdes] && pid != -1);
13535675Sbostic 	(void)sigsetmask(omask);
13635675Sbostic 	pids[fdes] = 0;
13736304Skarels 	return(pid == -1 ? -1 : stat_loc.w_status);
13835675Sbostic }
139