xref: /titanic_44/usr/src/cmd/make/lib/mksh/dosys.cc (revision 10d63b7db37a83b39c7f511cf9426c9d03ea0760)
1*10d63b7dSRichard Lowe /*
2*10d63b7dSRichard Lowe  * CDDL HEADER START
3*10d63b7dSRichard Lowe  *
4*10d63b7dSRichard Lowe  * The contents of this file are subject to the terms of the
5*10d63b7dSRichard Lowe  * Common Development and Distribution License (the "License").
6*10d63b7dSRichard Lowe  * You may not use this file except in compliance with the License.
7*10d63b7dSRichard Lowe  *
8*10d63b7dSRichard Lowe  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9*10d63b7dSRichard Lowe  * or http://www.opensolaris.org/os/licensing.
10*10d63b7dSRichard Lowe  * See the License for the specific language governing permissions
11*10d63b7dSRichard Lowe  * and limitations under the License.
12*10d63b7dSRichard Lowe  *
13*10d63b7dSRichard Lowe  * When distributing Covered Code, include this CDDL HEADER in each
14*10d63b7dSRichard Lowe  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15*10d63b7dSRichard Lowe  * If applicable, add the following below this CDDL HEADER, with the
16*10d63b7dSRichard Lowe  * fields enclosed by brackets "[]" replaced with your own identifying
17*10d63b7dSRichard Lowe  * information: Portions Copyright [yyyy] [name of copyright owner]
18*10d63b7dSRichard Lowe  *
19*10d63b7dSRichard Lowe  * CDDL HEADER END
20*10d63b7dSRichard Lowe  */
21*10d63b7dSRichard Lowe /*
22*10d63b7dSRichard Lowe  * Copyright 2005 Sun Microsystems, Inc. All rights reserved.
23*10d63b7dSRichard Lowe  * Use is subject to license terms.
24*10d63b7dSRichard Lowe  */
25*10d63b7dSRichard Lowe 
26*10d63b7dSRichard Lowe 
27*10d63b7dSRichard Lowe /*
28*10d63b7dSRichard Lowe  *	dosys.cc
29*10d63b7dSRichard Lowe  *
30*10d63b7dSRichard Lowe  *	Execute one commandline
31*10d63b7dSRichard Lowe  */
32*10d63b7dSRichard Lowe 
33*10d63b7dSRichard Lowe /*
34*10d63b7dSRichard Lowe  * Included files
35*10d63b7dSRichard Lowe  */
36*10d63b7dSRichard Lowe #include <sys/wait.h>			/* WIFEXITED(status) */
37*10d63b7dSRichard Lowe #include <alloca.h>		/* alloca() */
38*10d63b7dSRichard Lowe 
39*10d63b7dSRichard Lowe #include <stdio.h>		/* errno */
40*10d63b7dSRichard Lowe #include <errno.h>		/* errno */
41*10d63b7dSRichard Lowe #include <fcntl.h>		/* open() */
42*10d63b7dSRichard Lowe #include <mksh/dosys.h>
43*10d63b7dSRichard Lowe #include <mksh/macro.h>		/* getvar() */
44*10d63b7dSRichard Lowe #include <mksh/misc.h>		/* getmem(), fatal_mksh(), errmsg() */
45*10d63b7dSRichard Lowe #include <sys/signal.h>		/* SIG_DFL */
46*10d63b7dSRichard Lowe #include <sys/stat.h>		/* open() */
47*10d63b7dSRichard Lowe #include <sys/wait.h>		/* wait() */
48*10d63b7dSRichard Lowe #include <ulimit.h>		/* ulimit() */
49*10d63b7dSRichard Lowe #include <unistd.h>		/* close(), dup2() */
50*10d63b7dSRichard Lowe #include <libintl.h>
51*10d63b7dSRichard Lowe 
52*10d63b7dSRichard Lowe /*
53*10d63b7dSRichard Lowe  * typedefs & structs
54*10d63b7dSRichard Lowe  */
55*10d63b7dSRichard Lowe 
56*10d63b7dSRichard Lowe /*
57*10d63b7dSRichard Lowe  * Static variables
58*10d63b7dSRichard Lowe  */
59*10d63b7dSRichard Lowe 
60*10d63b7dSRichard Lowe /*
61*10d63b7dSRichard Lowe  * File table of contents
62*10d63b7dSRichard Lowe  */
63*10d63b7dSRichard Lowe static Boolean	exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path);
64*10d63b7dSRichard Lowe 
65*10d63b7dSRichard Lowe /*
66*10d63b7dSRichard Lowe  * Workaround for NFS bug. Sometimes, when running 'open' on a remote
67*10d63b7dSRichard Lowe  * dmake server, it fails with "Stale NFS file handle" error.
68*10d63b7dSRichard Lowe  * The second attempt seems to work.
69*10d63b7dSRichard Lowe  */
70*10d63b7dSRichard Lowe int
my_open(const char * path,int oflag,mode_t mode)71*10d63b7dSRichard Lowe my_open(const char *path, int oflag, mode_t mode) {
72*10d63b7dSRichard Lowe 	int res = open(path, oflag, mode);
73*10d63b7dSRichard Lowe 	if (res < 0 && (errno == ESTALE || errno == EAGAIN)) {
74*10d63b7dSRichard Lowe 		/* Stale NFS file handle. Try again */
75*10d63b7dSRichard Lowe 		res = open(path, oflag, mode);
76*10d63b7dSRichard Lowe 	}
77*10d63b7dSRichard Lowe 	return res;
78*10d63b7dSRichard Lowe }
79*10d63b7dSRichard Lowe 
80*10d63b7dSRichard Lowe /*
81*10d63b7dSRichard Lowe  *	void
82*10d63b7dSRichard Lowe  *	redirect_io(char *stdout_file, char *stderr_file)
83*10d63b7dSRichard Lowe  *
84*10d63b7dSRichard Lowe  *	Redirects stdout and stderr for a child mksh process.
85*10d63b7dSRichard Lowe  */
86*10d63b7dSRichard Lowe void
redirect_io(char * stdout_file,char * stderr_file)87*10d63b7dSRichard Lowe redirect_io(char *stdout_file, char *stderr_file)
88*10d63b7dSRichard Lowe {
89*10d63b7dSRichard Lowe 	long		descriptor_limit;
90*10d63b7dSRichard Lowe 	int		i;
91*10d63b7dSRichard Lowe 
92*10d63b7dSRichard Lowe 	if ((descriptor_limit = ulimit(UL_GDESLIM)) < 0) {
93*10d63b7dSRichard Lowe 		fatal_mksh(gettext("ulimit() failed: %s"), errmsg(errno));
94*10d63b7dSRichard Lowe 	}
95*10d63b7dSRichard Lowe 	for (i = 3; i < descriptor_limit; i++) {
96*10d63b7dSRichard Lowe 		(void) close(i);
97*10d63b7dSRichard Lowe 	}
98*10d63b7dSRichard Lowe 	if ((i = my_open(stdout_file,
99*10d63b7dSRichard Lowe 	         O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC,
100*10d63b7dSRichard Lowe 	         S_IREAD | S_IWRITE)) < 0) {
101*10d63b7dSRichard Lowe 		fatal_mksh(gettext("Couldn't open standard out temp file `%s': %s"),
102*10d63b7dSRichard Lowe 		      stdout_file,
103*10d63b7dSRichard Lowe 		      errmsg(errno));
104*10d63b7dSRichard Lowe 	} else {
105*10d63b7dSRichard Lowe 		if (dup2(i, 1) == -1) {
106*10d63b7dSRichard Lowe 			fatal_mksh("*** Error: dup2(3, 1) failed: %s",
107*10d63b7dSRichard Lowe 				errmsg(errno));
108*10d63b7dSRichard Lowe 		}
109*10d63b7dSRichard Lowe 		close(i);
110*10d63b7dSRichard Lowe 	}
111*10d63b7dSRichard Lowe 	if (stderr_file == NULL) {
112*10d63b7dSRichard Lowe 		if (dup2(1, 2) == -1) {
113*10d63b7dSRichard Lowe 			fatal_mksh("*** Error: dup2(1, 2) failed: %s",
114*10d63b7dSRichard Lowe 				errmsg(errno));
115*10d63b7dSRichard Lowe 		}
116*10d63b7dSRichard Lowe 	} else if ((i = my_open(stderr_file,
117*10d63b7dSRichard Lowe 	                O_WRONLY | O_CREAT | O_TRUNC | O_DSYNC,
118*10d63b7dSRichard Lowe 	                S_IREAD | S_IWRITE)) < 0) {
119*10d63b7dSRichard Lowe 		fatal_mksh(gettext("Couldn't open standard error temp file `%s': %s"),
120*10d63b7dSRichard Lowe 		      stderr_file,
121*10d63b7dSRichard Lowe 		      errmsg(errno));
122*10d63b7dSRichard Lowe 	} else {
123*10d63b7dSRichard Lowe 		if (dup2(i, 2) == -1) {
124*10d63b7dSRichard Lowe 			fatal_mksh("*** Error: dup2(3, 2) failed: %s",
125*10d63b7dSRichard Lowe 				errmsg(errno));
126*10d63b7dSRichard Lowe 		}
127*10d63b7dSRichard Lowe 		close(i);
128*10d63b7dSRichard Lowe 	}
129*10d63b7dSRichard Lowe }
130*10d63b7dSRichard Lowe 
131*10d63b7dSRichard Lowe /*
132*10d63b7dSRichard Lowe  *	doshell(command, ignore_error)
133*10d63b7dSRichard Lowe  *
134*10d63b7dSRichard Lowe  *	Used to run command lines that include shell meta-characters.
135*10d63b7dSRichard Lowe  *	The make macro SHELL is supposed to contain a path to the shell.
136*10d63b7dSRichard Lowe  *
137*10d63b7dSRichard Lowe  *	Return value:
138*10d63b7dSRichard Lowe  *				The pid of the process we started
139*10d63b7dSRichard Lowe  *
140*10d63b7dSRichard Lowe  *	Parameters:
141*10d63b7dSRichard Lowe  *		command		The command to run
142*10d63b7dSRichard Lowe  *		ignore_error	Should we abort on error?
143*10d63b7dSRichard Lowe  *
144*10d63b7dSRichard Lowe  *	Global variables used:
145*10d63b7dSRichard Lowe  *		filter_stderr	If -X is on we redirect stderr
146*10d63b7dSRichard Lowe  *		shell_name	The Name "SHELL", used to get the path to shell
147*10d63b7dSRichard Lowe  */
148*10d63b7dSRichard Lowe int
doshell(wchar_t * command,register Boolean ignore_error,char * stdout_file,char * stderr_file,int nice_prio)149*10d63b7dSRichard Lowe doshell(wchar_t *command, register Boolean ignore_error, char *stdout_file, char *stderr_file, int nice_prio)
150*10d63b7dSRichard Lowe {
151*10d63b7dSRichard Lowe 	char			*argv[6];
152*10d63b7dSRichard Lowe 	int			argv_index = 0;
153*10d63b7dSRichard Lowe 	int			cmd_argv_index;
154*10d63b7dSRichard Lowe 	int			length;
155*10d63b7dSRichard Lowe 	char			nice_prio_buf[MAXPATHLEN];
156*10d63b7dSRichard Lowe 	register Name		shell = getvar(shell_name);
157*10d63b7dSRichard Lowe 	register char		*shellname;
158*10d63b7dSRichard Lowe 	char			*tmp_mbs_buffer;
159*10d63b7dSRichard Lowe 
160*10d63b7dSRichard Lowe 
161*10d63b7dSRichard Lowe 	if (IS_EQUAL(shell->string_mb, "")) {
162*10d63b7dSRichard Lowe 		shell = shell_name;
163*10d63b7dSRichard Lowe 	}
164*10d63b7dSRichard Lowe 	if ((shellname = strrchr(shell->string_mb, (int) slash_char)) == NULL) {
165*10d63b7dSRichard Lowe 		shellname = shell->string_mb;
166*10d63b7dSRichard Lowe 	} else {
167*10d63b7dSRichard Lowe 		shellname++;
168*10d63b7dSRichard Lowe 	}
169*10d63b7dSRichard Lowe 
170*10d63b7dSRichard Lowe 	/*
171*10d63b7dSRichard Lowe 	 * Only prepend the /usr/bin/nice command to the original command
172*10d63b7dSRichard Lowe 	 * if the nice priority, nice_prio, is NOT zero (0).
173*10d63b7dSRichard Lowe 	 * Nice priorities can be a positive or a negative number.
174*10d63b7dSRichard Lowe 	 */
175*10d63b7dSRichard Lowe 	if (nice_prio != 0) {
176*10d63b7dSRichard Lowe 		argv[argv_index++] = (char *)"nice";
177*10d63b7dSRichard Lowe 		(void) sprintf(nice_prio_buf, "-%d", nice_prio);
178*10d63b7dSRichard Lowe 		argv[argv_index++] = strdup(nice_prio_buf);
179*10d63b7dSRichard Lowe 	}
180*10d63b7dSRichard Lowe 	argv[argv_index++] = shellname;
181*10d63b7dSRichard Lowe 	argv[argv_index++] = (char*)(ignore_error ? "-c" : "-ce");
182*10d63b7dSRichard Lowe 	if ((length = wcslen(command)) >= MAXPATHLEN) {
183*10d63b7dSRichard Lowe 		tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
184*10d63b7dSRichard Lowe                 (void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1);
185*10d63b7dSRichard Lowe 		cmd_argv_index = argv_index;
186*10d63b7dSRichard Lowe                 argv[argv_index++] = strdup(tmp_mbs_buffer);
187*10d63b7dSRichard Lowe                 retmem_mb(tmp_mbs_buffer);
188*10d63b7dSRichard Lowe 	} else {
189*10d63b7dSRichard Lowe 		WCSTOMBS(mbs_buffer, command);
190*10d63b7dSRichard Lowe 		cmd_argv_index = argv_index;
191*10d63b7dSRichard Lowe 		argv[argv_index++] = strdup(mbs_buffer);
192*10d63b7dSRichard Lowe 	}
193*10d63b7dSRichard Lowe 	argv[argv_index] = NULL;
194*10d63b7dSRichard Lowe 	(void) fflush(stdout);
195*10d63b7dSRichard Lowe 	if ((childPid = fork()) == 0) {
196*10d63b7dSRichard Lowe 		enable_interrupt((void (*) (int)) SIG_DFL);
197*10d63b7dSRichard Lowe #if 0
198*10d63b7dSRichard Lowe 		if (filter_stderr) {
199*10d63b7dSRichard Lowe 			redirect_stderr();
200*10d63b7dSRichard Lowe 		}
201*10d63b7dSRichard Lowe #endif
202*10d63b7dSRichard Lowe 		if (nice_prio != 0) {
203*10d63b7dSRichard Lowe 			(void) execve("/usr/bin/nice", argv, environ);
204*10d63b7dSRichard Lowe 			fatal_mksh(gettext("Could not load `/usr/bin/nice': %s"),
205*10d63b7dSRichard Lowe 			      errmsg(errno));
206*10d63b7dSRichard Lowe 		} else {
207*10d63b7dSRichard Lowe 			(void) execve(shell->string_mb, argv, environ);
208*10d63b7dSRichard Lowe 			fatal_mksh(gettext("Could not load Shell from `%s': %s"),
209*10d63b7dSRichard Lowe 			      shell->string_mb,
210*10d63b7dSRichard Lowe 			      errmsg(errno));
211*10d63b7dSRichard Lowe 		}
212*10d63b7dSRichard Lowe 	}
213*10d63b7dSRichard Lowe 	if (childPid  == -1) {
214*10d63b7dSRichard Lowe 		fatal_mksh(gettext("fork failed: %s"),
215*10d63b7dSRichard Lowe 		      errmsg(errno));
216*10d63b7dSRichard Lowe 	}
217*10d63b7dSRichard Lowe 	retmem_mb(argv[cmd_argv_index]);
218*10d63b7dSRichard Lowe 	return childPid;
219*10d63b7dSRichard Lowe }
220*10d63b7dSRichard Lowe 
221*10d63b7dSRichard Lowe /*
222*10d63b7dSRichard Lowe  *	exec_vp(name, argv, envp, ignore_error)
223*10d63b7dSRichard Lowe  *
224*10d63b7dSRichard Lowe  *	Like execve, but does path search.
225*10d63b7dSRichard Lowe  *	This starts command when make invokes it directly (without a shell).
226*10d63b7dSRichard Lowe  *
227*10d63b7dSRichard Lowe  *	Return value:
228*10d63b7dSRichard Lowe  *				Returns false if the exec failed
229*10d63b7dSRichard Lowe  *
230*10d63b7dSRichard Lowe  *	Parameters:
231*10d63b7dSRichard Lowe  *		name		The name of the command to run
232*10d63b7dSRichard Lowe  *		argv		Arguments for the command
233*10d63b7dSRichard Lowe  *		envp		The environment for it
234*10d63b7dSRichard Lowe  *		ignore_error	Should we abort on error?
235*10d63b7dSRichard Lowe  *
236*10d63b7dSRichard Lowe  *	Global variables used:
237*10d63b7dSRichard Lowe  *		shell_name	The Name "SHELL", used to get the path to shell
238*10d63b7dSRichard Lowe  *		vroot_path	The path used by the vroot package
239*10d63b7dSRichard Lowe  */
240*10d63b7dSRichard Lowe static Boolean
exec_vp(register char * name,register char ** argv,char ** envp,register Boolean ignore_error,pathpt vroot_path)241*10d63b7dSRichard Lowe exec_vp(register char *name, register char **argv, char **envp, register Boolean ignore_error, pathpt vroot_path)
242*10d63b7dSRichard Lowe {
243*10d63b7dSRichard Lowe 	register Name		shell = getvar(shell_name);
244*10d63b7dSRichard Lowe 	register char		*shellname;
245*10d63b7dSRichard Lowe 	char			*shargv[4];
246*10d63b7dSRichard Lowe 	Name			tmp_shell;
247*10d63b7dSRichard Lowe 
248*10d63b7dSRichard Lowe 	if (IS_EQUAL(shell->string_mb, "")) {
249*10d63b7dSRichard Lowe 		shell = shell_name;
250*10d63b7dSRichard Lowe 	}
251*10d63b7dSRichard Lowe 
252*10d63b7dSRichard Lowe 	for (int i = 0; i < 5; i++) {
253*10d63b7dSRichard Lowe 		(void) execve_vroot(name,
254*10d63b7dSRichard Lowe 				    argv + 1,
255*10d63b7dSRichard Lowe 				    envp,
256*10d63b7dSRichard Lowe 				    vroot_path,
257*10d63b7dSRichard Lowe 				    VROOT_DEFAULT);
258*10d63b7dSRichard Lowe 		switch (errno) {
259*10d63b7dSRichard Lowe 		case ENOEXEC:
260*10d63b7dSRichard Lowe 		case ENOENT:
261*10d63b7dSRichard Lowe 			/* That failed. Let the shell handle it */
262*10d63b7dSRichard Lowe 			shellname = strrchr(shell->string_mb, (int) slash_char);
263*10d63b7dSRichard Lowe 			if (shellname == NULL) {
264*10d63b7dSRichard Lowe 				shellname = shell->string_mb;
265*10d63b7dSRichard Lowe 			} else {
266*10d63b7dSRichard Lowe 				shellname++;
267*10d63b7dSRichard Lowe 			}
268*10d63b7dSRichard Lowe 			shargv[0] = shellname;
269*10d63b7dSRichard Lowe 			shargv[1] = (char*)(ignore_error ? "-c" : "-ce");
270*10d63b7dSRichard Lowe 			shargv[2] = argv[0];
271*10d63b7dSRichard Lowe 			shargv[3] = NULL;
272*10d63b7dSRichard Lowe 			tmp_shell = getvar(shell_name);
273*10d63b7dSRichard Lowe 			if (IS_EQUAL(tmp_shell->string_mb, "")) {
274*10d63b7dSRichard Lowe 				tmp_shell = shell_name;
275*10d63b7dSRichard Lowe 			}
276*10d63b7dSRichard Lowe 			(void) execve_vroot(tmp_shell->string_mb,
277*10d63b7dSRichard Lowe 					    shargv,
278*10d63b7dSRichard Lowe 					    envp,
279*10d63b7dSRichard Lowe 					    vroot_path,
280*10d63b7dSRichard Lowe 					    VROOT_DEFAULT);
281*10d63b7dSRichard Lowe 			return failed;
282*10d63b7dSRichard Lowe 		case ETXTBSY:
283*10d63b7dSRichard Lowe 			/*
284*10d63b7dSRichard Lowe 			 * The program is busy (debugged?).
285*10d63b7dSRichard Lowe 			 * Wait and then try again.
286*10d63b7dSRichard Lowe 			 */
287*10d63b7dSRichard Lowe 			(void) sleep((unsigned) i);
288*10d63b7dSRichard Lowe 		case EAGAIN:
289*10d63b7dSRichard Lowe 			break;
290*10d63b7dSRichard Lowe 		default:
291*10d63b7dSRichard Lowe 			return failed;
292*10d63b7dSRichard Lowe 		}
293*10d63b7dSRichard Lowe 	}
294*10d63b7dSRichard Lowe 	return failed;
295*10d63b7dSRichard Lowe }
296*10d63b7dSRichard Lowe 
297*10d63b7dSRichard Lowe /*
298*10d63b7dSRichard Lowe  *	doexec(command, ignore_error)
299*10d63b7dSRichard Lowe  *
300*10d63b7dSRichard Lowe  *	Will scan an argument string and split it into words
301*10d63b7dSRichard Lowe  *	thus building an argument list that can be passed to exec_ve()
302*10d63b7dSRichard Lowe  *
303*10d63b7dSRichard Lowe  *	Return value:
304*10d63b7dSRichard Lowe  *				The pid of the process started here
305*10d63b7dSRichard Lowe  *
306*10d63b7dSRichard Lowe  *	Parameters:
307*10d63b7dSRichard Lowe  *		command		The command to run
308*10d63b7dSRichard Lowe  *		ignore_error	Should we abort on error?
309*10d63b7dSRichard Lowe  *
310*10d63b7dSRichard Lowe  *	Global variables used:
311*10d63b7dSRichard Lowe  *		filter_stderr	If -X is on we redirect stderr
312*10d63b7dSRichard Lowe  */
313*10d63b7dSRichard Lowe int
doexec(register wchar_t * command,register Boolean ignore_error,char * stdout_file,char * stderr_file,pathpt vroot_path,int nice_prio)314*10d63b7dSRichard Lowe doexec(register wchar_t *command, register Boolean ignore_error, char *stdout_file, char *stderr_file, pathpt vroot_path, int nice_prio)
315*10d63b7dSRichard Lowe {
316*10d63b7dSRichard Lowe 	int			arg_count = 5;
317*10d63b7dSRichard Lowe 	char			**argv;
318*10d63b7dSRichard Lowe 	int			length;
319*10d63b7dSRichard Lowe 	char			nice_prio_buf[MAXPATHLEN];
320*10d63b7dSRichard Lowe 	register char		**p;
321*10d63b7dSRichard Lowe 	wchar_t			*q;
322*10d63b7dSRichard Lowe 	register wchar_t	*t;
323*10d63b7dSRichard Lowe 	char			*tmp_mbs_buffer;
324*10d63b7dSRichard Lowe 
325*10d63b7dSRichard Lowe 	/*
326*10d63b7dSRichard Lowe 	 * Only prepend the /usr/bin/nice command to the original command
327*10d63b7dSRichard Lowe 	 * if the nice priority, nice_prio, is NOT zero (0).
328*10d63b7dSRichard Lowe 	 * Nice priorities can be a positive or a negative number.
329*10d63b7dSRichard Lowe 	 */
330*10d63b7dSRichard Lowe 	if (nice_prio != 0) {
331*10d63b7dSRichard Lowe 		arg_count += 2;
332*10d63b7dSRichard Lowe 	}
333*10d63b7dSRichard Lowe 	for (t = command; *t != (int) nul_char; t++) {
334*10d63b7dSRichard Lowe 		if (iswspace(*t)) {
335*10d63b7dSRichard Lowe 			arg_count++;
336*10d63b7dSRichard Lowe 		}
337*10d63b7dSRichard Lowe 	}
338*10d63b7dSRichard Lowe 	argv = (char **)alloca(arg_count * (sizeof(char *)));
339*10d63b7dSRichard Lowe 	/*
340*10d63b7dSRichard Lowe 	 * Reserve argv[0] for sh in case of exec_vp failure.
341*10d63b7dSRichard Lowe 	 * Don't worry about prepending /usr/bin/nice command to argv[0].
342*10d63b7dSRichard Lowe 	 * In fact, doing it may cause the sh command to fail!
343*10d63b7dSRichard Lowe 	 */
344*10d63b7dSRichard Lowe 	p = &argv[1];
345*10d63b7dSRichard Lowe 	if ((length = wcslen(command)) >= MAXPATHLEN) {
346*10d63b7dSRichard Lowe 		tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
347*10d63b7dSRichard Lowe 		(void) wcstombs(tmp_mbs_buffer, command, (length * MB_LEN_MAX) + 1);
348*10d63b7dSRichard Lowe 		argv[0] = strdup(tmp_mbs_buffer);
349*10d63b7dSRichard Lowe 		retmem_mb(tmp_mbs_buffer);
350*10d63b7dSRichard Lowe         } else {
351*10d63b7dSRichard Lowe 		WCSTOMBS(mbs_buffer, command);
352*10d63b7dSRichard Lowe 		argv[0] = strdup(mbs_buffer);
353*10d63b7dSRichard Lowe 	}
354*10d63b7dSRichard Lowe 
355*10d63b7dSRichard Lowe 	if (nice_prio != 0) {
356*10d63b7dSRichard Lowe 		*p++ = strdup("/usr/bin/nice");
357*10d63b7dSRichard Lowe 		(void) sprintf(nice_prio_buf, "-%d", nice_prio);
358*10d63b7dSRichard Lowe 		*p++ = strdup(nice_prio_buf);
359*10d63b7dSRichard Lowe 	}
360*10d63b7dSRichard Lowe 	/* Build list of argument words. */
361*10d63b7dSRichard Lowe 	for (t = command; *t;) {
362*10d63b7dSRichard Lowe 		if (p >= &argv[arg_count]) {
363*10d63b7dSRichard Lowe 			/* This should never happen, right? */
364*10d63b7dSRichard Lowe 			WCSTOMBS(mbs_buffer, command);
365*10d63b7dSRichard Lowe 			fatal_mksh(gettext("Command `%s' has more than %d arguments"),
366*10d63b7dSRichard Lowe 			      mbs_buffer,
367*10d63b7dSRichard Lowe 			      arg_count);
368*10d63b7dSRichard Lowe 		}
369*10d63b7dSRichard Lowe 		q = t;
370*10d63b7dSRichard Lowe 		while (!iswspace(*t) && (*t != (int) nul_char)) {
371*10d63b7dSRichard Lowe 			t++;
372*10d63b7dSRichard Lowe 		}
373*10d63b7dSRichard Lowe 		if (*t) {
374*10d63b7dSRichard Lowe 			for (*t++ = (int) nul_char; iswspace(*t); t++);
375*10d63b7dSRichard Lowe 		}
376*10d63b7dSRichard Lowe 		if ((length = wcslen(q)) >= MAXPATHLEN) {
377*10d63b7dSRichard Lowe 			tmp_mbs_buffer = getmem((length * MB_LEN_MAX) + 1);
378*10d63b7dSRichard Lowe 			(void) wcstombs(tmp_mbs_buffer, q, (length * MB_LEN_MAX) + 1);
379*10d63b7dSRichard Lowe 			*p++ = strdup(tmp_mbs_buffer);
380*10d63b7dSRichard Lowe 			retmem_mb(tmp_mbs_buffer);
381*10d63b7dSRichard Lowe 		} else {
382*10d63b7dSRichard Lowe 			WCSTOMBS(mbs_buffer, q);
383*10d63b7dSRichard Lowe 			*p++ = strdup(mbs_buffer);
384*10d63b7dSRichard Lowe 		}
385*10d63b7dSRichard Lowe 	}
386*10d63b7dSRichard Lowe 	*p = NULL;
387*10d63b7dSRichard Lowe 
388*10d63b7dSRichard Lowe 	/* Then exec the command with that argument list. */
389*10d63b7dSRichard Lowe 	(void) fflush(stdout);
390*10d63b7dSRichard Lowe 	if ((childPid = fork()) == 0) {
391*10d63b7dSRichard Lowe 		enable_interrupt((void (*) (int)) SIG_DFL);
392*10d63b7dSRichard Lowe #if 0
393*10d63b7dSRichard Lowe 		if (filter_stderr) {
394*10d63b7dSRichard Lowe 			redirect_stderr();
395*10d63b7dSRichard Lowe 		}
396*10d63b7dSRichard Lowe #endif
397*10d63b7dSRichard Lowe 		(void) exec_vp(argv[1], argv, environ, ignore_error, vroot_path);
398*10d63b7dSRichard Lowe 		fatal_mksh(gettext("Cannot load command `%s': %s"), argv[1], errmsg(errno));
399*10d63b7dSRichard Lowe 	}
400*10d63b7dSRichard Lowe 	if (childPid  == -1) {
401*10d63b7dSRichard Lowe 		fatal_mksh(gettext("fork failed: %s"),
402*10d63b7dSRichard Lowe 		      errmsg(errno));
403*10d63b7dSRichard Lowe 	}
404*10d63b7dSRichard Lowe 	for (int i = 0; argv[i] != NULL; i++) {
405*10d63b7dSRichard Lowe 		retmem_mb(argv[i]);
406*10d63b7dSRichard Lowe 	}
407*10d63b7dSRichard Lowe 	return childPid;
408*10d63b7dSRichard Lowe }
409*10d63b7dSRichard Lowe 
410*10d63b7dSRichard Lowe /*
411*10d63b7dSRichard Lowe  *	await(ignore_error, silent_error, target, command, running_pid)
412*10d63b7dSRichard Lowe  *
413*10d63b7dSRichard Lowe  *	Wait for one child process and analyzes
414*10d63b7dSRichard Lowe  *	the returned status when the child process terminates.
415*10d63b7dSRichard Lowe  *
416*10d63b7dSRichard Lowe  *	Return value:
417*10d63b7dSRichard Lowe  *				Returns true if commands ran OK
418*10d63b7dSRichard Lowe  *
419*10d63b7dSRichard Lowe  *	Parameters:
420*10d63b7dSRichard Lowe  *		ignore_error	Should we abort on error?
421*10d63b7dSRichard Lowe  *		silent_error	Should error messages be suppressed for dmake?
422*10d63b7dSRichard Lowe  *		target		The target we are building, for error msgs
423*10d63b7dSRichard Lowe  *		command		The command we ran, for error msgs
424*10d63b7dSRichard Lowe  *		running_pid	The pid of the process we are waiting for
425*10d63b7dSRichard Lowe  *
426*10d63b7dSRichard Lowe  *	Static variables used:
427*10d63b7dSRichard Lowe  *		filter_file	The fd for the filter file
428*10d63b7dSRichard Lowe  *		filter_file_name The name of the filter file
429*10d63b7dSRichard Lowe  *
430*10d63b7dSRichard Lowe  *	Global variables used:
431*10d63b7dSRichard Lowe  *		filter_stderr	Set if -X is on
432*10d63b7dSRichard Lowe  */
433*10d63b7dSRichard Lowe Boolean
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)434*10d63b7dSRichard 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)
435*10d63b7dSRichard Lowe {
436*10d63b7dSRichard Lowe         int                     status;
437*10d63b7dSRichard Lowe 	char			*buffer;
438*10d63b7dSRichard Lowe 	int			core_dumped;
439*10d63b7dSRichard Lowe 	int			exit_status;
440*10d63b7dSRichard Lowe 	FILE			*outfp;
441*10d63b7dSRichard Lowe 	register pid_t		pid;
442*10d63b7dSRichard Lowe 	struct stat		stat_buff;
443*10d63b7dSRichard Lowe 	int			termination_signal;
444*10d63b7dSRichard Lowe 	char			tmp_buf[MAXPATHLEN];
445*10d63b7dSRichard Lowe 
446*10d63b7dSRichard Lowe 	while ((pid = wait(&status)) != running_pid) {
447*10d63b7dSRichard Lowe 		if (pid == -1) {
448*10d63b7dSRichard Lowe 			fatal_mksh(gettext("wait() failed: %s"), errmsg(errno));
449*10d63b7dSRichard Lowe 		}
450*10d63b7dSRichard Lowe 	}
451*10d63b7dSRichard Lowe 	(void) fflush(stdout);
452*10d63b7dSRichard Lowe 	(void) fflush(stderr);
453*10d63b7dSRichard Lowe 
454*10d63b7dSRichard Lowe         if (status == 0) {
455*10d63b7dSRichard Lowe 
456*10d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS
457*10d63b7dSRichard Lowe 		warning_mksh("I'm in await(), and status is 0.");
458*10d63b7dSRichard Lowe #endif
459*10d63b7dSRichard Lowe 
460*10d63b7dSRichard Lowe                 return succeeded;
461*10d63b7dSRichard Lowe 	}
462*10d63b7dSRichard Lowe 
463*10d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS
464*10d63b7dSRichard Lowe 	warning_mksh("I'm in await(), and status is *NOT* 0.");
465*10d63b7dSRichard Lowe #endif
466*10d63b7dSRichard Lowe 
467*10d63b7dSRichard Lowe 
468*10d63b7dSRichard Lowe         exit_status = WEXITSTATUS(status);
469*10d63b7dSRichard Lowe 
470*10d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS
471*10d63b7dSRichard Lowe 	warning_mksh("I'm in await(), and exit_status is %d.", exit_status);
472*10d63b7dSRichard Lowe #endif
473*10d63b7dSRichard Lowe 
474*10d63b7dSRichard Lowe         termination_signal = WTERMSIG(status);
475*10d63b7dSRichard Lowe         core_dumped = WCOREDUMP(status);
476*10d63b7dSRichard Lowe 
477*10d63b7dSRichard Lowe 	/*
478*10d63b7dSRichard Lowe 	 * If the child returned an error, we now try to print a
479*10d63b7dSRichard Lowe 	 * nice message about it.
480*10d63b7dSRichard Lowe 	 */
481*10d63b7dSRichard Lowe 
482*10d63b7dSRichard Lowe 	tmp_buf[0] = (int) nul_char;
483*10d63b7dSRichard Lowe 	if (!silent_error) {
484*10d63b7dSRichard Lowe 		if (exit_status != 0) {
485*10d63b7dSRichard Lowe 			(void) fprintf(stdout,
486*10d63b7dSRichard Lowe 				       gettext("*** Error code %d"),
487*10d63b7dSRichard Lowe 				       exit_status);
488*10d63b7dSRichard Lowe 		} else {
489*10d63b7dSRichard Lowe 				(void) fprintf(stdout,
490*10d63b7dSRichard Lowe 					       gettext("*** Signal %d"),
491*10d63b7dSRichard Lowe 					       termination_signal);
492*10d63b7dSRichard Lowe 			if (core_dumped) {
493*10d63b7dSRichard Lowe 				(void) fprintf(stdout,
494*10d63b7dSRichard Lowe 					       gettext(" - core dumped"));
495*10d63b7dSRichard Lowe 			}
496*10d63b7dSRichard Lowe 		}
497*10d63b7dSRichard Lowe 		if (ignore_error) {
498*10d63b7dSRichard Lowe 			(void) fprintf(stdout,
499*10d63b7dSRichard Lowe 				       gettext(" (ignored)"));
500*10d63b7dSRichard Lowe 		}
501*10d63b7dSRichard Lowe 		(void) fprintf(stdout, "\n");
502*10d63b7dSRichard Lowe 		(void) fflush(stdout);
503*10d63b7dSRichard Lowe 	}
504*10d63b7dSRichard Lowe 
505*10d63b7dSRichard Lowe #ifdef PRINT_EXIT_STATUS
506*10d63b7dSRichard Lowe 	warning_mksh("I'm in await(), returning failed.");
507*10d63b7dSRichard Lowe #endif
508*10d63b7dSRichard Lowe 
509*10d63b7dSRichard Lowe 	return failed;
510*10d63b7dSRichard Lowe }
511*10d63b7dSRichard Lowe 
512*10d63b7dSRichard Lowe /*
513*10d63b7dSRichard Lowe  *	sh_command2string(command, destination)
514*10d63b7dSRichard Lowe  *
515*10d63b7dSRichard Lowe  *	Run one sh command and capture the output from it.
516*10d63b7dSRichard Lowe  *
517*10d63b7dSRichard Lowe  *	Return value:
518*10d63b7dSRichard Lowe  *
519*10d63b7dSRichard Lowe  *	Parameters:
520*10d63b7dSRichard Lowe  *		command		The command to run
521*10d63b7dSRichard Lowe  *		destination	Where to deposit the output from the command
522*10d63b7dSRichard Lowe  *
523*10d63b7dSRichard Lowe  *	Static variables used:
524*10d63b7dSRichard Lowe  *
525*10d63b7dSRichard Lowe  *	Global variables used:
526*10d63b7dSRichard Lowe  */
527*10d63b7dSRichard Lowe void
sh_command2string(register String command,register String destination)528*10d63b7dSRichard Lowe sh_command2string(register String command, register String destination)
529*10d63b7dSRichard Lowe {
530*10d63b7dSRichard Lowe 	register FILE		*fd;
531*10d63b7dSRichard Lowe 	register int		chr;
532*10d63b7dSRichard Lowe 	int			status;
533*10d63b7dSRichard Lowe 	Boolean			command_generated_output = false;
534*10d63b7dSRichard Lowe 
535*10d63b7dSRichard Lowe 	command->text.p = (int) nul_char;
536*10d63b7dSRichard Lowe 	WCSTOMBS(mbs_buffer, command->buffer.start);
537*10d63b7dSRichard Lowe 	if ((fd = popen(mbs_buffer, "r")) == NULL) {
538*10d63b7dSRichard Lowe 		WCSTOMBS(mbs_buffer, command->buffer.start);
539*10d63b7dSRichard Lowe 		fatal_mksh(gettext("Could not run command `%s' for :sh transformation"),
540*10d63b7dSRichard Lowe 		      mbs_buffer);
541*10d63b7dSRichard Lowe 	}
542*10d63b7dSRichard Lowe 	while ((chr = getc(fd)) != EOF) {
543*10d63b7dSRichard Lowe 		if (chr == (int) newline_char) {
544*10d63b7dSRichard Lowe 			chr = (int) space_char;
545*10d63b7dSRichard Lowe 		}
546*10d63b7dSRichard Lowe 		command_generated_output = true;
547*10d63b7dSRichard Lowe 		append_char(chr, destination);
548*10d63b7dSRichard Lowe 	}
549*10d63b7dSRichard Lowe 
550*10d63b7dSRichard Lowe 	/*
551*10d63b7dSRichard Lowe 	 * We don't want to keep the last LINE_FEED since usually
552*10d63b7dSRichard Lowe 	 * the output of the 'sh:' command is used to evaluate
553*10d63b7dSRichard Lowe 	 * some MACRO. ( /bin/sh and other shell add a line feed
554*10d63b7dSRichard Lowe 	 * to the output so that the prompt appear in the right place.
555*10d63b7dSRichard Lowe 	 * We don't need that
556*10d63b7dSRichard Lowe 	 */
557*10d63b7dSRichard Lowe 	if (command_generated_output){
558*10d63b7dSRichard Lowe 		if ( *(destination->text.p-1) == (int) space_char) {
559*10d63b7dSRichard Lowe 			* (-- destination->text.p) = '\0';
560*10d63b7dSRichard Lowe 		}
561*10d63b7dSRichard Lowe 	} else {
562*10d63b7dSRichard Lowe 		/*
563*10d63b7dSRichard Lowe 		 * If the command didn't generate any output,
564*10d63b7dSRichard Lowe 		 * set the buffer to a null string.
565*10d63b7dSRichard Lowe 		 */
566*10d63b7dSRichard Lowe 		*(destination->text.p) = '\0';
567*10d63b7dSRichard Lowe 	}
568*10d63b7dSRichard Lowe 
569*10d63b7dSRichard Lowe 	status = pclose(fd);
570*10d63b7dSRichard Lowe 	if (status != 0) {
571*10d63b7dSRichard Lowe 		WCSTOMBS(mbs_buffer, command->buffer.start);
572*10d63b7dSRichard Lowe 		fatal_mksh(gettext("The command `%s' returned status `%d'"),
573*10d63b7dSRichard Lowe 		      mbs_buffer,
574*10d63b7dSRichard Lowe 		      WEXITSTATUS(status));
575*10d63b7dSRichard Lowe 	}
576*10d63b7dSRichard Lowe }
577*10d63b7dSRichard Lowe 
578*10d63b7dSRichard Lowe 
579