1 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004, 2005
2 Free Software Foundation, Inc.
3 Written by James Clark (jjc@jclark.com)
5 This file is part of groff.
7 groff is free software; you can redistribute it and/or modify it under
8 the terms of the GNU General Public License as published by the Free
9 Software Foundation; either version 2, or (at your option) any later
12 groff is distributed in the hope that it will be useful, but WITHOUT ANY
13 WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
17 You should have received a copy of the GNU General Public License along
18 with groff; see the file COPYING. If not, write to the Free Software
19 Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */
28 #include <sys/types.h>
36 extern char *strerror();
44 #else /* not _POSIX_VERSION */
46 /* traditional Unix */
48 #define WIFEXITED(s) (((s) & 0377) == 0)
49 #define WIFSTOPPED(s) (((s) & 0377) == 0177)
50 #define WIFSIGNALED(s) (((s) & 0377) != 0 && (((s) & 0377) != 0177))
51 #define WEXITSTATUS(s) (((s) >> 8) & 0377)
52 #define WTERMSIG(s) ((s) & 0177)
53 #define WSTOPSIG(s) (((s) >> 8) & 0377)
56 #define WCOREFLAG 0200
61 #endif /* not _POSIX_VERSION */
63 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
66 #define WCOREFLAG WCOREFLG
68 #endif /* not WCOREFLAG */
72 #define WCOREDUMP(s) ((s) & WCOREFLAG)
73 #else /* not WCOREFLAG */
74 #define WCOREDUMP(s) (0)
75 #endif /* WCOREFLAG */
76 #endif /* not WCOREDUMP */
86 extern void error(const char *, const char *, const char *, const char *);
87 extern void c_fatal(const char *, const char *, const char *, const char *);
88 extern const char *i_to_a(int); /* from libgroff */
94 static void sys_fatal(const char *);
95 static const char *xstrsignal(int);
98 #if defined(__MSDOS__) \
99 || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
107 #include "nonposix.h"
109 static const char *sh = "sh";
110 static const char *cmd = "cmd";
111 static const char *command = "command";
113 extern int strcasecmp(const char *, const char *);
115 char *sbasename(const char *path)
121 if ((p2 = strrchr(p1, '\\'))
122 || (p2 = strrchr(p1, '/'))
123 || (p2 = strrchr(p1, ':')))
125 if ((p2 = strrchr(p1, '.'))
126 && ((strcasecmp(p2, ".exe") == 0)
127 || (strcasecmp(p2, ".com") == 0)))
130 p2 = p1 + strlen(p1);
132 base = malloc((size_t)(p2 - p1));
133 strncpy(base, p1, p2 - p1);
134 *(base + (p2 - p1)) = '\0';
139 /* Get the name of the system shell */
140 char *system_shell_name(void)
142 const char *shell_name;
145 Use a Unixy shell if it's installed. Use SHELL if set; otherwise,
146 let spawnlp try to find sh; if that fails, use COMSPEC if set; if
147 not, try cmd.exe; if that fails, default to command.com.
150 if ((shell_name = getenv("SHELL")) != NULL)
152 else if (spawnlp(_P_WAIT, sh, sh, "-c", ":", NULL) == 0)
154 else if ((shell_name = getenv("COMSPEC")) != NULL)
156 else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0)
159 shell_name = command;
161 return sbasename(shell_name);
164 const char *system_shell_dash_c(void)
169 shell_name = system_shell_name();
171 /* Assume that if the shell name ends in "sh", it's Unixy */
172 if (strcasecmp(shell_name + strlen(shell_name) - strlen("sh"), "sh") == 0)
181 int is_system_shell(const char *prog)
184 char *this_prog, *system_shell;
186 if (!prog) /* paranoia */
189 this_prog = sbasename(prog);
190 system_shell = system_shell_name();
192 result = strcasecmp(this_prog, system_shell) == 0;
203 Windows 32 doesn't have fork(), so we need to start asynchronous child
204 processes with spawn() rather than exec(). If there is more than one
205 command, i.e., a pipeline, the parent must set up each child's I/O
206 redirection prior to the spawn. The original stdout must be restored
207 before spawning the last process in the pipeline, and the original
208 stdin must be restored in the parent after spawning the last process
209 and before waiting for any of the children.
212 int run_pipeline(int ncommands, char ***commands, int no_pipe)
215 int last_input = 0; /* pacify some compilers */
219 char err_str[BUFSIZ];
220 PID_T pids[MAX_COMMANDS];
222 for (i = 0; i < ncommands; i++) {
226 /* If no_pipe is set, just run the commands in sequence
227 to show the version numbers */
228 if (ncommands > 1 && !no_pipe) {
229 /* last command doesn't need a new pipe */
230 if (i < ncommands - 1) {
231 if (pipe(pdes) < 0) {
232 sprintf(err_str, "%s: pipe", commands[i][0]);
236 /* 1st command; writer */
239 if ((save_stdin = dup(STDIN_FILENO)) < 0)
240 sys_fatal("dup stdin");
242 if ((save_stdout = dup(STDOUT_FILENO)) < 0)
243 sys_fatal("dup stdout");
245 /* connect stdout to write end of pipe */
246 if (dup2(pdes[1], STDOUT_FILENO) < 0) {
247 sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
250 if (close(pdes[1]) < 0) {
251 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
255 Save the read end of the pipe so that it can be connected to
256 stdin of the next program in the pipeline during the next
257 pass through the loop.
259 last_input = pdes[0];
261 /* reader and writer */
262 else if (i < ncommands - 1) {
263 /* connect stdin to read end of last pipe */
264 if (dup2(last_input, STDIN_FILENO) < 0) {
265 sprintf(err_str, " %s: dup2(stdin)", commands[i][0]);
268 if (close(last_input) < 0) {
269 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
272 /* connect stdout to write end of new pipe */
273 if (dup2(pdes[1], STDOUT_FILENO) < 0) {
274 sprintf(err_str, "%s: dup2(stdout)", commands[i][0]);
277 if (close(pdes[1]) < 0) {
278 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
281 last_input = pdes[0];
283 /* last command; reader */
285 /* connect stdin to read end of last pipe */
286 if (dup2(last_input, STDIN_FILENO) < 0) {
287 sprintf(err_str, "%s: dup2(stdin)", commands[i][0]);
290 if (close(last_input) < 0) {
291 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
294 /* restore original stdout */
295 if (dup2(save_stdout, STDOUT_FILENO) < 0) {
296 sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
299 /* close stdout copy */
300 if (close(save_stdout) < 0) {
301 sprintf(err_str, "%s: close(save_stdout)", commands[i][0]);
306 if ((pid = spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) {
307 error("couldn't exec %1: %2",
308 commands[i][0], strerror(errno), (char *)0);
309 fflush(stderr); /* just in case error() doesn't */
310 _exit(EXEC_FAILED_EXIT_STATUS);
315 if (ncommands > 1 && !no_pipe) {
316 /* restore original stdin if it was redirected */
317 if (dup2(save_stdin, STDIN_FILENO) < 0) {
318 sprintf(err_str, "dup2(save_stdin))");
321 /* close stdin copy */
322 if (close(save_stdin) < 0) {
323 sprintf(err_str, "close(save_stdin)");
328 for (i = 0; i < ncommands; i++) {
333 if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
334 sprintf(err_str, "%s: wait", commands[i][0]);
337 else if (status != 0)
343 #else /* not _WIN32 */
345 /* MSDOS doesn't have `fork', so we need to simulate the pipe by running
346 the programs in sequence with standard streams redirected to and
347 from temporary files.
351 /* A signal handler that just records that a signal has happened. */
352 static int child_interrupted;
354 static RETSIGTYPE signal_catcher(int signo)
359 int run_pipeline(int ncommands, char ***commands, int no_pipe)
361 int save_stdin = dup(0);
362 int save_stdout = dup(1);
368 /* Choose names for a pair of temporary files to implement the pipeline.
369 Microsoft's `tempnam' uses the directory specified by `getenv("TMP")'
370 if it exists; in case it doesn't, try the GROFF alternatives, or
371 `getenv("TEMP")' as last resort -- at least one of these had better
372 be set, since Microsoft's default has a high probability of failure. */
374 if ((tmpdir = getenv("GROFF_TMPDIR")) == NULL
375 && (tmpdir = getenv("TMPDIR")) == NULL)
376 tmpdir = getenv("TEMP");
378 /* Don't use `tmpnam' here: Microsoft's implementation yields unusable
379 file names if current directory is on network share with read-only
381 tmpfiles[0] = tempnam(tmpdir, NULL);
382 tmpfiles[1] = tempnam(tmpdir, NULL);
384 for (i = 0; i < ncommands; i++) {
386 RETSIGTYPE (*prev_handler)(int);
389 /* redirect stdin from temp file */
390 f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
392 sys_fatal("open stdin");
394 sys_fatal("dup2 stdin");
396 sys_fatal("close stdin");
398 if ((i < ncommands - 1) && !no_pipe) {
399 /* redirect stdout to temp file */
400 f = open(tmpfiles[outfile], O_WRONLY|O_CREAT|O_TRUNC|O_BINARY, 0666);
402 sys_fatal("open stdout");
404 sys_fatal("dup2 stdout");
406 sys_fatal("close stdout");
408 else if (dup2(save_stdout, 1) < 0)
409 sys_fatal("restore stdout");
411 /* run the program */
412 child_interrupted = 0;
413 prev_handler = signal(SIGINT, signal_catcher);
414 exit_status = spawnvp(P_WAIT, commands[i][0], commands[i]);
415 signal(SIGINT, prev_handler);
416 if (child_interrupted) {
417 error("%1: Interrupted", commands[i][0], (char *)0, (char *)0);
420 else if (exit_status < 0) {
421 error("couldn't exec %1: %2",
422 commands[i][0], strerror(errno), (char *)0);
423 fflush(stderr); /* just in case error() doesn't */
426 if (exit_status != 0)
428 /* There's no sense to continue with the pipe if one of the
429 programs has ended abnormally, is there? */
432 /* swap temp files: make output of this program be input for the next */
434 outfile = 1 - outfile;
436 if (dup2(save_stdin, 0) < 0)
437 sys_fatal("restore stdin");
443 #endif /* not _WIN32 */
445 #else /* not __MSDOS__, not _WIN32 */
447 int run_pipeline(int ncommands, char ***commands, int no_pipe)
451 PID_T pids[MAX_COMMANDS];
453 int proc_count = ncommands;
455 for (i = 0; i < ncommands; i++) {
459 if ((i != ncommands - 1) && !no_pipe) {
468 if (last_input != 0) {
471 if (dup(last_input) < 0)
473 if (close(last_input) < 0)
476 if ((i != ncommands - 1) && !no_pipe) {
479 if (dup(pdes[1]) < 0)
481 if (close(pdes[1]) < 0)
486 execvp(commands[i][0], commands[i]);
487 error("couldn't exec %1: %2",
488 commands[i][0], strerror(errno), (char *)0);
489 fflush(stderr); /* just in case error() doesn't */
490 _exit(EXEC_FAILED_EXIT_STATUS);
493 if (last_input != 0) {
494 if (close(last_input) < 0)
497 if ((i != ncommands - 1) && !no_pipe) {
498 if (close(pdes[1]) < 0)
500 last_input = pdes[0];
504 while (proc_count > 0) {
506 PID_T pid = wait(&status);
510 for (i = 0; i < ncommands; i++)
511 if (pids[i] == pid) {
514 if (WIFSIGNALED(status)) {
515 int sig = WTERMSIG(status);
517 if (sig == SIGPIPE) {
518 if (i == ncommands - 1) {
519 /* This works around a problem that occurred when using the
520 rerasterize action in gxditview. What seemed to be
521 happening (on SunOS 4.1.1) was that pclose() closed the
522 pipe and waited for groff, gtroff got a SIGPIPE, but
523 gpic blocked writing to gtroff, and so groff blocked
524 waiting for gpic and gxditview blocked waiting for
525 groff. I don't understand why gpic wasn't getting a
529 for (j = 0; j < ncommands; j++)
531 (void)kill(pids[j], SIGPIPE);
540 WCOREDUMP(status) ? " (core dumped)" : "");
544 else if (WIFEXITED(status)) {
545 int exit_status = WEXITSTATUS(status);
547 if (exit_status == EXEC_FAILED_EXIT_STATUS)
549 else if (exit_status != 0)
553 error("unexpected status %1", i_to_a(status), (char *)0, (char *)0);
560 #endif /* not __MSDOS__, not _WIN32 */
562 static void sys_fatal(const char *s)
564 c_fatal("%1: %2", s, strerror(errno), (char *)0);
567 static const char *xstrsignal(int n)
569 static char buf[sizeof("Signal ") + 1 + sizeof(int) * 3];
572 #if HAVE_DECL_SYS_SIGLIST
573 if (n >= 0 && n < NSIG && sys_siglist[n] != 0)
574 return sys_siglist[n];
575 #endif /* HAVE_DECL_SYS_SIGLIST */
577 sprintf(buf, "Signal %d", n);