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