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 * 4. Neither the name of the University nor the names of its contributors
171556Srgrimes *    may be used to endorse or promote products derived from this software
181556Srgrimes *    without specific prior written permission.
191556Srgrimes *
201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
231556Srgrimes * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
301556Srgrimes * SUCH DAMAGE.
311556Srgrimes */
321556Srgrimes
331556Srgrimes#ifndef lint
3420425Sstevestatic char const copyright[] =
351556Srgrimes"@(#) Copyright (c) 1991, 1993\n\
361556Srgrimes	The Regents of the University of California.  All rights reserved.\n";
371556Srgrimes#endif /* not lint */
381556Srgrimes
391556Srgrimes#ifndef lint
4036150Scharnier#if 0
4136150Scharnierstatic char sccsid[] = "@(#)main.c	8.6 (Berkeley) 5/28/95";
4236150Scharnier#endif
431556Srgrimes#endif /* not lint */
4499110Sobrien#include <sys/cdefs.h>
4599110Sobrien__FBSDID("$FreeBSD$");
461556Srgrimes
4717987Speter#include <stdio.h>
481556Srgrimes#include <signal.h>
4917987Speter#include <sys/stat.h>
5017987Speter#include <unistd.h>
511556Srgrimes#include <fcntl.h>
5217525Sache#include <locale.h>
5359214Simp#include <errno.h>
5417525Sache
551556Srgrimes#include "shell.h"
561556Srgrimes#include "main.h"
571556Srgrimes#include "mail.h"
581556Srgrimes#include "options.h"
591556Srgrimes#include "output.h"
601556Srgrimes#include "parser.h"
611556Srgrimes#include "nodes.h"
6217987Speter#include "expand.h"
631556Srgrimes#include "eval.h"
641556Srgrimes#include "jobs.h"
651556Srgrimes#include "input.h"
661556Srgrimes#include "trap.h"
671556Srgrimes#include "var.h"
6817987Speter#include "show.h"
691556Srgrimes#include "memalloc.h"
701556Srgrimes#include "error.h"
711556Srgrimes#include "mystring.h"
7217987Speter#include "exec.h"
7320425Ssteve#include "cd.h"
74253650Sjilles#include "redir.h"
75223060Sjilles#include "builtins.h"
761556Srgrimes
771556Srgrimesint rootpid;
781556Srgrimesint rootshell;
79200998Sjillesstruct jmploc main_handler;
80221669Sjillesint localeisutf8, initial_localeisutf8;
811556Srgrimes
82253650Sjillesstatic void reset(void);
83229220Sjillesstatic void cmdloop(int);
84248980Sjillesstatic void read_profile(const char *);
85213811Sobrienstatic char *find_dot_file(char *);
861556Srgrimes
871556Srgrimes/*
881556Srgrimes * Main routine.  We initialize things, parse the arguments, execute
891556Srgrimes * profiles if we're a login shell, and then call cmdloop to execute
901556Srgrimes * commands.  The setjmp call sets up the location to jump to when an
911556Srgrimes * exception occurs.  When an exception occurs the variable "state"
921556Srgrimes * is used to figure out how far we had gotten.
931556Srgrimes */
941556Srgrimes
9517987Speterint
9690111Simpmain(int argc, char *argv[])
9717987Speter{
98222957Sjilles	struct stackmark smark, smark2;
991556Srgrimes	volatile int state;
1001556Srgrimes	char *shinit;
1011556Srgrimes
10217525Sache	(void) setlocale(LC_ALL, "");
103221669Sjilles	initcharset();
1041556Srgrimes	state = 0;
105200998Sjilles	if (setjmp(main_handler.loc)) {
10620425Ssteve		switch (exception) {
10720425Ssteve		case EXEXEC:
10820425Ssteve			exitstatus = exerrno;
10920425Ssteve			break;
11020425Ssteve
11120425Ssteve		case EXERROR:
11220425Ssteve			exitstatus = 2;
11320425Ssteve			break;
11420425Ssteve
11520425Ssteve		default:
11620425Ssteve			break;
11720425Ssteve		}
11820425Ssteve
119220978Sjilles		if (state == 0 || iflag == 0 || ! rootshell ||
120220978Sjilles		    exception == EXEXIT)
121218306Sjilles			exitshell(exitstatus);
1221556Srgrimes		reset();
123215567Sjilles		if (exception == EXINT)
124215567Sjilles			out2fmt_flush("\n");
1251556Srgrimes		popstackmark(&smark);
1261556Srgrimes		FORCEINTON;				/* enable interrupts */
1271556Srgrimes		if (state == 1)
1281556Srgrimes			goto state1;
1291556Srgrimes		else if (state == 2)
1301556Srgrimes			goto state2;
1311556Srgrimes		else if (state == 3)
1321556Srgrimes			goto state3;
1331556Srgrimes		else
1341556Srgrimes			goto state4;
1351556Srgrimes	}
136200998Sjilles	handler = &main_handler;
1371556Srgrimes#ifdef DEBUG
1381556Srgrimes	opentrace();
1391556Srgrimes	trputs("Shell args:  ");  trargs(argv);
1401556Srgrimes#endif
1411556Srgrimes	rootpid = getpid();
1421556Srgrimes	rootshell = 1;
143245689Sjilles	initvar();
1441556Srgrimes	setstackmark(&smark);
145222957Sjilles	setstackmark(&smark2);
1461556Srgrimes	procargs(argc, argv);
147206759Sjilles	pwd_init(iflag);
148203576Sjilles	if (iflag)
149203576Sjilles		chkmail(1);
1501556Srgrimes	if (argv[0] && argv[0][0] == '-') {
1511556Srgrimes		state = 1;
1521556Srgrimes		read_profile("/etc/profile");
1531556Srgrimesstate1:
1541556Srgrimes		state = 2;
15519240Ssteve		if (privileged == 0)
156223005Sjilles			read_profile("${HOME-}/.profile");
15719240Ssteve		else
15819240Ssteve			read_profile("/etc/suid_profile");
1598855Srgrimes	}
1601556Srgrimesstate2:
1611556Srgrimes	state = 3;
16225471Ssteve	if (!privileged && iflag) {
16317987Speter		if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
16417987Speter			state = 3;
16517987Speter			read_profile(shinit);
16617987Speter		}
1671556Srgrimes	}
1681556Srgrimesstate3:
1691556Srgrimes	state = 4;
170222957Sjilles	popstackmark(&smark2);
1711556Srgrimes	if (minusc) {
172194128Sjilles		evalstring(minusc, sflag ? 0 : EV_EXIT);
1731556Srgrimes	}
174253271Sjillesstate4:
1751556Srgrimes	if (sflag || minusc == NULL) {
1761556Srgrimes		cmdloop(1);
1771556Srgrimes	}
1781556Srgrimes	exitshell(exitstatus);
17917987Speter	/*NOTREACHED*/
18017987Speter	return 0;
1811556Srgrimes}
1821556Srgrimes
183253650Sjillesstatic void
184253650Sjillesreset(void)
185253650Sjilles{
186253650Sjilles	reseteval();
187253650Sjilles	resetinput();
188253650Sjilles}
1891556Srgrimes
1901556Srgrimes/*
1911556Srgrimes * Read and execute commands.  "Top" is nonzero for the top level command
1921556Srgrimes * loop; it turns on prompting if the shell is interactive.
1931556Srgrimes */
1941556Srgrimes
195229220Sjillesstatic void
19690111Simpcmdloop(int top)
19717987Speter{
1981556Srgrimes	union node *n;
1991556Srgrimes	struct stackmark smark;
2001556Srgrimes	int inter;
2011556Srgrimes	int numeof = 0;
2021556Srgrimes
2031556Srgrimes	TRACE(("cmdloop(%d) called\n", top));
2041556Srgrimes	setstackmark(&smark);
2051556Srgrimes	for (;;) {
206247206Sjilles		if (pendingsig)
2071556Srgrimes			dotrap();
2081556Srgrimes		inter = 0;
2091556Srgrimes		if (iflag && top) {
2101556Srgrimes			inter++;
211163085Sstefanf			showjobs(1, SHOWJOBS_DEFAULT);
2121556Srgrimes			chkmail(0);
2131556Srgrimes			flushout(&output);
2141556Srgrimes		}
2151556Srgrimes		n = parsecmd(inter);
2161556Srgrimes		/* showtree(n); DEBUG */
2171556Srgrimes		if (n == NEOF) {
2181556Srgrimes			if (!top || numeof >= 50)
2191556Srgrimes				break;
2201556Srgrimes			if (!stoppedjobs()) {
2211556Srgrimes				if (!Iflag)
2221556Srgrimes					break;
223199629Sjilles				out2fmt_flush("\nUse \"exit\" to leave shell.\n");
2241556Srgrimes			}
2251556Srgrimes			numeof++;
2261556Srgrimes		} else if (n != NULL && nflag == 0) {
2271556Srgrimes			job_warning = (job_warning == 2) ? 1 : 0;
2281556Srgrimes			numeof = 0;
2291556Srgrimes			evaltree(n, 0);
2301556Srgrimes		}
2311556Srgrimes		popstackmark(&smark);
23264702Scracauer		setstackmark(&smark);
233211349Sjilles		if (evalskip != 0) {
234255215Sjilles			if (evalskip == SKIPRETURN)
235211349Sjilles				evalskip = 0;
23620425Ssteve			break;
23720425Ssteve		}
2381556Srgrimes	}
23964702Scracauer	popstackmark(&smark);
2401556Srgrimes}
2411556Srgrimes
2421556Srgrimes
2431556Srgrimes
2441556Srgrimes/*
2451556Srgrimes * Read /etc/profile or .profile.  Return on error.
2461556Srgrimes */
2471556Srgrimes
248213811Sobrienstatic void
249248980Sjillesread_profile(const char *name)
25090111Simp{
2511556Srgrimes	int fd;
252222957Sjilles	const char *expandedname;
2531556Srgrimes
254222957Sjilles	expandedname = expandstr(name);
255222957Sjilles	if (expandedname == NULL)
256222957Sjilles		return;
2571556Srgrimes	INTOFF;
258250267Sjilles	if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0)
2591556Srgrimes		setinputfd(fd, 1);
2601556Srgrimes	INTON;
2611556Srgrimes	if (fd < 0)
2621556Srgrimes		return;
2631556Srgrimes	cmdloop(0);
2641556Srgrimes	popfile();
2651556Srgrimes}
2661556Srgrimes
2671556Srgrimes
2681556Srgrimes
2691556Srgrimes/*
2701556Srgrimes * Read a file containing shell functions.
2711556Srgrimes */
2721556Srgrimes
2731556Srgrimesvoid
274200956Sjillesreadcmdfile(const char *name)
27517987Speter{
276240505Sjilles	setinputfile(name, 1);
2771556Srgrimes	cmdloop(0);
2781556Srgrimes	popfile();
2791556Srgrimes}
2801556Srgrimes
2811556Srgrimes
2821556Srgrimes
2831556Srgrimes/*
28446684Skris * Take commands from a file.  To be compatible we should do a path
28517987Speter * search for the file, which is necessary to find sub-commands.
2861556Srgrimes */
2871556Srgrimes
28817987Speter
289213811Sobrienstatic char *
29090111Simpfind_dot_file(char *basename)
29117987Speter{
29217987Speter	char *fullname;
293200956Sjilles	const char *path = pathval();
29417987Speter	struct stat statb;
29517987Speter
29617987Speter	/* don't try this for absolute or relative paths */
29717987Speter	if( strchr(basename, '/'))
29817987Speter		return basename;
29917987Speter
30017987Speter	while ((fullname = padvance(&path, basename)) != NULL) {
301222173Sjilles		if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) {
302222173Sjilles			/*
303222173Sjilles			 * Don't bother freeing here, since it will
304222173Sjilles			 * be freed by the caller.
305222173Sjilles			 */
306222173Sjilles			return fullname;
307222173Sjilles		}
30817987Speter		stunalloc(fullname);
30917987Speter	}
31017987Speter	return basename;
31117987Speter}
31217987Speter
31317987Speterint
31490111Simpdotcmd(int argc, char **argv)
31517987Speter{
316208630Sjilles	char *filename, *fullname;
317157414Sstefanf
318157414Sstefanf	if (argc < 2)
319157414Sstefanf		error("missing filename");
320157414Sstefanf
3211556Srgrimes	exitstatus = 0;
32217987Speter
323208630Sjilles	/*
324208630Sjilles	 * Because we have historically not supported any options,
325208630Sjilles	 * only treat "--" specially.
326208630Sjilles	 */
327208630Sjilles	filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1];
328208630Sjilles
329208630Sjilles	fullname = find_dot_file(filename);
330157414Sstefanf	setinputfile(fullname, 1);
331157414Sstefanf	commandname = fullname;
332157414Sstefanf	cmdloop(0);
333157414Sstefanf	popfile();
3341556Srgrimes	return exitstatus;
3351556Srgrimes}
3361556Srgrimes
3371556Srgrimes
33817987Speterint
33990111Simpexitcmd(int argc, char **argv)
34017987Speter{
3411556Srgrimes	if (stoppedjobs())
34217987Speter		return 0;
34320425Ssteve	if (argc > 1)
344217175Sjilles		exitshell(number(argv[1]));
34520425Ssteve	else
346217175Sjilles		exitshell_savedstatus();
3471556Srgrimes}
348