xref: /freebsd/libexec/ftpd/popen.c (revision 148531ef1e6681bf21fa82c8afd667377b9c057f)
1ea022d16SRodney W. Grimes /*
2ea022d16SRodney W. Grimes  * Copyright (c) 1988, 1993, 1994
3ea022d16SRodney W. Grimes  *	The Regents of the University of California.  All rights reserved.
4ea022d16SRodney W. Grimes  *
5ea022d16SRodney W. Grimes  * This code is derived from software written by Ken Arnold and
6ea022d16SRodney W. Grimes  * published in UNIX Review, Vol. 6, No. 8.
7ea022d16SRodney W. Grimes  *
8ea022d16SRodney W. Grimes  * Redistribution and use in source and binary forms, with or without
9ea022d16SRodney W. Grimes  * modification, are permitted provided that the following conditions
10ea022d16SRodney W. Grimes  * are met:
11ea022d16SRodney W. Grimes  * 1. Redistributions of source code must retain the above copyright
12ea022d16SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer.
13ea022d16SRodney W. Grimes  * 2. Redistributions in binary form must reproduce the above copyright
14ea022d16SRodney W. Grimes  *    notice, this list of conditions and the following disclaimer in the
15ea022d16SRodney W. Grimes  *    documentation and/or other materials provided with the distribution.
16ea022d16SRodney W. Grimes  * 3. All advertising materials mentioning features or use of this software
17ea022d16SRodney W. Grimes  *    must display the following acknowledgement:
18ea022d16SRodney W. Grimes  *	This product includes software developed by the University of
19ea022d16SRodney W. Grimes  *	California, Berkeley and its contributors.
20ea022d16SRodney W. Grimes  * 4. Neither the name of the University nor the names of its contributors
21ea022d16SRodney W. Grimes  *    may be used to endorse or promote products derived from this software
22ea022d16SRodney W. Grimes  *    without specific prior written permission.
23ea022d16SRodney W. Grimes  *
24ea022d16SRodney W. Grimes  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25ea022d16SRodney W. Grimes  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26ea022d16SRodney W. Grimes  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27ea022d16SRodney W. Grimes  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28ea022d16SRodney W. Grimes  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29ea022d16SRodney W. Grimes  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30ea022d16SRodney W. Grimes  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31ea022d16SRodney W. Grimes  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32ea022d16SRodney W. Grimes  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33ea022d16SRodney W. Grimes  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34ea022d16SRodney W. Grimes  * SUCH DAMAGE.
35ea022d16SRodney W. Grimes  *
36148531efSWolfram Schneider  *	$Id$
37ea022d16SRodney W. Grimes  */
38148531efSWolfram Schneider 
399aca17cbSMark Murray #if 0
40ea022d16SRodney W. Grimes #ifndef lint
41ea022d16SRodney W. Grimes static char sccsid[] = "@(#)popen.c	8.3 (Berkeley) 4/6/94";
42ea022d16SRodney W. Grimes #endif /* not lint */
439aca17cbSMark Murray #endif
44ea022d16SRodney W. Grimes 
45ea022d16SRodney W. Grimes #include <sys/types.h>
46ea022d16SRodney W. Grimes #include <sys/wait.h>
47ea022d16SRodney W. Grimes 
48ea022d16SRodney W. Grimes #include <errno.h>
49ea022d16SRodney W. Grimes #include <glob.h>
50ea022d16SRodney W. Grimes #include <signal.h>
51ea022d16SRodney W. Grimes #include <stdio.h>
52ea022d16SRodney W. Grimes #include <stdlib.h>
53ea022d16SRodney W. Grimes #include <string.h>
54ea022d16SRodney W. Grimes #include <unistd.h>
55ea022d16SRodney W. Grimes 
56ea022d16SRodney W. Grimes #include "extern.h"
57ea022d16SRodney W. Grimes 
58ea022d16SRodney W. Grimes /*
59ea022d16SRodney W. Grimes  * Special version of popen which avoids call to shell.  This ensures noone
60ea022d16SRodney W. Grimes  * may create a pipe to a hidden program as a side effect of a list or dir
61ea022d16SRodney W. Grimes  * command.
62ea022d16SRodney W. Grimes  */
63ea022d16SRodney W. Grimes static int *pids;
64ea022d16SRodney W. Grimes static int fds;
65ea022d16SRodney W. Grimes 
66ea022d16SRodney W. Grimes FILE *
67ea022d16SRodney W. Grimes ftpd_popen(program, type)
68ea022d16SRodney W. Grimes 	char *program, *type;
69ea022d16SRodney W. Grimes {
70ea022d16SRodney W. Grimes 	char *cp;
71ea022d16SRodney W. Grimes 	FILE *iop;
72ea022d16SRodney W. Grimes 	int argc, gargc, pdes[2], pid;
73ea022d16SRodney W. Grimes 	char **pop, *argv[100], *gargv[1000];
74ea022d16SRodney W. Grimes 
7539ea627dSPaul Traina 	if (((*type != 'r') && (*type != 'w')) || type[1])
76ea022d16SRodney W. Grimes 		return (NULL);
77ea022d16SRodney W. Grimes 
78ea022d16SRodney W. Grimes 	if (!pids) {
79ea022d16SRodney W. Grimes 		if ((fds = getdtablesize()) <= 0)
80ea022d16SRodney W. Grimes 			return (NULL);
81ea022d16SRodney W. Grimes 		if ((pids = (int *)malloc((u_int)(fds * sizeof(int)))) == NULL)
82ea022d16SRodney W. Grimes 			return (NULL);
83ea022d16SRodney W. Grimes 		memset(pids, 0, fds * sizeof(int));
84ea022d16SRodney W. Grimes 	}
85ea022d16SRodney W. Grimes 	if (pipe(pdes) < 0)
86ea022d16SRodney W. Grimes 		return (NULL);
87ea022d16SRodney W. Grimes 
88ea022d16SRodney W. Grimes 	/* break up string into pieces */
89ea022d16SRodney W. Grimes 	for (argc = 0, cp = program;; cp = NULL)
90ea022d16SRodney W. Grimes 		if (!(argv[argc++] = strtok(cp, " \t\n")))
91ea022d16SRodney W. Grimes 			break;
92ea022d16SRodney W. Grimes 
93ea022d16SRodney W. Grimes 	/* glob each piece */
94ea022d16SRodney W. Grimes 	gargv[0] = argv[0];
95ea022d16SRodney W. Grimes 	for (gargc = argc = 1; argv[argc]; argc++) {
96ea022d16SRodney W. Grimes 		glob_t gl;
97ea022d16SRodney W. Grimes 		int flags = GLOB_BRACE|GLOB_NOCHECK|GLOB_QUOTE|GLOB_TILDE;
98ea022d16SRodney W. Grimes 
99ea022d16SRodney W. Grimes 		memset(&gl, 0, sizeof(gl));
100ea022d16SRodney W. Grimes 		if (glob(argv[argc], flags, NULL, &gl))
101ea022d16SRodney W. Grimes 			gargv[gargc++] = strdup(argv[argc]);
102ea022d16SRodney W. Grimes 		else
103ea022d16SRodney W. Grimes 			for (pop = gl.gl_pathv; *pop; pop++)
104ea022d16SRodney W. Grimes 				gargv[gargc++] = strdup(*pop);
105ea022d16SRodney W. Grimes 		globfree(&gl);
106ea022d16SRodney W. Grimes 	}
107ea022d16SRodney W. Grimes 	gargv[gargc] = NULL;
108ea022d16SRodney W. Grimes 
109ea022d16SRodney W. Grimes 	iop = NULL;
110ea022d16SRodney W. Grimes 	switch(pid = vfork()) {
111ea022d16SRodney W. Grimes 	case -1:			/* error */
112ea022d16SRodney W. Grimes 		(void)close(pdes[0]);
113ea022d16SRodney W. Grimes 		(void)close(pdes[1]);
114ea022d16SRodney W. Grimes 		goto pfree;
115ea022d16SRodney W. Grimes 		/* NOTREACHED */
116ea022d16SRodney W. Grimes 	case 0:				/* child */
117ea022d16SRodney W. Grimes 		if (*type == 'r') {
118ea022d16SRodney W. Grimes 			if (pdes[1] != STDOUT_FILENO) {
119ea022d16SRodney W. Grimes 				dup2(pdes[1], STDOUT_FILENO);
120ea022d16SRodney W. Grimes 				(void)close(pdes[1]);
121ea022d16SRodney W. Grimes 			}
122ea022d16SRodney W. Grimes 			dup2(STDOUT_FILENO, STDERR_FILENO); /* stderr too! */
123ea022d16SRodney W. Grimes 			(void)close(pdes[0]);
124ea022d16SRodney W. Grimes 		} else {
125ea022d16SRodney W. Grimes 			if (pdes[0] != STDIN_FILENO) {
126ea022d16SRodney W. Grimes 				dup2(pdes[0], STDIN_FILENO);
127ea022d16SRodney W. Grimes 				(void)close(pdes[0]);
128ea022d16SRodney W. Grimes 			}
129ea022d16SRodney W. Grimes 			(void)close(pdes[1]);
130ea022d16SRodney W. Grimes 		}
131ea022d16SRodney W. Grimes 		execv(gargv[0], gargv);
132ea022d16SRodney W. Grimes 		_exit(1);
133ea022d16SRodney W. Grimes 	}
134ea022d16SRodney W. Grimes 	/* parent; assume fdopen can't fail...  */
135ea022d16SRodney W. Grimes 	if (*type == 'r') {
136ea022d16SRodney W. Grimes 		iop = fdopen(pdes[0], type);
137ea022d16SRodney W. Grimes 		(void)close(pdes[1]);
138ea022d16SRodney W. Grimes 	} else {
139ea022d16SRodney W. Grimes 		iop = fdopen(pdes[1], type);
140ea022d16SRodney W. Grimes 		(void)close(pdes[0]);
141ea022d16SRodney W. Grimes 	}
142ea022d16SRodney W. Grimes 	pids[fileno(iop)] = pid;
143ea022d16SRodney W. Grimes 
144ea022d16SRodney W. Grimes pfree:	for (argc = 1; gargv[argc] != NULL; argc++)
145ea022d16SRodney W. Grimes 		free(gargv[argc]);
146ea022d16SRodney W. Grimes 
147ea022d16SRodney W. Grimes 	return (iop);
148ea022d16SRodney W. Grimes }
149ea022d16SRodney W. Grimes 
150ea022d16SRodney W. Grimes int
151ea022d16SRodney W. Grimes ftpd_pclose(iop)
152ea022d16SRodney W. Grimes 	FILE *iop;
153ea022d16SRodney W. Grimes {
154ea022d16SRodney W. Grimes 	int fdes, omask, status;
155ea022d16SRodney W. Grimes 	pid_t pid;
156ea022d16SRodney W. Grimes 
157ea022d16SRodney W. Grimes 	/*
158ea022d16SRodney W. Grimes 	 * pclose returns -1 if stream is not associated with a
159ea022d16SRodney W. Grimes 	 * `popened' command, or, if already `pclosed'.
160ea022d16SRodney W. Grimes 	 */
161ea022d16SRodney W. Grimes 	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
162ea022d16SRodney W. Grimes 		return (-1);
163ea022d16SRodney W. Grimes 	(void)fclose(iop);
164ea022d16SRodney W. Grimes 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
165ea022d16SRodney W. Grimes 	while ((pid = waitpid(pids[fdes], &status, 0)) < 0 && errno == EINTR)
166ea022d16SRodney W. Grimes 		continue;
167ea022d16SRodney W. Grimes 	(void)sigsetmask(omask);
168ea022d16SRodney W. Grimes 	pids[fdes] = 0;
169ea022d16SRodney W. Grimes 	if (pid < 0)
170ea022d16SRodney W. Grimes 		return (pid);
171ea022d16SRodney W. Grimes 	if (WIFEXITED(status))
172ea022d16SRodney W. Grimes 		return (WEXITSTATUS(status));
173ea022d16SRodney W. Grimes 	return (1);
174ea022d16SRodney W. Grimes }
175