diff options
Diffstat (limited to 'src')
-rw-r--r-- | src/include/nonposix.h | 45 | ||||
-rw-r--r-- | src/libs/libgroff/quotearg.c | 10 | ||||
-rw-r--r-- | src/libs/libgroff/spawnvp.c | 14 | ||||
-rw-r--r-- | src/preproc/html/pre-html.cpp | 129 | ||||
-rw-r--r-- | src/roff/groff/pipeline.c | 64 |
5 files changed, 174 insertions, 88 deletions
diff --git a/src/include/nonposix.h b/src/include/nonposix.h index dfbe6d0a..706729d0 100644 --- a/src/include/nonposix.h +++ b/src/include/nonposix.h @@ -59,17 +59,11 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # define WAIT(s,p,m) _cwait(s,p,m) # define creat(p,m) _creat(p,m) # define read(f,b,s) _read(f,b,s) +# define write(f,b,s) _write(f,b,s) +# define dup(f) _dup(f) +# define dup2(f1,f2) _dup2(f1,f2) +# define close(f) _close(f) # define isatty(f) _isatty(f) - -/* Workaround for broken argument parsing - in child process invoked through MSVC `spawnvp()' function. */ -# ifndef SPAWNVP_C -# undef spawnvp -# define spawnvp spawnvp_wrapper -# undef _spawnvp -# define _spawnvp spawnvp -# endif - # endif # define SET_BINARY(f) do {if (!isatty(f)) setmode(f,O_BINARY);} while(0) # define FOPEN_RB "rb" @@ -123,17 +117,19 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # ifdef __cplusplus extern "C" { # endif - const char * system_shell_name(void); + char * system_shell_name(void); const char * system_shell_dash_c(void); int is_system_shell(const char *); - int spawnvp_wrapper(int, char *, char **); # ifdef __cplusplus } # endif #endif -#if defined(_WIN32) && !defined(__CYGWIN__) +#if defined(_WIN32) && !defined(_UWIN) && !defined(__CYGWIN__) +/* Win32 implementations which use the Microsoft runtime library + * are prone to hanging when a pipe reader quits with unread data in the pipe. + * `gtroff' avoids this, by invoking `FLUSH_INPUT_PIPE()', defined as ... */ # define FLUSH_INPUT_PIPE(fd) \ do if (!isatty(fd)) \ { \ @@ -141,7 +137,30 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ while (read(fd, drain, sizeof(drain)) > 0) \ ; \ } while (0) + +/* The Microsoft runtime library also has a broken argument passing mechanism, + * which may result in improper grouping of arguments passed to a child process + * by the `spawn()' family of functions. In `groff', only the `spawnvp()' + * function is affected; we work around this defect, by substituting a + * wrapper function in place of `spawnvp()' calls. */ + +# ifdef __cplusplus + extern "C" { +# endif + int spawnvp_wrapper(int, char *, char **); +# ifdef __cplusplus + } +# endif +# ifndef SPAWN_FUNCTION_WRAPPERS +# undef spawnvp +# define spawnvp spawnvp_wrapper +# undef _spawnvp +# define _spawnvp spawnvp +# endif /* SPAWN_FUNCTION_WRAPPERS */ + #else +/* Other implementations do not suffer from Microsoft runtime bugs, + * but `gtroff' requires a dummy definition for FLUSH_INPUT_PIPE() */ # define FLUSH_INPUT_PIPE(fd) do {} while(0) #endif diff --git a/src/libs/libgroff/quotearg.c b/src/libs/libgroff/quotearg.c index 62edfd27..728a29ea 100644 --- a/src/libs/libgroff/quotearg.c +++ b/src/libs/libgroff/quotearg.c @@ -28,7 +28,7 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ /* Define the default mechanism, and messages, for error reporting * (user may substitute a preferred alternative, by defining his own * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED - * and QUOTE_ARG_REALLOC_FAILED, in a header file called 'nonposix.h'). + * and QUOTE_ARG_REALLOC_FAILED, in the header file `nonposix.h'). */ #include "nonposix.h" @@ -37,10 +37,10 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY) #endif #ifndef QUOTE_ARG_MALLOC_ERROR -# define QUOTE_ARG_MALLOC_ERROR "malloc:buffer allocation failed" +# define QUOTE_ARG_MALLOC_ERROR "malloc: Buffer allocation failed" #endif #ifndef QUOTE_ARG_REALLOC_ERROR -# define QUOTE_ARG_REALLOC_ERROR "realloc:buffer resize failed" +# define QUOTE_ARG_REALLOC_ERROR "realloc: Buffer resize failed" #endif extern char *program_name; /* main program must define this */ @@ -58,8 +58,8 @@ needs_quoting(const char *string) if (string == NULL) /* ignore NULL strings */ return FALSE; - if (*string == '\0') /* preserve explicit null arguments */ - return TRUE; + if (*string == '\0') /* explicit arguments of zero length */ + return TRUE; /* need quoting, so they aren't discarded */ while (*string) { /* Scan non-NULL strings, up to '\0' terminator, diff --git a/src/libs/libgroff/spawnvp.c b/src/libs/libgroff/spawnvp.c index 3022fdbd..e185ec30 100644 --- a/src/libs/libgroff/spawnvp.c +++ b/src/libs/libgroff/spawnvp.c @@ -29,12 +29,12 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # include <process.h> #endif -#define SPAWNVP_C 1 +#define SPAWN_FUNCTION_WRAPPERS 1 /* Define the default mechanism, and messages, for error reporting * (user may substitute a preferred alternative, by defining his own - * implementation of the macros REPORT_ERROR, QUOTE_ARG_MALLOC_FAILED - * and QUOTE_ARG_REALLOC_FAILED, in a header file called 'nonposix.h'). + * implementation of the macros REPORT_ERROR and ARGV_MALLOC_ERROR, + * in the header file `nonposix.h'). */ #include "nonposix.h" @@ -42,8 +42,8 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ #ifndef REPORT_ERROR # define REPORT_ERROR(WHY) fprintf(stderr, "%s:%s\n", program_name, WHY) #endif -#ifndef SPAWNVP_MALLOC_ERROR -# define SPAWNVP_MALLOC_ERROR "malloc:allocation for 'argv' failed" +#ifndef ARGV_MALLOC_ERROR +# define ARGV_MALLOC_ERROR "malloc: Allocation for 'argv' failed" #endif extern char *program_name; @@ -84,12 +84,12 @@ spawnvp_wrapper(int mode, char *path, char **argv) /* If we didn't get enough space, * then complain, and bail out gracefully. */ - REPORT_ERROR(SPAWNVP_MALLOC_ERROR); + REPORT_ERROR(ARGV_MALLOC_ERROR); exit(1); } /* Now copy the passed `argv' into our new vector, - * quoting it contents as required. */ + * quoting its contents as required. */ for (i = 0; i < argc; i++) quoted_argv[i] = quote_arg(argv[i]); diff --git a/src/preproc/html/pre-html.cpp b/src/preproc/html/pre-html.cpp index 604547d1..0eb0772e 100644 --- a/src/preproc/html/pre-html.cpp +++ b/src/preproc/html/pre-html.cpp @@ -70,28 +70,23 @@ Foundation, 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. */ # include <process.h> // for `spawn...' # include <fcntl.h> // for attributes of pipes -# if defined(__CYGWIN__) || defined(_UWIN) \ - || defined(__MINGW32__) || defined(_WIN32) +# if defined(__CYGWIN__) || defined(_UWIN) || defined(_WIN32) // These Win32 implementations allow parent and `spawn...'ed child to // multitask asynchronously. -# ifdef __cplusplus -extern "C" spawnvp_wrapper(int, char *, char **); -# endif - # define MAY_SPAWN_ASYNCHRONOUS_CHILD 1 # else // Others may adopt MS-DOS behaviour where parent must sleep, -// from `spawn...' until child terminates. */ +// from `spawn...' until child terminates. # define MAY_SPAWN_ASYNCHRONOUS_CHILD 0 -# endif /* not defined __CYGWIN__, _UWIN, or __MINGW32__ */ +# endif /* not defined __CYGWIN__, _UWIN, or _WIN32 */ -# if defined(DEBUGGING) && !defined(DEBUG_FILE) +# if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR) /* When we are building a DEBUGGING version we need to tell pre-grohtml where to put intermediate files (the DEBUGGING version will preserve these on exit). @@ -101,11 +96,11 @@ extern "C" spawnvp_wrapper(int, char *, char **); `c:/temp' instead. (Note that user may choose to override this by supplying a definition such as - -DDEBUG_FILE="d:/path/to/debug/files/" + -DDEBUG_FILE_DIR=d:/path/to/debug/files + + in the CPPFLAGS to `make'.) */ - in the CPPFLAGS to `make'. If overriding in this manner, the trailing - `/' MUST be included in the definition.) */ -# define DEBUG_FILE "c:/temp/" +# define DEBUG_FILE_DIR c:/temp # endif #else /* not __MSDOS__ or _WIN32 */ @@ -115,20 +110,31 @@ extern "C" spawnvp_wrapper(int, char *, char **); # define MAY_FORK_CHILD_PROCESS 1 # define MAY_SPAWN_ASYNCHRONOUS_CHILD 1 -# if defined(DEBUGGING) && !defined(DEBUG_FILE) +# if defined(DEBUGGING) && !defined(DEBUG_FILE_DIR) /* For a DEBUGGING version, on the UNIX host, we can also usually rely on being able to use `/tmp' for temporary file storage. (Note that, as in the __MSDOS__ or _WIN32 case above, the user may override this by defining - -DDEBUG_FILE="/path/to/debug/files/" + -DDEBUG_FILE_DIR=/path/to/debug/files - in the CPPFLAGS, again noting that the trailing `/' is REQUIRED.) */ -# define DEBUG_FILE "/tmp/" + in the CPPFLAGS.) */ + +# define DEBUG_FILE_DIR /tmp # endif #endif /* not __MSDOS__ or _WIN32 */ +#ifdef DEBUGGING +// For a DEBUGGING version, we need some additional macros, +// to direct the captured debug mode output to appropriately named files +// in the specified DEBUG_FILE_DIR. + +# define DEBUG_TEXT(text) #text +# define DEBUG_NAME(text) DEBUG_TEXT(text) +# define DEBUG_FILE(name) DEBUG_NAME(DEBUG_FILE_DIR) "/" name +#endif + extern "C" const char *Version_string; #include "pre-html.h" @@ -744,8 +750,11 @@ void char_buffer::skip_until_newline(char_block **t, int *i) } #define DEVICE_FORMAT(filter) (filter == HTML_OUTPUT_FILTER) -#define HTML_OUTPUT_FILTER 0 -#define IMAGE_OUTPUT_FILTER 1 +#define HTML_OUTPUT_FILTER 0 +#define IMAGE_OUTPUT_FILTER 1 +#define OUTPUT_STREAM(name) creat((name), S_IWUSR | S_IRUSR) +#define PS_OUTPUT_STREAM OUTPUT_STREAM(psFileName) +#define REGION_OUTPUT_STREAM OUTPUT_STREAM(regionFileName) /* * emit_troff_output - Write formatted buffer content to the troff @@ -1276,7 +1285,6 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) sys_fatal("pipe"); #if MAY_FORK_CHILD_PROCESS - // This is the UNIX process model. To invoke our post-processor, // we must `fork' the current process. @@ -1290,8 +1298,8 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) set_redirection(STDIN_FILENO, pipedes[0]); - // The parent process will be writing this data so we should release - // the child's writeable handle on the pipe. + // The parent process will be writing this data, so we should release + // the child's writeable handle on the pipe, since we have no use for it. if (close(pipedes[1]) < 0) sys_fatal("close"); @@ -1301,10 +1309,8 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) if (filter == IMAGE_OUTPUT_FILTER) { // with BOTH `stdout' AND `stderr' diverted to files. - set_redirection(STDOUT_FILENO, - creat(psFileName, S_IWUSR | S_IRUSR)); - set_redirection(STDERR_FILENO, - creat(regionFileName, S_IWUSR | S_IRUSR)); + set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM); + set_redirection(STDERR_FILENO, REGION_OUTPUT_STREAM); } // Now we are ready to launch the output filter. @@ -1321,14 +1327,14 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) else { // This is the parent process fork. We will be writing data to the - // filter pipeline but we can close our handle on the output end of - // the pipe so we don't block the output data stream. + // filter pipeline, and the child will be reading it. We have no further + // use for our read handle on the pipe, and should close it. if (close(pipedes[0]) < 0) sys_fatal("close"); - // Now we redirect the `stdout' stream to the inlet end of the pipe. - // Push out the appropiately formatted data to the filter. + // Now we redirect the `stdout' stream to the inlet end of the pipe, + // and push out the appropiately formatted data to the filter. pipedes[1] = save_and_redirect(STDOUT_FILENO, pipedes[1]); emit_troff_output(DEVICE_FORMAT(filter)); @@ -1338,16 +1344,16 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) set_redirection(STDOUT_FILENO, pipedes[1]); - // Finally we must wait for the child process to complete. + // Finally, we must wait for the child process to complete. - if (WAIT(&status, &child_pid, _WAIT_CHILD) != child_pid) + if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid) sys_fatal("wait"); } #elif MAY_SPAWN_ASYNCHRONOUS_CHILD - int i, j; - + // We do not have `fork', (or we prefer not to use it), + // but asynchronous processes are allowed, passing data through pipes. // This should be ok for most Win32 systems and is preferred to `fork' // for starting child processes under Cygwin. @@ -1357,6 +1363,9 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) pipedes[0] = save_and_redirect(STDIN_FILENO, pipedes[0]); + // for the Win32 model, + // we need special provision for saving BOTH `stdout' and `stderr'. + int saved_stdout = dup(STDOUT_FILENO); int saved_stderr = STDERR_FILENO; @@ -1366,10 +1375,8 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) // with BOTH `stdout' AND `stderr' diverted to files while saving a // duplicate handle for `stderr'. - set_redirection(STDOUT_FILENO, creat(psFileName, S_IWUSR | S_IRUSR)); - saved_stderr = - save_and_redirect(STDERR_FILENO, - creat(regionFileName, S_IWUSR | S_IRUSR)); + set_redirection(STDOUT_FILENO, PS_OUTPUT_STREAM); + saved_stderr = save_and_redirect(STDERR_FILENO, REGION_OUTPUT_STREAM); } // We then use an asynchronous spawn request to start the post-processor. @@ -1382,20 +1389,38 @@ int char_buffer::run_output_filter(int filter, int argc, char **argv) } // Once the post-processor has been started we revert our `stdin' - // to its original saved source which also closes the readable handle + // to its original saved source, which also closes the readable handle // for the pipe. set_redirection(STDIN_FILENO, pipedes[0]); - set_redirection(STDERR_FILENO, saved_stderr); + // if we redirected `stderr', for use by the image post-processor, + // then we also need to reinstate its original assignment. + + if (filter == IMAGE_OUTPUT_FILTER) + set_redirection(STDERR_FILENO, saved_stderr); + + // Now we redirect the `stdout' stream to the inlet end of the pipe, + // and push out the appropiately formatted data to the filter. + set_redirection(STDOUT_FILENO, pipedes[1]); emit_troff_output(DEVICE_FORMAT(filter)); + // After emitting all the data we close our connection to the inlet + // end of the pipe so the child process will detect end of data. + set_redirection(STDOUT_FILENO, saved_stdout); + // And finally, we must wait for the child process to complete. + if (WAIT(&status, child_pid, _WAIT_CHILD) != child_pid) sys_fatal("wait"); +#else /* can't do asynchronous pipes! */ + + // TODO: code to support an MS-DOS style process model + // should go here + #endif /* MAY_FORK_CHILD_PROCESS or MAY_SPAWN_ASYNCHRONOUS_CHILD */ return 0; @@ -1424,10 +1449,12 @@ int char_buffer::do_html(int argc, char *argv[]) argc++; #if defined(DEBUGGING) +# define HTML_DEBUG_STREAM OUTPUT_STREAM(htmlFileName) // slight security risk so only enabled if compiled with defined(DEBUGGING) if (debug) { - set_redirection(STDOUT_FILENO, creat(htmlFileName, S_IWUSR | S_IRUSR)); + int saved_stdout = save_and_redirect(STDOUT_FILENO, HTML_DEBUG_STREAM); emit_troff_output(DEVICE_FORMAT(HTML_OUTPUT_FILTER)); + set_redirection(STDOUT_FILENO, saved_stdout); } #endif @@ -1459,10 +1486,12 @@ int char_buffer::do_image(int argc, char *argv[]) argc++; #if defined(DEBUGGING) +# define IMAGE_DEBUG_STREAM OUTPUT_STREAM(troffFileName) // slight security risk so only enabled if compiled with defined(DEBUGGING) if (debug) { - set_redirection(STDOUT_FILENO, creat(troffFileName, S_IWUSR | S_IRUSR)); + int saved_stdout = save_and_redirect(STDOUT_FILENO, IMAGE_DEBUG_STREAM); emit_troff_output(DEVICE_FORMAT(IMAGE_OUTPUT_FILTER)); + set_redirection(STDOUT_FILENO, saved_stdout); } #endif @@ -1480,7 +1509,7 @@ static void usage(FILE *stream) fprintf(stream, "usage: %s troffname [-Iimage_name] [-Dimage_directory]\n" " [-P-o vertical_image_offset] [-P-i image_resolution]\n" - " [troff flags] [files]\n", + " [troff flags]\n", program_name); fprintf(stream, " vertical_image_offset (default %d/72 of an inch)\n", @@ -1602,12 +1631,12 @@ static int scanArguments(int argc, char **argv) static int makeTempFiles(void) { #if defined(DEBUGGING) - psFileName = DEBUG_FILE"prehtml-ps"; - regionFileName = DEBUG_FILE"prehtml-region"; - imagePageName = DEBUG_FILE"prehtml-page"; - psPageName = DEBUG_FILE"prehtml-psn"; - troffFileName = DEBUG_FILE"prehtml-troff"; - htmlFileName = DEBUG_FILE"prehtml-html"; + psFileName = DEBUG_FILE("prehtml-ps"); + regionFileName = DEBUG_FILE("prehtml-region"); + imagePageName = DEBUG_FILE("prehtml-page"); + psPageName = DEBUG_FILE("prehtml-psn"); + troffFileName = DEBUG_FILE("prehtml-troff"); + htmlFileName = DEBUG_FILE("prehtml-html"); #else /* not DEBUGGING */ FILE *f; @@ -1667,7 +1696,7 @@ int main(int argc, char **argv) fprintf(stderr, "%s: invoked with %d arguments ...\n", argv[0], argc); for (i = 0; i < argc; i++) fprintf(stderr, "%2d: %s\n", i, argv[i]); - if ((dump = fopen(DEBUG_FILE"pre-html-data", "wb")) != NULL) { + if ((dump = fopen(DEBUG_FILE("pre-html-data"), "wb")) != NULL) { while((i = fgetc(stdin)) >= 0) fputc(i, dump); fclose(dump); diff --git a/src/roff/groff/pipeline.c b/src/roff/groff/pipeline.c index 2d7ba362..b51ed50e 100644 --- a/src/roff/groff/pipeline.c +++ b/src/roff/groff/pipeline.c @@ -102,6 +102,8 @@ static const char *sh = "sh"; static const char *cmd = "cmd"; static const char *command = "command"; +extern int strcasecmp(const char *, const char *); + char *sbasename(const char *path) { char *base; @@ -189,13 +191,22 @@ int is_system_shell(const char *prog) #ifdef _WIN32 -/* Windows 32 doesn't have fork() */ +/* + Windows 32 doesn't have fork(), so we need to start asynchronous child + processes with spawn() rather than exec(). If there is more than one + command, i.e., a pipeline, the parent must set up each child's I/O + redirection prior to the spawn. The original stdout must be restored + before spawning the last process in the pipeline, and the original + stdin must be restored in the parent after spawning the last process + and before waiting for any of the children. +*/ int run_pipeline(int ncommands, char ***commands, int no_pipe) { - int save_stdin, save_stdout; int i; - int last_input = 0; + int last_input; + int save_stdin; + int save_stdout; int ret = 0; char err_str[BUFSIZ]; PID_T pids[MAX_COMMANDS]; @@ -209,18 +220,22 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe) if (ncommands > 1 && !no_pipe) { /* last command doesn't need a new pipe */ if (i < ncommands - 1) { - if (_pipe(pdes, BUFSIZ, _O_BINARY | _O_NOINHERIT) < 0) { + if (pipe(pdes) < 0) { sprintf(err_str, "%s: pipe", commands[i][0]); sys_fatal(err_str); } } /* 1st command; writer */ if (i == 0) { + /* save stdin */ + if ((save_stdin = dup(STDIN_FILENO)) < 0) + sys_fatal("dup stdin"); /* save stdout */ - if ((save_stdout = _dup(STDOUT_FILENO)) < 0) + if ((save_stdout = dup(STDOUT_FILENO)) < 0) sys_fatal("dup stdout"); + /* connect stdout to write end of pipe */ - if (_dup2(pdes[1], STDOUT_FILENO) < 0) { + if (dup2(pdes[1], STDOUT_FILENO) < 0) { sprintf(err_str, "%s: dup2(stdout)", commands[i][0]); sys_fatal(err_str); } @@ -228,17 +243,26 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe) sprintf(err_str, "%s: close(pipe[WRITE])", commands[i][0]); sys_fatal(err_str); } + /* + Save the read end of the pipe so that it can be connected to + stdin of the next program in the pipeline during the next + pass through the loop. + */ last_input = pdes[0]; } /* reader and writer */ else if (i < ncommands - 1) { /* connect stdin to read end of last pipe */ - if (_dup2(last_input, STDIN_FILENO) < 0) { + if (dup2(last_input, STDIN_FILENO) < 0) { sprintf(err_str, " %s: dup2(stdin)", commands[i][0]); sys_fatal(err_str); } + if (close(last_input) < 0) { + sprintf(err_str, "%s: close(last_input)", commands[i][0]); + sys_fatal(err_str); + } /* connect stdout to write end of new pipe */ - if (_dup2(pdes[1], STDOUT_FILENO) < 0) { + if (dup2(pdes[1], STDOUT_FILENO) < 0) { sprintf(err_str, "%s: dup2(stdout)", commands[i][0]); sys_fatal(err_str); } @@ -251,7 +275,7 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe) /* last command; reader */ else { /* connect stdin to read end of last pipe */ - if (_dup2(last_input, STDIN_FILENO) < 0) { + if (dup2(last_input, STDIN_FILENO) < 0) { sprintf(err_str, "%s: dup2(stdin)", commands[i][0]); sys_fatal(err_str); } @@ -260,7 +284,7 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe) sys_fatal(err_str); } /* restore original stdout */ - if (_dup2(save_stdout, STDOUT_FILENO) < 0) { + if (dup2(save_stdout, STDOUT_FILENO) < 0) { sprintf(err_str, "%s: dup2(save_stdout))", commands[i][0]); sys_fatal(err_str); } @@ -271,7 +295,7 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe) } } } - if ((pid = _spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) { + if ((pid = spawnvp(_P_NOWAIT, commands[i][0], commands[i])) < 0) { error("couldn't exec %1: %2", commands[i][0], strerror(errno), (char *)0); fflush(stderr); /* just in case error() doesn't */ @@ -279,13 +303,27 @@ int run_pipeline(int ncommands, char ***commands, int no_pipe) } pids[i] = pid; } + + if (ncommands > 1 && !no_pipe) { + /* restore original stdin if it was redirected */ + if (dup2(save_stdin, STDIN_FILENO) < 0) { + sprintf(err_str, "dup2(save_stdin))"); + sys_fatal(err_str); + } + /* close stdin copy */ + if (close(save_stdin) < 0) { + sprintf(err_str, "close(save_stdin)"); + sys_fatal(err_str); + } + } + for (i = 0; i < ncommands; i++) { int status; - int pid; + PID_T pid; pid = pids[i]; if ((pid = WAIT(&status, pid, _WAIT_CHILD)) < 0) { - sprintf(err_str, "%s: cwait", commands[i][0]); + sprintf(err_str, "%s: wait", commands[i][0]); sys_fatal(err_str); } else if (status != 0) |