1 /*
2  * fpopen.c --- unlike the libc popen, it directly executes the
3  * command instead of call out to the shell.
4  *
5  * Copyright Theodore Ts'o, 1996-1999.
6  *
7  * Permission to use this file is granted for any purposes, as long as
8  * this copyright statement is kept intact and the author is not held
9  * liable for any damages resulting from the use of this program.
10  *
11  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESS OR IMPLIED
12  * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
13  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE, ALL OF
14  * WHICH ARE HEREBY DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR BE
15  * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
16  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT
17  * OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
18  * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
19  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
20  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
21  * USE OF THIS SOFTWARE.
22  */
23 
24 #include <unistd.h>
25 #include <stdlib.h>
26 #include <stdio.h>
27 #include <errno.h>
28 #include <string.h>
29 #include <ctype.h>
30 
31 #define MAX_ARGV 256
32 
33 extern FILE *fpopen(const char *cmd, const char *mode);
34 
fpopen(const char * cmd,const char * mode)35 FILE *fpopen(const char *cmd, const char *mode)
36 {
37 	char	*argv[MAX_ARGV];
38 	int	i = 0;
39 	char	*buf, *prog = 0;
40 	char	*p;
41 	int	do_stdin, do_stderr = 0;
42 	int	fds[2];
43 	pid_t	pid;
44 
45 	if (!mode) {
46 		errno = EFAULT;
47 		return NULL;
48 	}
49 
50 	switch (*mode) {
51 	case 'r':
52 		do_stdin = 0;
53 		break;
54 	case 'w':
55 		do_stdin = 1;
56 		break;
57 	default:
58 		errno = EINVAL;
59 		return NULL;
60 	}
61 	switch (*(mode+1)) {
62 	case '&':
63 		do_stderr = 1;
64 	}
65 
66 	/*
67 	 * Create the argv vector....
68 	 */
69 	buf = malloc(strlen(cmd)+1);
70 	if (!buf)
71 		return NULL;
72 	strcpy(buf, cmd);
73 	p = buf;
74 	while (p && *p) {
75 		if (isspace(*p)) {
76 			p++;
77 			continue;
78 		}
79 		if (i == 0)
80 			prog = p;
81 		argv[i++] = p;
82 		p = strchr(p, ' ');
83 		if (p)
84 			*p++ = 0;
85 	}
86 
87 	argv[i] = 0;
88 
89 	/*
90 	 * Get the pipe
91 	 */
92 	if (pipe(fds) < 0)
93 		return NULL;
94 
95 	/* Fork and execute the correct program. */
96 	if ((pid = fork()) < 0) {
97 		perror("fork");
98 		return NULL;
99 	} else if (pid == 0) {
100 		if (do_stdin) {
101 			close(fds[1]);
102 			dup2(fds[0], 0);
103 		} else {
104 			close(fds[0]);
105 			dup2(fds[1], 1);
106 			if (do_stderr)
107 				dup2(fds[1], 2);
108 		}
109 		(void) execvp(prog, argv);
110 		perror(prog);
111 		exit(1);
112 	}
113 	return fdopen(do_stdin ? fds[1] : fds[0], mode);
114 }
115 
116