110d63b7dSRichard Lowe /* 210d63b7dSRichard Lowe * CDDL HEADER START 310d63b7dSRichard Lowe * 410d63b7dSRichard Lowe * The contents of this file are subject to the terms of the 510d63b7dSRichard Lowe * Common Development and Distribution License (the "License"). 610d63b7dSRichard Lowe * You may not use this file except in compliance with the License. 710d63b7dSRichard Lowe * 810d63b7dSRichard Lowe * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 910d63b7dSRichard Lowe * or http://www.opensolaris.org/os/licensing. 1010d63b7dSRichard Lowe * See the License for the specific language governing permissions 1110d63b7dSRichard Lowe * and limitations under the License. 1210d63b7dSRichard Lowe * 1310d63b7dSRichard Lowe * When distributing Covered Code, include this CDDL HEADER in each 1410d63b7dSRichard Lowe * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 1510d63b7dSRichard Lowe * If applicable, add the following below this CDDL HEADER, with the 1610d63b7dSRichard Lowe * fields enclosed by brackets "[]" replaced with your own identifying 1710d63b7dSRichard Lowe * information: Portions Copyright [yyyy] [name of copyright owner] 1810d63b7dSRichard Lowe * 1910d63b7dSRichard Lowe * CDDL HEADER END 2010d63b7dSRichard Lowe */ 2110d63b7dSRichard Lowe /* 2210d63b7dSRichard Lowe * Copyright 2005 Sun Microsystems, Inc. All rights reserved. 2310d63b7dSRichard Lowe * Use is subject to license terms. 2410d63b7dSRichard Lowe */ 2510d63b7dSRichard Lowe 26*da2c0e64SPatrick Mooney /* 27*da2c0e64SPatrick Mooney * Copyright 2015, Joyent, Inc. 28*da2c0e64SPatrick Mooney */ 29*da2c0e64SPatrick Mooney 3010d63b7dSRichard Lowe 3110d63b7dSRichard Lowe /* 3210d63b7dSRichard Lowe * dosys.cc 3310d63b7dSRichard Lowe * 3410d63b7dSRichard Lowe * Execute one commandline 3510d63b7dSRichard Lowe */ 3610d63b7dSRichard Lowe 3710d63b7dSRichard Lowe /* 3810d63b7dSRichard Lowe * Included files 3910d63b7dSRichard Lowe */ 4010d63b7dSRichard Lowe #include <sys/wait.h> /* WIFEXITED(status) */ 4110d63b7dSRichard Lowe #include <alloca.h> /* alloca() */ 4210d63b7dSRichard Lowe 4310d63b7dSRichard Lowe #include <stdio.h> /* errno */ 4410d63b7dSRichard Lowe #include <errno.h> /* errno */ 4510d63b7dSRichard Lowe #include <fcntl.h> /* open() */ 4610d63b7dSRichard Lowe #include <mksh/dosys.h> 4710d63b7dSRichard Lowe #include <mksh/macro.h> /* getvar() */ 4810d63b7dSRichard Lowe #include <mksh/misc.h> /* getmem(), fatal_mksh(), errmsg() */ 4910d63b7dSRichard Lowe #include <sys/signal.h> /* SIG_DFL */ 5010d63b7dSRichard Lowe #include <sys/stat.h> /* open() */ 5110d63b7dSRichard Lowe #include <sys/wait.h> /* wait() */ 5210d63b7dSRichard Lowe #include <ulimit.h> /* ulimit() */ 5310d63b7dSRichard Lowe #include <unistd.h> /* close(), dup2() */ 54*da2c0e64SPatrick Mooney #include <stdlib.h> /* closefrom() */ 5510d63b7dSRichard Lowe #include <libintl.h> 5610d63b7dSRichard Lowe 5710d63b7dSRichard Lowe /* 5810d63b7dSRichard Lowe * typedefs & structs 5910d63b7dSRichard Lowe */ 6010d63b7dSRichard Lowe 6110d63b7dSRichard Lowe /* 6210d63b7dSRichard Lowe * Static variables 6310d63b7dSRichard Lowe */ 6410d63b7dSRichard Lowe 6510d63b7dSRichard Lowe /* 6610d63b7dSRichard Lowe * File table of contents 6710d63b7dSRichard Lowe */ 6810d63b7dSRichard Lowe static Boolean exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path); 6910d63b7dSRichard Lowe 7010d63b7dSRichard Lowe /* 7110d63b7dSRichard Lowe * Workaround for NFS bug. Sometimes, when running 'open' on a remote 7210d63b7dSRichard Lowe * dmake server, it fails with "Stale NFS file handle" error. 7310d63b7dSRichard Lowe * The second attempt seems to work. 7410d63b7dSRichard Lowe */ 7510d63b7dSRichard Lowe int 7610d63b7dSRichard Lowe my_open(const char *path, int oflag, mode_t mode) { 7710d63b7dSRichard Lowe int res = open(path, oflag, mode); 7810d63b7dSRichard Lowe if (res < 0 && (errno == ESTALE || errno == EAGAIN)) { 7910d63b7dSRichard Lowe /* Stale NFS file handle. Try again */ 8010d63b7dSRichard Lowe res = open(path, oflag, mode); 8110d63b7dSRichard Lowe } 8210d63b7dSRichard Lowe return res; 8310d63b7dSRichard Lowe } 8410d63b7dSRichard Lowe 8510d63b7dSRichard Lowe /* 8610d63b7dSRichard Lowe * void 8710d63b7dSRichard Lowe * redirect_io(char *stdout_file, char *stderr_file) 8810d63b7dSRichard Lowe * 8910d63b7dSRichard Lowe * Redirects stdout and stderr for a child mksh process. 9010d63b7dSRichard Lowe */ 9110d63b7dSRichard Lowe void 9210d63b7dSRichard Lowe redirect_io(char *stdout_file, char *stderr_file) 9310d63b7dSRichard Lowe { 9410d63b7dSRichard Lowe int i; 9510d63b7dSRichard Lowe 96*da2c0e64SPatrick Mooney (void) closefrom(3); 9710d63b7dSRichard Lowe if ((i = my_open(stdout_file, 9810d63b7dSRichard Lowe O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC, 9910d63b7dSRichard Lowe S_IREAD | S_IWRITE)) < 0) { 10010d63b7dSRichard Lowe fatal_mksh(gettext("Couldn't open standard out temp file `%s': %s"), 10110d63b7dSRichard Lowe stdout_file, 10210d63b7dSRichard Lowe errmsg(errno)); 10310d63b7dSRichard Lowe } else { 10410d63b7dSRichard Lowe if (dup2(i, 1) == -1) { 10510d63b7dSRichard Lowe fatal_mksh("*** Error: dup2(3, 1) failed: %s", 10610d63b7dSRichard Lowe errmsg(errno)); 10710d63b7dSRichard Lowe } 10810d63b7dSRichard Lowe close(i); 10910d63b7dSRichard Lowe } 11010d63b7dSRichard Lowe if (stderr_file == NULL) { 11110d63b7dSRichard Lowe if (dup2(1, 2) == -1) { 11210d63b7dSRichard Lowe fatal_mksh("*** Error: dup2(1, 2) failed: %s", 11310d63b7dSRichard Lowe errmsg(errno)); 11410d63b7dSRichard Lowe } 11510d63b7dSRichard Lowe } else if ((i = my_open(stderr_file, 11610d63b7dSRichard Lowe O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC, 11710d63b7dSRichard Lowe S_IREAD | S_IWRITE)) < 0) { 11810d63b7dSRichard Lowe fatal_mksh(gettext("Couldn't open standard error temp file `%s': %s"), 11910d63b7dSRichard Lowe stderr_file, 12010d63b7dSRichard Lowe errmsg(errno)); 12110d63b7dSRichard Lowe } else { 12210d63b7dSRichard Lowe if (dup2(i, 2) == -1) { 12310d63b7dSRichard Lowe fatal_mksh("*** Error: dup2(3, 2) failed: %s", 12410d63b7dSRichard Lowe errmsg(errno)); 12510d63b7dSRichard Lowe } 12610d63b7dSRichard Lowe close(i); 12710d63b7dSRichard Lowe } 12810d63b7dSRichard Lowe } 12910d63b7dSRichard Lowe 13010d63b7dSRichard Lowe /* 13110d63b7dSRichard Lowe * doshell(command, ignore_error) 13210d63b7dSRichard Lowe * 13310d63b7dSRichard Lowe * Used to run command lines that include shell meta-characters. 13410d63b7dSRichard Lowe * The make macro SHELL is supposed to contain a path to the shell. 13510d63b7dSRichard Lowe * 13610d63b7dSRichard Lowe * Return value: 13710d63b7dSRichard Lowe * The pid of the process we started 13810d63b7dSRichard Lowe * 13910d63b7dSRichard Lowe * Parameters: 14010d63b7dSRichard Lowe * command The command to run 14110d63b7dSRichard Lowe * ignore_error Should we abort on error? 14210d63b7dSRichard Lowe * 14310d63b7dSRichard Lowe * Global variables used: 14410d63b7dSRichard Lowe * filter_stderr If -X is on we redirect stderr 14510d63b7dSRichard Lowe * shell_name The Name "SHELL", used to get the path to shell 14610d63b7dSRichard Lowe */ 14710d63b7dSRichard Lowe int 14810d63b7dSRichard Lowe doshell(wchar_t *command, register Boolean ignore_error, char *stdout_file, char *stderr_file, int nice_prio) 14910d63b7dSRichard Lowe { 15010d63b7dSRichard Lowe char *argv[6]; 15110d63b7dSRichard Lowe int argv_index = 0; 15210d63b7dSRichard Lowe int cmd_argv_index; 15310d63b7dSRichard Lowe int length; 15410d63b7dSRichard Lowe char nice_prio_buf[MAXPATHLEN]; 15510d63b7dSRichard Lowe register Name shell = getvar(shell_name); 15610d63b7dSRichard Lowe register char *shellname; 15710d63b7dSRichard Lowe char *tmp_mbs_buffer; 15810d63b7dSRichard Lowe 15910d63b7dSRichard Lowe 16010d63b7dSRichard Lowe if (IS_EQUAL(shell->string_mb, "")) { 16110d63b7dSRichard Lowe shell = shell_name; 16210d63b7dSRichard Lowe } 16310d63b7dSRichard Lowe if ((shellname = strrchr(shell->string_mb, (int) slash_char)) == NULL) { 16410d63b7dSRichard Lowe shellname = shell->string_mb; 16510d63b7dSRichard Lowe } else { 16610d63b7dSRichard Lowe shellname++; 16710d63b7dSRichard Lowe } 16810d63b7dSRichard Lowe 16910d63b7dSRichard Lowe /* 17010d63b7dSRichard Lowe * Only prepend the /usr/bin/nice command to the original command 17110d63b7dSRichard Lowe * if the nice priority, nice_prio, is NOT zero (0). 17210d63b7dSRichard Lowe * Nice priorities can be a positive or a negative number. 17310d63b7dSRichard Lowe */ 17410d63b7dSRichard Lowe if (nice_prio != 0) { 17510d63b7dSRichard Lowe argv[argv_index++] = (char *)"nice"; 17610d63b7dSRichard Lowe (void) sprintf(nice_prio_buf, "-%d", nice_prio); 17710d63b7dSRichard Lowe argv[argv_index++] = strdup(nice_prio_buf); 17810d63b7dSRichard Lowe } 17910d63b7dSRichard Lowe argv[argv_index++] = shellname; 18010d63b7dSRichard Lowe argv[argv_index++] = (char*)(ignore_error ? "-c" : "-ce"); 18110d63b7dSRichard Lowe if ((length = wcslen(command)) >= MAXPATHLEN) { 18210d63b7dSRichard Lowe tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); 18310d63b7dSRichard Lowe (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1); 18410d63b7dSRichard Lowe cmd_argv_index = argv_index; 18510d63b7dSRichard Lowe argv[argv_index++] = strdup(tmp_mbs_buffer); 18610d63b7dSRichard Lowe retmem_mb(tmp_mbs_buffer); 18710d63b7dSRichard Lowe } else { 18810d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, command); 18910d63b7dSRichard Lowe cmd_argv_index = argv_index; 19010d63b7dSRichard Lowe argv[argv_index++] = strdup(mbs_buffer); 19110d63b7dSRichard Lowe } 19210d63b7dSRichard Lowe argv[argv_index] = NULL; 19310d63b7dSRichard Lowe (void) fflush(stdout); 19410d63b7dSRichard Lowe if ((childPid = fork()) == 0) { 19510d63b7dSRichard Lowe enable_interrupt((void (*) (int)) SIG_DFL); 19610d63b7dSRichard Lowe #if 0 19710d63b7dSRichard Lowe if (filter_stderr) { 19810d63b7dSRichard Lowe redirect_stderr(); 19910d63b7dSRichard Lowe } 20010d63b7dSRichard Lowe #endif 20110d63b7dSRichard Lowe if (nice_prio != 0) { 20210d63b7dSRichard Lowe (void) execve("/usr/bin/nice", argv, environ); 20310d63b7dSRichard Lowe fatal_mksh(gettext("Could not load `/usr/bin/nice': %s"), 20410d63b7dSRichard Lowe errmsg(errno)); 20510d63b7dSRichard Lowe } else { 20610d63b7dSRichard Lowe (void) execve(shell->string_mb, argv, environ); 20710d63b7dSRichard Lowe fatal_mksh(gettext("Could not load Shell from `%s': %s"), 20810d63b7dSRichard Lowe shell->string_mb, 20910d63b7dSRichard Lowe errmsg(errno)); 21010d63b7dSRichard Lowe } 21110d63b7dSRichard Lowe } 21210d63b7dSRichard Lowe if (childPid == -1) { 21310d63b7dSRichard Lowe fatal_mksh(gettext("fork failed: %s"), 21410d63b7dSRichard Lowe errmsg(errno)); 21510d63b7dSRichard Lowe } 21610d63b7dSRichard Lowe retmem_mb(argv[cmd_argv_index]); 21710d63b7dSRichard Lowe return childPid; 21810d63b7dSRichard Lowe } 21910d63b7dSRichard Lowe 22010d63b7dSRichard Lowe /* 22110d63b7dSRichard Lowe * exec_vp(name, argv, envp, ignore_error) 22210d63b7dSRichard Lowe * 22310d63b7dSRichard Lowe * Like execve, but does path search. 22410d63b7dSRichard Lowe * This starts command when make invokes it directly (without a shell). 22510d63b7dSRichard Lowe * 22610d63b7dSRichard Lowe * Return value: 22710d63b7dSRichard Lowe * Returns false if the exec failed 22810d63b7dSRichard Lowe * 22910d63b7dSRichard Lowe * Parameters: 23010d63b7dSRichard Lowe * name The name of the command to run 23110d63b7dSRichard Lowe * argv Arguments for the command 23210d63b7dSRichard Lowe * envp The environment for it 23310d63b7dSRichard Lowe * ignore_error Should we abort on error? 23410d63b7dSRichard Lowe * 23510d63b7dSRichard Lowe * Global variables used: 23610d63b7dSRichard Lowe * shell_name The Name "SHELL", used to get the path to shell 23710d63b7dSRichard Lowe * vroot_path The path used by the vroot package 23810d63b7dSRichard Lowe */ 23910d63b7dSRichard Lowe static Boolean 24010d63b7dSRichard Lowe exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path) 24110d63b7dSRichard Lowe { 24210d63b7dSRichard Lowe register Name shell = getvar(shell_name); 24310d63b7dSRichard Lowe register char *shellname; 24410d63b7dSRichard Lowe char *shargv[4]; 24510d63b7dSRichard Lowe Name tmp_shell; 24610d63b7dSRichard Lowe 24710d63b7dSRichard Lowe if (IS_EQUAL(shell->string_mb, "")) { 24810d63b7dSRichard Lowe shell = shell_name; 24910d63b7dSRichard Lowe } 25010d63b7dSRichard Lowe 25110d63b7dSRichard Lowe for (int i = 0; i < 5; i++) { 25210d63b7dSRichard Lowe (void) execve_vroot(name, 25310d63b7dSRichard Lowe argv + 1, 25410d63b7dSRichard Lowe envp, 25510d63b7dSRichard Lowe vroot_path, 25610d63b7dSRichard Lowe VROOT_DEFAULT); 25710d63b7dSRichard Lowe switch (errno) { 25810d63b7dSRichard Lowe case ENOEXEC: 25910d63b7dSRichard Lowe case ENOENT: 26010d63b7dSRichard Lowe /* That failed. Let the shell handle it */ 26110d63b7dSRichard Lowe shellname = strrchr(shell->string_mb, (int) slash_char); 26210d63b7dSRichard Lowe if (shellname == NULL) { 26310d63b7dSRichard Lowe shellname = shell->string_mb; 26410d63b7dSRichard Lowe } else { 26510d63b7dSRichard Lowe shellname++; 26610d63b7dSRichard Lowe } 26710d63b7dSRichard Lowe shargv[0] = shellname; 26810d63b7dSRichard Lowe shargv[1] = (char*)(ignore_error ? "-c" : "-ce"); 26910d63b7dSRichard Lowe shargv[2] = argv[0]; 27010d63b7dSRichard Lowe shargv[3] = NULL; 27110d63b7dSRichard Lowe tmp_shell = getvar(shell_name); 27210d63b7dSRichard Lowe if (IS_EQUAL(tmp_shell->string_mb, "")) { 27310d63b7dSRichard Lowe tmp_shell = shell_name; 27410d63b7dSRichard Lowe } 27510d63b7dSRichard Lowe (void) execve_vroot(tmp_shell->string_mb, 27610d63b7dSRichard Lowe shargv, 27710d63b7dSRichard Lowe envp, 27810d63b7dSRichard Lowe vroot_path, 27910d63b7dSRichard Lowe VROOT_DEFAULT); 28010d63b7dSRichard Lowe return failed; 28110d63b7dSRichard Lowe case ETXTBSY: 28210d63b7dSRichard Lowe /* 28310d63b7dSRichard Lowe * The program is busy (debugged?). 28410d63b7dSRichard Lowe * Wait and then try again. 28510d63b7dSRichard Lowe */ 28610d63b7dSRichard Lowe (void) sleep((unsigned) i); 28710d63b7dSRichard Lowe case EAGAIN: 28810d63b7dSRichard Lowe break; 28910d63b7dSRichard Lowe default: 29010d63b7dSRichard Lowe return failed; 29110d63b7dSRichard Lowe } 29210d63b7dSRichard Lowe } 29310d63b7dSRichard Lowe return failed; 29410d63b7dSRichard Lowe } 29510d63b7dSRichard Lowe 29610d63b7dSRichard Lowe /* 29710d63b7dSRichard Lowe * doexec(command, ignore_error) 29810d63b7dSRichard Lowe * 29910d63b7dSRichard Lowe * Will scan an argument string and split it into words 30010d63b7dSRichard Lowe * thus building an argument list that can be passed to exec_ve() 30110d63b7dSRichard Lowe * 30210d63b7dSRichard Lowe * Return value: 30310d63b7dSRichard Lowe * The pid of the process started here 30410d63b7dSRichard Lowe * 30510d63b7dSRichard Lowe * Parameters: 30610d63b7dSRichard Lowe * command The command to run 30710d63b7dSRichard Lowe * ignore_error Should we abort on error? 30810d63b7dSRichard Lowe * 30910d63b7dSRichard Lowe * Global variables used: 31010d63b7dSRichard Lowe * filter_stderr If -X is on we redirect stderr 31110d63b7dSRichard Lowe */ 31210d63b7dSRichard Lowe int 31310d63b7dSRichard Lowe doexec(register wchar_t *command, register Boolean ignore_error, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio) 31410d63b7dSRichard Lowe { 31510d63b7dSRichard Lowe int arg_count = 5; 31610d63b7dSRichard Lowe char **argv; 31710d63b7dSRichard Lowe int length; 31810d63b7dSRichard Lowe char nice_prio_buf[MAXPATHLEN]; 31910d63b7dSRichard Lowe register char **p; 32010d63b7dSRichard Lowe wchar_t *q; 32110d63b7dSRichard Lowe register wchar_t *t; 32210d63b7dSRichard Lowe char *tmp_mbs_buffer; 32310d63b7dSRichard Lowe 32410d63b7dSRichard Lowe /* 32510d63b7dSRichard Lowe * Only prepend the /usr/bin/nice command to the original command 32610d63b7dSRichard Lowe * if the nice priority, nice_prio, is NOT zero (0). 32710d63b7dSRichard Lowe * Nice priorities can be a positive or a negative number. 32810d63b7dSRichard Lowe */ 32910d63b7dSRichard Lowe if (nice_prio != 0) { 33010d63b7dSRichard Lowe arg_count += 2; 33110d63b7dSRichard Lowe } 33210d63b7dSRichard Lowe for (t = command; *t != (int) nul_char; t++) { 33310d63b7dSRichard Lowe if (iswspace(*t)) { 33410d63b7dSRichard Lowe arg_count++; 33510d63b7dSRichard Lowe } 33610d63b7dSRichard Lowe } 33710d63b7dSRichard Lowe argv = (char **)alloca(arg_count * (sizeof(char *))); 33810d63b7dSRichard Lowe /* 33910d63b7dSRichard Lowe * Reserve argv[0] for sh in case of exec_vp failure. 34010d63b7dSRichard Lowe * Don't worry about prepending /usr/bin/nice command to argv[0]. 34110d63b7dSRichard Lowe * In fact, doing it may cause the sh command to fail! 34210d63b7dSRichard Lowe */ 34310d63b7dSRichard Lowe p = &argv[1]; 34410d63b7dSRichard Lowe if ((length = wcslen(command)) >= MAXPATHLEN) { 34510d63b7dSRichard Lowe tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); 34610d63b7dSRichard Lowe (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1); 34710d63b7dSRichard Lowe argv[0] = strdup(tmp_mbs_buffer); 34810d63b7dSRichard Lowe retmem_mb(tmp_mbs_buffer); 34910d63b7dSRichard Lowe } else { 35010d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, command); 35110d63b7dSRichard Lowe argv[0] = strdup(mbs_buffer); 35210d63b7dSRichard Lowe } 35310d63b7dSRichard Lowe 35410d63b7dSRichard Lowe if (nice_prio != 0) { 35510d63b7dSRichard Lowe *p++ = strdup("/usr/bin/nice"); 35610d63b7dSRichard Lowe (void) sprintf(nice_prio_buf, "-%d", nice_prio); 35710d63b7dSRichard Lowe *p++ = strdup(nice_prio_buf); 35810d63b7dSRichard Lowe } 35910d63b7dSRichard Lowe /* Build list of argument words. */ 36010d63b7dSRichard Lowe for (t = command; *t;) { 36110d63b7dSRichard Lowe if (p >= &argv[arg_count]) { 36210d63b7dSRichard Lowe /* This should never happen, right? */ 36310d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, command); 36410d63b7dSRichard Lowe fatal_mksh(gettext("Command `%s' has more than %d arguments"), 36510d63b7dSRichard Lowe mbs_buffer, 36610d63b7dSRichard Lowe arg_count); 36710d63b7dSRichard Lowe } 36810d63b7dSRichard Lowe q = t; 36910d63b7dSRichard Lowe while (!iswspace(*t) && (*t != (int) nul_char)) { 37010d63b7dSRichard Lowe t++; 37110d63b7dSRichard Lowe } 37210d63b7dSRichard Lowe if (*t) { 37310d63b7dSRichard Lowe for (*t++ = (int) nul_char; iswspace(*t); t++); 37410d63b7dSRichard Lowe } 37510d63b7dSRichard Lowe if ((length = wcslen(q)) >= MAXPATHLEN) { 37610d63b7dSRichard Lowe tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1); 37710d63b7dSRichard Lowe (void) wcstombs(tmp_mbs_buffer, q, (length * MB_LEN_MAX) + 1); 37810d63b7dSRichard Lowe *p++ = strdup(tmp_mbs_buffer); 37910d63b7dSRichard Lowe retmem_mb(tmp_mbs_buffer); 38010d63b7dSRichard Lowe } else { 38110d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, q); 38210d63b7dSRichard Lowe *p++ = strdup(mbs_buffer); 38310d63b7dSRichard Lowe } 38410d63b7dSRichard Lowe } 38510d63b7dSRichard Lowe *p = NULL; 38610d63b7dSRichard Lowe 38710d63b7dSRichard Lowe /* Then exec the command with that argument list. */ 38810d63b7dSRichard Lowe (void) fflush(stdout); 38910d63b7dSRichard Lowe if ((childPid = fork()) == 0) { 39010d63b7dSRichard Lowe enable_interrupt((void (*) (int)) SIG_DFL); 39110d63b7dSRichard Lowe #if 0 39210d63b7dSRichard Lowe if (filter_stderr) { 39310d63b7dSRichard Lowe redirect_stderr(); 39410d63b7dSRichard Lowe } 39510d63b7dSRichard Lowe #endif 39610d63b7dSRichard Lowe (void) exec_vp(argv[1], argv, environ, ignore_error, vroot_path); 39710d63b7dSRichard Lowe fatal_mksh(gettext("Cannot load command `%s': %s"), argv[1], errmsg(errno)); 39810d63b7dSRichard Lowe } 39910d63b7dSRichard Lowe if (childPid == -1) { 40010d63b7dSRichard Lowe fatal_mksh(gettext("fork failed: %s"), 40110d63b7dSRichard Lowe errmsg(errno)); 40210d63b7dSRichard Lowe } 40310d63b7dSRichard Lowe for (int i = 0; argv[i] != NULL; i++) { 40410d63b7dSRichard Lowe retmem_mb(argv[i]); 40510d63b7dSRichard Lowe } 40610d63b7dSRichard Lowe return childPid; 40710d63b7dSRichard Lowe } 40810d63b7dSRichard Lowe 40910d63b7dSRichard Lowe /* 41010d63b7dSRichard Lowe * await(ignore_error, silent_error, target, command, running_pid) 41110d63b7dSRichard Lowe * 41210d63b7dSRichard Lowe * Wait for one child process and analyzes 41310d63b7dSRichard Lowe * the returned status when the child process terminates. 41410d63b7dSRichard Lowe * 41510d63b7dSRichard Lowe * Return value: 41610d63b7dSRichard Lowe * Returns true if commands ran OK 41710d63b7dSRichard Lowe * 41810d63b7dSRichard Lowe * Parameters: 41910d63b7dSRichard Lowe * ignore_error Should we abort on error? 42010d63b7dSRichard Lowe * silent_error Should error messages be suppressed for dmake? 42110d63b7dSRichard Lowe * target The target we are building, for error msgs 42210d63b7dSRichard Lowe * command The command we ran, for error msgs 42310d63b7dSRichard Lowe * running_pid The pid of the process we are waiting for 42410d63b7dSRichard Lowe * 42510d63b7dSRichard Lowe * Static variables used: 42610d63b7dSRichard Lowe * filter_file The fd for the filter file 42710d63b7dSRichard Lowe * filter_file_name The name of the filter file 42810d63b7dSRichard Lowe * 42910d63b7dSRichard Lowe * Global variables used: 43010d63b7dSRichard Lowe * filter_stderr Set if -X is on 43110d63b7dSRichard Lowe */ 43210d63b7dSRichard Lowe Boolean 43310d63b7dSRichard Lowe await(register Boolean ignore_error, register Boolean silent_error, Name target, wchar_t *command, pid_t running_pid, void *xdrs_p, int job_msg_id) 43410d63b7dSRichard Lowe { 43510d63b7dSRichard Lowe int status; 43610d63b7dSRichard Lowe char *buffer; 43710d63b7dSRichard Lowe int core_dumped; 43810d63b7dSRichard Lowe int exit_status; 43910d63b7dSRichard Lowe FILE *outfp; 44010d63b7dSRichard Lowe register pid_t pid; 44110d63b7dSRichard Lowe struct stat stat_buff; 44210d63b7dSRichard Lowe int termination_signal; 44310d63b7dSRichard Lowe char tmp_buf[MAXPATHLEN]; 44410d63b7dSRichard Lowe 44510d63b7dSRichard Lowe while ((pid = wait(&status)) != running_pid) { 44610d63b7dSRichard Lowe if (pid == -1) { 44710d63b7dSRichard Lowe fatal_mksh(gettext("wait() failed: %s"), errmsg(errno)); 44810d63b7dSRichard Lowe } 44910d63b7dSRichard Lowe } 45010d63b7dSRichard Lowe (void) fflush(stdout); 45110d63b7dSRichard Lowe (void) fflush(stderr); 45210d63b7dSRichard Lowe 45310d63b7dSRichard Lowe if (status == 0) { 45410d63b7dSRichard Lowe 45510d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS 45610d63b7dSRichard Lowe warning_mksh("I'm in await(), and status is 0."); 45710d63b7dSRichard Lowe #endif 45810d63b7dSRichard Lowe 45910d63b7dSRichard Lowe return succeeded; 46010d63b7dSRichard Lowe } 46110d63b7dSRichard Lowe 46210d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS 46310d63b7dSRichard Lowe warning_mksh("I'm in await(), and status is *NOT* 0."); 46410d63b7dSRichard Lowe #endif 46510d63b7dSRichard Lowe 46610d63b7dSRichard Lowe 46710d63b7dSRichard Lowe exit_status = WEXITSTATUS(status); 46810d63b7dSRichard Lowe 46910d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS 47010d63b7dSRichard Lowe warning_mksh("I'm in await(), and exit_status is %d.", exit_status); 47110d63b7dSRichard Lowe #endif 47210d63b7dSRichard Lowe 47310d63b7dSRichard Lowe termination_signal = WTERMSIG(status); 47410d63b7dSRichard Lowe core_dumped = WCOREDUMP(status); 47510d63b7dSRichard Lowe 47610d63b7dSRichard Lowe /* 47710d63b7dSRichard Lowe * If the child returned an error, we now try to print a 47810d63b7dSRichard Lowe * nice message about it. 47910d63b7dSRichard Lowe */ 48010d63b7dSRichard Lowe 48110d63b7dSRichard Lowe tmp_buf[0] = (int) nul_char; 48210d63b7dSRichard Lowe if (!silent_error) { 48310d63b7dSRichard Lowe if (exit_status != 0) { 48410d63b7dSRichard Lowe (void) fprintf(stdout, 48510d63b7dSRichard Lowe gettext("*** Error code %d"), 48610d63b7dSRichard Lowe exit_status); 48710d63b7dSRichard Lowe } else { 48810d63b7dSRichard Lowe (void) fprintf(stdout, 48910d63b7dSRichard Lowe gettext("*** Signal %d"), 49010d63b7dSRichard Lowe termination_signal); 49110d63b7dSRichard Lowe if (core_dumped) { 49210d63b7dSRichard Lowe (void) fprintf(stdout, 49310d63b7dSRichard Lowe gettext(" - core dumped")); 49410d63b7dSRichard Lowe } 49510d63b7dSRichard Lowe } 49610d63b7dSRichard Lowe if (ignore_error) { 49710d63b7dSRichard Lowe (void) fprintf(stdout, 49810d63b7dSRichard Lowe gettext(" (ignored)")); 49910d63b7dSRichard Lowe } 50010d63b7dSRichard Lowe (void) fprintf(stdout, "\n"); 50110d63b7dSRichard Lowe (void) fflush(stdout); 50210d63b7dSRichard Lowe } 50310d63b7dSRichard Lowe 50410d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS 50510d63b7dSRichard Lowe warning_mksh("I'm in await(), returning failed."); 50610d63b7dSRichard Lowe #endif 50710d63b7dSRichard Lowe 50810d63b7dSRichard Lowe return failed; 50910d63b7dSRichard Lowe } 51010d63b7dSRichard Lowe 51110d63b7dSRichard Lowe /* 51210d63b7dSRichard Lowe * sh_command2string(command, destination) 51310d63b7dSRichard Lowe * 51410d63b7dSRichard Lowe * Run one sh command and capture the output from it. 51510d63b7dSRichard Lowe * 51610d63b7dSRichard Lowe * Return value: 51710d63b7dSRichard Lowe * 51810d63b7dSRichard Lowe * Parameters: 51910d63b7dSRichard Lowe * command The command to run 52010d63b7dSRichard Lowe * destination Where to deposit the output from the command 52110d63b7dSRichard Lowe * 52210d63b7dSRichard Lowe * Static variables used: 52310d63b7dSRichard Lowe * 52410d63b7dSRichard Lowe * Global variables used: 52510d63b7dSRichard Lowe */ 52610d63b7dSRichard Lowe void 52710d63b7dSRichard Lowe sh_command2string(register String command, register String destination) 52810d63b7dSRichard Lowe { 52910d63b7dSRichard Lowe register FILE *fd; 53010d63b7dSRichard Lowe register int chr; 53110d63b7dSRichard Lowe int status; 53210d63b7dSRichard Lowe Boolean command_generated_output = false; 53310d63b7dSRichard Lowe 53410d63b7dSRichard Lowe command->text.p = (int) nul_char; 53510d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, command->buffer.start); 53610d63b7dSRichard Lowe if ((fd = popen(mbs_buffer, "r")) == NULL) { 53710d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, command->buffer.start); 53810d63b7dSRichard Lowe fatal_mksh(gettext("Could not run command `%s' for :sh transformation"), 53910d63b7dSRichard Lowe mbs_buffer); 54010d63b7dSRichard Lowe } 54110d63b7dSRichard Lowe while ((chr = getc(fd)) != EOF) { 54210d63b7dSRichard Lowe if (chr == (int) newline_char) { 54310d63b7dSRichard Lowe chr = (int) space_char; 54410d63b7dSRichard Lowe } 54510d63b7dSRichard Lowe command_generated_output = true; 54610d63b7dSRichard Lowe append_char(chr, destination); 54710d63b7dSRichard Lowe } 54810d63b7dSRichard Lowe 54910d63b7dSRichard Lowe /* 55010d63b7dSRichard Lowe * We don't want to keep the last LINE_FEED since usually 55110d63b7dSRichard Lowe * the output of the 'sh:' command is used to evaluate 55210d63b7dSRichard Lowe * some MACRO. ( /bin/sh and other shell add a line feed 55310d63b7dSRichard Lowe * to the output so that the prompt appear in the right place. 55410d63b7dSRichard Lowe * We don't need that 55510d63b7dSRichard Lowe */ 55610d63b7dSRichard Lowe if (command_generated_output){ 55710d63b7dSRichard Lowe if ( *(destination->text.p-1) == (int) space_char) { 55810d63b7dSRichard Lowe * (-- destination->text.p) = '\0'; 55910d63b7dSRichard Lowe } 56010d63b7dSRichard Lowe } else { 56110d63b7dSRichard Lowe /* 56210d63b7dSRichard Lowe * If the command didn't generate any output, 56310d63b7dSRichard Lowe * set the buffer to a null string. 56410d63b7dSRichard Lowe */ 56510d63b7dSRichard Lowe *(destination->text.p) = '\0'; 56610d63b7dSRichard Lowe } 56710d63b7dSRichard Lowe 56810d63b7dSRichard Lowe status = pclose(fd); 56910d63b7dSRichard Lowe if (status != 0) { 57010d63b7dSRichard Lowe WCSTOMBS(mbs_buffer, command->buffer.start); 57110d63b7dSRichard Lowe fatal_mksh(gettext("The command `%s' returned status `%d'"), 57210d63b7dSRichard Lowe mbs_buffer, 57310d63b7dSRichard Lowe WEXITSTATUS(status)); 57410d63b7dSRichard Lowe } 57510d63b7dSRichard Lowe } 57610d63b7dSRichard Lowe 57710d63b7dSRichard Lowe 578