* src/include/nonposix.h (write, dup, dup2, close) [_MSC_VER]:
[s-roff.git] / src / roff / groff / pipeline.c
blobb51ed50e5bccc69f28056ee168fa0cdab0224823
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
10 version.
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
15 for more details.
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. */
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <stdio.h>
26 #include <signal.h>
27 #include <errno.h>
28 #include <sys/types.h>
29 #ifdef HAVE_UNISTD_H
30 #include <unistd.h>
31 #endif
33 #ifdef HAVE_STRERROR
34 #include <string.h>
35 #else
36 extern char *strerror();
37 #endif
39 #ifdef _POSIX_VERSION
41 #include <sys/wait.h>
42 #define PID_T pid_t
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)
55 #ifndef WCOREFLAG
56 #define WCOREFLAG 0200
57 #endif
59 #define PID_T int
61 #endif /* not _POSIX_VERSION */
63 /* SVR4 uses WCOREFLG; Net 2 uses WCOREFLAG. */
64 #ifndef WCOREFLAG
65 #ifdef WCOREFLG
66 #define WCOREFLAG WCOREFLG
67 #endif /* WCOREFLG */
68 #endif /* not WCOREFLAG */
70 #ifndef WCOREDUMP
71 #ifdef WCOREFLAG
72 #define WCOREDUMP(s) ((s) & WCOREFLAG)
73 #else /* not WCOREFLAG */
74 #define WCOREDUMP(s) (0)
75 #endif /* WCOREFLAG */
76 #endif /* not WCOREDUMP */
78 #include "pipeline.h"
80 #define error c_error
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__)) \
91 || defined(__EMX__)
93 #include <process.h>
94 #include <fcntl.h>
95 #include <ctype.h>
96 #include <string.h>
97 #include <stdlib.h>
99 #include "nonposix.h"
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)
109 char *base;
110 const char *p1, *p2;
112 p1 = path;
113 if ((p2 = strrchr(p1, '\\'))
114 || (p2 = strrchr(p1, '/'))
115 || (p2 = strrchr(p1, ':')))
116 p1 = p2 + 1;
117 if ((p2 = strrchr(p1, '.'))
118 && ((strcasecmp(p2, ".exe") == 0)
119 || (strcasecmp(p2, ".com") == 0)))
121 else
122 p2 = p1 + strlen(p1);
124 base = malloc((size_t)(p2 - p1));
125 strncpy(base, p1, p2 - p1);
126 *(base + (p2 - p1)) = '\0';
128 return(base);
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)
145 shell_name = sh;
146 else if ((shell_name = getenv("COMSPEC")) != NULL)
148 else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0)
149 shell_name = cmd;
150 else
151 shell_name = command;
153 return sbasename(shell_name);
156 const char *system_shell_dash_c(void)
158 char *shell_name;
159 const char *dash_c;
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)
165 dash_c = "-c";
166 else
167 dash_c = "/c";
169 free(shell_name);
170 return dash_c;
173 int is_system_shell(const char *prog)
175 int result;
176 char *this_prog, *system_shell;
178 if (!prog) /* paranoia */
179 return 0;
181 this_prog = sbasename(prog);
182 system_shell = system_shell_name();
184 result = strcasecmp(this_prog, system_shell) == 0;
186 free(this_prog);
187 free(system_shell);
189 return result;
192 #ifdef _WIN32
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)
206 int i;
207 int last_input;
208 int save_stdin;
209 int save_stdout;
210 int ret = 0;
211 char err_str[BUFSIZ];
212 PID_T pids[MAX_COMMANDS];
214 for (i = 0; i < ncommands; i++) {
215 int pdes[2];
216 PID_T pid;
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]);
225 sys_fatal(err_str);
228 /* 1st command; writer */
229 if (i == 0) {
230 /* save stdin */
231 if ((save_stdin = dup(STDIN_FILENO)) < 0)
232 sys_fatal("dup stdin");
233 /* save stdout */
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]);
240 sys_fatal(err_str);
242 if (close(pdes[1]) < 0) {
243 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
244 sys_fatal(err_str);
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]);
258 sys_fatal(err_str);
260 if (close(last_input) < 0) {
261 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
262 sys_fatal(err_str);
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]);
267 sys_fatal(err_str);
269 if (close(pdes[1]) < 0) {
270 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]);
271 sys_fatal(err_str);
273 last_input = pdes[0];
275 /* last command; reader */
276 else {
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]);
280 sys_fatal(err_str);
282 if (close(last_input) < 0) {
283 sprintf(err_str, "%s: close(last_input)", commands[i][0]);
284 sys_fatal(err_str);
286 /* restore original stdout */
287 if (dup2(save_stdout, STDOUT_FILENO) < 0) {
288 sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]);
289 sys_fatal(err_str);
291 /* close stdout copy */
292 if (close(save_stdout) < 0) {
293 sprintf(err_str, "%s: close(save_stdout)", commands[i][0]);
294 sys_fatal(err_str);
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);
304 pids[i] = pid;
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))");
311 sys_fatal(err_str);
313 /* close stdin copy */
314 if (close(save_stdin) < 0) {
315 sprintf(err_str, "close(save_stdin)");
316 sys_fatal(err_str);
320 for (i = 0; i < ncommands; i++) {
321 int status;
322 PID_T pid;
324 pid = pids[i];
325 if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) {
326 sprintf(err_str, "%s: wait", commands[i][0]);
327 sys_fatal(err_str);
329 else if (status != 0)
330 ret |= 1;
332 return ret;
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)
348 child_interrupted++;
351 int run_pipeline(int ncommands, char ***commands, int no_pipe)
353 int save_stdin = dup(0);
354 int save_stdout = dup(1);
355 char *tmpfiles[2];
356 int infile = 0;
357 int outfile = 1;
358 int i, f, ret = 0;
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. */
365 char *tmpdir;
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
372 root. */
373 tmpfiles[0] = tempnam(tmpdir, NULL);
374 tmpfiles[1] = tempnam(tmpdir, NULL);
376 for (i = 0; i < ncommands; i++) {
377 int exit_status;
378 RETSIGTYPE (*prev_handler)(int);
380 if (i && !no_pipe) {
381 /* redirect stdin from temp file */
382 f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666);
383 if (f < 0)
384 sys_fatal("open stdin");
385 if (dup2(f, 0) < 0)
386 sys_fatal("dup2 stdin");
387 if (close(f) < 0)
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);
393 if (f < 0)
394 sys_fatal("open stdout");
395 if (dup2(f, 1) < 0)
396 sys_fatal("dup2 stdout");
397 if (close(f) < 0)
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);
410 ret |= 2;
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 */
416 ret |= 4;
418 if (exit_status != 0)
419 ret |= 1;
420 /* There's no sense to continue with the pipe if one of the
421 programs has ended abnormally, is there? */
422 if (ret != 0)
423 break;
424 /* swap temp files: make output of this program be input for the next */
425 infile = 1 - infile;
426 outfile = 1 - outfile;
428 if (dup2(save_stdin, 0) < 0)
429 sys_fatal("restore stdin");
430 unlink(tmpfiles[0]);
431 unlink(tmpfiles[1]);
432 return ret;
435 #endif /* not _WIN32 */
437 #else /* not __MSDOS__, not _WIN32 */
439 int run_pipeline(int ncommands, char ***commands, int no_pipe)
441 int i;
442 int last_input = 0;
443 PID_T pids[MAX_COMMANDS];
444 int ret = 0;
445 int proc_count = ncommands;
447 for (i = 0; i < ncommands; i++) {
448 int pdes[2];
449 PID_T pid;
451 if ((i != ncommands - 1) && !no_pipe) {
452 if (pipe(pdes) < 0)
453 sys_fatal("pipe");
455 pid = fork();
456 if (pid < 0)
457 sys_fatal("fork");
458 if (pid == 0) {
459 /* child */
460 if (last_input != 0) {
461 if (close(0) < 0)
462 sys_fatal("close");
463 if (dup(last_input) < 0)
464 sys_fatal("dup");
465 if (close(last_input) < 0)
466 sys_fatal("close");
468 if ((i != ncommands - 1) && !no_pipe) {
469 if (close(1) < 0)
470 sys_fatal("close");
471 if (dup(pdes[1]) < 0)
472 sys_fatal("dup");
473 if (close(pdes[1]) < 0)
474 sys_fatal("close");
475 if (close(pdes[0]))
476 sys_fatal("close");
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);
484 /* in the parent */
485 if (last_input != 0) {
486 if (close(last_input) < 0)
487 sys_fatal("close");
489 if ((i != ncommands - 1) && !no_pipe) {
490 if (close(pdes[1]) < 0)
491 sys_fatal("close");
492 last_input = pdes[0];
494 pids[i] = pid;
496 while (proc_count > 0) {
497 int status;
498 PID_T pid = wait(&status);
500 if (pid < 0)
501 sys_fatal("wait");
502 for (i = 0; i < ncommands; i++)
503 if (pids[i] == pid) {
504 pids[i] = -1;
505 --proc_count;
506 if (WIFSIGNALED(status)) {
507 int sig = WTERMSIG(status);
508 #ifdef SIGPIPE
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
518 SIGPIPE. */
519 int j;
521 for (j = 0; j < ncommands; j++)
522 if (pids[j] > 0)
523 (void)kill(pids[j], SIGPIPE);
526 else
527 #endif /* SIGPIPE */
529 error("%1: %2%3",
530 commands[i][0],
531 xstrsignal(sig),
532 WCOREDUMP(status) ? " (core dumped)" : "");
533 ret |= 2;
536 else if (WIFEXITED(status)) {
537 int exit_status = WEXITSTATUS(status);
539 if (exit_status == EXEC_FAILED_EXIT_STATUS)
540 ret |= 4;
541 else if (exit_status != 0)
542 ret |= 1;
544 else
545 error("unexpected status %1", i_to_a(status), (char *)0, (char *)0);
546 break;
549 return ret;
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];
563 #ifdef NSIG
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 */
568 #endif /* NSIG */
569 sprintf(buf, "Signal %d", n);
570 return buf;