1 /* pipe.c - for opening a process as a pipe and reading both stderr and stdout together
2    Copyright (C) 1996-2017 Paul Sheer
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
17    02111-1307, USA.
18  */
19 
20 #include <config.h>
21 #include "global.h"
22 #include "pipe-headers.h"
23 #include <my_string.h>
24 
25 #include "pool.h"
26 
27 #include "mad.h"
28 
29 #ifndef _PATH_DEV
30 #define _PATH_DEV "/dev/"
31 #endif
32 
33 #define _PATH_DEV_PTYXX _PATH_DEV "ptyXX"
34 
35 int data_read_ready (int f);
36 int data_read_wait (int f);
37 int data_write_ready (int f);
38 int data_write_wait (int f);
39 pid_t triple_pipe_open (int *in, int *out, int *err, int mix, const char *file, char *const argv[]);
40 char *read_pipe (int fd, int *len);
41 
42 #undef min
43 #define min(x,y)     (((x) < (y)) ? (x) : (y))
44 
set_signal_handlers_to_default(void)45 void set_signal_handlers_to_default (void)
46 {
47     signal (SIGHUP, SIG_DFL);
48     signal (SIGQUIT, SIG_DFL);
49     signal (SIGINT, SIG_DFL);
50     signal (SIGTERM, SIG_DFL);
51     signal (SIGABRT, SIG_DFL);
52     signal (SIGCHLD, SIG_DFL);
53     signal (SIGALRM, SIG_IGN);
54 }
55 
56 /* returns non-zero if the file exists in the PATH. mimicks the behavior
57 of execvp */
PATH_search(const char * file)58 int PATH_search (const char *file)
59 {
60     int fd;
61     if (strchr (file, '/')) {
62 	if ((fd = open (file, O_RDONLY)) >= 0) {
63 	    close (fd);
64 	    return 1;
65 	}
66     } else {
67 	char *path, *p, *name;
68 	int len;
69 	if (!(path = getenv ("PATH")))
70 	    return 0;
71 	len = strlen ((char *) file) + 1;
72 	name = (char *) malloc (strlen (path) + len + 1);
73 	p = path;
74 	do {
75 	    path = p;
76 	    if (!(p = strchr (path, ':')))
77 		p = path + strlen (path);
78 	    if (p == path) {	/* double colons */
79 		strcpy (name, (char *) file);
80 	    } else {
81 		memcpy (name, path, (int) (p - path));
82 		strcpy (&name[(int) (p - path)], "/");
83 		strcat (name, (char *) file);
84 	    }
85 	    if ((fd = open (name, O_RDONLY)) >= 0) {
86 		free (name);
87 		close (fd);
88 		return 1;
89 	    }
90 	} while (*p++);
91 	free (name);
92     }
93     return 0;
94 }
95 
96 
97 /*
98    This opens a process as a pipe. 'in', 'out' and 'err' are pointers to file handles
99    which are filled in by popen. 'in' refers to stdin of the process, to
100    which you can write. 'out' and 'err' refer to stdout and stderr of the process
101    from which you can read. 'in', 'out' and 'err' can be passed
102    as NULL if you want to ignore output or input of those pipes.
103    If 'mix' is non-zero, then both stderr and stdout of the process
104    can be read from 'out'. If mix is non-zero, then 'err' must be passed as NULL.
105    Popen forks and then calls execvp (see execvp(3)) --- which must also take argv[0]
106    and args must terminate with a NULL.
107    Returns -1 if the fork failed, and -2 if pipe() failed.
108    Otherwise returns the pid of the child.
109  */
triple_pipe_open(int * in,int * out,int * err,int mix,const char * file,char * const argv[])110 pid_t triple_pipe_open (int *in, int *out, int *err, int mix, const char *file, char *const argv[])
111 {
112     pid_t p;
113     int e;
114     int f0[2], f1[2], f2[2];
115 
116 /* we must at least check if the file is in the PATH and is readable.
117 catching this basic condition helps a lot even though an exec may still
118 fail for other reasons: */
119     if (!PATH_search (file)) {
120 	errno = ENOENT;
121 	return -1;
122     }
123 
124     e = (pipe (f0) | pipe (f1) | pipe (f2));
125 
126     if (e) {
127 	close (f0[0]);
128 	close (f0[1]);
129 	close (f1[0]);
130 	close (f1[1]);
131 	close (f2[0]);
132 	close (f2[1]);
133 	return -2;
134     }
135 
136     p = fork ();
137 
138     if (p == -1) {
139 	close (f0[0]);
140 	close (f0[1]);
141 	close (f1[0]);
142 	close (f1[1]);
143 	close (f2[0]);
144 	close (f2[1]);
145 	return -1;
146     }
147     if (p) {
148 	if (in) {
149 	    *in = f0[1];
150 	} else {
151 	    close (f0[1]);
152 	}
153 	if (out) {
154 	    *out = f1[0];
155 	} else {
156 	    close (f1[0]);
157 	}
158 	if (err) {
159 	    *err = f2[0];
160 	} else {
161 	    close (f2[0]);
162 	}
163 	close (f0[0]);
164 	close (f1[1]);
165 	close (f2[1]);
166 	return p;
167     } else {
168 	int nulldevice_wr, nulldevice_rd;
169 
170 	nulldevice_wr = open ("/dev/null", O_WRONLY);
171 	nulldevice_rd = open ("/dev/null", O_RDONLY);
172 
173 	close (0);
174 	if (in)
175 	    dup (f0[0]);
176 	else
177 	    dup (nulldevice_rd);
178 	close (1);
179 	if (out)
180 	    dup (f1[1]);
181 	else
182 	    dup (nulldevice_wr);
183 	close (2);
184 	if (err)
185 	    dup (f2[1]);
186 	else {
187 	    if (mix)
188 		dup (f1[1]);
189 	    else
190 		dup (nulldevice_wr);
191 	}
192 	close (f0[0]);
193 	close (f0[1]);
194 	close (f1[0]);
195 	close (f1[1]);
196 	close (f2[0]);
197 	close (f2[1]);
198 
199 	close (nulldevice_rd);
200 	close (nulldevice_wr);
201 	set_signal_handlers_to_default ();
202 	execvp (file, argv);
203 	exit (1);
204     }
205     return 0; /* prevents warning */
206 }
207 
208 #if 0
209 #ifndef HAVE_FORKPTY
210 
211 /* This is stolen from libc-5.4.46 with the intention of having
212    this all still work on systems that do not have the forkpty()
213    function (like non-BSD systems like solaris). No idea if it will
214    actually work on these systems. */
215 
216 static int my_openpty (int *amaster, int *aslave, char *name)
217 {
218     char line[] = _PATH_DEV_PTYXX;
219     const char *p, *q;
220     int master, slave, ttygid;
221     struct group *gr;
222     if ((gr = getgrnam ("tty")) != NULL)
223 	ttygid = gr->gr_gid;
224     else
225 	ttygid = -1;
226     for (p = "pqrstuvwxyzabcde"; *p; p++) {
227 	line[sizeof (_PATH_DEV_PTYXX) - 3] = *p;
228 	for (q = "0123456789abcdef"; *q; q++) {
229 	    line[sizeof (_PATH_DEV_PTYXX) - 2] = *q;
230 	    if ((master = open (line, O_RDWR, 0)) == -1) {
231 		if (errno == ENOENT)
232 		    return -1;
233 	    } else {
234 		line[sizeof (_PATH_DEV) - 1] = 't';
235 		chown (line, getuid (), ttygid);
236 		chmod (line, S_IRUSR | S_IWUSR | S_IWGRP);
237 		if ((slave = open (line, O_RDWR, 0)) != -1) {
238 		    *amaster = master;
239 		    *aslave = slave;
240 		    strcpy (name, line);
241 		    return 0;
242 		}
243 		close (master);
244 		line[sizeof (_PATH_DEV) - 1] = 'p';
245 	    }
246 	}
247     }
248     errno = ENOENT;
249     return -1;
250 }
251 
252 static int forkpty (int *amaster, char *name,...)
253 {
254     int master, slave;
255     pid_t pid;
256     if (my_openpty (&master, &slave, name) == -1)
257 	return -1;
258     switch (pid = fork ()) {
259     case -1:
260 	return -1;
261     case 0:
262 	close (master);
263 #ifdef HAVE_SETSID
264 	pid = setsid ();
265 #define HAVE_PID_THIS_TTY
266 #elif defined (HAVE_SETPGRP)
267 	pid = setpgrp (0, 0);
268 #define HAVE_PID_THIS_TTY
269 #endif
270 #ifdef TIOCSCTTY
271 	ioctl (slave, TIOCSCTTY, 0);
272 #ifdef HAVE_PID_THIS_TTY
273 #elif defined (HAVE_TCSETPGRP)
274 	tcsetpgrp (slave, pid);
275 #elif defined (TIOCSPGRP)
276 	ioctl (slave, TIOCSPGRP, &pid);
277 #endif
278 #endif
279 	close (0);
280 	dup (slave);
281 	close (1);
282 	dup (slave);
283 	close (2);
284 	dup (slave);
285 	if (slave > 2)
286 	    close (slave);
287 	return 0;
288     }
289     *amaster = master;
290     close (slave);
291     return pid;
292 }
293 
294 #endif				/* ! HAVE_FORKPTY */
295 
296 static void set_termios (int fd)
297 {
298 #ifdef HAVE_TCGETATTR
299     struct termios tios;
300     memset (&tios, 0, sizeof (tios));
301     if (tcgetattr (fd, &tios) != 0)
302 	return;
303 #ifdef B19200
304 #ifdef OCRNL
305     tios.c_oflag &= ~(ONLCR | OCRNL);
306 #else
307     tios.c_oflag &= ~ONLCR;
308 #endif
309     tios.c_lflag &= ~(ECHO | ICANON | ISIG);
310     tios.c_iflag &= ~(ICRNL);
311 #ifdef VTIME
312     tios.c_cc[VTIME] = 1;
313 #endif
314 #ifdef VMIN
315     tios.c_cc[VMIN] = 1;
316 #endif
317     tios.c_iflag &= ~(ISTRIP);
318 #if defined(TABDLY) && defined(TAB3)
319     if ((tios.c_oflag & TABDLY) == TAB3)
320 	tios.c_oflag &= ~TAB3;
321 #endif
322 /* disable interpretation of ^S: */
323     tios.c_iflag &= ~IXON;
324 #ifdef VDISCARD
325     tios.c_cc[VDISCARD] = 255;
326 #endif
327 #ifdef VEOL2
328     tios.c_cc[VEOL2] = 255;
329 #endif
330 #ifdef VEOL
331     tios.c_cc[VEOL] = 255;
332 #endif
333 #ifdef VLNEXT
334     tios.c_cc[VLNEXT] = 255;
335 #endif
336 #ifdef VREPRINT
337     tios.c_cc[VREPRINT] = 255;
338 #endif
339 #ifdef VSUSP
340     tios.c_cc[VSUSP] = 255;
341 #endif
342 #ifdef VWERASE
343     tios.c_cc[VWERASE] = 255;
344 #endif
345     tcsetattr (fd, TCSADRAIN, &tios);
346 #endif
347 #endif				/* HAVE_TCGETATTR */
348 }
349 
350 pid_t open_under_pty (int *in, int *out, char *line, const char *file, char *const argv[])
351 {
352     int master = 0;
353     char l[80];
354     pid_t p;
355 #ifdef HAVE_FORKPTY
356 #ifdef NEED_WINSIZE
357     struct winsize {
358 	unsigned short ws_row;
359 	unsigned short ws_col;
360 	unsigned short ws_xpixel;
361 	unsigned short ws_ypixel;
362     } win;
363 #else
364     struct winsize win;
365 #endif
366     memset (&win, 0, sizeof (win));
367     p = (pid_t) forkpty (&master, l, NULL, &win);
368 #else
369     p = (pid_t) forkpty (&master, l);
370 #endif
371     if (p == -1)
372 	return -1;
373 #if 0
374     ioctl (master, FIONBIO, &yes);
375     ioctl (master, FIONBIO, &yes);
376 #endif
377     strcpy (line, l);
378     if (p) {
379 	*in = dup (master);
380 	*out = dup (master);
381 	close (master);
382 	return p;
383     }
384     set_termios (0);
385     execvp (file, argv);
386     exit (1);
387     return 0;
388 }
389 #endif
390 
391 #define CHUNK 8192
392 
393 /*
394    Reads all available data and mallocs space for it plus
395    one byte, and sets that byte to zero. If len is non-NULL
396    bytes read is placed in len. If *len is passed non-zero then
397    reads that amount max.
398  */
read_pipe(int fd,int * len)399 char *read_pipe (int fd, int *len)
400 {
401     POOL *p;
402     int c, count = 0;
403     int l = CHUNK;
404     p = pool_init ();
405     if (len)
406 	if (*len)
407 	    if (l > *len)
408 		l = *len;
409     for (;;) {
410 	if (pool_freespace (p) < l + 1)
411 	    pool_advance (p, l + 1);
412 	do {
413 	    c = read (fd, pool_current (p), l);
414 	} while (c < 0 && errno == EINTR);
415 	if (c <= 0)
416 	    break;
417 	count += c;
418 	pool_current (p) += c;
419 	if (len)
420 	    if (*len)
421 		if (pool_length (p) >= l)
422 		    break;
423     }
424     pool_null (p);
425     if (len)
426 	*len = pool_length (p);
427     return (char *) pool_break (p);
428 }
429 
430