main.c revision 25471
1327Sjkh/*-
2327Sjkh * Copyright (c) 1991, 1993
3327Sjkh *	The Regents of the University of California.  All rights reserved.
4327Sjkh *
5327Sjkh * This code is derived from software contributed to Berkeley by
6327Sjkh * Kenneth Almquist.
7327Sjkh *
8327Sjkh * Redistribution and use in source and binary forms, with or without
9327Sjkh * modification, are permitted provided that the following conditions
10327Sjkh * are met:
11327Sjkh * 1. Redistributions of source code must retain the above copyright
12327Sjkh *    notice, this list of conditions and the following disclaimer.
13327Sjkh * 2. Redistributions in binary form must reproduce the above copyright
14327Sjkh *    notice, this list of conditions and the following disclaimer in the
15327Sjkh *    documentation and/or other materials provided with the distribution.
16327Sjkh * 3. All advertising materials mentioning features or use of this software
17327Sjkh *    must display the following acknowledgement:
18327Sjkh *	This product includes software developed by the University of
19327Sjkh *	California, Berkeley and its contributors.
20327Sjkh * 4. Neither the name of the University nor the names of its contributors
2193520Sobrien *    may be used to endorse or promote products derived from this software
2293520Sobrien *    without specific prior written permission.
2393520Sobrien *
2430221Scharnier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25222035Sflz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26327Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27327Sjkh * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28327Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29327Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
3096613Ssobomax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31327Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32327Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33327Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34327Sjkh * SUCH DAMAGE.
35327Sjkh *
36327Sjkh *	$Id: main.c,v 1.13 1997/02/22 13:58:33 peter Exp $
3783663Ssobomax */
3883663Ssobomax
3972694Ssobomax#ifndef lint
4083663Ssobomaxstatic char const copyright[] =
4183663Ssobomax"@(#) Copyright (c) 1991, 1993\n\
42327Sjkh	The Regents of the University of California.  All rights reserved.\n";
4373134Ssobomax#endif /* not lint */
4473134Ssobomax
4573134Ssobomax#ifndef lint
4673134Ssobomaxstatic char const sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/28/95";
4773134Ssobomax#endif /* not lint */
4873134Ssobomax
4996613Ssobomax#include <stdio.h>
5096613Ssobomax#include <signal.h>
5196613Ssobomax#include <sys/stat.h>
5296613Ssobomax#include <unistd.h>
5396613Ssobomax#include <fcntl.h>
5496613Ssobomax#include <locale.h>
5596613Ssobomax
5696613Ssobomax
5796613Ssobomax#include "shell.h"
5896613Ssobomax#include "main.h"
5996613Ssobomax#include "mail.h"
6096613Ssobomax#include "options.h"
6173134Ssobomax#include "output.h"
6273134Ssobomax#include "parser.h"
6373134Ssobomax#include "nodes.h"
6473134Ssobomax#include "expand.h"
6573134Ssobomax#include "eval.h"
6673134Ssobomax#include "jobs.h"
67131275Seik#include "input.h"
6873134Ssobomax#include "trap.h"
6973134Ssobomax#include "var.h"
7073134Ssobomax#include "show.h"
7173134Ssobomax#include "memalloc.h"
7273134Ssobomax#include "error.h"
7373134Ssobomax#include "init.h"
7473134Ssobomax#include "mystring.h"
7573134Ssobomax#include "exec.h"
7674295Ssobomax#include "cd.h"
7772694Ssobomax
7883663Ssobomax#define PROFILE 0
7983663Ssobomax
8083663Ssobomaxint rootpid;
8183663Ssobomaxint rootshell;
8283663Ssobomaxextern int errno;
8383663Ssobomax#if PROFILE
8483663Ssobomaxshort profile_buf[16384];
8583663Ssobomaxextern int etext();
8683663Ssobomax#endif
8783663Ssobomax
8883663SsobomaxSTATIC void read_profile __P((char *));
8983663SsobomaxSTATIC char *find_dot_file __P((char *));
9083663Ssobomax
9196392Salfred/*
9283663Ssobomax * Main routine.  We initialize things, parse the arguments, execute
9383663Ssobomax * profiles if we're a login shell, and then call cmdloop to execute
9483663Ssobomax * commands.  The setjmp call sets up the location to jump to when an
9583663Ssobomax * exception occurs.  When an exception occurs the variable "state"
9683663Ssobomax * is used to figure out how far we had gotten.
9783663Ssobomax */
9896392Salfred
9983663Ssobomaxint
10083663Ssobomaxmain(argc, argv)
10183663Ssobomax	int argc;
10283663Ssobomax	char **argv;
10383663Ssobomax{
10483663Ssobomax	struct jmploc jmploc;
10583663Ssobomax	struct stackmark smark;
10683663Ssobomax	volatile int state;
10783663Ssobomax	char *shinit;
10883663Ssobomax
10983663Ssobomax#if PROFILE
11083663Ssobomax	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
11183663Ssobomax#endif
112327Sjkh	(void) setlocale(LC_ALL, "");
11372694Ssobomax	state = 0;
11472694Ssobomax	if (setjmp(jmploc.loc)) {
115327Sjkh		/*
116327Sjkh		 * When a shell procedure is executed, we raise the
117327Sjkh		 * exception EXSHELLPROC to clean up before executing
118327Sjkh		 * the shell procedure.
119327Sjkh		 */
120327Sjkh		switch (exception) {
121327Sjkh		case EXSHELLPROC:
122327Sjkh			rootpid = getpid();
123327Sjkh			rootshell = 1;
124327Sjkh			minusc = NULL;
125178753Spav			state = 3;
1261550Sasami			break;
12796613Ssobomax
128131280Seik		case EXEXEC:
12941866Sjkh			exitstatus = exerrno;
130178103Spav			break;
131111486Sdes
132111486Sdes		case EXERROR:
13383663Ssobomax			exitstatus = 2;
13483663Ssobomax			break;
135206043Sflz
136206043Sflz		default:
137327Sjkh			break;
13841080Sjkh		}
13941080Sjkh
14041080Sjkh		if (exception != EXSHELLPROC) {
14141080Sjkh		    if (state == 0 || iflag == 0 || ! rootshell)
14241080Sjkh			    exitshell(exitstatus);
143327Sjkh		}
144327Sjkh		reset();
145327Sjkh		if (exception == EXINT
146327Sjkh#if ATTY
147131280Seik		 && (! attyset() || equal(termval(), "emacs"))
148131280Seik#endif
149131280Seik		 ) {
150131280Seik			out2c('\n');
15130221Scharnier			flushout(&errout);
152327Sjkh		}
153131280Seik		popstackmark(&smark);
154131280Seik		FORCEINTON;				/* enable interrupts */
155131280Seik		if (state == 1)
156131280Seik			goto state1;
157131280Seik		else if (state == 2)
158131280Seik			goto state2;
159131280Seik		else if (state == 3)
160131280Seik			goto state3;
161131280Seik		else
162131280Seik			goto state4;
163131280Seik	}
164131280Seik	handler = &jmploc;
165131280Seik#ifdef DEBUG
166131280Seik	opentrace();
167327Sjkh	trputs("Shell args:  ");  trargs(argv);
16841866Sjkh#endif
16939068Sjkh	rootpid = getpid();
17039068Sjkh	rootshell = 1;
17196392Salfred	init();
17239068Sjkh	setstackmark(&smark);
17341866Sjkh	procargs(argc, argv);
174327Sjkh	if (getpwd() == NULL && iflag)
17530221Scharnier		out2str("sh: cannot determine working directory\n");
176327Sjkh	if (argv[0] && argv[0][0] == '-') {
177327Sjkh		state = 1;
17841866Sjkh		read_profile("/etc/profile");
17973134Ssobomaxstate1:
18073134Ssobomax		state = 2;
18173134Ssobomax		if (privileged == 0)
18273134Ssobomax			read_profile(".profile");
18373134Ssobomax		else
18473134Ssobomax			read_profile("/etc/suid_profile");
18573134Ssobomax	}
18673134Ssobomaxstate2:
18773134Ssobomax	state = 3;
18873134Ssobomax	if (!privileged && iflag) {
18973134Ssobomax		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
19073134Ssobomax			state = 3;
19173134Ssobomax			read_profile(shinit);
19283663Ssobomax		}
19383663Ssobomax	}
19483663Ssobomaxstate3:
19581046Ssobomax	state = 4;
19683663Ssobomax	if (minusc) {
19783663Ssobomax		evalstring(minusc);
19883663Ssobomax	}
19983663Ssobomax	if (sflag || minusc == NULL) {
2004996Sjkhstate4:	/* XXX ??? - why isn't this before the "if" statement */
2014996Sjkh		cmdloop(1);
2024996Sjkh	}
20341866Sjkh#if PROFILE
204327Sjkh	monitor(0);
205327Sjkh#endif
20641866Sjkh	exitshell(exitstatus);
207327Sjkh	/*NOTREACHED*/
20830221Scharnier	return 0;
209327Sjkh}
210327Sjkh
21141866Sjkh
212327Sjkh/*
213327Sjkh * Read and execute commands.  "Top" is nonzero for the top level command
214327Sjkh * loop; it turns on prompting if the shell is interactive.
215327Sjkh */
216327Sjkh
21723442Sjkhvoid
21841866Sjkhcmdloop(top)
21923442Sjkh	int top;
22030221Scharnier{
22123442Sjkh	union node *n;
22223442Sjkh	struct stackmark smark;
22341866Sjkh	int inter;
22423442Sjkh	int numeof = 0;
22541866Sjkh
226206043Sflz	TRACE(("cmdloop(%d) called\n", top));
227206043Sflz	setstackmark(&smark);
228206043Sflz	for (;;) {
229206043Sflz		if (pendingsigs)
2301550Sasami			dotrap();
2311550Sasami		inter = 0;
2321550Sasami		if (iflag && top) {
23330221Scharnier			inter++;
23430221Scharnier			showjobs(1);
2354996Sjkh			chkmail(0);
2364996Sjkh			flushout(&output);
2371550Sasami		}
2381550Sasami		n = parsecmd(inter);
23941866Sjkh		/* showtree(n); DEBUG */
24076739Ssobomax		if (n == NEOF) {
24176739Ssobomax			if (!top || numeof >= 50)
24241866Sjkh				break;
24341866Sjkh			if (!stoppedjobs()) {
24441866Sjkh				if (!Iflag)
24541866Sjkh					break;
24641866Sjkh				out2str("\nUse \"exit\" to leave shell.\n");
247111486Sdes			}
248111486Sdes			numeof++;
249111486Sdes		} else if (n != NULL && nflag == 0) {
250111486Sdes			job_warning = (job_warning == 2) ? 1 : 0;
251111486Sdes			numeof = 0;
252111486Sdes			evaltree(n, 0);
25341866Sjkh		}
254111486Sdes		popstackmark(&smark);
25541866Sjkh		if (evalskip == SKIPFILE) {
25641866Sjkh			evalskip = 0;
257206043Sflz			break;
258327Sjkh		}
259327Sjkh	}
260327Sjkh	popstackmark(&smark);		/* unnecessary */
261206043Sflz}
262206043Sflz
263206043Sflz
26441866Sjkh
26530221Scharnier/*
2664996Sjkh * Read /etc/profile or .profile.  Return on error.
2674996Sjkh */
268327Sjkh
269327SjkhSTATIC void
270327Sjkhread_profile(name)
27141866Sjkh	char *name;
272131280Seik	{
273131280Seik	int fd;
274131280Seik
275173533Skrion	INTOFF;
276131280Seik	if ((fd = open(name, O_RDONLY)) >= 0)
277131280Seik		setinputfd(fd, 1);
278131280Seik	INTON;
279131280Seik	if (fd < 0)
280131280Seik		return;
281131280Seik	cmdloop(0);
282131280Seik	popfile();
283131280Seik}
284178103Spav
285178103Spav
286178103Spav
287178103Spav/*
288178103Spav * Read a file containing shell functions.
289178103Spav */
290178103Spav
291178103Spavvoid
292178103Spavreadcmdfile(name)
293131280Seik	char *name;
294131280Seik{
295131280Seik	int fd;
296131280Seik
297178103Spav	INTOFF;
298178103Spav	if ((fd = open(name, O_RDONLY)) >= 0)
299178103Spav		setinputfd(fd, 1);
300178103Spav	else
301178103Spav		error("Can't open %s", name);
302178103Spav	INTON;
303178103Spav	cmdloop(0);
304178753Spav	popfile();
305178753Spav}
306178753Spav
307178753Spav
308178103Spav
309178103Spav/*
310178103Spav * Take commands from a file.  To be compatable we should do a path
311178103Spav * search for the file, which is necessary to find sub-commands.
312178103Spav */
313178103Spav
314178103Spav
31539068SjkhSTATIC char *
31639068Sjkhfind_dot_file(basename)
31796392Salfred	char *basename;
31896388Salfred{
31939068Sjkh	static char localname[FILENAME_MAX+1];
32041866Sjkh	char *fullname;
32176739Ssobomax	char *path = pathval();
32276739Ssobomax	struct stat statb;
32376739Ssobomax
32476739Ssobomax	/* don't try this for absolute or relative paths */
32573525Sroberto	if( strchr(basename, '/'))
32673525Sroberto		return basename;
327225610Spluknet
328225610Spluknet	while ((fullname = padvance(&path, basename)) != NULL) {
32941866Sjkh		strcpy(localname, fullname);
33041866Sjkh		stunalloc(fullname);
33141866Sjkh		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
33241866Sjkh			return localname;
33341866Sjkh	}
33441866Sjkh	return basename;
335206043Sflz}
33641866Sjkh
33741866Sjkhint
33841866Sjkhdotcmd(argc, argv)
339206043Sflz	int argc;
340206043Sflz	char **argv;
341206043Sflz{
34241866Sjkh	struct strlist *sp;
34341866Sjkh	exitstatus = 0;
34441866Sjkh
34541866Sjkh	for (sp = cmdenviron; sp ; sp = sp->next)
34641866Sjkh		setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
34741866Sjkh
34841866Sjkh	if (argc >= 2) {		/* That's what SVR2 does */
34941866Sjkh		char *fullname = find_dot_file(argv[1]);
35041866Sjkh
35141866Sjkh		setinputfile(fullname, 1);
35296392Salfred		commandname = fullname;
35396388Salfred		cmdloop(0);
35441866Sjkh		popfile();
35541866Sjkh	}
35641866Sjkh	return exitstatus;
35761171Shoek}
35830221Scharnier
35917338Sjkh
36017338Sjkhint
36112219Sjkhexitcmd(argc, argv)
362327Sjkh	int argc;
363327Sjkh	char **argv;
364327Sjkh{
365327Sjkh	extern int oexitstatus;
366327Sjkh
367327Sjkh	if (stoppedjobs())
368327Sjkh		return 0;
36939068Sjkh	if (argc > 1)
37039068Sjkh		exitstatus = number(argv[1]);
37196392Salfred	else
37296388Salfred		exitstatus = oexitstatus;
37339068Sjkh	exitshell(exitstatus);
374327Sjkh	/*NOTREACHED*/
375327Sjkh	return 0;
376327Sjkh}
377327Sjkh
378327Sjkh
37939068Sjkh#ifdef notdef
38039068Sjkh/*
381327Sjkh * Should never be called.
3824996Sjkh */
3834996Sjkh
38496613Ssobomaxvoid
3854996Sjkhexit(exitstatus) {
38683663Ssobomax	_exit(exitstatus);
38783663Ssobomax}
38883663Ssobomax#endif
38983663Ssobomax