OSDN Git Service

merge in master-release history after reset to 2079d768f79f636223d89b988a30209adf8dddbe
[android-x86/external-e2fsprogs.git] / lib / fpopen.c
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
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