main.c revision 17525
1215651Sweongyo/*-
2215651Sweongyo * Copyright (c) 1991, 1993
3215651Sweongyo *	The Regents of the University of California.  All rights reserved.
4215651Sweongyo *
5215651Sweongyo * This code is derived from software contributed to Berkeley by
6215651Sweongyo * Kenneth Almquist.
7215651Sweongyo *
8215651Sweongyo * Redistribution and use in source and binary forms, with or without
9215651Sweongyo * modification, are permitted provided that the following conditions
10215651Sweongyo * are met:
11215651Sweongyo * 1. Redistributions of source code must retain the above copyright
12215651Sweongyo *    notice, this list of conditions and the following disclaimer.
13215651Sweongyo * 2. Redistributions in binary form must reproduce the above copyright
14215651Sweongyo *    notice, this list of conditions and the following disclaimer in the
15215651Sweongyo *    documentation and/or other materials provided with the distribution.
16215651Sweongyo * 3. All advertising materials mentioning features or use of this software
17215651Sweongyo *    must display the following acknowledgement:
18215651Sweongyo *	This product includes software developed by the University of
19215651Sweongyo *	California, Berkeley and its contributors.
20215651Sweongyo * 4. Neither the name of the University nor the names of its contributors
21215651Sweongyo *    may be used to endorse or promote products derived from this software
22215651Sweongyo *    without specific prior written permission.
23215651Sweongyo *
24215651Sweongyo * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25215651Sweongyo * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26215651Sweongyo * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27215651Sweongyo * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28215651Sweongyo * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29215651Sweongyo * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30215651Sweongyo * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31215651Sweongyo * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32215651Sweongyo * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33215651Sweongyo * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34215651Sweongyo * SUCH DAMAGE.
35215803Sweongyo *
36215651Sweongyo *	$Id: main.c,v 1.3 1995/05/30 00:07:18 rgrimes Exp $
37215651Sweongyo */
38232035Shselasky
39215803Sweongyo#ifndef lint
40215803Sweongyostatic char copyright[] =
41215651Sweongyo"@(#) Copyright (c) 1991, 1993\n\
42215651Sweongyo	The Regents of the University of California.  All rights reserved.\n";
43215651Sweongyo#endif /* not lint */
44215651Sweongyo
45215651Sweongyo#ifndef lint
46215651Sweongyostatic char sccsid[] = "@(#)main.c	8.1 (Berkeley) 5/31/93";
47215651Sweongyo#endif /* not lint */
48215651Sweongyo
49232035Shselasky#include <signal.h>
50215651Sweongyo#include <fcntl.h>
51215651Sweongyo#include <locale.h>
52215651Sweongyo
53221604Shselasky#include "shell.h"
54221604Shselasky#include "main.h"
55215651Sweongyo#include "mail.h"
56232035Shselasky#include "options.h"
57232035Shselasky#include "output.h"
58232035Shselasky#include "parser.h"
59232035Shselasky#include "nodes.h"
60232035Shselasky#include "eval.h"
61232035Shselasky#include "jobs.h"
62232035Shselasky#include "input.h"
63232035Shselasky#include "trap.h"
64232035Shselasky#include "var.h"
65232035Shselasky#include "memalloc.h"
66232035Shselasky#include "error.h"
67232035Shselasky#include "init.h"
68232035Shselasky#include "mystring.h"
69232035Shselasky
70232035Shselasky#define PROFILE 0
71232035Shselasky
72232035Shselaskyint rootpid;
73232035Shselaskyint rootshell;
74232035ShselaskySTATIC union node *curcmd;
75232035ShselaskySTATIC union node *prevcmd;
76215651Sweongyoextern int errno;
77215651Sweongyo#if PROFILE
78220301Shselaskyshort profile_buf[16384];
79220301Shselaskyextern int etext();
80215651Sweongyo#endif
81215651Sweongyo
82215651Sweongyo#ifdef __STDC__
83215651SweongyoSTATIC void read_profile(char *);
84215651Sweongyochar *getenv(char *);
85215651Sweongyo#else
86215651SweongyoSTATIC void read_profile();
87215651Sweongyochar *getenv();
88220301Shselasky#endif
89215651Sweongyo
90220301Shselasky
91220301Shselasky/*
92220301Shselasky * Main routine.  We initialize things, parse the arguments, execute
93215651Sweongyo * profiles if we're a login shell, and then call cmdloop to execute
94215651Sweongyo * commands.  The setjmp call sets up the location to jump to when an
95215651Sweongyo * exception occurs.  When an exception occurs the variable "state"
96215651Sweongyo * is used to figure out how far we had gotten.
97215651Sweongyo */
98218010Shselasky
99215651Sweongyomain(argc, argv)  char **argv; {
100215651Sweongyo	struct jmploc jmploc;
101215651Sweongyo	struct stackmark smark;
102220301Shselasky	volatile int state;
103215651Sweongyo	char *shinit;
104215651Sweongyo
105215651Sweongyo#if PROFILE
106215651Sweongyo	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
107215651Sweongyo#endif
108215651Sweongyo	(void) setlocale(LC_ALL, "");
109215651Sweongyo	state = 0;
110215651Sweongyo	if (setjmp(jmploc.loc)) {
111215651Sweongyo		/*
112215651Sweongyo		 * When a shell procedure is executed, we raise the
113215651Sweongyo		 * exception EXSHELLPROC to clean up before executing
114215651Sweongyo		 * the shell procedure.
115215651Sweongyo		 */
116215651Sweongyo		if (exception == EXSHELLPROC) {
117215651Sweongyo			rootpid = getpid();
118215651Sweongyo			rootshell = 1;
119215651Sweongyo			minusc = NULL;
120215651Sweongyo			state = 3;
121215651Sweongyo		} else if (state == 0 || iflag == 0 || ! rootshell)
122215651Sweongyo			exitshell(2);
123215651Sweongyo		reset();
124215651Sweongyo		if (exception == EXINT
125215651Sweongyo#if ATTY
126215651Sweongyo		 && (! attyset() || equal(termval(), "emacs"))
127215651Sweongyo#endif
128215651Sweongyo		 ) {
129215651Sweongyo			out2c('\n');
130215651Sweongyo			flushout(&errout);
131215651Sweongyo		}
132215651Sweongyo		popstackmark(&smark);
133220301Shselasky		FORCEINTON;				/* enable interrupts */
134215651Sweongyo		if (state == 1)
135215651Sweongyo			goto state1;
136215651Sweongyo		else if (state == 2)
137215651Sweongyo			goto state2;
138215651Sweongyo		else if (state == 3)
139215651Sweongyo			goto state3;
140220301Shselasky		else
141220301Shselasky			goto state4;
142220301Shselasky	}
143220301Shselasky	handler = &jmploc;
144220301Shselasky#ifdef DEBUG
145220301Shselasky	opentrace();
146220301Shselasky	trputs("Shell args:  ");  trargs(argv);
147220301Shselasky#endif
148232035Shselasky	rootpid = getpid();
149232035Shselasky	rootshell = 1;
150232035Shselasky	init();
151215651Sweongyo	setstackmark(&smark);
152232035Shselasky	procargs(argc, argv);
153232035Shselasky	if (argv[0] && argv[0][0] == '-') {
154232035Shselasky		state = 1;
155232035Shselasky		read_profile("/etc/profile");
156232035Shselaskystate1:
157232035Shselasky		state = 2;
158232035Shselasky		read_profile(".profile");
159232035Shselasky	}
160232035Shselaskystate2:
161232035Shselasky	state = 3;
162232035Shselasky	if ((shinit = lookupvar("ENV")) != NULL &&
163232035Shselasky	     *shinit != '\0') {
164232035Shselasky		state = 3;
165232035Shselasky		read_profile(shinit);
166232035Shselasky	}
167232035Shselaskystate3:
168232035Shselasky	state = 4;
169232035Shselasky	if (minusc) {
170232035Shselasky		evalstring(minusc);
171232035Shselasky	}
172232035Shselasky	if (sflag || minusc == NULL) {
173232035Shselaskystate4:	/* XXX ??? - why isn't this before the "if" statement */
174232035Shselasky		cmdloop(1);
175232035Shselasky	}
176232035Shselasky#if PROFILE
177232035Shselasky	monitor(0);
178232035Shselasky#endif
179232035Shselasky	exitshell(exitstatus);
180232035Shselasky}
181232035Shselasky
182232035Shselasky
183232035Shselasky/*
184232035Shselasky * Read and execute commands.  "Top" is nonzero for the top level command
185232035Shselasky * loop; it turns on prompting if the shell is interactive.
186232035Shselasky */
187232035Shselasky
188232035Shselaskyvoid
189232035Shselaskycmdloop(top) {
190232035Shselasky	union node *n;
191232035Shselasky	struct stackmark smark;
192232035Shselasky	int inter;
193232035Shselasky	int numeof = 0;
194232035Shselasky
195232035Shselasky	TRACE(("cmdloop(%d) called\n", top));
196232035Shselasky	setstackmark(&smark);
197232035Shselasky	for (;;) {
198232035Shselasky		if (pendingsigs)
199232035Shselasky			dotrap();
200232035Shselasky		inter = 0;
201232035Shselasky		if (iflag && top) {
202232035Shselasky			inter++;
203232035Shselasky			showjobs(1);
204232035Shselasky			chkmail(0);
205232035Shselasky			flushout(&output);
206232035Shselasky		}
207232035Shselasky		n = parsecmd(inter);
208232035Shselasky		/* showtree(n); DEBUG */
209232035Shselasky		if (n == NEOF) {
210232035Shselasky			if (!top || numeof >= 50)
211232035Shselasky				break;
212232035Shselasky			if (!stoppedjobs()) {
213232035Shselasky				if (!Iflag)
214232035Shselasky					break;
215232035Shselasky				out2str("\nUse \"exit\" to leave shell.\n");
216232035Shselasky			}
217232035Shselasky			numeof++;
218232035Shselasky		} else if (n != NULL && nflag == 0) {
219232035Shselasky			job_warning = (job_warning == 2) ? 1 : 0;
220232035Shselasky			numeof = 0;
221232035Shselasky			evaltree(n, 0);
222232035Shselasky		}
223232035Shselasky		popstackmark(&smark);
224232035Shselasky	}
225232035Shselasky	popstackmark(&smark);		/* unnecessary */
226232035Shselasky}
227232035Shselasky
228232035Shselasky
229232035Shselasky
230232035Shselasky/*
231232035Shselasky * Read /etc/profile or .profile.  Return on error.
232232035Shselasky */
233232035Shselasky
234232035ShselaskySTATIC void
235232035Shselaskyread_profile(name)
236232035Shselasky	char *name;
237232035Shselasky	{
238232035Shselasky	int fd;
239232035Shselasky
240232035Shselasky	INTOFF;
241232035Shselasky	if ((fd = open(name, O_RDONLY)) >= 0)
242232035Shselasky		setinputfd(fd, 1);
243232035Shselasky	INTON;
244232035Shselasky	if (fd < 0)
245232035Shselasky		return;
246232035Shselasky	cmdloop(0);
247232035Shselasky	popfile();
248232035Shselasky}
249232035Shselasky
250232035Shselasky
251232035Shselasky
252232035Shselasky/*
253232035Shselasky * Read a file containing shell functions.
254232035Shselasky */
255232035Shselasky
256232035Shselaskyvoid
257215651Sweongyoreadcmdfile(name)
258215651Sweongyo	char *name;
259215651Sweongyo	{
260215651Sweongyo	int fd;
261215651Sweongyo
262215651Sweongyo	INTOFF;
263215651Sweongyo	if ((fd = open(name, O_RDONLY)) >= 0)
264220301Shselasky		setinputfd(fd, 1);
265220301Shselasky	else
266220301Shselasky		error("Can't open %s", name);
267220301Shselasky	INTON;
268220301Shselasky	cmdloop(0);
269220301Shselasky	popfile();
270220301Shselasky}
271220301Shselasky
272220301Shselasky
273220301Shselasky
274220301Shselasky/*
275220301Shselasky * Take commands from a file.  To be compatable we should do a path
276220301Shselasky * search for the file, but a path search doesn't make any sense.
277220301Shselasky */
278220301Shselasky
279220301Shselaskydotcmd(argc, argv)  char **argv; {
280220301Shselasky	exitstatus = 0;
281220301Shselasky	if (argc >= 2) {		/* That's what SVR2 does */
282220301Shselasky		setinputfile(argv[1], 1);
283220301Shselasky		commandname = argv[1];
284220301Shselasky		cmdloop(0);
285220301Shselasky		popfile();
286220301Shselasky	}
287220301Shselasky	return exitstatus;
288215651Sweongyo}
289220301Shselasky
290215651Sweongyo
291220301Shselaskyexitcmd(argc, argv)  char **argv; {
292220301Shselasky	if (stoppedjobs())
293220301Shselasky		return;
294220301Shselasky	if (argc > 1)
295220301Shselasky		exitstatus = number(argv[1]);
296220301Shselasky	exitshell(exitstatus);
297220301Shselasky}
298220301Shselasky
299220301Shselasky
300220301Shselasky#ifdef notdef
301220301Shselasky/*
302215651Sweongyo * Should never be called.
303215651Sweongyo */
304215651Sweongyo
305220301Shselaskyvoid
306215651Sweongyoexit(exitstatus) {
307220301Shselasky	_exit(exitstatus);
308220301Shselasky}
309220301Shselasky#endif
310220301Shselasky