popen.c revision 29452
1262152Sluigi/*
2262152Sluigi * Copyright (c) 1988 The Regents of the University of California.
3262152Sluigi * All rights reserved.
4262152Sluigi *
5262152Sluigi * This code is derived from software written by Ken Arnold and
6262152Sluigi * published in UNIX Review, Vol. 6, No. 8.
7262152Sluigi *
8262152Sluigi * Redistribution and use in source and binary forms are permitted
9262152Sluigi * provided that the above copyright notice and this paragraph are
10262152Sluigi * duplicated in all such forms and that any documentation,
11262152Sluigi * advertising materials, and other materials related to such
12262152Sluigi * distribution and use acknowledge that the software was developed
13262152Sluigi * by the University of California, Berkeley.  The name of the
14262152Sluigi * University may not be used to endorse or promote products derived
15262152Sluigi * from this software without specific prior written permission.
16262152Sluigi * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17262152Sluigi * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18262152Sluigi * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19262152Sluigi *
20262152Sluigi */
21262152Sluigi
22262152Sluigi/* this came out of the ftpd sources; it's been modified to avoid the
23262152Sluigi * globbing stuff since we don't need it.  also execvp instead of execv.
24262152Sluigi */
25262152Sluigi
26262152Sluigi#ifndef lint
27262152Sluigi#if 0
28262152Sluigistatic char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 2/14/89";
29262152Sluigi#endif
30262152Sluigistatic const char rcsid[] =
31262152Sluigi	"$Id$";
32262152Sluigi#endif /* not lint */
33262152Sluigi
34262152Sluigi#include "cron.h"
35262152Sluigi#include <sys/signal.h>
36262152Sluigi
37262152Sluigi
38262152Sluigi#define MAX_ARGS 100
39262152Sluigi#define WANT_GLOBBING 0
40262152Sluigi
41262152Sluigi/*
42262152Sluigi * Special version of popen which avoids call to shell.  This insures noone
43262152Sluigi * may create a pipe to a hidden program as a side effect of a list or dir
44262152Sluigi * command.
45262152Sluigi */
46262152Sluigistatic PID_T *pids;
47262152Sluigistatic int fds;
48262152Sluigi
49262152SluigiFILE *
50262152Sluigicron_popen(program, type)
51262152Sluigi	char *program, *type;
52262152Sluigi{
53262152Sluigi	register char *cp;
54262152Sluigi	FILE *iop;
55262152Sluigi	int argc, pdes[2];
56262152Sluigi	PID_T pid;
57262152Sluigi	char *argv[MAX_ARGS + 1];
58262152Sluigi#if WANT_GLOBBING
59262152Sluigi	char **pop, *vv[2];
60262152Sluigi	int gargc;
61262152Sluigi	char *gargv[1000];
62262152Sluigi	extern char **glob(), **copyblk();
63262152Sluigi#endif
64262152Sluigi
65262152Sluigi	if ((*type != 'r' && *type != 'w') || type[1])
66262152Sluigi		return(NULL);
67262152Sluigi
68262152Sluigi	if (!pids) {
69262152Sluigi		if ((fds = getdtablesize()) <= 0)
70262152Sluigi			return(NULL);
71262152Sluigi		if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
72262152Sluigi			return(NULL);
73262152Sluigi		bzero((char *)pids, fds * sizeof(PID_T));
74262152Sluigi	}
75262152Sluigi	if (pipe(pdes) < 0)
76262152Sluigi		return(NULL);
77262152Sluigi
78262152Sluigi	/* break up string into pieces */
79262152Sluigi	for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
80262152Sluigi		if (!(argv[argc++] = strtok(cp, " \t\n")))
81262152Sluigi			break;
82262152Sluigi
83262152Sluigi#if WANT_GLOBBING
84262152Sluigi	/* glob each piece */
85262152Sluigi	gargv[0] = argv[0];
86262152Sluigi	for (gargc = argc = 1; argv[argc]; argc++) {
87262152Sluigi		if (!(pop = glob(argv[argc]))) {	/* globbing failed */
88262152Sluigi			vv[0] = argv[argc];
89262152Sluigi			vv[1] = NULL;
90262152Sluigi			pop = copyblk(vv);
91262152Sluigi		}
92262152Sluigi		argv[argc] = (char *)pop;		/* save to free later */
93262152Sluigi		while (*pop && gargc < 1000)
94262152Sluigi			gargv[gargc++] = *pop++;
95262152Sluigi	}
96262152Sluigi	gargv[gargc] = NULL;
97262152Sluigi#endif
98262152Sluigi
99262152Sluigi	iop = NULL;
100262152Sluigi	switch(pid = vfork()) {
101262152Sluigi	case -1:			/* error */
102262152Sluigi		(void)close(pdes[0]);
103262152Sluigi		(void)close(pdes[1]);
104262152Sluigi		goto pfree;
105262152Sluigi		/* NOTREACHED */
106262152Sluigi	case 0:				/* child */
107262152Sluigi		if (*type == 'r') {
108262152Sluigi			if (pdes[1] != 1) {
109262152Sluigi				dup2(pdes[1], 1);
110262152Sluigi				dup2(pdes[1], 2);	/* stderr, too! */
111262152Sluigi				(void)close(pdes[1]);
112262152Sluigi			}
113262152Sluigi			(void)close(pdes[0]);
114262152Sluigi		} else {
115262152Sluigi			if (pdes[0] != 0) {
116262152Sluigi				dup2(pdes[0], 0);
117262152Sluigi				(void)close(pdes[0]);
118262152Sluigi			}
119262152Sluigi			(void)close(pdes[1]);
120262152Sluigi		}
121262152Sluigi#if WANT_GLOBBING
122262152Sluigi		execvp(gargv[0], gargv);
123262152Sluigi#else
124262152Sluigi		execvp(argv[0], argv);
125262152Sluigi#endif
126262152Sluigi		_exit(1);
127262152Sluigi	}
128262152Sluigi	/* parent; assume fdopen can't fail...  */
129262152Sluigi	if (*type == 'r') {
130262152Sluigi		iop = fdopen(pdes[0], type);
131262152Sluigi		(void)close(pdes[1]);
132262152Sluigi	} else {
133262152Sluigi		iop = fdopen(pdes[1], type);
134262152Sluigi		(void)close(pdes[0]);
135262152Sluigi	}
136262152Sluigi	pids[fileno(iop)] = pid;
137262152Sluigi
138262152Sluigipfree:
139262152Sluigi#if WANT_GLOBBING
140262152Sluigi	for (argc = 1; argv[argc] != NULL; argc++) {
141262152Sluigi/*		blkfree((char **)argv[argc]);	*/
142262152Sluigi		free((char *)argv[argc]);
143262152Sluigi	}
144262152Sluigi#endif
145262152Sluigi	return(iop);
146262152Sluigi}
147262152Sluigi
148262152Sluigiint
149262152Sluigicron_pclose(iop)
150262152Sluigi	FILE *iop;
151262152Sluigi{
152262152Sluigi	register int fdes;
153262152Sluigi	int omask;
154262152Sluigi	WAIT_T stat_loc;
155262152Sluigi	PID_T pid;
156262152Sluigi
157262152Sluigi	/*
158262152Sluigi	 * pclose returns -1 if stream is not associated with a
159262152Sluigi	 * `popened' command, or, if already `pclosed'.
160262152Sluigi	 */
161262152Sluigi	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
162270252Sluigi		return(-1);
163262152Sluigi	(void)fclose(iop);
164262152Sluigi	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
165262152Sluigi	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
166262152Sluigi		;
167262152Sluigi	(void)sigsetmask(omask);
168262152Sluigi	pids[fdes] = 0;
169262152Sluigi	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
170262152Sluigi}
171262152Sluigi