fpopen.c revision d1154eb460efe588eaed3d439c1caaca149fa362
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 "config.h"
25#include <unistd.h>
26#include <stdlib.h>
27#include <stdio.h>
28#include <errno.h>
29#include <string.h>
30#include <ctype.h>
31
32#define MAX_ARGV 256
33
34extern FILE *fpopen(const char *cmd, const char *mode);
35
36FILE *fpopen(const char *cmd, const char *mode)
37{
38	char	*argv[MAX_ARGV];
39	int	i = 0;
40	char	*buf, *prog = 0;
41	char	*p;
42	int	do_stdin, do_stderr = 0;
43	int	fds[2];
44	pid_t	pid;
45
46	if (!mode) {
47		errno = EFAULT;
48		return NULL;
49	}
50
51	switch (*mode) {
52	case 'r':
53		do_stdin = 0;
54		break;
55	case 'w':
56		do_stdin = 1;
57		break;
58	default:
59		errno = EINVAL;
60		return NULL;
61	}
62	switch (*(mode+1)) {
63	case '&':
64		do_stderr = 1;
65	}
66
67	/*
68	 * Create the argv vector....
69	 */
70	buf = malloc(strlen(cmd)+1);
71	if (!buf)
72		return NULL;
73	strcpy(buf, cmd);
74	p = buf;
75	while (p && *p) {
76		if (isspace(*p)) {
77			p++;
78			continue;
79		}
80		if (i == 0)
81			prog = p;
82		argv[i++] = p;
83		p = strchr(p, ' ');
84		if (p)
85			*p++ = 0;
86	}
87
88	argv[i] = 0;
89
90	/*
91	 * Get the pipe
92	 */
93	if (pipe(fds) < 0)
94		return NULL;
95
96	/* Fork and execute the correct program. */
97	if ((pid = fork()) < 0) {
98		perror("fork");
99		return NULL;
100	} else if (pid == 0) {
101		if (do_stdin) {
102			close(fds[1]);
103			dup2(fds[0], 0);
104		} else {
105			close(fds[0]);
106			dup2(fds[1], 1);
107			if (do_stderr)
108				dup2(fds[1], 2);
109		}
110		(void) execvp(prog, argv);
111		perror(prog);
112		exit(1);
113	}
114	return fdopen(do_stdin ? fds[1] : fds[0], mode);
115}
116
117