main.c revision 20425
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 *
3620425Ssteve *	$Id: main.c,v 1.9 1996/10/29 03:12:47 steve Exp $
371556Srgrimes */
381556Srgrimes
391556Srgrimes#ifndef lint
4020425Sstevestatic char const 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
4620425Sstevestatic char const 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"
7620425Ssteve#include "cd.h"
771556Srgrimes
781556Srgrimes#define PROFILE 0
791556Srgrimes
801556Srgrimesint rootpid;
811556Srgrimesint rootshell;
821556Srgrimesextern int errno;
831556Srgrimes#if PROFILE
841556Srgrimesshort profile_buf[16384];
851556Srgrimesextern int etext();
861556Srgrimes#endif
871556Srgrimes
8817987SpeterSTATIC void read_profile __P((char *));
8917987SpeterSTATIC char *find_dot_file __P((char *));
901556Srgrimes
911556Srgrimes/*
921556Srgrimes * Main routine.  We initialize things, parse the arguments, execute
931556Srgrimes * profiles if we're a login shell, and then call cmdloop to execute
941556Srgrimes * commands.  The setjmp call sets up the location to jump to when an
951556Srgrimes * exception occurs.  When an exception occurs the variable "state"
961556Srgrimes * is used to figure out how far we had gotten.
971556Srgrimes */
981556Srgrimes
9917987Speterint
10017987Spetermain(argc, argv)
10117987Speter	int argc;
10220425Ssteve	char **argv;
10317987Speter{
1041556Srgrimes	struct jmploc jmploc;
1051556Srgrimes	struct stackmark smark;
1061556Srgrimes	volatile int state;
1071556Srgrimes	char *shinit;
1081556Srgrimes
1091556Srgrimes#if PROFILE
1101556Srgrimes	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
1111556Srgrimes#endif
11217525Sache	(void) setlocale(LC_ALL, "");
1131556Srgrimes	state = 0;
1141556Srgrimes	if (setjmp(jmploc.loc)) {
1151556Srgrimes		/*
1161556Srgrimes		 * When a shell procedure is executed, we raise the
1171556Srgrimes		 * exception EXSHELLPROC to clean up before executing
1181556Srgrimes		 * the shell procedure.
1191556Srgrimes		 */
12020425Ssteve		switch (exception) {
12120425Ssteve		case EXSHELLPROC:
1221556Srgrimes			rootpid = getpid();
1231556Srgrimes			rootshell = 1;
1241556Srgrimes			minusc = NULL;
1251556Srgrimes			state = 3;
12620425Ssteve			break;
12720425Ssteve
12820425Ssteve		case EXEXEC:
12920425Ssteve			exitstatus = exerrno;
13020425Ssteve			break;
13120425Ssteve
13220425Ssteve		case EXERROR:
13320425Ssteve			exitstatus = 2;
13420425Ssteve			break;
13520425Ssteve
13620425Ssteve		default:
13720425Ssteve			break;
13820425Ssteve		}
13920425Ssteve
14020425Ssteve		if (exception != EXSHELLPROC) {
14120425Ssteve		    if (state == 0 || iflag == 0 || ! rootshell)
14220425Ssteve			    exitshell(exitstatus);
14320425Ssteve		}
1441556Srgrimes		reset();
1451556Srgrimes		if (exception == EXINT
1461556Srgrimes#if ATTY
1471556Srgrimes		 && (! attyset() || equal(termval(), "emacs"))
1481556Srgrimes#endif
1491556Srgrimes		 ) {
1501556Srgrimes			out2c('\n');
1511556Srgrimes			flushout(&errout);
1521556Srgrimes		}
1531556Srgrimes		popstackmark(&smark);
1541556Srgrimes		FORCEINTON;				/* enable interrupts */
1551556Srgrimes		if (state == 1)
1561556Srgrimes			goto state1;
1571556Srgrimes		else if (state == 2)
1581556Srgrimes			goto state2;
1591556Srgrimes		else if (state == 3)
1601556Srgrimes			goto state3;
1611556Srgrimes		else
1621556Srgrimes			goto state4;
1631556Srgrimes	}
1641556Srgrimes	handler = &jmploc;
1651556Srgrimes#ifdef DEBUG
1661556Srgrimes	opentrace();
1671556Srgrimes	trputs("Shell args:  ");  trargs(argv);
1681556Srgrimes#endif
1691556Srgrimes	rootpid = getpid();
1701556Srgrimes	rootshell = 1;
1711556Srgrimes	init();
1721556Srgrimes	setstackmark(&smark);
1731556Srgrimes	procargs(argc, argv);
17420425Ssteve	getpwd();
1751556Srgrimes	if (argv[0] && argv[0][0] == '-') {
1761556Srgrimes		state = 1;
1771556Srgrimes		read_profile("/etc/profile");
1781556Srgrimesstate1:
1791556Srgrimes		state = 2;
18019240Ssteve		if (privileged == 0)
18119240Ssteve			read_profile(".profile");
18219240Ssteve		else
18319240Ssteve			read_profile("/etc/suid_profile");
1848855Srgrimes	}
1851556Srgrimesstate2:
1861556Srgrimes	state = 3;
18719240Ssteve	if (privileged == 0) {
18817987Speter		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
18917987Speter			state = 3;
19017987Speter			read_profile(shinit);
19117987Speter		}
1921556Srgrimes	}
1931556Srgrimesstate3:
1941556Srgrimes	state = 4;
1951556Srgrimes	if (minusc) {
1961556Srgrimes		evalstring(minusc);
1971556Srgrimes	}
1981556Srgrimes	if (sflag || minusc == NULL) {
1991556Srgrimesstate4:	/* XXX ??? - why isn't this before the "if" statement */
2001556Srgrimes		cmdloop(1);
2011556Srgrimes	}
2021556Srgrimes#if PROFILE
2031556Srgrimes	monitor(0);
2041556Srgrimes#endif
2051556Srgrimes	exitshell(exitstatus);
20617987Speter	/*NOTREACHED*/
20717987Speter	return 0;
2081556Srgrimes}
2091556Srgrimes
2101556Srgrimes
2111556Srgrimes/*
2121556Srgrimes * Read and execute commands.  "Top" is nonzero for the top level command
2131556Srgrimes * loop; it turns on prompting if the shell is interactive.
2141556Srgrimes */
2151556Srgrimes
2161556Srgrimesvoid
21720425Sstevecmdloop(top)
21817987Speter	int top;
21917987Speter{
2201556Srgrimes	union node *n;
2211556Srgrimes	struct stackmark smark;
2221556Srgrimes	int inter;
2231556Srgrimes	int numeof = 0;
2241556Srgrimes
2251556Srgrimes	TRACE(("cmdloop(%d) called\n", top));
2261556Srgrimes	setstackmark(&smark);
2271556Srgrimes	for (;;) {
2281556Srgrimes		if (pendingsigs)
2291556Srgrimes			dotrap();
2301556Srgrimes		inter = 0;
2311556Srgrimes		if (iflag && top) {
2321556Srgrimes			inter++;
2331556Srgrimes			showjobs(1);
2341556Srgrimes			chkmail(0);
2351556Srgrimes			flushout(&output);
2361556Srgrimes		}
2371556Srgrimes		n = parsecmd(inter);
2381556Srgrimes		/* showtree(n); DEBUG */
2391556Srgrimes		if (n == NEOF) {
2401556Srgrimes			if (!top || numeof >= 50)
2411556Srgrimes				break;
2421556Srgrimes			if (!stoppedjobs()) {
2431556Srgrimes				if (!Iflag)
2441556Srgrimes					break;
2451556Srgrimes				out2str("\nUse \"exit\" to leave shell.\n");
2461556Srgrimes			}
2471556Srgrimes			numeof++;
2481556Srgrimes		} else if (n != NULL && nflag == 0) {
2491556Srgrimes			job_warning = (job_warning == 2) ? 1 : 0;
2501556Srgrimes			numeof = 0;
2511556Srgrimes			evaltree(n, 0);
2521556Srgrimes		}
2531556Srgrimes		popstackmark(&smark);
25420425Ssteve		if (evalskip == SKIPFILE) {
25520425Ssteve			evalskip = 0;
25620425Ssteve			break;
25720425Ssteve		}
2581556Srgrimes	}
2591556Srgrimes	popstackmark(&smark);		/* unnecessary */
2601556Srgrimes}
2611556Srgrimes
2621556Srgrimes
2631556Srgrimes
2641556Srgrimes/*
2651556Srgrimes * Read /etc/profile or .profile.  Return on error.
2661556Srgrimes */
2671556Srgrimes
2681556SrgrimesSTATIC void
2691556Srgrimesread_profile(name)
2701556Srgrimes	char *name;
2711556Srgrimes	{
2721556Srgrimes	int fd;
2731556Srgrimes
2741556Srgrimes	INTOFF;
2751556Srgrimes	if ((fd = open(name, O_RDONLY)) >= 0)
2761556Srgrimes		setinputfd(fd, 1);
2771556Srgrimes	INTON;
2781556Srgrimes	if (fd < 0)
2791556Srgrimes		return;
2801556Srgrimes	cmdloop(0);
2811556Srgrimes	popfile();
2821556Srgrimes}
2831556Srgrimes
2841556Srgrimes
2851556Srgrimes
2861556Srgrimes/*
2871556Srgrimes * Read a file containing shell functions.
2881556Srgrimes */
2891556Srgrimes
2901556Srgrimesvoid
2911556Srgrimesreadcmdfile(name)
2921556Srgrimes	char *name;
29317987Speter{
2941556Srgrimes	int fd;
2951556Srgrimes
2961556Srgrimes	INTOFF;
2971556Srgrimes	if ((fd = open(name, O_RDONLY)) >= 0)
2981556Srgrimes		setinputfd(fd, 1);
2991556Srgrimes	else
3001556Srgrimes		error("Can't open %s", name);
3011556Srgrimes	INTON;
3021556Srgrimes	cmdloop(0);
3031556Srgrimes	popfile();
3041556Srgrimes}
3051556Srgrimes
3061556Srgrimes
3071556Srgrimes
3081556Srgrimes/*
3091556Srgrimes * Take commands from a file.  To be compatable we should do a path
31017987Speter * search for the file, which is necessary to find sub-commands.
3111556Srgrimes */
3121556Srgrimes
31317987Speter
31417987SpeterSTATIC char *
31517987Speterfind_dot_file(basename)
31617987Speter	char *basename;
31717987Speter{
31817987Speter	static char localname[FILENAME_MAX+1];
31917987Speter	char *fullname;
32017987Speter	char *path = pathval();
32117987Speter	struct stat statb;
32217987Speter
32317987Speter	/* don't try this for absolute or relative paths */
32417987Speter	if( strchr(basename, '/'))
32517987Speter		return basename;
32617987Speter
32717987Speter	while ((fullname = padvance(&path, basename)) != NULL) {
32817987Speter		strcpy(localname, fullname);
32917987Speter		stunalloc(fullname);
33017987Speter		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
33117987Speter			return localname;
33217987Speter	}
33317987Speter	return basename;
33417987Speter}
33517987Speter
33617987Speterint
33720425Sstevedotcmd(argc, argv)
33817987Speter	int argc;
33920425Ssteve	char **argv;
34017987Speter{
34117987Speter	struct strlist *sp;
3421556Srgrimes	exitstatus = 0;
34317987Speter
34417987Speter	for (sp = cmdenviron; sp ; sp = sp->next)
34517987Speter		setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
34617987Speter
3471556Srgrimes	if (argc >= 2) {		/* That's what SVR2 does */
34817987Speter		char *fullname = find_dot_file(argv[1]);
34917987Speter
35017987Speter		setinputfile(fullname, 1);
35117987Speter		commandname = fullname;
3521556Srgrimes		cmdloop(0);
3531556Srgrimes		popfile();
3541556Srgrimes	}
3551556Srgrimes	return exitstatus;
3561556Srgrimes}
3571556Srgrimes
3581556Srgrimes
35917987Speterint
36020425Ssteveexitcmd(argc, argv)
36117987Speter	int argc;
36220425Ssteve	char **argv;
36317987Speter{
36418267Sadam	extern int oexitstatus;
36518267Sadam
3661556Srgrimes	if (stoppedjobs())
36717987Speter		return 0;
36820425Ssteve	if (argc > 1)
36920425Ssteve		exitstatus = number(argv[1]);
37020425Ssteve	else
37120425Ssteve		exitstatus = oexitstatus;
37218254Sbde	exitshell(exitstatus);
37317987Speter	/*NOTREACHED*/
37417987Speter	return 0;
3751556Srgrimes}
3761556Srgrimes
3771556Srgrimes
3781556Srgrimes#ifdef notdef
3791556Srgrimes/*
3801556Srgrimes * Should never be called.
3811556Srgrimes */
3821556Srgrimes
3831556Srgrimesvoid
3841556Srgrimesexit(exitstatus) {
3851556Srgrimes	_exit(exitstatus);
3861556Srgrimes}
3871556Srgrimes#endif
388