1 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
2 Written by James Clark (jjc@jclark.com)
3
4 This file is part of groff.
5
6 groff is free software; you can redistribute it and/or modify it under
7 the terms of the GNU General Public License as published by the Free
8 Software Foundation, either version 3 of the License, or
9 (at your option) any later version.
10
11 groff is distributed in the hope that it will be useful, but WITHOUT ANY
12 WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 for more details.
15
16 You should have received a copy of the GNU General Public License
17 along with this program. If not, see <http://www.gnu.org/licenses/>. */
18
19 #ifdef HAVE_CONFIG_H
20 #include <config.h>
21 #endif
22
23 #include <stdio.h>
24 #include <signal.h>
25 #include <errno.h>
26 #include <sys/types.h>
27 #ifdef HAVE_UNISTD_H
28 #include <unistd.h>
29 #endif
30
31 #ifdef HAVE_STRERROR
32 #include <string.h>
33 #else
34 extern char *strerror();
35 #endif
36
37 #ifdef _POSIX_VERSION
38
39 #include <sys/wait.h>
40 #define PID_T pid_t
41
42 #else /* not _POSIX_VERSION */
43
44 /* traditional Unix */
45
46 #define WIFEXITED(s) (((s) & 0377) == 0)
47 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
48 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
49 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
50 #define WTERMSIG(s) ((s) & 0177)
51 #define WSTOPSIG(s) (((s) >> 8) & 0377)
52
53 #ifndef WCOREFLAG
54 #define WCOREFLAG 0200
55 #endif
56
57 #define PID_T int
58
59 #endif /* not _POSIX_VERSION */
60
61 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
62 #ifndef WCOREFLAG
63 #ifdef WCOREFLG
64 #define WCOREFLAG WCOREFLG
65 #endif /* WCOREFLG */
66 #endif /* not WCOREFLAG */
67
68 #ifndef WCOREDUMP
69 #ifdef WCOREFLAG
70 #define WCOREDUMP(s) ((s) & WCOREFLAG)
71 #else /* not WCOREFLAG */
72 #define WCOREDUMP(s) (0)
73 #endif /* WCOREFLAG */
74 #endif /* not WCOREDUMP */
75
76 #include "pipeline.h"
77
78 #define error c_error
79
80 /* Prototype */
81 int run_pipeline(int, char ***, int);
82
83 #ifdef __cplusplus
84 extern "C" {
85 #endif
86
87 extern void error(const char *, const char *, const char *, const char *);
88 extern void c_fatal(const char *, const char *, const char *, const char *);
89 extern const char *i_to_a(int); /* from libgroff */
90
91 #ifdef __cplusplus
92 }
93 #endif
94
95 static void sys_fatal(const char *);
96 static const char *xstrsignal(int);
97
98
99 #if defined(__MSDOS__) \
100 || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
101 || defined(__EMX__)
102
103 #include <process.h>
104 #include <fcntl.h>
105 #include <string.h>
106 #include <stdlib.h>
107
108 #include "nonposix.h"
109
110 static const char *sh = "sh";
111 static const char *cmd = "cmd";
112 static const char *command = "command";
113
114 extern int strcasecmp(const char *, const char *);
115
sbasename(const char * path)116 char *sbasename(const char *path)
117 {
118 char *base;
119 const char *p1, *p2;
120
121 p1 = path;
122 if ((p2 = strrchr(p1, '\\'))
123 || (p2 = strrchr(p1, '/'))
124 || (p2 = strrchr(p1, ':')))
125 p1 = p2 + 1;
126 if ((p2 = strrchr(p1, '.'))
127 && ((strcasecmp(p2, ".exe") == 0)
128 || (strcasecmp(p2, ".com") == 0)))
129 ;
130 else
131 p2 = p1 + strlen(p1);
132
133 base = malloc((size_t)(p2 - p1));
134 strncpy(base, p1, p2 - p1);
135 *(base + (p2 - p1)) = '\0';
136
137 return(base);
138 }
139
140 /* Get the name of the system shell */
system_shell_name(void)141 char *system_shell_name(void)
142 {
143 const char *shell_name;
144
145 /*
146 Use a Unixy shell if it's installed. Use SHELL if set; otherwise,
147 let spawnlp try to find sh; if that fails, use COMSPEC if set; if
148 not, try cmd.exe; if that fails, default to command.com.
149 */
150
151 if ((shell_name = getenv("SHELL")) != NULL)
152 ;
153 else if (spawnlp(_P_WAIT, sh, sh, "-c", ":", NULL) == 0)
154 shell_name = sh;
155 else if ((shell_name = getenv("COMSPEC")) != NULL)
156 ;
157 else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0)
158 shell_name = cmd;
159 else
160 shell_name = command;
161
162 return sbasename(shell_name);
163 }
164
system_shell_dash_c(void)165 const char *system_shell_dash_c(void)
166 {
167 char *shell_name;
168 const char *dash_c;
169
170 shell_name = system_shell_name();
171
172 /* Assume that if the shell name ends in 'sh', it's Unixy */
173 if (strcasecmp(shell_name + strlen(shell_name) - strlen("sh"), "sh") == 0)
174 dash_c = "-c";
175 else
176 dash_c = "/c";
177
178 free(shell_name);
179 return dash_c;
180 }
181
is_system_shell(const char * prog)182 int is_system_shell(const char *prog)
183 {
184 int result;
185 char *this_prog, *system_shell;
186
187 if (!prog) /* paranoia */
188 return 0;
189
190 this_prog = sbasename(prog);
191 system_shell = system_shell_name();
192
193 result = strcasecmp(this_prog, system_shell) == 0;
194
195 free(this_prog);
196 free(system_shell);
197
198 return result;
199 }
200
201 #ifdef _WIN32
202
203 /*
204 Windows 32 doesn't have fork(), so we need to start asynchronous child
205 processes with spawn() rather than exec(). If there is more than one
206 command, i.e., a pipeline, the parent must set up each child's I/O
207 redirection prior to the spawn. The original stdout must be restored
208 before spawning the last process in the pipeline, and the original
209 stdin must be restored in the parent after spawning the last process
210 and before waiting for any of the children.
211 */
212
run_pipeline(int ncommands,char *** commands,int no_pipe)213 int run_pipeline(int ncommands, char ***commands, int no_pipe)
214 {
215 int i;
216 int last_input = 0; /* pacify some compilers */
217 int save_stdin = 0;
218 int save_stdout = 0;
219 int ret = 0;
220 char err_str[BUFSIZ];
221 PID_T pids[MAX_COMMANDS];
222
223 for (i = 0; i < ncommands; i++) {
224 int pdes[2];
225 PID_T pid;
226
227 /* If no_pipe is set, just run the commands in sequence
228 to show the version numbers */
229 if (ncommands > 1 && !no_pipe) {
230 /* last command doesn't need a new pipe */
231 if (i < ncommands - 1) {
232 if (pipe(pdes) < 0) {
233 sprintf(err_str, "%s: pipe", commands[i][0]);
234 sys_fatal(err_str);
235 }
236 }
237 /* 1st command; writer */
238 if (i == 0) {
239 /* save stdin */
240 if ((save_stdin = dup(STDIN_FILENO)) < 0)
241 sys_fatal("dup stdin");
242 /* save stdout */
243 if ((save_stdout = dup(STDOUT_FILENO)) < 0)
244 sys_fatal("dup stdout");
245
246 /* connect stdout to write end of pipe */
247 if (dup2(pdes[1], STDOUT_FILENO) < 0) {
248 sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
249 sys_fatal(err_str);
250 }
251 if (close(pdes[1]) < 0) {
252 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
253 sys_fatal(err_str);
254 }
255 /*
256 Save the read end of the pipe so that it can be connected to
257 stdin of the next program in the pipeline during the next
258 pass through the loop.
259 */
260 last_input = pdes[0];
261 }
262 /* reader and writer */
263 else if (i < ncommands - 1) {
264 /* connect stdin to read end of last pipe */
265 if (dup2(last_input, STDIN_FILENO) < 0) {
266 sprintf(err_str, " %s: dup2(stdin)", commands[i][0]);
267 sys_fatal(err_str);
268 }
269 if (close(last_input) < 0) {
270 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
271 sys_fatal(err_str);
272 }
273 /* connect stdout to write end of new pipe */
274 if (dup2(pdes[1], STDOUT_FILENO) < 0) {
275 sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
276 sys_fatal(err_str);
277 }
278 if (close(pdes[1]) < 0) {
279 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
280 sys_fatal(err_str);
281 }
282 last_input = pdes[0];
283 }
284 /* last command; reader */
285 else {
286 /* connect stdin to read end of last pipe */
287 if (dup2(last_input, STDIN_FILENO) < 0) {
288 sprintf(err_str, "%s: dup2(stdin)", commands[i][0]);
289 sys_fatal(err_str);
290 }
291 if (close(last_input) < 0) {
292 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
293 sys_fatal(err_str);
294 }
295 /* restore original stdout */
296 if (dup2(save_stdout, STDOUT_FILENO) < 0) {
297 sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
298 sys_fatal(err_str);
299 }
300 /* close stdout copy */
301 if (close(save_stdout) < 0) {
302 sprintf(err_str, "%s: close(save_stdout)", commands[i][0]);
303 sys_fatal(err_str);
304 }
305 }
306 }
307 if ((pid = spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) {
308 error("couldn't exec %1: %2",
309 commands[i][0], strerror(errno), (char *)0);
310 fflush(stderr); /* just in case error() doesn't */
311 _exit(EXEC_FAILED_EXIT_STATUS);
312 }
313 pids[i] = pid;
314 }
315
316 if (ncommands > 1 && !no_pipe) {
317 /* restore original stdin if it was redirected */
318 if (dup2(save_stdin, STDIN_FILENO) < 0) {
319 sprintf(err_str, "dup2(save_stdin))");
320 sys_fatal(err_str);
321 }
322 /* close stdin copy */
323 if (close(save_stdin) < 0) {
324 sprintf(err_str, "close(save_stdin)");
325 sys_fatal(err_str);
326 }
327 }
328
329 for (i = 0; i < ncommands; i++) {
330 int status;
331 PID_T pid;
332
333 pid = pids[i];
334 if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
335 sprintf(err_str, "%s: wait", commands[i][0]);
336 sys_fatal(err_str);
337 }
338 else if (status != 0)
339 ret |= 1;
340 }
341 return ret;
342 }
343
344 #else /* not _WIN32 */
345
346 /* MSDOS doesn't have 'fork', so we need to simulate the pipe by running
347 the programs in sequence with standard streams redirected to and
348 from temporary files.
349 */
350
351
352 /* A signal handler that just records that a signal has happened. */
353 static int child_interrupted;
354
signal_catcher(int signo)355 static RETSIGTYPE signal_catcher(int signo)
356 {
357 child_interrupted++;
358 }
359
run_pipeline(int ncommands,char *** commands,int no_pipe)360 int run_pipeline(int ncommands, char ***commands, int no_pipe)
361 {
362 int save_stdin = dup(0);
363 int save_stdout = dup(1);
364 char *tmpfiles[2];
365 int infile = 0;
366 int outfile = 1;
367 int i, f, ret = 0;
368
369 /* Choose names for a pair of temporary files to implement the pipeline.
370 Microsoft's 'tempnam' uses the directory specified by 'getenv("TMP")'
371 if it exists; in case it doesn't, try the GROFF alternatives, or
372 'getenv("TEMP")' as last resort -- at least one of these had better
373 be set, since Microsoft's default has a high probability of failure. */
374 char *tmpdir;
375 if ((tmpdir = getenv("GROFF_TMPDIR")) == NULL
376 && (tmpdir = getenv("TMPDIR")) == NULL)
377 tmpdir = getenv("TEMP");
378
379 /* Don't use 'tmpnam' here: Microsoft's implementation yields unusable
380 file names if current directory is on network share with read-only
381 root. */
382 tmpfiles[0] = tempnam(tmpdir, NULL);
383 tmpfiles[1] = tempnam(tmpdir, NULL);
384
385 for (i = 0; i < ncommands; i++) {
386 int exit_status;
387 RETSIGTYPE (*prev_handler)(int);
388
389 if (i && !no_pipe) {
390 /* redirect stdin from temp file */
391 f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
392 if (f < 0)
393 sys_fatal("open stdin");
394 if (dup2(f, 0) < 0)
395 sys_fatal("dup2 stdin");
396 if (close(f) < 0)
397 sys_fatal("close stdin");
398 }
399 if ((i < ncommands - 1) && !no_pipe) {
400 /* redirect stdout to temp file */
401 f = open(tmpfiles[outfile], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
402 if (f < 0)
403 sys_fatal("open stdout");
404 if (dup2(f, 1) < 0)
405 sys_fatal("dup2 stdout");
406 if (close(f) < 0)
407 sys_fatal("close stdout");
408 }
409 else if (dup2(save_stdout, 1) < 0)
410 sys_fatal("restore stdout");
411
412 /* run the program */
413 child_interrupted = 0;
414 prev_handler = signal(SIGINT, signal_catcher);
415 exit_status = spawnvp(P_WAIT, commands[i][0], commands[i]);
416 signal(SIGINT, prev_handler);
417 if (child_interrupted) {
418 error("%1: Interrupted", commands[i][0], (char *)0, (char *)0);
419 ret |= 2;
420 }
421 else if (exit_status < 0) {
422 error("couldn't exec %1: %2",
423 commands[i][0], strerror(errno), (char *)0);
424 fflush(stderr); /* just in case error() doesn't */
425 ret |= 4;
426 }
427 if (exit_status != 0)
428 ret |= 1;
429 /* There's no sense to continue with the pipe if one of the
430 programs has ended abnormally, is there? */
431 if (ret != 0)
432 break;
433 /* swap temp files: make output of this program be input for the next */
434 infile = 1 - infile;
435 outfile = 1 - outfile;
436 }
437 if (dup2(save_stdin, 0) < 0)
438 sys_fatal("restore stdin");
439 unlink(tmpfiles[0]);
440 unlink(tmpfiles[1]);
441 return ret;
442 }
443
444 #endif /* not _WIN32 */
445
446 #else /* not __MSDOS__, not _WIN32 */
447
run_pipeline(int ncommands,char *** commands,int no_pipe)448 int run_pipeline(int ncommands, char ***commands, int no_pipe)
449 {
450 int i;
451 int last_input = 0;
452 PID_T pids[MAX_COMMANDS];
453 int ret = 0;
454 int proc_count = ncommands;
455
456 for (i = 0; i < ncommands; i++) {
457 int pdes[2];
458 PID_T pid;
459
460 if ((i != ncommands - 1) && !no_pipe) {
461 if (pipe(pdes) < 0)
462 sys_fatal("pipe");
463 }
464 pid = fork();
465 if (pid < 0)
466 sys_fatal("fork");
467 if (pid == 0) {
468 /* child */
469 if (last_input != 0) {
470 if (close(0) < 0)
471 sys_fatal("close");
472 if (dup(last_input) < 0)
473 sys_fatal("dup");
474 if (close(last_input) < 0)
475 sys_fatal("close");
476 }
477 if ((i != ncommands - 1) && !no_pipe) {
478 if (close(1) < 0)
479 sys_fatal("close");
480 if (dup(pdes[1]) < 0)
481 sys_fatal("dup");
482 if (close(pdes[1]) < 0)
483 sys_fatal("close");
484 if (close(pdes[0]))
485 sys_fatal("close");
486 }
487 execvp(commands[i][0], commands[i]);
488 error("couldn't exec %1: %2",
489 commands[i][0], strerror(errno), (char *)0);
490 fflush(stderr); /* just in case error() doesn't */
491 _exit(EXEC_FAILED_EXIT_STATUS);
492 }
493 /* in the parent */
494 if (last_input != 0) {
495 if (close(last_input) < 0)
496 sys_fatal("close");
497 }
498 if ((i != ncommands - 1) && !no_pipe) {
499 if (close(pdes[1]) < 0)
500 sys_fatal("close");
501 last_input = pdes[0];
502 }
503 pids[i] = pid;
504 }
505 while (proc_count > 0) {
506 int status;
507 PID_T pid = wait(&status);
508
509 if (pid < 0)
510 sys_fatal("wait");
511 for (i = 0; i < ncommands; i++)
512 if (pids[i] == pid) {
513 pids[i] = -1;
514 --proc_count;
515 if (WIFSIGNALED(status)) {
516 int sig = WTERMSIG(status);
517 #ifdef SIGPIPE
518 if (sig == SIGPIPE) {
519 if (i == ncommands - 1) {
520 /* This works around a problem that occurred when using the
521 rerasterize action in gxditview. What seemed to be
522 happening (on SunOS 4.1.1) was that pclose() closed the
523 pipe and waited for groff, gtroff got a SIGPIPE, but
524 gpic blocked writing to gtroff, and so groff blocked
525 waiting for gpic and gxditview blocked waiting for
526 groff. I don't understand why gpic wasn't getting a
527 SIGPIPE. */
528 int j;
529
530 for (j = 0; j < ncommands; j++)
531 if (pids[j] > 0)
532 (void)kill(pids[j], SIGPIPE);
533 }
534 }
535 else
536 #endif /* SIGPIPE */
537 {
538 error("%1: %2%3",
539 commands[i][0],
540 xstrsignal(sig),
541 WCOREDUMP(status) ? " (core dumped)" : "");
542 ret |= 2;
543 }
544 }
545 else if (WIFEXITED(status)) {
546 int exit_status = WEXITSTATUS(status);
547
548 if (exit_status == EXEC_FAILED_EXIT_STATUS)
549 ret |= 4;
550 else if (exit_status != 0)
551 ret |= 1;
552 }
553 else
554 error("unexpected status %1", i_to_a(status), (char *)0, (char *)0);
555 break;
556 }
557 }
558 return ret;
559 }
560
561 #endif /* not __MSDOS__, not _WIN32 */
562
sys_fatal(const char * s)563 static void sys_fatal(const char *s)
564 {
565 c_fatal("%1: %2", s, strerror(errno), (char *)0);
566 }
567
xstrsignal(int n)568 static const char *xstrsignal(int n)
569 {
570 static char buf[sizeof("Signal ") + 1 + sizeof(int) * 3];
571
572 #ifdef NSIG
573 #if HAVE_DECL_SYS_SIGLIST
574 if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
575 return sys_siglist[n];
576 #endif /* HAVE_DECL_SYS_SIGLIST */
577 #endif /* NSIG */
578 sprintf(buf, "Signal %d", n);
579 return buf;
580 }
581