blob: 47346e1d4c85eee00b80498a486ae8f7a3f140a0 [file] [log] [blame]
Theodore Ts'of3db3561997-04-26 13:34:30 +00001/*
2 * fpopen.c --- unlike the libc popen, it directly executes the
3 * command instead of call out to the shell.
Theodore Ts'oe2e69ba1999-06-18 01:13:31 +00004 *
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.
Theodore Ts'of3db3561997-04-26 13:34:30 +000022 */
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
33extern FILE *fpopen(const char *cmd, const char *mode);
34
35FILE *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;
Theodore Ts'oe2e69ba1999-06-18 01:13:31 +000041 int do_stdin, do_stderr = 0;
Theodore Ts'of3db3561997-04-26 13:34:30 +000042 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 }
Theodore Ts'oe2e69ba1999-06-18 01:13:31 +000061 switch (*(mode+1)) {
62 case '&':
63 do_stderr = 1;
64 }
Theodore Ts'of3db3561997-04-26 13:34:30 +000065
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);
Theodore Ts'oe2e69ba1999-06-18 01:13:31 +0000106 if (do_stderr)
107 dup2(fds[1], 2);
Theodore Ts'of3db3561997-04-26 13:34:30 +0000108 }
109 (void) execvp(prog, argv);
110 perror(prog);
111 exit(1);
112 }
113 return fdopen(do_stdin ? fds[1] : fds[0], mode);
114}
115