| /* |
| * 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 <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); |
| } |
| |