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