main.c revision 17987
11556Srgrimes/*-
21556Srgrimes * Copyright (c) 1991, 1993
31556Srgrimes *	The Regents of the University of California.  All rights reserved.
41556Srgrimes *
51556Srgrimes * This code is derived from software contributed to Berkeley by
61556Srgrimes * Kenneth Almquist.
71556Srgrimes *
81556Srgrimes * Redistribution and use in source and binary forms, with or without
91556Srgrimes * modification, are permitted provided that the following conditions
101556Srgrimes * are met:
111556Srgrimes * 1. Redistributions of source code must retain the above copyright
121556Srgrimes *    notice, this list of conditions and the following disclaimer.
131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright
141556Srgrimes *    notice, this list of conditions and the following disclaimer in the
151556Srgrimes *    documentation and/or other materials provided with the distribution.
161556Srgrimes * 3. All advertising materials mentioning features or use of this software
171556Srgrimes *    must display the following acknowledgement:
181556Srgrimes *	This product includes software developed by the University of
191556Srgrimes *	California, Berkeley and its contributors.
201556Srgrimes * 4. Neither the name of the University nor the names of its contributors
211556Srgrimes *    may be used to endorse or promote products derived from this software
221556Srgrimes *    without specific prior written permission.
231556Srgrimes *
241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
271556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
341556Srgrimes * SUCH DAMAGE.
353044Sdg *
3617987Speter *	$Id: main.c,v 1.4 1996/08/11 22:50:58 ache Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
401556Srgrimesstatic char copyright[] =
411556Srgrimes"@(#) Copyright (c) 1991, 1993\n\
421556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
431556Srgrimes#endif /* not lint */
441556Srgrimes
451556Srgrimes#ifndef lint
4617987Speterstatic char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/28/95";
471556Srgrimes#endif /* not lint */
481556Srgrimes
4917987Speter#include <stdio.h>
501556Srgrimes#include <signal.h>
5117987Speter#include <sys/stat.h>
5217987Speter#include <unistd.h>
531556Srgrimes#include <fcntl.h>
5417525Sache#include <locale.h>
5517525Sache
5617987Speter
571556Srgrimes#include "shell.h"
581556Srgrimes#include "main.h"
591556Srgrimes#include "mail.h"
601556Srgrimes#include "options.h"
611556Srgrimes#include "output.h"
621556Srgrimes#include "parser.h"
631556Srgrimes#include "nodes.h"
6417987Speter#include "expand.h"
651556Srgrimes#include "eval.h"
661556Srgrimes#include "jobs.h"
671556Srgrimes#include "input.h"
681556Srgrimes#include "trap.h"
691556Srgrimes#include "var.h"
7017987Speter#include "show.h"
711556Srgrimes#include "memalloc.h"
721556Srgrimes#include "error.h"
731556Srgrimes#include "init.h"
741556Srgrimes#include "mystring.h"
7517987Speter#include "exec.h"
761556Srgrimes
771556Srgrimes#define PROFILE 0
781556Srgrimes
791556Srgrimesint rootpid;
801556Srgrimesint rootshell;
811556SrgrimesSTATIC union node *curcmd;
821556SrgrimesSTATIC union node *prevcmd;
831556Srgrimesextern int errno;
841556Srgrimes#if PROFILE
851556Srgrimesshort profile_buf[16384];
861556Srgrimesextern int etext();
871556Srgrimes#endif
881556Srgrimes
8917987SpeterSTATIC void read_profile __P((char *));
9017987SpeterSTATIC char *find_dot_file __P((char *));
911556Srgrimes
921556Srgrimes/*
931556Srgrimes * Main routine.  We initialize things, parse the arguments, execute
941556Srgrimes * profiles if we're a login shell, and then call cmdloop to execute
951556Srgrimes * commands.  The setjmp call sets up the location to jump to when an
961556Srgrimes * exception occurs.  When an exception occurs the variable "state"
971556Srgrimes * is used to figure out how far we had gotten.
981556Srgrimes */
991556Srgrimes
10017987Speterint
10117987Spetermain(argc, argv)
10217987Speter	int argc;
10317987Speter	char **argv;
10417987Speter{
1051556Srgrimes	struct jmploc jmploc;
1061556Srgrimes	struct stackmark smark;
1071556Srgrimes	volatile int state;
1081556Srgrimes	char *shinit;
1091556Srgrimes
1101556Srgrimes#if PROFILE
1111556Srgrimes	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
1121556Srgrimes#endif
11317525Sache	(void) setlocale(LC_ALL, "");
1141556Srgrimes	state = 0;
1151556Srgrimes	if (setjmp(jmploc.loc)) {
1161556Srgrimes		/*
1171556Srgrimes		 * When a shell procedure is executed, we raise the
1181556Srgrimes		 * exception EXSHELLPROC to clean up before executing
1191556Srgrimes		 * the shell procedure.
1201556Srgrimes		 */
12117987Speter		if (exception == EXERROR)
12217987Speter			exitstatus = 2;
1231556Srgrimes		if (exception == EXSHELLPROC) {
1241556Srgrimes			rootpid = getpid();
1251556Srgrimes			rootshell = 1;
1261556Srgrimes			minusc = NULL;
1271556Srgrimes			state = 3;
1281556Srgrimes		} else if (state == 0 || iflag == 0 || ! rootshell)
1291556Srgrimes			exitshell(2);
1301556Srgrimes		reset();
1311556Srgrimes		if (exception == EXINT
1321556Srgrimes#if ATTY
1331556Srgrimes		 && (! attyset() || equal(termval(), "emacs"))
1341556Srgrimes#endif
1351556Srgrimes		 ) {
1361556Srgrimes			out2c('\n');
1371556Srgrimes			flushout(&errout);
1381556Srgrimes		}
1391556Srgrimes		popstackmark(&smark);
1401556Srgrimes		FORCEINTON;				/* enable interrupts */
1411556Srgrimes		if (state == 1)
1421556Srgrimes			goto state1;
1431556Srgrimes		else if (state == 2)
1441556Srgrimes			goto state2;
1451556Srgrimes		else if (state == 3)
1461556Srgrimes			goto state3;
1471556Srgrimes		else
1481556Srgrimes			goto state4;
1491556Srgrimes	}
1501556Srgrimes	handler = &jmploc;
1511556Srgrimes#ifdef DEBUG
1521556Srgrimes	opentrace();
1531556Srgrimes	trputs("Shell args:  ");  trargs(argv);
1541556Srgrimes#endif
1551556Srgrimes	rootpid = getpid();
1561556Srgrimes	rootshell = 1;
1571556Srgrimes	init();
1581556Srgrimes	setstackmark(&smark);
1591556Srgrimes	procargs(argc, argv);
1601556Srgrimes	if (argv[0] && argv[0][0] == '-') {
1611556Srgrimes		state = 1;
1621556Srgrimes		read_profile("/etc/profile");
1631556Srgrimesstate1:
1641556Srgrimes		state = 2;
1651556Srgrimes		read_profile(".profile");
1668855Srgrimes	}
1671556Srgrimesstate2:
1681556Srgrimes	state = 3;
16917987Speter	if (getuid() == geteuid() && getgid() == getegid()) {
17017987Speter		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
17117987Speter			state = 3;
17217987Speter			read_profile(shinit);
17317987Speter		}
1741556Srgrimes	}
1751556Srgrimesstate3:
1761556Srgrimes	state = 4;
1771556Srgrimes	if (minusc) {
1781556Srgrimes		evalstring(minusc);
1791556Srgrimes	}
1801556Srgrimes	if (sflag || minusc == NULL) {
1811556Srgrimesstate4:	/* XXX ??? - why isn't this before the "if" statement */
1821556Srgrimes		cmdloop(1);
1831556Srgrimes	}
1841556Srgrimes#if PROFILE
1851556Srgrimes	monitor(0);
1861556Srgrimes#endif
1871556Srgrimes	exitshell(exitstatus);
18817987Speter	/*NOTREACHED*/
18917987Speter	return 0;
1901556Srgrimes}
1911556Srgrimes
1921556Srgrimes
1931556Srgrimes/*
1941556Srgrimes * Read and execute commands.  "Top" is nonzero for the top level command
1951556Srgrimes * loop; it turns on prompting if the shell is interactive.
1961556Srgrimes */
1971556Srgrimes
1981556Srgrimesvoid
19917987Spetercmdloop(top)
20017987Speter	int top;
20117987Speter{
2021556Srgrimes	union node *n;
2031556Srgrimes	struct stackmark smark;
2041556Srgrimes	int inter;
2051556Srgrimes	int numeof = 0;
2061556Srgrimes
2071556Srgrimes	TRACE(("cmdloop(%d) called\n", top));
2081556Srgrimes	setstackmark(&smark);
2091556Srgrimes	for (;;) {
2101556Srgrimes		if (pendingsigs)
2111556Srgrimes			dotrap();
2121556Srgrimes		inter = 0;
2131556Srgrimes		if (iflag && top) {
2141556Srgrimes			inter++;
2151556Srgrimes			showjobs(1);
2161556Srgrimes			chkmail(0);
2171556Srgrimes			flushout(&output);
2181556Srgrimes		}
2191556Srgrimes		n = parsecmd(inter);
2201556Srgrimes		/* showtree(n); DEBUG */
2211556Srgrimes		if (n == NEOF) {
2221556Srgrimes			if (!top || numeof >= 50)
2231556Srgrimes				break;
2241556Srgrimes			if (!stoppedjobs()) {
2251556Srgrimes				if (!Iflag)
2261556Srgrimes					break;
2271556Srgrimes				out2str("\nUse \"exit\" to leave shell.\n");
2281556Srgrimes			}
2291556Srgrimes			numeof++;
2301556Srgrimes		} else if (n != NULL && nflag == 0) {
2311556Srgrimes			job_warning = (job_warning == 2) ? 1 : 0;
2321556Srgrimes			numeof = 0;
2331556Srgrimes			evaltree(n, 0);
2341556Srgrimes		}
2351556Srgrimes		popstackmark(&smark);
2361556Srgrimes	}
2371556Srgrimes	popstackmark(&smark);		/* unnecessary */
2381556Srgrimes}
2391556Srgrimes
2401556Srgrimes
2411556Srgrimes
2421556Srgrimes/*
2431556Srgrimes * Read /etc/profile or .profile.  Return on error.
2441556Srgrimes */
2451556Srgrimes
2461556SrgrimesSTATIC void
2471556Srgrimesread_profile(name)
2481556Srgrimes	char *name;
2491556Srgrimes	{
2501556Srgrimes	int fd;
2511556Srgrimes
2521556Srgrimes	INTOFF;
2531556Srgrimes	if ((fd = open(name, O_RDONLY)) >= 0)
2541556Srgrimes		setinputfd(fd, 1);
2551556Srgrimes	INTON;
2561556Srgrimes	if (fd < 0)
2571556Srgrimes		return;
2581556Srgrimes	cmdloop(0);
2591556Srgrimes	popfile();
2601556Srgrimes}
2611556Srgrimes
2621556Srgrimes
2631556Srgrimes
2641556Srgrimes/*
2651556Srgrimes * Read a file containing shell functions.
2661556Srgrimes */
2671556Srgrimes
2681556Srgrimesvoid
2691556Srgrimesreadcmdfile(name)
2701556Srgrimes	char *name;
27117987Speter{
2721556Srgrimes	int fd;
2731556Srgrimes
2741556Srgrimes	INTOFF;
2751556Srgrimes	if ((fd = open(name, O_RDONLY)) >= 0)
2761556Srgrimes		setinputfd(fd, 1);
2771556Srgrimes	else
2781556Srgrimes		error("Can't open %s", name);
2791556Srgrimes	INTON;
2801556Srgrimes	cmdloop(0);
2811556Srgrimes	popfile();
2821556Srgrimes}
2831556Srgrimes
2841556Srgrimes
2851556Srgrimes
2861556Srgrimes/*
2871556Srgrimes * Take commands from a file.  To be compatable we should do a path
28817987Speter * search for the file, which is necessary to find sub-commands.
2891556Srgrimes */
2901556Srgrimes
29117987Speter
29217987SpeterSTATIC char *
29317987Speterfind_dot_file(basename)
29417987Speter	char *basename;
29517987Speter{
29617987Speter	static char localname[FILENAME_MAX+1];
29717987Speter	char *fullname;
29817987Speter	char *path = pathval();
29917987Speter	struct stat statb;
30017987Speter
30117987Speter	/* don't try this for absolute or relative paths */
30217987Speter	if( strchr(basename, '/'))
30317987Speter		return basename;
30417987Speter
30517987Speter	while ((fullname = padvance(&path, basename)) != NULL) {
30617987Speter		strcpy(localname, fullname);
30717987Speter		stunalloc(fullname);
30817987Speter		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
30917987Speter			return localname;
31017987Speter	}
31117987Speter	return basename;
31217987Speter}
31317987Speter
31417987Speterint
31517987Speterdotcmd(argc, argv)
31617987Speter	int argc;
31717987Speter	char **argv;
31817987Speter{
31917987Speter	struct strlist *sp;
3201556Srgrimes	exitstatus = 0;
32117987Speter
32217987Speter	for (sp = cmdenviron; sp ; sp = sp->next)
32317987Speter		setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
32417987Speter
3251556Srgrimes	if (argc >= 2) {		/* That's what SVR2 does */
32617987Speter		char *fullname = find_dot_file(argv[1]);
32717987Speter
32817987Speter		setinputfile(fullname, 1);
32917987Speter		commandname = fullname;
3301556Srgrimes		cmdloop(0);
3311556Srgrimes		popfile();
3321556Srgrimes	}
3331556Srgrimes	return exitstatus;
3341556Srgrimes}
3351556Srgrimes
3361556Srgrimes
33717987Speterint
33817987Speterexitcmd(argc, argv)
33917987Speter	int argc;
34017987Speter	char **argv;
34117987Speter{
3421556Srgrimes	if (stoppedjobs())
34317987Speter		return 0;
3441556Srgrimes	if (argc > 1)
3451556Srgrimes		exitstatus = number(argv[1]);
3461556Srgrimes	exitshell(exitstatus);
34717987Speter	/*NOTREACHED*/
34817987Speter	return 0;
3491556Srgrimes}
3501556Srgrimes
3511556Srgrimes
3521556Srgrimes#ifdef notdef
3531556Srgrimes/*
3541556Srgrimes * Should never be called.
3551556Srgrimes */
3561556Srgrimes
3571556Srgrimesvoid
3581556Srgrimesexit(exitstatus) {
3591556Srgrimes	_exit(exitstatus);
3601556Srgrimes}
3611556Srgrimes#endif
362