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