1 /* Copyright (C) 1989-2018 Free Software Foundation, Inc.
2 Written by James Clark (jjc@jclark.com)
4 This file is part of groff.
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.
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
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/>. */
26 #include <sys/types.h>
34 extern char *strerror();
42 #else /* not _POSIX_VERSION */
44 /* traditional Unix */
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)
54 #define WCOREFLAG 0200
59 #endif /* not _POSIX_VERSION */
61 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
64 #define WCOREFLAG WCOREFLG
66 #endif /* not WCOREFLAG */
70 #define WCOREDUMP(s) ((s) & WCOREFLAG)
71 #else /* not WCOREFLAG */
72 #define WCOREDUMP(s) (0)
73 #endif /* WCOREFLAG */
74 #endif /* not WCOREDUMP */
81 int run_pipeline(int, char ***, int);
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 */
95 static void sys_fatal(const char *);
96 static const char *xstrsignal(int);
99 #if defined(__MSDOS__) \
100 || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
108 #include "nonposix.h"
110 static const char *sh = "sh";
111 static const char *cmd = "cmd";
112 static const char *command = "command";
114 extern int strcasecmp(const char *, const char *);
116 char *sbasename(const char *path)
122 if ((p2 = strrchr(p1, '\\'))
123 || (p2 = strrchr(p1, '/'))
124 || (p2 = strrchr(p1, ':')))
126 if ((p2 = strrchr(p1, '.'))
127 && ((strcasecmp(p2, ".exe") == 0)
128 || (strcasecmp(p2, ".com") == 0)))
131 p2 = p1 + strlen(p1);
133 base = malloc((size_t)(p2 - p1));
134 strncpy(base, p1, p2 - p1);
135 *(base + (p2 - p1)) = '\0';
140 /* Get the name of the system shell */
141 char *system_shell_name(void)
143 const char *shell_name;
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.
151 if ((shell_name = getenv("SHELL")) != NULL)
153 else if (spawnlp(_P_WAIT, sh, sh, "-c", ":", NULL) == 0)
155 else if ((shell_name = getenv("COMSPEC")) != NULL)
157 else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0)
160 shell_name = command;
162 return sbasename(shell_name);
165 const char *system_shell_dash_c(void)
170 shell_name = system_shell_name();
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)
182 int is_system_shell(const char *prog)
185 char *this_prog, *system_shell;
187 if (!prog) /* paranoia */
190 this_prog = sbasename(prog);
191 system_shell = system_shell_name();
193 result = strcasecmp(this_prog, system_shell) == 0;
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.
213 int run_pipeline(int ncommands, char ***commands, int no_pipe)
216 int last_input = 0; /* pacify some compilers */
220 char err_str[BUFSIZ];
221 PID_T pids[MAX_COMMANDS];
223 for (i = 0; i < ncommands; i++) {
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]);
237 /* 1st command; writer */
240 if ((save_stdin = dup(STDIN_FILENO)) < 0)
241 sys_fatal("dup stdin");
243 if ((save_stdout = dup(STDOUT_FILENO)) < 0)
244 sys_fatal("dup stdout");
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]);
251 if (close(pdes[1]) < 0) {
252 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
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.
260 last_input = pdes[0];
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]);
269 if (close(last_input) < 0) {
270 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
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]);
278 if (close(pdes[1]) < 0) {
279 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
282 last_input = pdes[0];
284 /* last command; reader */
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]);
291 if (close(last_input) < 0) {
292 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
295 /* restore original stdout */
296 if (dup2(save_stdout, STDOUT_FILENO) < 0) {
297 sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
300 /* close stdout copy */
301 if (close(save_stdout) < 0) {
302 sprintf(err_str, "%s: close(save_stdout)", commands[i][0]);
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);
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))");
322 /* close stdin copy */
323 if (close(save_stdin) < 0) {
324 sprintf(err_str, "close(save_stdin)");
329 for (i = 0; i < ncommands; i++) {
334 if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
335 sprintf(err_str, "%s: wait", commands[i][0]);
338 else if (status != 0)
344 #else /* not _WIN32 */
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.
352 /* A signal handler that just records that a signal has happened. */
353 static int child_interrupted;
355 static RETSIGTYPE signal_catcher(int signo)
360 int run_pipeline(int ncommands, char ***commands, int no_pipe)
362 int save_stdin = dup(0);
363 int save_stdout = dup(1);
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. */
375 if ((tmpdir = getenv("GROFF_TMPDIR")) == NULL
376 && (tmpdir = getenv("TMPDIR")) == NULL)
377 tmpdir = getenv("TEMP");
379 /* Don't use 'tmpnam' here: Microsoft's implementation yields unusable
380 file names if current directory is on network share with read-only
382 tmpfiles[0] = tempnam(tmpdir, NULL);
383 tmpfiles[1] = tempnam(tmpdir, NULL);
385 for (i = 0; i < ncommands; i++) {
387 RETSIGTYPE (*prev_handler)(int);
390 /* redirect stdin from temp file */
391 f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
393 sys_fatal("open stdin");
395 sys_fatal("dup2 stdin");
397 sys_fatal("close stdin");
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);
403 sys_fatal("open stdout");
405 sys_fatal("dup2 stdout");
407 sys_fatal("close stdout");
409 else if (dup2(save_stdout, 1) < 0)
410 sys_fatal("restore stdout");
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);
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 */
427 if (exit_status != 0)
429 /* There's no sense to continue with the pipe if one of the
430 programs has ended abnormally, is there? */
433 /* swap temp files: make output of this program be input for the next */
435 outfile = 1 - outfile;
437 if (dup2(save_stdin, 0) < 0)
438 sys_fatal("restore stdin");
444 #endif /* not _WIN32 */
446 #else /* not __MSDOS__, not _WIN32 */
448 int run_pipeline(int ncommands, char ***commands, int no_pipe)
452 PID_T pids[MAX_COMMANDS];
454 int proc_count = ncommands;
456 for (i = 0; i < ncommands; i++) {
460 if ((i != ncommands - 1) && !no_pipe) {
469 if (last_input != 0) {
472 if (dup(last_input) < 0)
474 if (close(last_input) < 0)
477 if ((i != ncommands - 1) && !no_pipe) {
480 if (dup(pdes[1]) < 0)
482 if (close(pdes[1]) < 0)
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);
494 if (last_input != 0) {
495 if (close(last_input) < 0)
498 if ((i != ncommands - 1) && !no_pipe) {
499 if (close(pdes[1]) < 0)
501 last_input = pdes[0];
505 while (proc_count > 0) {
507 PID_T pid = wait(&status);
511 for (i = 0; i < ncommands; i++)
512 if (pids[i] == pid) {
515 if (WIFSIGNALED(status)) {
516 int sig = WTERMSIG(status);
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
530 for (j = 0; j < ncommands; j++)
532 (void)kill(pids[j], SIGPIPE);
541 WCOREDUMP(status) ? " (core dumped)" : "");
545 else if (WIFEXITED(status)) {
546 int exit_status = WEXITSTATUS(status);
548 if (exit_status == EXEC_FAILED_EXIT_STATUS)
550 else if (exit_status != 0)
554 error("unexpected status %1", i_to_a(status), (char *)0, (char *)0);
561 #endif /* not __MSDOS__, not _WIN32 */
563 static void sys_fatal(const char *s)
565 c_fatal("%1: %2", s, strerror(errno), (char *)0);
568 static const char *xstrsignal(int n)
570 static char buf[sizeof("Signal ") + 1 + sizeof(int) * 3];
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 */
578 sprintf(buf, "Signal %d", n);