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