xref: /386bsd/usr/src/libexec/cron/popen.c (revision a2142627)
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
27 static char rcsid[] = "$Id: popen.c,v 1.5 1994/01/15 20:43:43 vixie Exp $";
28 static 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 WANT_GLOBBING 0
36 
37 /*
38  * Special version of popen which avoids call to shell.  This insures noone
39  * may create a pipe to a hidden program as a side effect of a list or dir
40  * command.
41  */
42 static PID_T *pids;
43 static int fds;
44 
45 FILE *
cron_popen(program,type)46 cron_popen(program, type)
47 	char *program, *type;
48 {
49 	register char *cp;
50 	FILE *iop;
51 	int argc, pdes[2];
52 	PID_T pid;
53 	char *argv[100];
54 #if WANT_GLOBBING
55 	char **pop, *vv[2];
56 	int gargc;
57 	char *gargv[1000];
58 	extern char **glob(), **copyblk();
59 #endif
60 
61 	if (*type != 'r' && *type != 'w' || type[1])
62 		return(NULL);
63 
64 	if (!pids) {
65 		if ((fds = getdtablesize()) <= 0)
66 			return(NULL);
67 		if (!(pids = (PID_T *)malloc((u_int)(fds * sizeof(PID_T)))))
68 			return(NULL);
69 		bzero((char *)pids, fds * sizeof(PID_T));
70 	}
71 	if (pipe(pdes) < 0)
72 		return(NULL);
73 
74 	/* break up string into pieces */
75 	for (argc = 0, cp = program;; cp = NULL)
76 		if (!(argv[argc++] = strtok(cp, " \t\n")))
77 			break;
78 
79 #if WANT_GLOBBING
80 	/* glob each piece */
81 	gargv[0] = argv[0];
82 	for (gargc = argc = 1; argv[argc]; argc++) {
83 		if (!(pop = glob(argv[argc]))) {	/* globbing failed */
84 			vv[0] = argv[argc];
85 			vv[1] = NULL;
86 			pop = copyblk(vv);
87 		}
88 		argv[argc] = (char *)pop;		/* save to free later */
89 		while (*pop && gargc < 1000)
90 			gargv[gargc++] = *pop++;
91 	}
92 	gargv[gargc] = NULL;
93 #endif
94 
95 	iop = NULL;
96 	switch(pid = vfork()) {
97 	case -1:			/* error */
98 		(void)close(pdes[0]);
99 		(void)close(pdes[1]);
100 		goto pfree;
101 		/* NOTREACHED */
102 	case 0:				/* child */
103 		if (*type == 'r') {
104 			if (pdes[1] != 1) {
105 				dup2(pdes[1], 1);
106 				dup2(pdes[1], 2);	/* stderr, too! */
107 				(void)close(pdes[1]);
108 			}
109 			(void)close(pdes[0]);
110 		} else {
111 			if (pdes[0] != 0) {
112 				dup2(pdes[0], 0);
113 				(void)close(pdes[0]);
114 			}
115 			(void)close(pdes[1]);
116 		}
117 #if WANT_GLOBBING
118 		execvp(gargv[0], gargv);
119 #else
120 		execvp(argv[0], argv);
121 #endif
122 		_exit(1);
123 	}
124 	/* parent; assume fdopen can't fail...  */
125 	if (*type == 'r') {
126 		iop = fdopen(pdes[0], type);
127 		(void)close(pdes[1]);
128 	} else {
129 		iop = fdopen(pdes[1], type);
130 		(void)close(pdes[0]);
131 	}
132 	pids[fileno(iop)] = pid;
133 
134 pfree:
135 #if WANT_GLOBBING
136 	for (argc = 1; argv[argc] != NULL; argc++) {
137 /*		blkfree((char **)argv[argc]);	*/
138 		free((char *)argv[argc]);
139 	}
140 #endif
141 	return(iop);
142 }
143 
144 int
cron_pclose(iop)145 cron_pclose(iop)
146 	FILE *iop;
147 {
148 	register int fdes;
149 	int omask;
150 	WAIT_T stat_loc;
151 	PID_T pid;
152 
153 	/*
154 	 * pclose returns -1 if stream is not associated with a
155 	 * `popened' command, or, if already `pclosed'.
156 	 */
157 	if (pids == 0 || pids[fdes = fileno(iop)] == 0)
158 		return(-1);
159 	(void)fclose(iop);
160 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
161 	while ((pid = wait(&stat_loc)) != pids[fdes] && pid != -1)
162 		;
163 	(void)sigsetmask(omask);
164 	pids[fdes] = 0;
165 	return (pid == -1 ? -1 : WEXITSTATUS(stat_loc));
166 }
167