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