popen.c revision 21673
1/*
2 * Copyright (c) 1988 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software written by Ken Arnold and
6 * published in UNIX Review, Vol. 6, No. 8.
7 *
8 * Redistribution and use in source and binary forms are permitted
9 * provided that the above copyright notice and this paragraph are
10 * duplicated in all such forms and that any documentation,
11 * advertising materials, and other materials related to such
12 * distribution and use acknowledge that the software was developed
13 * by the University of California, Berkeley.  The name of the
14 * University may not be used to endorse or promote products derived
15 * from this software without specific prior written permission.
16 * THIS SOFTWARE IS PROVIDED ``AS IS'' AND WITHOUT ANY EXPRESS OR
17 * IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
18 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19 *
20 */
21
22/* this came out of the ftpd sources; it's been modified to avoid the
23 * globbing stuff since we don't need it.  also execvp instead of execv.
24 */
25
26#ifndef lint
27static char rcsid[] = "$FreeBSD: head/usr.sbin/cron/cron/popen.c 21673 1997-01-14 07:20:47Z jkh $";
28static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 2/14/89";
29#endif /* not lint */
30
31#include "cron.h"
32#include <sys/signal.h>
33
34
35#define MAX_ARGS 100
36#define WANT_GLOBBING 0
37
38/*
39 * Special version of popen which avoids call to shell.  This insures noone
40 * may create a pipe to a hidden program as a side effect of a list or dir
41 * command.
42 */
43static PID_T *pids;
44static int fds;
45
46FILE *
47cron_popen(program, type)
48	char *program, *type;
49{
50	register char *cp;
51	FILE *iop;
52	int argc, pdes[2];
53	PID_T pid;
54	char *argv[MAX_ARGS + 1];
55#if WANT_GLOBBING
56	char **pop, *vv[2];
57	int gargc;
58	char *gargv[1000];
59	extern char **glob(), **copyblk();
60#endif
61
62	if (*type != 'r' && *type != 'w' || type[1])
63		return(NULL);
64
65	if (!pids) {
66		if ((fds = getdtablesize()) <= 0)
67			return(NULL);
68		if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
69			return(NULL);
70		bzero((char *)pids, fds * sizeof(PID_T));
71	}
72	if (pipe(pdes) < 0)
73		return(NULL);
74
75	/* break up string into pieces */
76	for (argc = 0, cp = program; argc < MAX_ARGS; cp = NULL)
77		if (!(argv[argc++] = strtok(cp, " \t\n")))
78			break;
79
80#if WANT_GLOBBING
81	/* glob each piece */
82	gargv[0] = argv[0];
83	for (gargc = argc = 1; argv[argc]; argc++) {
84		if (!(pop = glob(argv[argc]))) {	/* globbing failed */
85			vv[0] = argv[argc];
86			vv[1] = NULL;
87			pop = copyblk(vv);
88		}
89		argv[argc] = (char *)pop;		/* save to free later */
90		while (*pop && gargc < 1000)
91			gargv[gargc++] = *pop++;
92	}
93	gargv[gargc] = NULL;
94#endif
95
96	iop = NULL;
97	switch(pid = vfork()) {
98	case -1:			/* error */
99		(void)close(pdes[0]);
100		(void)close(pdes[1]);
101		goto pfree;
102		/* NOTREACHED */
103	case 0:				/* child */
104		if (*type == 'r') {
105			if (pdes[1] != 1) {
106				dup2(pdes[1], 1);
107				dup2(pdes[1], 2);	/* stderr, too! */
108				(void)close(pdes[1]);
109			}
110			(void)close(pdes[0]);
111		} else {
112			if (pdes[0] != 0) {
113				dup2(pdes[0], 0);
114				(void)close(pdes[0]);
115			}
116			(void)close(pdes[1]);
117		}
118#if WANT_GLOBBING
119		execvp(gargv[0], gargv);
120#else
121		execvp(argv[0], argv);
122#endif
123		_exit(1);
124	}
125	/* parent; assume fdopen can't fail...  */
126	if (*type == 'r') {
127		iop = fdopen(pdes[0], type);
128		(void)close(pdes[1]);
129	} else {
130		iop = fdopen(pdes[1], type);
131		(void)close(pdes[0]);
132	}
133	pids[fileno(iop)] = pid;
134
135pfree:
136#if WANT_GLOBBING
137	for (argc = 1; argv[argc] != NULL; argc++) {
138/*		blkfree((char **)argv[argc]);	*/
139		free((char *)argv[argc]);
140	}
141#endif
142	return(iop);
143}
144
145int
146cron_pclose(iop)
147	FILE *iop;
148{
149	register int fdes;
150	int omask;
151	WAIT_T stat_loc;
152	PID_T pid;
153
154	/*
155	 * pclose returns -1 if stream is not associated with a
156	 * `popened' command, or, if already `pclosed'.
157	 */
158	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
159		return(-1);
160	(void)fclose(iop);
161	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
162	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
163		;
164	(void)sigsetmask(omask);
165	pids[fdes] = 0;
166	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
167}
168