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