xref: /minix3/bin/sh/main.c (revision 0a6a1f1d05b60e214de2f05a7310ddd1f0e590e7)
1*0a6a1f1dSLionel Sambuc /*	$NetBSD: main.c,v 1.59 2015/05/26 21:35:15 christos Exp $	*/
2d90bee97SLionel Sambuc 
3d90bee97SLionel Sambuc /*-
4d90bee97SLionel Sambuc  * Copyright (c) 1991, 1993
5d90bee97SLionel Sambuc  *	The Regents of the University of California.  All rights reserved.
6d90bee97SLionel Sambuc  *
7d90bee97SLionel Sambuc  * This code is derived from software contributed to Berkeley by
8d90bee97SLionel Sambuc  * Kenneth Almquist.
9d90bee97SLionel Sambuc  *
10d90bee97SLionel Sambuc  * Redistribution and use in source and binary forms, with or without
11d90bee97SLionel Sambuc  * modification, are permitted provided that the following conditions
12d90bee97SLionel Sambuc  * are met:
13d90bee97SLionel Sambuc  * 1. Redistributions of source code must retain the above copyright
14d90bee97SLionel Sambuc  *    notice, this list of conditions and the following disclaimer.
15d90bee97SLionel Sambuc  * 2. Redistributions in binary form must reproduce the above copyright
16d90bee97SLionel Sambuc  *    notice, this list of conditions and the following disclaimer in the
17d90bee97SLionel Sambuc  *    documentation and/or other materials provided with the distribution.
18d90bee97SLionel Sambuc  * 3. Neither the name of the University nor the names of its contributors
19d90bee97SLionel Sambuc  *    may be used to endorse or promote products derived from this software
20d90bee97SLionel Sambuc  *    without specific prior written permission.
21d90bee97SLionel Sambuc  *
22d90bee97SLionel Sambuc  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23d90bee97SLionel Sambuc  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24d90bee97SLionel Sambuc  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25d90bee97SLionel Sambuc  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26d90bee97SLionel Sambuc  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27d90bee97SLionel Sambuc  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28d90bee97SLionel Sambuc  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29d90bee97SLionel Sambuc  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30d90bee97SLionel Sambuc  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31d90bee97SLionel Sambuc  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32d90bee97SLionel Sambuc  * SUCH DAMAGE.
33d90bee97SLionel Sambuc  */
34d90bee97SLionel Sambuc 
35d90bee97SLionel Sambuc #include <sys/cdefs.h>
36d90bee97SLionel Sambuc #ifndef lint
37d90bee97SLionel Sambuc __COPYRIGHT("@(#) Copyright (c) 1991, 1993\
38d90bee97SLionel Sambuc  The Regents of the University of California.  All rights reserved.");
39d90bee97SLionel Sambuc #endif /* not lint */
40d90bee97SLionel Sambuc 
41d90bee97SLionel Sambuc #ifndef lint
42d90bee97SLionel Sambuc #if 0
43d90bee97SLionel Sambuc static char sccsid[] = "@(#)main.c	8.7 (Berkeley) 7/19/95";
44d90bee97SLionel Sambuc #else
45*0a6a1f1dSLionel Sambuc __RCSID("$NetBSD: main.c,v 1.59 2015/05/26 21:35:15 christos Exp $");
46d90bee97SLionel Sambuc #endif
47d90bee97SLionel Sambuc #endif /* not lint */
48d90bee97SLionel Sambuc 
49d90bee97SLionel Sambuc #include <errno.h>
50d90bee97SLionel Sambuc #include <stdio.h>
51d90bee97SLionel Sambuc #include <signal.h>
52d90bee97SLionel Sambuc #include <sys/stat.h>
53d90bee97SLionel Sambuc #include <unistd.h>
54d90bee97SLionel Sambuc #include <stdlib.h>
55d90bee97SLionel Sambuc #include <locale.h>
56d90bee97SLionel Sambuc #include <fcntl.h>
57d90bee97SLionel Sambuc 
58d90bee97SLionel Sambuc 
59d90bee97SLionel Sambuc #include "shell.h"
60d90bee97SLionel Sambuc #include "main.h"
61d90bee97SLionel Sambuc #include "mail.h"
62d90bee97SLionel Sambuc #include "options.h"
63d90bee97SLionel Sambuc #include "builtins.h"
64d90bee97SLionel Sambuc #include "output.h"
65d90bee97SLionel Sambuc #include "parser.h"
66d90bee97SLionel Sambuc #include "nodes.h"
67d90bee97SLionel Sambuc #include "expand.h"
68d90bee97SLionel Sambuc #include "eval.h"
69d90bee97SLionel Sambuc #include "jobs.h"
70d90bee97SLionel Sambuc #include "input.h"
71d90bee97SLionel Sambuc #include "trap.h"
72d90bee97SLionel Sambuc #include "var.h"
73d90bee97SLionel Sambuc #include "show.h"
74d90bee97SLionel Sambuc #include "memalloc.h"
75d90bee97SLionel Sambuc #include "error.h"
76d90bee97SLionel Sambuc #include "init.h"
77d90bee97SLionel Sambuc #include "mystring.h"
78d90bee97SLionel Sambuc #include "exec.h"
79d90bee97SLionel Sambuc #include "cd.h"
80d90bee97SLionel Sambuc 
81d90bee97SLionel Sambuc #define PROFILE 0
82d90bee97SLionel Sambuc 
83d90bee97SLionel Sambuc int rootpid;
84d90bee97SLionel Sambuc int rootshell;
85d90bee97SLionel Sambuc int posix;
86d90bee97SLionel Sambuc #if PROFILE
87d90bee97SLionel Sambuc short profile_buf[16384];
88d90bee97SLionel Sambuc extern int etext();
89d90bee97SLionel Sambuc #endif
90d90bee97SLionel Sambuc 
91d90bee97SLionel Sambuc STATIC void read_profile(const char *);
92d90bee97SLionel Sambuc int main(int, char **);
93d90bee97SLionel Sambuc 
94d90bee97SLionel Sambuc /*
95d90bee97SLionel Sambuc  * Main routine.  We initialize things, parse the arguments, execute
96d90bee97SLionel Sambuc  * profiles if we're a login shell, and then call cmdloop to execute
97d90bee97SLionel Sambuc  * commands.  The setjmp call sets up the location to jump to when an
98d90bee97SLionel Sambuc  * exception occurs.  When an exception occurs the variable "state"
99d90bee97SLionel Sambuc  * is used to figure out how far we had gotten.
100d90bee97SLionel Sambuc  */
101d90bee97SLionel Sambuc 
102d90bee97SLionel Sambuc int
main(int argc,char ** argv)103d90bee97SLionel Sambuc main(int argc, char **argv)
104d90bee97SLionel Sambuc {
105d90bee97SLionel Sambuc 	struct jmploc jmploc;
106d90bee97SLionel Sambuc 	struct stackmark smark;
107d90bee97SLionel Sambuc 	volatile int state;
108d90bee97SLionel Sambuc 	char *shinit;
109*0a6a1f1dSLionel Sambuc 	uid_t uid;
110*0a6a1f1dSLionel Sambuc 	gid_t gid;
111*0a6a1f1dSLionel Sambuc 
112*0a6a1f1dSLionel Sambuc 	uid = getuid();
113*0a6a1f1dSLionel Sambuc 	gid = getgid();
114d90bee97SLionel Sambuc 
115d90bee97SLionel Sambuc 	setlocale(LC_ALL, "");
116d90bee97SLionel Sambuc 
117d90bee97SLionel Sambuc 	posix = getenv("POSIXLY_CORRECT") != NULL;
118d90bee97SLionel Sambuc #if PROFILE
119d90bee97SLionel Sambuc 	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
120d90bee97SLionel Sambuc #endif
121d90bee97SLionel Sambuc 	state = 0;
122d90bee97SLionel Sambuc 	if (setjmp(jmploc.loc)) {
123d90bee97SLionel Sambuc 		/*
124d90bee97SLionel Sambuc 		 * When a shell procedure is executed, we raise the
125d90bee97SLionel Sambuc 		 * exception EXSHELLPROC to clean up before executing
126d90bee97SLionel Sambuc 		 * the shell procedure.
127d90bee97SLionel Sambuc 		 */
128d90bee97SLionel Sambuc 		switch (exception) {
129d90bee97SLionel Sambuc 		case EXSHELLPROC:
130d90bee97SLionel Sambuc 			rootpid = getpid();
131d90bee97SLionel Sambuc 			rootshell = 1;
132d90bee97SLionel Sambuc 			minusc = NULL;
133d90bee97SLionel Sambuc 			state = 3;
134d90bee97SLionel Sambuc 			break;
135d90bee97SLionel Sambuc 
136d90bee97SLionel Sambuc 		case EXEXEC:
137d90bee97SLionel Sambuc 			exitstatus = exerrno;
138d90bee97SLionel Sambuc 			break;
139d90bee97SLionel Sambuc 
140d90bee97SLionel Sambuc 		case EXERROR:
141d90bee97SLionel Sambuc 			exitstatus = 2;
142d90bee97SLionel Sambuc 			break;
143d90bee97SLionel Sambuc 
144d90bee97SLionel Sambuc 		default:
145d90bee97SLionel Sambuc 			break;
146d90bee97SLionel Sambuc 		}
147d90bee97SLionel Sambuc 
148d90bee97SLionel Sambuc 		if (exception != EXSHELLPROC) {
149d90bee97SLionel Sambuc 			if (state == 0 || iflag == 0 || ! rootshell)
150d90bee97SLionel Sambuc 				exitshell(exitstatus);
151d90bee97SLionel Sambuc 		}
152d90bee97SLionel Sambuc 		reset();
153d90bee97SLionel Sambuc 		if (exception == EXINT
154d90bee97SLionel Sambuc #if ATTY
155d90bee97SLionel Sambuc 		 && (! attyset() || equal(termval(), "emacs"))
156d90bee97SLionel Sambuc #endif
157d90bee97SLionel Sambuc 		 ) {
158d90bee97SLionel Sambuc 			out2c('\n');
159d90bee97SLionel Sambuc 			flushout(&errout);
160d90bee97SLionel Sambuc 		}
161d90bee97SLionel Sambuc 		popstackmark(&smark);
162d90bee97SLionel Sambuc 		FORCEINTON;				/* enable interrupts */
163d90bee97SLionel Sambuc 		if (state == 1)
164d90bee97SLionel Sambuc 			goto state1;
165d90bee97SLionel Sambuc 		else if (state == 2)
166d90bee97SLionel Sambuc 			goto state2;
167d90bee97SLionel Sambuc 		else if (state == 3)
168d90bee97SLionel Sambuc 			goto state3;
169d90bee97SLionel Sambuc 		else
170d90bee97SLionel Sambuc 			goto state4;
171d90bee97SLionel Sambuc 	}
172d90bee97SLionel Sambuc 	handler = &jmploc;
173d90bee97SLionel Sambuc #ifdef DEBUG
174d90bee97SLionel Sambuc #if DEBUG == 2
175d90bee97SLionel Sambuc 	debug = 1;
176d90bee97SLionel Sambuc #endif
177d90bee97SLionel Sambuc 	opentrace();
178d90bee97SLionel Sambuc 	trputs("Shell args:  ");  trargs(argv);
179d90bee97SLionel Sambuc #endif
180d90bee97SLionel Sambuc 	rootpid = getpid();
181d90bee97SLionel Sambuc 	rootshell = 1;
182d90bee97SLionel Sambuc 	init();
183d90bee97SLionel Sambuc 	initpwd();
184d90bee97SLionel Sambuc 	setstackmark(&smark);
185d90bee97SLionel Sambuc 	procargs(argc, argv);
186*0a6a1f1dSLionel Sambuc 
187*0a6a1f1dSLionel Sambuc 	/*
188*0a6a1f1dSLionel Sambuc 	 * Limit bogus system(3) or popen(3) calls in setuid binaries,
189*0a6a1f1dSLionel Sambuc 	 * by requiring the -p flag
190*0a6a1f1dSLionel Sambuc 	 */
191*0a6a1f1dSLionel Sambuc 	if (!pflag && (uid != geteuid() || gid != getegid())) {
192*0a6a1f1dSLionel Sambuc 		setuid(uid);
193*0a6a1f1dSLionel Sambuc 		setgid(gid);
194*0a6a1f1dSLionel Sambuc 		/* PS1 might need to be changed accordingly. */
195*0a6a1f1dSLionel Sambuc 		choose_ps1();
196*0a6a1f1dSLionel Sambuc 	}
197*0a6a1f1dSLionel Sambuc 
198d90bee97SLionel Sambuc 	if (argv[0] && argv[0][0] == '-') {
199d90bee97SLionel Sambuc 		state = 1;
200d90bee97SLionel Sambuc 		read_profile("/etc/profile");
201d90bee97SLionel Sambuc state1:
202d90bee97SLionel Sambuc 		state = 2;
203d90bee97SLionel Sambuc 		read_profile(".profile");
204d90bee97SLionel Sambuc 	}
205d90bee97SLionel Sambuc state2:
206d90bee97SLionel Sambuc 	state = 3;
207d90bee97SLionel Sambuc 	if ((iflag || !posix) &&
208d90bee97SLionel Sambuc 	    getuid() == geteuid() && getgid() == getegid()) {
209d90bee97SLionel Sambuc 		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
210d90bee97SLionel Sambuc 			state = 3;
211d90bee97SLionel Sambuc 			read_profile(shinit);
212d90bee97SLionel Sambuc 		}
213d90bee97SLionel Sambuc 	}
214d90bee97SLionel Sambuc state3:
215d90bee97SLionel Sambuc 	state = 4;
216d90bee97SLionel Sambuc 	if (sflag == 0 || minusc) {
217d90bee97SLionel Sambuc 		static int sigs[] =  {
218d90bee97SLionel Sambuc 		    SIGINT, SIGQUIT, SIGHUP,
219d90bee97SLionel Sambuc #ifdef SIGTSTP
220d90bee97SLionel Sambuc 		    SIGTSTP,
221d90bee97SLionel Sambuc #endif
222d90bee97SLionel Sambuc 		    SIGPIPE
223d90bee97SLionel Sambuc 		};
224d90bee97SLionel Sambuc #define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0]))
225d90bee97SLionel Sambuc 		size_t i;
226d90bee97SLionel Sambuc 
227d90bee97SLionel Sambuc 		for (i = 0; i < SIGSSIZE; i++)
228d90bee97SLionel Sambuc 		    setsignal(sigs[i], 0);
229d90bee97SLionel Sambuc 	}
230d90bee97SLionel Sambuc 
231d90bee97SLionel Sambuc 	if (minusc)
232d90bee97SLionel Sambuc 		evalstring(minusc, 0);
233d90bee97SLionel Sambuc 
234d90bee97SLionel Sambuc 	if (sflag || minusc == NULL) {
235d90bee97SLionel Sambuc state4:	/* XXX ??? - why isn't this before the "if" statement */
236d90bee97SLionel Sambuc 		cmdloop(1);
237d90bee97SLionel Sambuc 	}
238d90bee97SLionel Sambuc #if PROFILE
239d90bee97SLionel Sambuc 	monitor(0);
240d90bee97SLionel Sambuc #endif
241d90bee97SLionel Sambuc 	exitshell(exitstatus);
242d90bee97SLionel Sambuc 	/* NOTREACHED */
243d90bee97SLionel Sambuc }
244d90bee97SLionel Sambuc 
245d90bee97SLionel Sambuc 
246d90bee97SLionel Sambuc /*
247d90bee97SLionel Sambuc  * Read and execute commands.  "Top" is nonzero for the top level command
248d90bee97SLionel Sambuc  * loop; it turns on prompting if the shell is interactive.
249d90bee97SLionel Sambuc  */
250d90bee97SLionel Sambuc 
251d90bee97SLionel Sambuc void
cmdloop(int top)252d90bee97SLionel Sambuc cmdloop(int top)
253d90bee97SLionel Sambuc {
254d90bee97SLionel Sambuc 	union node *n;
255d90bee97SLionel Sambuc 	struct stackmark smark;
256d90bee97SLionel Sambuc 	int inter;
257d90bee97SLionel Sambuc 	int numeof = 0;
258*0a6a1f1dSLionel Sambuc 	enum skipstate skip;
259d90bee97SLionel Sambuc 
260d90bee97SLionel Sambuc 	TRACE(("cmdloop(%d) called\n", top));
261d90bee97SLionel Sambuc 	setstackmark(&smark);
262d90bee97SLionel Sambuc 	for (;;) {
263d90bee97SLionel Sambuc 		if (pendingsigs)
264d90bee97SLionel Sambuc 			dotrap();
265d90bee97SLionel Sambuc 		inter = 0;
266d90bee97SLionel Sambuc 		if (iflag == 1 && top) {
267d90bee97SLionel Sambuc 			inter = 1;
268d90bee97SLionel Sambuc 			showjobs(out2, SHOW_CHANGED);
269d90bee97SLionel Sambuc 			chkmail(0);
270d90bee97SLionel Sambuc 			flushout(&errout);
271d90bee97SLionel Sambuc 		}
272d90bee97SLionel Sambuc 		n = parsecmd(inter);
273d90bee97SLionel Sambuc 		/* showtree(n); DEBUG */
274d90bee97SLionel Sambuc 		if (n == NEOF) {
275d90bee97SLionel Sambuc 			if (!top || numeof >= 50)
276d90bee97SLionel Sambuc 				break;
277d90bee97SLionel Sambuc 			if (!stoppedjobs()) {
278d90bee97SLionel Sambuc 				if (!Iflag)
279d90bee97SLionel Sambuc 					break;
280d90bee97SLionel Sambuc 				out2str("\nUse \"exit\" to leave shell.\n");
281d90bee97SLionel Sambuc 			}
282d90bee97SLionel Sambuc 			numeof++;
283d90bee97SLionel Sambuc 		} else if (n != NULL && nflag == 0) {
284d90bee97SLionel Sambuc 			job_warning = (job_warning == 2) ? 1 : 0;
285d90bee97SLionel Sambuc 			numeof = 0;
286d90bee97SLionel Sambuc 			evaltree(n, 0);
287d90bee97SLionel Sambuc 		}
288d90bee97SLionel Sambuc 		popstackmark(&smark);
289d90bee97SLionel Sambuc 		setstackmark(&smark);
290*0a6a1f1dSLionel Sambuc 
291*0a6a1f1dSLionel Sambuc 		/*
292*0a6a1f1dSLionel Sambuc 		 * Any SKIP* can occur here!  SKIP(FUNC|BREAK|CONT) occur when
293*0a6a1f1dSLionel Sambuc 		 * a dotcmd is in a loop or a function body and appropriate
294*0a6a1f1dSLionel Sambuc 		 * built-ins occurs in file scope in the sourced file.  Values
295*0a6a1f1dSLionel Sambuc 		 * other than SKIPFILE are reset by the appropriate eval*()
296*0a6a1f1dSLionel Sambuc 		 * that contained the dotcmd() call.
297*0a6a1f1dSLionel Sambuc 		 */
298*0a6a1f1dSLionel Sambuc 		skip = current_skipstate();
299*0a6a1f1dSLionel Sambuc 		if (skip != SKIPNONE) {
300*0a6a1f1dSLionel Sambuc 			if (skip == SKIPFILE)
301*0a6a1f1dSLionel Sambuc 				stop_skipping();
302d90bee97SLionel Sambuc 			break;
303d90bee97SLionel Sambuc 		}
304d90bee97SLionel Sambuc 	}
305d90bee97SLionel Sambuc 	popstackmark(&smark);
306d90bee97SLionel Sambuc }
307d90bee97SLionel Sambuc 
308d90bee97SLionel Sambuc 
309d90bee97SLionel Sambuc 
310d90bee97SLionel Sambuc /*
311d90bee97SLionel Sambuc  * Read /etc/profile or .profile.  Return on error.
312d90bee97SLionel Sambuc  */
313d90bee97SLionel Sambuc 
314d90bee97SLionel Sambuc STATIC void
read_profile(const char * name)315d90bee97SLionel Sambuc read_profile(const char *name)
316d90bee97SLionel Sambuc {
317d90bee97SLionel Sambuc 	int fd;
318d90bee97SLionel Sambuc 	int xflag_set = 0;
319d90bee97SLionel Sambuc 	int vflag_set = 0;
320d90bee97SLionel Sambuc 
321d90bee97SLionel Sambuc 	INTOFF;
322d90bee97SLionel Sambuc 	if ((fd = open(name, O_RDONLY)) >= 0)
323d90bee97SLionel Sambuc 		setinputfd(fd, 1);
324d90bee97SLionel Sambuc 	INTON;
325d90bee97SLionel Sambuc 	if (fd < 0)
326d90bee97SLionel Sambuc 		return;
327d90bee97SLionel Sambuc 	/* -q turns off -x and -v just when executing init files */
328d90bee97SLionel Sambuc 	if (qflag)  {
329d90bee97SLionel Sambuc 	    if (xflag)
330d90bee97SLionel Sambuc 		    xflag = 0, xflag_set = 1;
331d90bee97SLionel Sambuc 	    if (vflag)
332d90bee97SLionel Sambuc 		    vflag = 0, vflag_set = 1;
333d90bee97SLionel Sambuc 	}
334d90bee97SLionel Sambuc 	cmdloop(0);
335d90bee97SLionel Sambuc 	if (qflag)  {
336d90bee97SLionel Sambuc 	    if (xflag_set)
337d90bee97SLionel Sambuc 		    xflag = 1;
338d90bee97SLionel Sambuc 	    if (vflag_set)
339d90bee97SLionel Sambuc 		    vflag = 1;
340d90bee97SLionel Sambuc 	}
341d90bee97SLionel Sambuc 	popfile();
342d90bee97SLionel Sambuc }
343d90bee97SLionel Sambuc 
344d90bee97SLionel Sambuc 
345d90bee97SLionel Sambuc 
346d90bee97SLionel Sambuc /*
347d90bee97SLionel Sambuc  * Read a file containing shell functions.
348d90bee97SLionel Sambuc  */
349d90bee97SLionel Sambuc 
350d90bee97SLionel Sambuc void
readcmdfile(char * name)351d90bee97SLionel Sambuc readcmdfile(char *name)
352d90bee97SLionel Sambuc {
353d90bee97SLionel Sambuc 	int fd;
354d90bee97SLionel Sambuc 
355d90bee97SLionel Sambuc 	INTOFF;
356d90bee97SLionel Sambuc 	if ((fd = open(name, O_RDONLY)) >= 0)
357d90bee97SLionel Sambuc 		setinputfd(fd, 1);
358d90bee97SLionel Sambuc 	else
359d90bee97SLionel Sambuc 		error("Can't open %s", name);
360d90bee97SLionel Sambuc 	INTON;
361d90bee97SLionel Sambuc 	cmdloop(0);
362d90bee97SLionel Sambuc 	popfile();
363d90bee97SLionel Sambuc }
364d90bee97SLionel Sambuc 
365d90bee97SLionel Sambuc 
366d90bee97SLionel Sambuc 
367d90bee97SLionel Sambuc int
exitcmd(int argc,char ** argv)368d90bee97SLionel Sambuc exitcmd(int argc, char **argv)
369d90bee97SLionel Sambuc {
370d90bee97SLionel Sambuc 	if (stoppedjobs())
371d90bee97SLionel Sambuc 		return 0;
372d90bee97SLionel Sambuc 	if (argc > 1)
373d90bee97SLionel Sambuc 		exitstatus = number(argv[1]);
374d90bee97SLionel Sambuc 	exitshell(exitstatus);
375d90bee97SLionel Sambuc 	/* NOTREACHED */
376d90bee97SLionel Sambuc }
377