main.c revision 17525
1/*-
2 * Copyright (c) 1991, 1993
3 *	The Regents of the University of California.  All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 *    notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 *    notice, this list of conditions and the following disclaimer in the
15 *    documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 *    must display the following acknowledgement:
18 *	This product includes software developed by the University of
19 *	California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 *    may be used to endorse or promote products derived from this software
22 *    without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 *
36 *	$Id: main.c,v 1.3 1995/05/30 00:07:18 rgrimes Exp $
37 */
38
39#ifndef lint
40static char copyright[] =
41"@(#) Copyright (c) 1991, 1993\n\
42	The Regents of the University of California.  All rights reserved.\n";
43#endif /* not lint */
44
45#ifndef lint
46static char sccsid[] = "@(#)main.c	8.1 (Berkeley) 5/31/93";
47#endif /* not lint */
48
49#include <signal.h>
50#include <fcntl.h>
51#include <locale.h>
52
53#include "shell.h"
54#include "main.h"
55#include "mail.h"
56#include "options.h"
57#include "output.h"
58#include "parser.h"
59#include "nodes.h"
60#include "eval.h"
61#include "jobs.h"
62#include "input.h"
63#include "trap.h"
64#include "var.h"
65#include "memalloc.h"
66#include "error.h"
67#include "init.h"
68#include "mystring.h"
69
70#define PROFILE 0
71
72int rootpid;
73int rootshell;
74STATIC union node *curcmd;
75STATIC union node *prevcmd;
76extern int errno;
77#if PROFILE
78short profile_buf[16384];
79extern int etext();
80#endif
81
82#ifdef __STDC__
83STATIC void read_profile(char *);
84char *getenv(char *);
85#else
86STATIC void read_profile();
87char *getenv();
88#endif
89
90
91/*
92 * Main routine.  We initialize things, parse the arguments, execute
93 * profiles if we're a login shell, and then call cmdloop to execute
94 * commands.  The setjmp call sets up the location to jump to when an
95 * exception occurs.  When an exception occurs the variable "state"
96 * is used to figure out how far we had gotten.
97 */
98
99main(argc, argv)  char **argv; {
100	struct jmploc jmploc;
101	struct stackmark smark;
102	volatile int state;
103	char *shinit;
104
105#if PROFILE
106	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
107#endif
108	(void) setlocale(LC_ALL, "");
109	state = 0;
110	if (setjmp(jmploc.loc)) {
111		/*
112		 * When a shell procedure is executed, we raise the
113		 * exception EXSHELLPROC to clean up before executing
114		 * the shell procedure.
115		 */
116		if (exception == EXSHELLPROC) {
117			rootpid = getpid();
118			rootshell = 1;
119			minusc = NULL;
120			state = 3;
121		} else if (state == 0 || iflag == 0 || ! rootshell)
122			exitshell(2);
123		reset();
124		if (exception == EXINT
125#if ATTY
126		 && (! attyset() || equal(termval(), "emacs"))
127#endif
128		 ) {
129			out2c('\n');
130			flushout(&errout);
131		}
132		popstackmark(&smark);
133		FORCEINTON;				/* enable interrupts */
134		if (state == 1)
135			goto state1;
136		else if (state == 2)
137			goto state2;
138		else if (state == 3)
139			goto state3;
140		else
141			goto state4;
142	}
143	handler = &jmploc;
144#ifdef DEBUG
145	opentrace();
146	trputs("Shell args:  ");  trargs(argv);
147#endif
148	rootpid = getpid();
149	rootshell = 1;
150	init();
151	setstackmark(&smark);
152	procargs(argc, argv);
153	if (argv[0] && argv[0][0] == '-') {
154		state = 1;
155		read_profile("/etc/profile");
156state1:
157		state = 2;
158		read_profile(".profile");
159	}
160state2:
161	state = 3;
162	if ((shinit = lookupvar("ENV")) != NULL &&
163	     *shinit != '\0') {
164		state = 3;
165		read_profile(shinit);
166	}
167state3:
168	state = 4;
169	if (minusc) {
170		evalstring(minusc);
171	}
172	if (sflag || minusc == NULL) {
173state4:	/* XXX ??? - why isn't this before the "if" statement */
174		cmdloop(1);
175	}
176#if PROFILE
177	monitor(0);
178#endif
179	exitshell(exitstatus);
180}
181
182
183/*
184 * Read and execute commands.  "Top" is nonzero for the top level command
185 * loop; it turns on prompting if the shell is interactive.
186 */
187
188void
189cmdloop(top) {
190	union node *n;
191	struct stackmark smark;
192	int inter;
193	int numeof = 0;
194
195	TRACE(("cmdloop(%d) called\n", top));
196	setstackmark(&smark);
197	for (;;) {
198		if (pendingsigs)
199			dotrap();
200		inter = 0;
201		if (iflag && top) {
202			inter++;
203			showjobs(1);
204			chkmail(0);
205			flushout(&output);
206		}
207		n = parsecmd(inter);
208		/* showtree(n); DEBUG */
209		if (n == NEOF) {
210			if (!top || numeof >= 50)
211				break;
212			if (!stoppedjobs()) {
213				if (!Iflag)
214					break;
215				out2str("\nUse \"exit\" to leave shell.\n");
216			}
217			numeof++;
218		} else if (n != NULL && nflag == 0) {
219			job_warning = (job_warning == 2) ? 1 : 0;
220			numeof = 0;
221			evaltree(n, 0);
222		}
223		popstackmark(&smark);
224	}
225	popstackmark(&smark);		/* unnecessary */
226}
227
228
229
230/*
231 * Read /etc/profile or .profile.  Return on error.
232 */
233
234STATIC void
235read_profile(name)
236	char *name;
237	{
238	int fd;
239
240	INTOFF;
241	if ((fd = open(name, O_RDONLY)) >= 0)
242		setinputfd(fd, 1);
243	INTON;
244	if (fd < 0)
245		return;
246	cmdloop(0);
247	popfile();
248}
249
250
251
252/*
253 * Read a file containing shell functions.
254 */
255
256void
257readcmdfile(name)
258	char *name;
259	{
260	int fd;
261
262	INTOFF;
263	if ((fd = open(name, O_RDONLY)) >= 0)
264		setinputfd(fd, 1);
265	else
266		error("Can't open %s", name);
267	INTON;
268	cmdloop(0);
269	popfile();
270}
271
272
273
274/*
275 * Take commands from a file.  To be compatable we should do a path
276 * search for the file, but a path search doesn't make any sense.
277 */
278
279dotcmd(argc, argv)  char **argv; {
280	exitstatus = 0;
281	if (argc >= 2) {		/* That's what SVR2 does */
282		setinputfile(argv[1], 1);
283		commandname = argv[1];
284		cmdloop(0);
285		popfile();
286	}
287	return exitstatus;
288}
289
290
291exitcmd(argc, argv)  char **argv; {
292	if (stoppedjobs())
293		return;
294	if (argc > 1)
295		exitstatus = number(argv[1]);
296	exitshell(exitstatus);
297}
298
299
300#ifdef notdef
301/*
302 * Should never be called.
303 */
304
305void
306exit(exitstatus) {
307	_exit(exitstatus);
308}
309#endif
310