1 /* Copyright (C) 1989, 1990, 1991, 1992, 2000, 2001, 2002, 2003, 2004
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, 59 Temple Place - Suite 330, Boston, MA 02111-1307, 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 */
81 extern void error(const char *, const char *, const char *, const char *);
82 extern void c_fatal(const char *, const char *, const char *, const char *);
84 static void sys_fatal(const char *);
85 static const char *xstrsignal(int);
86 const char *i_to_a(int); // from libgroff
89 #if defined(__MSDOS__) \
90 || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \
101 static const char *sh
= "sh";
102 static const char *cmd
= "cmd";
103 static const char *command
= "command";
105 extern int strcasecmp(const char *, const char *);
107 char *sbasename(const char *path
)
113 if ((p2
= strrchr(p1
, '\\'))
114 || (p2
= strrchr(p1
, '/'))
115 || (p2
= strrchr(p1
, ':')))
117 if ((p2
= strrchr(p1
, '.'))
118 && ((strcasecmp(p2
, ".exe") == 0)
119 || (strcasecmp(p2
, ".com") == 0)))
122 p2
= p1
+ strlen(p1
);
124 base
= malloc((size_t)(p2
- p1
));
125 strncpy(base
, p1
, p2
- p1
);
126 *(base
+ (p2
- p1
)) = '\0';
131 /* Get the name of the system shell */
132 char *system_shell_name(void)
134 const char *shell_name
;
137 Use a Unixy shell if it's installed. Use SHELL if set; otherwise,
138 let spawnlp try to find sh; if that fails, use COMSPEC if set; if
139 not, try cmd.exe; if that fails, default to command.com.
142 if ((shell_name
= getenv("SHELL")) != NULL
)
144 else if (spawnlp(_P_WAIT
, sh
, sh
, "-c", ":", NULL
) == 0)
146 else if ((shell_name
= getenv("COMSPEC")) != NULL
)
148 else if (spawnlp(_P_WAIT
, cmd
, cmd
, "/c", ";", NULL
) == 0)
151 shell_name
= command
;
153 return sbasename(shell_name
);
156 const char *system_shell_dash_c(void)
161 shell_name
= system_shell_name();
163 /* Assume that if the shell name ends in "sh", it's Unixy */
164 if (strcasecmp(shell_name
+ strlen(shell_name
) - strlen("sh"), "sh") == 0)
173 int is_system_shell(const char *prog
)
176 char *this_prog
, *system_shell
;
178 if (!prog
) /* paranoia */
181 this_prog
= sbasename(prog
);
182 system_shell
= system_shell_name();
184 result
= strcasecmp(this_prog
, system_shell
) == 0;
195 Windows 32 doesn't have fork(), so we need to start asynchronous child
196 processes with spawn() rather than exec(). If there is more than one
197 command, i.e., a pipeline, the parent must set up each child's I/O
198 redirection prior to the spawn. The original stdout must be restored
199 before spawning the last process in the pipeline, and the original
200 stdin must be restored in the parent after spawning the last process
201 and before waiting for any of the children.
204 int run_pipeline(int ncommands
, char ***commands
, int no_pipe
)
211 char err_str
[BUFSIZ
];
212 PID_T pids
[MAX_COMMANDS
];
214 for (i
= 0; i
< ncommands
; i
++) {
218 /* If no_pipe is set, just run the commands in sequence
219 to show the version numbers */
220 if (ncommands
> 1 && !no_pipe
) {
221 /* last command doesn't need a new pipe */
222 if (i
< ncommands
- 1) {
223 if (pipe(pdes
) < 0) {
224 sprintf(err_str
, "%s: pipe", commands
[i
][0]);
228 /* 1st command; writer */
231 if ((save_stdin
= dup(STDIN_FILENO
)) < 0)
232 sys_fatal("dup stdin");
234 if ((save_stdout
= dup(STDOUT_FILENO
)) < 0)
235 sys_fatal("dup stdout");
237 /* connect stdout to write end of pipe */
238 if (dup2(pdes
[1], STDOUT_FILENO
) < 0) {
239 sprintf(err_str
, "%s: dup2(stdout)", commands
[i
][0]);
242 if (close(pdes
[1]) < 0) {
243 sprintf(err_str
, "%s: close(pipe[WRITE])", commands
[i
][0]);
247 Save the read end of the pipe so that it can be connected to
248 stdin of the next program in the pipeline during the next
249 pass through the loop.
251 last_input
= pdes
[0];
253 /* reader and writer */
254 else if (i
< ncommands
- 1) {
255 /* connect stdin to read end of last pipe */
256 if (dup2(last_input
, STDIN_FILENO
) < 0) {
257 sprintf(err_str
, " %s: dup2(stdin)", commands
[i
][0]);
260 if (close(last_input
) < 0) {
261 sprintf(err_str
, "%s: close(last_input)", commands
[i
][0]);
264 /* connect stdout to write end of new pipe */
265 if (dup2(pdes
[1], STDOUT_FILENO
) < 0) {
266 sprintf(err_str
, "%s: dup2(stdout)", commands
[i
][0]);
269 if (close(pdes
[1]) < 0) {
270 sprintf(err_str
, "%s: close(pipe[WRITE])", commands
[i
][0]);
273 last_input
= pdes
[0];
275 /* last command; reader */
277 /* connect stdin to read end of last pipe */
278 if (dup2(last_input
, STDIN_FILENO
) < 0) {
279 sprintf(err_str
, "%s: dup2(stdin)", commands
[i
][0]);
282 if (close(last_input
) < 0) {
283 sprintf(err_str
, "%s: close(last_input)", commands
[i
][0]);
286 /* restore original stdout */
287 if (dup2(save_stdout
, STDOUT_FILENO
) < 0) {
288 sprintf(err_str
, "%s: dup2(save_stdout))", commands
[i
][0]);
291 /* close stdout copy */
292 if (close(save_stdout
) < 0) {
293 sprintf(err_str
, "%s: close(save_stdout)", commands
[i
][0]);
298 if ((pid
= spawnvp(_P_NOWAIT
, commands
[i
][0], commands
[i
])) < 0) {
299 error("couldn't exec %1: %2",
300 commands
[i
][0], strerror(errno
), (char *)0);
301 fflush(stderr
); /* just in case error() doesn't */
302 _exit(EXEC_FAILED_EXIT_STATUS
);
307 if (ncommands
> 1 && !no_pipe
) {
308 /* restore original stdin if it was redirected */
309 if (dup2(save_stdin
, STDIN_FILENO
) < 0) {
310 sprintf(err_str
, "dup2(save_stdin))");
313 /* close stdin copy */
314 if (close(save_stdin
) < 0) {
315 sprintf(err_str
, "close(save_stdin)");
320 for (i
= 0; i
< ncommands
; i
++) {
325 if ((pid
= WAIT(&status
, pid
, _WAIT_CHILD
)) < 0) {
326 sprintf(err_str
, "%s: wait", commands
[i
][0]);
329 else if (status
!= 0)
335 #else /* not _WIN32 */
337 /* MSDOS doesn't have `fork', so we need to simulate the pipe by running
338 the programs in sequence with standard streams redirected to and
339 from temporary files.
343 /* A signal handler that just records that a signal has happened. */
344 static int child_interrupted
;
346 static RETSIGTYPE
signal_catcher(int signo
)
351 int run_pipeline(int ncommands
, char ***commands
, int no_pipe
)
353 int save_stdin
= dup(0);
354 int save_stdout
= dup(1);
360 /* Choose names for a pair of temporary files to implement the pipeline.
361 Microsoft's `tempnam' uses the directory specified by `getenv("TMP")'
362 if it exists; in case it doesn't, try the GROFF alternatives, or
363 `getenv("TEMP")' as last resort -- at least one of these had better
364 be set, since Microsoft's default has a high probability of failure. */
366 if ((tmpdir
= getenv("GROFF_TMPDIR")) == NULL
367 && (tmpdir
= getenv("TMPDIR")) == NULL
)
368 tmpdir
= getenv("TEMP");
370 /* Don't use `tmpnam' here: Microsoft's implementation yields unusable
371 file names if current directory is on network share with read-only
373 tmpfiles
[0] = tempnam(tmpdir
, NULL
);
374 tmpfiles
[1] = tempnam(tmpdir
, NULL
);
376 for (i
= 0; i
< ncommands
; i
++) {
378 RETSIGTYPE (*prev_handler
)(int);
381 /* redirect stdin from temp file */
382 f
= open(tmpfiles
[infile
], O_RDONLY
|O_BINARY
, 0666);
384 sys_fatal("open stdin");
386 sys_fatal("dup2 stdin");
388 sys_fatal("close stdin");
390 if ((i
< ncommands
- 1) && !no_pipe
) {
391 /* redirect stdout to temp file */
392 f
= open(tmpfiles
[outfile
], O_WRONLY
|O_CREAT
|O_TRUNC
|O_BINARY
, 0666);
394 sys_fatal("open stdout");
396 sys_fatal("dup2 stdout");
398 sys_fatal("close stdout");
400 else if (dup2(save_stdout
, 1) < 0)
401 sys_fatal("restore stdout");
403 /* run the program */
404 child_interrupted
= 0;
405 prev_handler
= signal(SIGINT
, signal_catcher
);
406 exit_status
= spawnvp(P_WAIT
, commands
[i
][0], commands
[i
]);
407 signal(SIGINT
, prev_handler
);
408 if (child_interrupted
) {
409 error("%1: Interrupted", commands
[i
][0], (char *)0, (char *)0);
412 else if (exit_status
< 0) {
413 error("couldn't exec %1: %2",
414 commands
[i
][0], strerror(errno
), (char *)0);
415 fflush(stderr
); /* just in case error() doesn't */
418 if (exit_status
!= 0)
420 /* There's no sense to continue with the pipe if one of the
421 programs has ended abnormally, is there? */
424 /* swap temp files: make output of this program be input for the next */
426 outfile
= 1 - outfile
;
428 if (dup2(save_stdin
, 0) < 0)
429 sys_fatal("restore stdin");
435 #endif /* not _WIN32 */
437 #else /* not __MSDOS__, not _WIN32 */
439 int run_pipeline(int ncommands
, char ***commands
, int no_pipe
)
443 PID_T pids
[MAX_COMMANDS
];
445 int proc_count
= ncommands
;
447 for (i
= 0; i
< ncommands
; i
++) {
451 if ((i
!= ncommands
- 1) && !no_pipe
) {
460 if (last_input
!= 0) {
463 if (dup(last_input
) < 0)
465 if (close(last_input
) < 0)
468 if ((i
!= ncommands
- 1) && !no_pipe
) {
471 if (dup(pdes
[1]) < 0)
473 if (close(pdes
[1]) < 0)
478 execvp(commands
[i
][0], commands
[i
]);
479 error("couldn't exec %1: %2",
480 commands
[i
][0], strerror(errno
), (char *)0);
481 fflush(stderr
); /* just in case error() doesn't */
482 _exit(EXEC_FAILED_EXIT_STATUS
);
485 if (last_input
!= 0) {
486 if (close(last_input
) < 0)
489 if ((i
!= ncommands
- 1) && !no_pipe
) {
490 if (close(pdes
[1]) < 0)
492 last_input
= pdes
[0];
496 while (proc_count
> 0) {
498 PID_T pid
= wait(&status
);
502 for (i
= 0; i
< ncommands
; i
++)
503 if (pids
[i
] == pid
) {
506 if (WIFSIGNALED(status
)) {
507 int sig
= WTERMSIG(status
);
509 if (sig
== SIGPIPE
) {
510 if (i
== ncommands
- 1) {
511 /* This works around a problem that occurred when using the
512 rerasterize action in gxditview. What seemed to be
513 happening (on SunOS 4.1.1) was that pclose() closed the
514 pipe and waited for groff, gtroff got a SIGPIPE, but
515 gpic blocked writing to gtroff, and so groff blocked
516 waiting for gpic and gxditview blocked waiting for
517 groff. I don't understand why gpic wasn't getting a
521 for (j
= 0; j
< ncommands
; j
++)
523 (void)kill(pids
[j
], SIGPIPE
);
532 WCOREDUMP(status
) ? " (core dumped)" : "");
536 else if (WIFEXITED(status
)) {
537 int exit_status
= WEXITSTATUS(status
);
539 if (exit_status
== EXEC_FAILED_EXIT_STATUS
)
541 else if (exit_status
!= 0)
545 error("unexpected status %1", i_to_a(status
), (char *)0, (char *)0);
552 #endif /* not __MSDOS__, not _WIN32 */
554 static void sys_fatal(const char *s
)
556 c_fatal("%1: %2", s
, strerror(errno
), (char *)0);
559 static const char *xstrsignal(int n
)
561 static char buf
[sizeof("Signal ") + 1 + sizeof(int) * 3];
564 #if HAVE_DECL_SYS_SIGLIST
565 if (n
>= 0 && n
< NSIG
&& sys_siglist
[n
] != 0)
566 return sys_siglist
[n
];
567 #endif /* HAVE_DECL_SYS_SIGLIST */
569 sprintf(buf
, "Signal %d", n
);