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