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) 4 5This file is part of groff. 6 7groff is free software; you can redistribute it and/or modify it under 8the terms of the GNU General Public License as published by the Free 9Software Foundation; either version 2, or (at your option) any later 10version. 11 12groff is distributed in the hope that it will be useful, but WITHOUT ANY 13WARRANTY; without even the implied warranty of MERCHANTABILITY or 14FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License 15for more details. 16 17You should have received a copy of the GNU General Public License along 18with groff; see the file COPYING. If not, write to the Free Software 19Foundation, 51 Franklin St - Fifth Floor, Boston, MA 02110-1301, USA. */ 20 21#ifdef HAVE_CONFIG_H 22#include <config.h> 23#endif 24 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 32 33#ifdef HAVE_STRERROR 34#include <string.h> 35#else 36extern char *strerror(); 37#endif 38 39#ifdef _POSIX_VERSION 40 41#include <sys/wait.h> 42#define PID_T pid_t 43 44#else /* not _POSIX_VERSION */ 45 46/* traditional Unix */ 47 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) 54 55#ifndef WCOREFLAG 56#define WCOREFLAG 0200 57#endif 58 59#define PID_T int 60 61#endif /* not _POSIX_VERSION */ 62 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 */ 69 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 */ 77 78#include "pipeline.h" 79 80#define error c_error 81 82#ifdef __cplusplus 83extern "C" { 84#endif 85 86extern void error(const char *, const char *, const char *, const char *); 87extern void c_fatal(const char *, const char *, const char *, const char *); 88extern const char *i_to_a(int); /* from libgroff */ 89 90#ifdef __cplusplus 91} 92#endif 93 94static void sys_fatal(const char *); 95static const char *xstrsignal(int); 96 97 98#if defined(__MSDOS__) \ 99 || (defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__)) \ 100 || defined(__EMX__) 101 102#include <process.h> 103#include <fcntl.h> 104#include <string.h> 105#include <stdlib.h> 106 107#include "nonposix.h" 108 109static const char *sh = "sh"; 110static const char *cmd = "cmd"; 111static const char *command = "command"; 112 113extern int strcasecmp(const char *, const char *); 114 115char *sbasename(const char *path) 116{ 117 char *base; 118 const char *p1, *p2; 119 120 p1 = path; 121 if ((p2 = strrchr(p1, '\\')) 122 || (p2 = strrchr(p1, '/')) 123 || (p2 = strrchr(p1, ':'))) 124 p1 = p2 + 1; 125 if ((p2 = strrchr(p1, '.')) 126 && ((strcasecmp(p2, ".exe") == 0) 127 || (strcasecmp(p2, ".com") == 0))) 128 ; 129 else 130 p2 = p1 + strlen(p1); 131 132 base = malloc((size_t)(p2 - p1)); 133 strncpy(base, p1, p2 - p1); 134 *(base + (p2 - p1)) = '\0'; 135 136 return(base); 137} 138 139/* Get the name of the system shell */ 140char *system_shell_name(void) 141{ 142 const char *shell_name; 143 144 /* 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. 148 */ 149 150 if ((shell_name = getenv("SHELL")) != NULL) 151 ; 152 else if (spawnlp(_P_WAIT, sh, sh, "-c", ":", NULL) == 0) 153 shell_name = sh; 154 else if ((shell_name = getenv("COMSPEC")) != NULL) 155 ; 156 else if (spawnlp(_P_WAIT, cmd, cmd, "/c", ";", NULL) == 0) 157 shell_name = cmd; 158 else 159 shell_name = command; 160 161 return sbasename(shell_name); 162} 163 164const char *system_shell_dash_c(void) 165{ 166 char *shell_name; 167 const char *dash_c; 168 169 shell_name = system_shell_name(); 170 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) 173 dash_c = "-c"; 174 else 175 dash_c = "/c"; 176 177 free(shell_name); 178 return dash_c; 179} 180 181int is_system_shell(const char *prog) 182{ 183 int result; 184 char *this_prog, *system_shell; 185 186 if (!prog) /* paranoia */ 187 return 0; 188 189 this_prog = sbasename(prog); 190 system_shell = system_shell_name(); 191 192 result = strcasecmp(this_prog, system_shell) == 0; 193 194 free(this_prog); 195 free(system_shell); 196 197 return result; 198} 199 200#ifdef _WIN32 201 202/* 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. 210*/ 211 212int run_pipeline(int ncommands, char ***commands, int no_pipe) 213{ 214 int i; 215 int last_input = 0; /* pacify some compilers */ 216 int save_stdin = 0; 217 int save_stdout = 0; 218 int ret = 0; 219 char err_str[BUFSIZ]; 220 PID_T pids[MAX_COMMANDS]; 221 222 for (i = 0; i < ncommands; i++) { 223 int pdes[2]; 224 PID_T pid; 225 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]); 233 sys_fatal(err_str); 234 } 235 } 236 /* 1st command; writer */ 237 if (i == 0) { 238 /* save stdin */ 239 if ((save_stdin = dup(STDIN_FILENO)) < 0) 240 sys_fatal("dup stdin"); 241 /* save stdout */ 242 if ((save_stdout = dup(STDOUT_FILENO)) < 0) 243 sys_fatal("dup stdout"); 244 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]); 248 sys_fatal(err_str); 249 } 250 if (close(pdes[1]) < 0) { 251 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]); 252 sys_fatal(err_str); 253 } 254 /* 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. 258 */ 259 last_input = pdes[0]; 260 } 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]); 266 sys_fatal(err_str); 267 } 268 if (close(last_input) < 0) { 269 sprintf(err_str, "%s: close(last_input)", commands[i][0]); 270 sys_fatal(err_str); 271 } 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]); 275 sys_fatal(err_str); 276 } 277 if (close(pdes[1]) < 0) { 278 sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]); 279 sys_fatal(err_str); 280 } 281 last_input = pdes[0]; 282 } 283 /* last command; reader */ 284 else { 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]); 288 sys_fatal(err_str); 289 } 290 if (close(last_input) < 0) { 291 sprintf(err_str, "%s: close(last_input)", commands[i][0]); 292 sys_fatal(err_str); 293 } 294 /* restore original stdout */ 295 if (dup2(save_stdout, STDOUT_FILENO) < 0) { 296 sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]); 297 sys_fatal(err_str); 298 } 299 /* close stdout copy */ 300 if (close(save_stdout) < 0) { 301 sprintf(err_str, "%s: close(save_stdout)", commands[i][0]); 302 sys_fatal(err_str); 303 } 304 } 305 } 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); 311 } 312 pids[i] = pid; 313 } 314 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))"); 319 sys_fatal(err_str); 320 } 321 /* close stdin copy */ 322 if (close(save_stdin) < 0) { 323 sprintf(err_str, "close(save_stdin)"); 324 sys_fatal(err_str); 325 } 326 } 327 328 for (i = 0; i < ncommands; i++) { 329 int status; 330 PID_T pid; 331 332 pid = pids[i]; 333 if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) { 334 sprintf(err_str, "%s: wait", commands[i][0]); 335 sys_fatal(err_str); 336 } 337 else if (status != 0) 338 ret |= 1; 339 } 340 return ret; 341} 342 343#else /* not _WIN32 */ 344 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. 348*/ 349 350 351/* A signal handler that just records that a signal has happened. */ 352static int child_interrupted; 353 354static RETSIGTYPE signal_catcher(int signo) 355{ 356 child_interrupted++; 357} 358 359int run_pipeline(int ncommands, char ***commands, int no_pipe) 360{ 361 int save_stdin = dup(0); 362 int save_stdout = dup(1); 363 char *tmpfiles[2]; 364 int infile = 0; 365 int outfile = 1; 366 int i, f, ret = 0; 367 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. */ 373 char *tmpdir; 374 if ((tmpdir = getenv("GROFF_TMPDIR")) == NULL 375 && (tmpdir = getenv("TMPDIR")) == NULL) 376 tmpdir = getenv("TEMP"); 377 378 /* Don't use `tmpnam' here: Microsoft's implementation yields unusable 379 file names if current directory is on network share with read-only 380 root. */ 381 tmpfiles[0] = tempnam(tmpdir, NULL); 382 tmpfiles[1] = tempnam(tmpdir, NULL); 383 384 for (i = 0; i < ncommands; i++) { 385 int exit_status; 386 RETSIGTYPE (*prev_handler)(int); 387 388 if (i && !no_pipe) { 389 /* redirect stdin from temp file */ 390 f = open(tmpfiles[infile], O_RDONLY|O_BINARY, 0666); 391 if (f < 0) 392 sys_fatal("open stdin"); 393 if (dup2(f, 0) < 0) 394 sys_fatal("dup2 stdin"); 395 if (close(f) < 0) 396 sys_fatal("close stdin"); 397 } 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); 401 if (f < 0) 402 sys_fatal("open stdout"); 403 if (dup2(f, 1) < 0) 404 sys_fatal("dup2 stdout"); 405 if (close(f) < 0) 406 sys_fatal("close stdout"); 407 } 408 else if (dup2(save_stdout, 1) < 0) 409 sys_fatal("restore stdout"); 410 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); 418 ret |= 2; 419 } 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 */ 424 ret |= 4; 425 } 426 if (exit_status != 0) 427 ret |= 1; 428 /* There's no sense to continue with the pipe if one of the 429 programs has ended abnormally, is there? */ 430 if (ret != 0) 431 break; 432 /* swap temp files: make output of this program be input for the next */ 433 infile = 1 - infile; 434 outfile = 1 - outfile; 435 } 436 if (dup2(save_stdin, 0) < 0) 437 sys_fatal("restore stdin"); 438 unlink(tmpfiles[0]); 439 unlink(tmpfiles[1]); 440 return ret; 441} 442 443#endif /* not _WIN32 */ 444 445#else /* not __MSDOS__, not _WIN32 */ 446 447int run_pipeline(int ncommands, char ***commands, int no_pipe) 448{ 449 int i; 450 int last_input = 0; 451 PID_T pids[MAX_COMMANDS]; 452 int ret = 0; 453 int proc_count = ncommands; 454 455 for (i = 0; i < ncommands; i++) { 456 int pdes[2]; 457 PID_T pid; 458 459 if ((i != ncommands - 1) && !no_pipe) { 460 if (pipe(pdes) < 0) 461 sys_fatal("pipe"); 462 } 463 pid = fork(); 464 if (pid < 0) 465 sys_fatal("fork"); 466 if (pid == 0) { 467 /* child */ 468 if (last_input != 0) { 469 if (close(0) < 0) 470 sys_fatal("close"); 471 if (dup(last_input) < 0) 472 sys_fatal("dup"); 473 if (close(last_input) < 0) 474 sys_fatal("close"); 475 } 476 if ((i != ncommands - 1) && !no_pipe) { 477 if (close(1) < 0) 478 sys_fatal("close"); 479 if (dup(pdes[1]) < 0) 480 sys_fatal("dup"); 481 if (close(pdes[1]) < 0) 482 sys_fatal("close"); 483 if (close(pdes[0])) 484 sys_fatal("close"); 485 } 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); 491 } 492 /* in the parent */ 493 if (last_input != 0) { 494 if (close(last_input) < 0) 495 sys_fatal("close"); 496 } 497 if ((i != ncommands - 1) && !no_pipe) { 498 if (close(pdes[1]) < 0) 499 sys_fatal("close"); 500 last_input = pdes[0]; 501 } 502 pids[i] = pid; 503 } 504 while (proc_count > 0) { 505 int status; 506 PID_T pid = wait(&status); 507 508 if (pid < 0) 509 sys_fatal("wait"); 510 for (i = 0; i < ncommands; i++) 511 if (pids[i] == pid) { 512 pids[i] = -1; 513 --proc_count; 514 if (WIFSIGNALED(status)) { 515 int sig = WTERMSIG(status); 516#ifdef SIGPIPE 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 526 SIGPIPE. */ 527 int j; 528 529 for (j = 0; j < ncommands; j++) 530 if (pids[j] > 0) 531 (void)kill(pids[j], SIGPIPE); 532 } 533 } 534 else 535#endif /* SIGPIPE */ 536 { 537 error("%1: %2%3", 538 commands[i][0], 539 xstrsignal(sig), 540 WCOREDUMP(status) ? " (core dumped)" : ""); 541 ret |= 2; 542 } 543 } 544 else if (WIFEXITED(status)) { 545 int exit_status = WEXITSTATUS(status); 546 547 if (exit_status == EXEC_FAILED_EXIT_STATUS) 548 ret |= 4; 549 else if (exit_status != 0) 550 ret |= 1; 551 } 552 else 553 error("unexpected status %1", i_to_a(status), (char *)0, (char *)0); 554 break; 555 } 556 } 557 return ret; 558} 559 560#endif /* not __MSDOS__, not _WIN32 */ 561 562static void sys_fatal(const char *s) 563{ 564 c_fatal("%1: %2", s, strerror(errno), (char *)0); 565} 566 567static const char *xstrsignal(int n) 568{ 569 static char buf[sizeof("Signal ") + 1 + sizeof(int) * 3]; 570 571#ifdef NSIG 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 */ 576#endif /* NSIG */ 577 sprintf(buf, "Signal %d", n); 578 return buf; 579} 580