xref: /csrg-svn/libexec/ftpd/popen.c (revision 35675)
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 MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
19  *
20  * static char sccsid[] = "@(#)popen.c	5.7 (Berkeley) 9/1/88";
21  */
22 
23 #ifndef lint
24 static char sccsid[] = "@(#)popen.c	5.1 (Berkeley) 09/22/88";
25 #endif /* not lint */
26 
27 #include <sys/param.h>
28 #include <sys/signal.h>
29 #include <sys/wait.h>
30 #include <stdio.h>
31 
32 static uid_t *pids;
33 static int fds;
34 
35 FILE *
36 popen(program, type)
37 	char *program, *type;
38 {
39 	FILE *iop;
40 	int pdes[2], pid;
41 	char *malloc();
42 
43 	if (*type != 'r' && *type != 'w' || type[1])
44 		return(NULL);
45 
46 	if (!pids) {
47 		if ((fds = getdtablesize()) <= 0)
48 			return(NULL);
49 		if (!(pids =
50 		    (uid_t *)malloc((u_int)(fds * sizeof(uid_t)))))
51 			return(NULL);
52 		bzero(pids, fds * sizeof(uid_t));
53 	}
54 	if (pipe(pdes) < 0)
55 		return(NULL);
56 	switch(pid = vfork()) {
57 	case -1:			/* error */
58 		(void)close(pdes[0]);
59 		(void)close(pdes[1]);
60 		return(NULL);
61 		/* NOTREACHED */
62 	case 0:				/* child */
63 		if (*type == 'r') {
64 			if (pdes[1] != 1) {
65 				dup2(pdes[1], 1);
66 				(void)close(pdes[1]);
67 			}
68 			(void)close(pdes[0]);
69 		} else {
70 			if (pdes[0] != 0) {
71 				dup2(pdes[0], 0);
72 				(void)close(pdes[0]);
73 			}
74 			(void)close(pdes[1]);
75 		}
76 		execl("/bin/sh", "sh", "-c", program, NULL);
77 		_exit(127);
78 		/* NOTREACHED */
79 	}
80 	/* parent; assume fdopen can't fail...  */
81 	if (*type == 'r') {
82 		iop = fdopen(pdes[0], type);
83 		(void)close(pdes[1]);
84 	} else {
85 		iop = fdopen(pdes[1], type);
86 		(void)close(pdes[0]);
87 	}
88 	pids[fileno(iop)] = pid;
89 	return(iop);
90 }
91 
92 pclose(iop)
93 	FILE *iop;
94 {
95 	register int fdes;
96 	long omask;
97 	int stat_loc;
98 	pid_t waitpid();
99 
100 	/*
101 	 * pclose returns -1 if stream is not associated with a
102 	 * `popened' command, or, if already `pclosed'.
103 	 */
104 	if (pids[fdes = fileno(iop)] == 0)
105 		return(-1);
106 	(void)fclose(iop);
107 	omask = sigblock(sigmask(SIGINT)|sigmask(SIGQUIT)|sigmask(SIGHUP));
108 	stat_loc = waitpid(pids[fdes], &stat_loc, 0) == -1 ?
109 	    -1 : WEXITSTATUS(stat_loc);
110 	(void)sigsetmask(omask);
111 	pids[fdes] = 0;
112 	return(stat_loc);
113 }
114