main.c revision 19240
167754Smsmith/*-
267754Smsmith * Copyright (c) 1991, 1993
377424Smsmith *	The Regents of the University of California.  All rights reserved.
467754Smsmith *
567754Smsmith * This code is derived from software contributed to Berkeley by
667754Smsmith * Kenneth Almquist.
7217365Sjkim *
8306536Sjkim * Redistribution and use in source and binary forms, with or without
970243Smsmith * modification, are permitted provided that the following conditions
1067754Smsmith * are met:
11217365Sjkim * 1. Redistributions of source code must retain the above copyright
12217365Sjkim *    notice, this list of conditions and the following disclaimer.
13217365Sjkim * 2. Redistributions in binary form must reproduce the above copyright
14217365Sjkim *    notice, this list of conditions and the following disclaimer in the
15217365Sjkim *    documentation and/or other materials provided with the distribution.
16217365Sjkim * 3. All advertising materials mentioning features or use of this software
17217365Sjkim *    must display the following acknowledgement:
18217365Sjkim *	This product includes software developed by the University of
19217365Sjkim *	California, Berkeley and its contributors.
20217365Sjkim * 4. Neither the name of the University nor the names of its contributors
21217365Sjkim *    may be used to endorse or promote products derived from this software
22217365Sjkim *    without specific prior written permission.
23217365Sjkim *
24217365Sjkim * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
2567754Smsmith * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26217365Sjkim * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27217365Sjkim * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28217365Sjkim * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
2967754Smsmith * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30217365Sjkim * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31217365Sjkim * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32217365Sjkim * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33217365Sjkim * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34217365Sjkim * SUCH DAMAGE.
35217365Sjkim *
36217365Sjkim *	$Id: main.c,v 1.8 1996/09/12 12:41:46 adam Exp $
37217365Sjkim */
38217365Sjkim
39217365Sjkim#ifndef lint
40217365Sjkimstatic char copyright[] =
41217365Sjkim"@(#) Copyright (c) 1991, 1993\n\
42217365Sjkim	The Regents of the University of California.  All rights reserved.\n";
4367754Smsmith#endif /* not lint */
44193341Sjkim
45193341Sjkim#ifndef lint
46193341Sjkimstatic char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/28/95";
47193341Sjkim#endif /* not lint */
48193341Sjkim
49193341Sjkim#include <stdio.h>
5067754Smsmith#include <signal.h>
5167754Smsmith#include <sys/stat.h>
5277424Smsmith#include <unistd.h>
5391116Smsmith#include <fcntl.h>
5467754Smsmith#include <locale.h>
55151937Sjkim
5667754Smsmith
57151937Sjkim#include "shell.h"
58151937Sjkim#include "main.h"
59151937Sjkim#include "mail.h"
60151937Sjkim#include "options.h"
61151937Sjkim#include "output.h"
62151937Sjkim#include "parser.h"
63281075Sdim#include "nodes.h"
64281075Sdim#include "expand.h"
65281075Sdim#include "eval.h"
66281075Sdim#include "jobs.h"
67281075Sdim#include "input.h"
68151937Sjkim#include "trap.h"
69281075Sdim#include "var.h"
7067754Smsmith#include "show.h"
7167754Smsmith#include "memalloc.h"
7277424Smsmith#include "error.h"
7367754Smsmith#include "init.h"
7485756Smsmith#include "mystring.h"
75238381Sjkim#include "exec.h"
76238381Sjkim
7787031Smsmith#define PROFILE 0
7887031Smsmith
7967754Smsmithint rootpid;
8067754Smsmithint rootshell;
8167754SmsmithSTATIC union node *curcmd;
8285756SmsmithSTATIC union node *prevcmd;
83238381Sjkimextern int errno;
8467754Smsmith#if PROFILE
8591116Smsmithshort profile_buf[16384];
8687031Smsmithextern int etext();
8767754Smsmith#endif
8867754Smsmith
8967754SmsmithSTATIC void read_profile __P((char *));
9067754SmsmithSTATIC char *find_dot_file __P((char *));
9177424Smsmith
9285756Smsmith/*
9367754Smsmith * Main routine.  We initialize things, parse the arguments, execute
9467754Smsmith * profiles if we're a login shell, and then call cmdloop to execute
9567754Smsmith * commands.  The setjmp call sets up the location to jump to when an
9667754Smsmith * exception occurs.  When an exception occurs the variable "state"
9771867Smsmith * is used to figure out how far we had gotten.
9867754Smsmith */
9967754Smsmith
100167802Sjkimint
10167754Smsmithmain(argc, argv)
10267754Smsmith	int argc;
10367754Smsmith	char **argv;
10467754Smsmith{
10585756Smsmith	struct jmploc jmploc;
10667754Smsmith	struct stackmark smark;
107167802Sjkim	volatile int state;
10867754Smsmith	char *shinit;
10967754Smsmith
11067754Smsmith#if PROFILE
11171867Smsmith	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
11267754Smsmith#endif
11391116Smsmith	(void) setlocale(LC_ALL, "");
11467754Smsmith	state = 0;
11577424Smsmith	if (setjmp(jmploc.loc)) {
11671867Smsmith		/*
117107325Siwasaki		 * When a shell procedure is executed, we raise the
11871867Smsmith		 * exception EXSHELLPROC to clean up before executing
11985756Smsmith		 * the shell procedure.
120306536Sjkim		 */
121306536Sjkim		if (exception == EXERROR)
12267754Smsmith			exitstatus = 2;
12371867Smsmith		if (exception == EXSHELLPROC) {
12467754Smsmith			rootpid = getpid();
12567754Smsmith			rootshell = 1;
12699679Siwasaki			minusc = NULL;
12767754Smsmith			state = 3;
128193267Sjkim		} else if (state == 0 || iflag == 0 || ! rootshell)
129102550Siwasaki			exitshell(2);
130107325Siwasaki		reset();
131250838Sjkim		if (exception == EXINT
13299679Siwasaki#if ATTY
13399679Siwasaki		 && (! attyset() || equal(termval(), "emacs"))
13499679Siwasaki#endif
13599679Siwasaki		 ) {
13699679Siwasaki			out2c('\n');
13799679Siwasaki			flushout(&errout);
13899679Siwasaki		}
13999679Siwasaki		popstackmark(&smark);
14099679Siwasaki		FORCEINTON;				/* enable interrupts */
14199679Siwasaki		if (state == 1)
14299679Siwasaki			goto state1;
143104470Siwasaki		else if (state == 2)
14499679Siwasaki			goto state2;
14599679Siwasaki		else if (state == 3)
14699679Siwasaki			goto state3;
147126372Snjl		else
14867754Smsmith			goto state4;
149167802Sjkim	}
150306536Sjkim	handler = &jmploc;
151138287Smarks#ifdef DEBUG
15267754Smsmith	opentrace();
15367754Smsmith	trputs("Shell args:  ");  trargs(argv);
15467754Smsmith#endif
15567754Smsmith	rootpid = getpid();
15677424Smsmith	rootshell = 1;
157193267Sjkim	init();
15871867Smsmith	setstackmark(&smark);
15971867Smsmith	procargs(argc, argv);
16071867Smsmith	if (argv[0] && argv[0][0] == '-') {
16171867Smsmith		state = 1;
16271867Smsmith		read_profile("/etc/profile");
16371867Smsmithstate1:
164193267Sjkim		state = 2;
16567754Smsmith		if (privileged == 0)
166193267Sjkim			read_profile(".profile");
16767754Smsmith		else
16871867Smsmith			read_profile("/etc/suid_profile");
16971867Smsmith	}
170151937Sjkimstate2:
171306536Sjkim	state = 3;
172306536Sjkim	if (privileged == 0) {
17371867Smsmith		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
17467754Smsmith			state = 3;
175193267Sjkim			read_profile(shinit);
17667754Smsmith		}
17771867Smsmith	}
17867754Smsmithstate3:
17985756Smsmith	state = 4;
18071867Smsmith	if (minusc) {
18171867Smsmith		evalstring(minusc);
182193267Sjkim	}
183193267Sjkim	if (sflag || minusc == NULL) {
18471867Smsmithstate4:	/* XXX ??? - why isn't this before the "if" statement */
18577424Smsmith		cmdloop(1);
18671867Smsmith	}
187193267Sjkim#if PROFILE
188306536Sjkim	monitor(0);
18971867Smsmith#endif
19071867Smsmith	exitshell(exitstatus);
191193267Sjkim	/*NOTREACHED*/
19267754Smsmith	return 0;
19371867Smsmith}
19471867Smsmith
19567754Smsmith
196138287Smarks/*
197306536Sjkim * Read and execute commands.  "Top" is nonzero for the top level command
198138287Smarks * loop; it turns on prompting if the shell is interactive.
19977424Smsmith */
200204773Sjkim
20171867Smsmithvoid
20271867Smsmithcmdloop(top)
20371867Smsmith	int top;
20471867Smsmith{
205204773Sjkim	union node *n;
206193267Sjkim	struct stackmark smark;
207193267Sjkim	int inter;
20871867Smsmith	int numeof = 0;
20971867Smsmith
21071867Smsmith	TRACE(("cmdloop(%d) called\n", top));
21199679Siwasaki	setstackmark(&smark);
21271867Smsmith	for (;;) {
21371867Smsmith		if (pendingsigs)
21471867Smsmith			dotrap();
21571867Smsmith		inter = 0;
21671867Smsmith		if (iflag && top) {
21771867Smsmith			inter++;
21871867Smsmith			showjobs(1);
21977424Smsmith			chkmail(0);
22071867Smsmith			flushout(&output);
22187031Smsmith		}
22287031Smsmith		n = parsecmd(inter);
22387031Smsmith		/* showtree(n); DEBUG */
22471867Smsmith		if (n == NEOF) {
22571867Smsmith			if (!top || numeof >= 50)
22671867Smsmith				break;
22787031Smsmith			if (!stoppedjobs()) {
22871867Smsmith				if (!Iflag)
22971867Smsmith					break;
23071867Smsmith				out2str("\nUse \"exit\" to leave shell.\n");
231151937Sjkim			}
23277424Smsmith			numeof++;
23385756Smsmith		} else if (n != NULL && nflag == 0) {
23491116Smsmith			job_warning = (job_warning == 2) ? 1 : 0;
23571867Smsmith			numeof = 0;
23671867Smsmith			evaltree(n, 0);
23771867Smsmith		}
23871867Smsmith		popstackmark(&smark);
23991116Smsmith	}
24071867Smsmith	popstackmark(&smark);		/* unnecessary */
241126372Snjl}
24271867Smsmith
24371867Smsmith
244167802Sjkim
24571867Smsmith/*
24671867Smsmith * Read /etc/profile or .profile.  Return on error.
24771867Smsmith */
24871867Smsmith
24971867SmsmithSTATIC void
25071867Smsmithread_profile(name)
25191116Smsmith	char *name;
25271867Smsmith	{
25371867Smsmith	int fd;
25471867Smsmith
255138287Smarks	INTOFF;
256138287Smarks	if ((fd = open(name, O_RDONLY)) >= 0)
257138287Smarks		setinputfd(fd, 1);
258138287Smarks	INTON;
25991116Smsmith	if (fd < 0)
26091116Smsmith		return;
261126372Snjl	cmdloop(0);
26291116Smsmith	popfile();
26391116Smsmith}
26485756Smsmith
265193267Sjkim
266193267Sjkim
26791116Smsmith/*
268193267Sjkim * Read a file containing shell functions.
269193267Sjkim */
270193267Sjkim
271193267Sjkimvoid
27291116Smsmithreadcmdfile(name)
273193267Sjkim	char *name;
274193267Sjkim{
275193267Sjkim	int fd;
27667754Smsmith
277306536Sjkim	INTOFF;
278306536Sjkim	if ((fd = open(name, O_RDONLY)) >= 0)
279193267Sjkim		setinputfd(fd, 1);
280193267Sjkim	else
281193267Sjkim		error("Can't open %s", name);
282193267Sjkim	INTON;
283193267Sjkim	cmdloop(0);
284193267Sjkim	popfile();
285138287Smarks}
28691116Smsmith
287138287Smarks
288104470Siwasaki
289151937Sjkim/*
290151937Sjkim * Take commands from a file.  To be compatable we should do a path
291151937Sjkim * search for the file, which is necessary to find sub-commands.
292151937Sjkim */
293104470Siwasaki
294138287Smarks
295104470SiwasakiSTATIC char *
296138287Smarksfind_dot_file(basename)
297151937Sjkim	char *basename;
298138287Smarks{
299126372Snjl	static char localname[FILENAME_MAX+1];
300151937Sjkim	char *fullname;
301126372Snjl	char *path = pathval();
302151937Sjkim	struct stat statb;
303151937Sjkim
304151937Sjkim	/* don't try this for absolute or relative paths */
305151937Sjkim	if( strchr(basename, '/'))
306138287Smarks		return basename;
307138287Smarks
30867754Smsmith	while ((fullname = padvance(&path, basename)) != NULL) {
309151937Sjkim		strcpy(localname, fullname);
31071867Smsmith		stunalloc(fullname);
31167754Smsmith		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
31271867Smsmith			return localname;
31367754Smsmith	}
314138287Smarks	return basename;
315138287Smarks}
31667754Smsmith
31787031Smsmithint
31887031Smsmithdotcmd(argc, argv)
31987031Smsmith	int argc;
32067754Smsmith	char **argv;
32167754Smsmith{
32267754Smsmith	struct strlist *sp;
323138287Smarks	exitstatus = 0;
324138287Smarks
325138287Smarks	for (sp = cmdenviron; sp ; sp = sp->next)
32667754Smsmith		setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
32791116Smsmith
328193267Sjkim	if (argc >= 2) {		/* That's what SVR2 does */
329193267Sjkim		char *fullname = find_dot_file(argv[1]);
33067754Smsmith
33171867Smsmith		setinputfile(fullname, 1);
33267754Smsmith		commandname = fullname;
33367754Smsmith		cmdloop(0);
33467754Smsmith		popfile();
33567754Smsmith	}
33667754Smsmith	return exitstatus;
33767754Smsmith}
338193267Sjkim
33967754Smsmith
34071867Smsmithint
34187031Smsmithexitcmd(argc, argv)
34287031Smsmith	int argc;
34387031Smsmith	char **argv;
34487031Smsmith{
34567754Smsmith	extern int oexitstatus;
34667754Smsmith
34787031Smsmith	if (stoppedjobs())
348138287Smarks		return 0;
34977424Smsmith	exitstatus = (argc > 1) ? number(argv[1]) : oexitstatus;
350138287Smarks	exitshell(exitstatus);
351138287Smarks	/*NOTREACHED*/
35287031Smsmith	return 0;
35367754Smsmith}
35467754Smsmith
35567754Smsmith
35677424Smsmith#ifdef notdef
35787031Smsmith/*
35877424Smsmith * Should never be called.
359167802Sjkim */
360306536Sjkim
36199679Siwasakivoid
36287031Smsmithexit(exitstatus) {
36367754Smsmith	_exit(exitstatus);
36487031Smsmith}
36587031Smsmith#endif
36687031Smsmith