diff options
Diffstat (limited to 'lib/fpopen.c')
-rw-r--r-- | lib/fpopen.c | 116 |
1 files changed, 116 insertions, 0 deletions
diff --git a/lib/fpopen.c b/lib/fpopen.c new file mode 100644 index 0000000..60af208 --- /dev/null +++ b/lib/fpopen.c @@ -0,0 +1,116 @@ +/* + * 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); +} + |