xref: /csrg-svn/bin/sh/main.c (revision 47125)
1*47125Sbostic /*-
2*47125Sbostic  * Copyright (c) 1991 The Regents of the University of California.
3*47125Sbostic  * All rights reserved.
4*47125Sbostic  *
5*47125Sbostic  * This code is derived from software contributed to Berkeley by
6*47125Sbostic  * Kenneth Almquist.
7*47125Sbostic  *
8*47125Sbostic  * %sccs.include.redist.c%
9*47125Sbostic  */
10*47125Sbostic 
11*47125Sbostic #ifndef lint
12*47125Sbostic char copyright[] =
13*47125Sbostic "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
14*47125Sbostic  All rights reserved.\n";
15*47125Sbostic #endif /* not lint */
16*47125Sbostic 
17*47125Sbostic #ifndef lint
18*47125Sbostic static char sccsid[] = "@(#)main.c	5.1 (Berkeley) 03/07/91";
19*47125Sbostic #endif /* not lint */
20*47125Sbostic 
21*47125Sbostic #include <signal.h>
22*47125Sbostic #include <fcntl.h>
23*47125Sbostic #include "shell.h"
24*47125Sbostic #include "main.h"
25*47125Sbostic #include "mail.h"
26*47125Sbostic #include "options.h"
27*47125Sbostic #include "output.h"
28*47125Sbostic #include "parser.h"
29*47125Sbostic #include "nodes.h"
30*47125Sbostic #include "eval.h"
31*47125Sbostic #include "jobs.h"
32*47125Sbostic #include "input.h"
33*47125Sbostic #include "trap.h"
34*47125Sbostic #if ATTY
35*47125Sbostic #include "var.h"
36*47125Sbostic #endif
37*47125Sbostic #include "memalloc.h"
38*47125Sbostic #include "error.h"
39*47125Sbostic #include "init.h"
40*47125Sbostic #include "mystring.h"
41*47125Sbostic 
42*47125Sbostic #define PROFILE 0
43*47125Sbostic 
44*47125Sbostic int rootpid;
45*47125Sbostic int rootshell;
46*47125Sbostic STATIC union node *curcmd;
47*47125Sbostic STATIC union node *prevcmd;
48*47125Sbostic extern int errno;
49*47125Sbostic #if PROFILE
50*47125Sbostic short profile_buf[16384];
51*47125Sbostic extern int etext();
52*47125Sbostic #endif
53*47125Sbostic 
54*47125Sbostic #ifdef __STDC__
55*47125Sbostic STATIC void read_profile(char *);
56*47125Sbostic char *getenv(char *);
57*47125Sbostic #else
58*47125Sbostic STATIC void read_profile();
59*47125Sbostic char *getenv();
60*47125Sbostic #endif
61*47125Sbostic 
62*47125Sbostic 
63*47125Sbostic /*
64*47125Sbostic  * Main routine.  We initialize things, parse the arguments, execute
65*47125Sbostic  * profiles if we're a login shell, and then call cmdloop to execute
66*47125Sbostic  * commands.  The setjmp call sets up the location to jump to when an
67*47125Sbostic  * exception occurs.  When an exception occurs the variable "state"
68*47125Sbostic  * is used to figure out how far we had gotten.
69*47125Sbostic  */
70*47125Sbostic 
71*47125Sbostic main(argc, argv)  char **argv; {
72*47125Sbostic 	struct jmploc jmploc;
73*47125Sbostic 	struct stackmark smark;
74*47125Sbostic 	volatile int state;
75*47125Sbostic 	char *shinit;
76*47125Sbostic 
77*47125Sbostic #if PROFILE
78*47125Sbostic 	monitor(4, etext, profile_buf, sizeof profile_buf, 50);
79*47125Sbostic #endif
80*47125Sbostic 	state = 0;
81*47125Sbostic 	if (setjmp(jmploc.loc)) {
82*47125Sbostic 		/*
83*47125Sbostic 		 * When a shell procedure is executed, we raise the
84*47125Sbostic 		 * exception EXSHELLPROC to clean up before executing
85*47125Sbostic 		 * the shell procedure.
86*47125Sbostic 		 */
87*47125Sbostic 		if (exception == EXSHELLPROC) {
88*47125Sbostic 			rootpid = getpid();
89*47125Sbostic 			rootshell = 1;
90*47125Sbostic 			minusc = NULL;
91*47125Sbostic 			state = 3;
92*47125Sbostic 		} else if (state == 0 || iflag == 0 || ! rootshell)
93*47125Sbostic 			exitshell(2);
94*47125Sbostic 		reset();
95*47125Sbostic #if ATTY
96*47125Sbostic 		if (exception == EXINT
97*47125Sbostic 		 && (! attyset() || equal(termval(), "emacs"))) {
98*47125Sbostic #else
99*47125Sbostic 		if (exception == EXINT) {
100*47125Sbostic #endif
101*47125Sbostic 			out2c('\n');
102*47125Sbostic 			flushout(&errout);
103*47125Sbostic 		}
104*47125Sbostic 		popstackmark(&smark);
105*47125Sbostic 		FORCEINTON;				/* enable interrupts */
106*47125Sbostic 		if (state == 1)
107*47125Sbostic 			goto state1;
108*47125Sbostic 		else if (state == 2)
109*47125Sbostic 			goto state2;
110*47125Sbostic 		else
111*47125Sbostic 			goto state3;
112*47125Sbostic 	}
113*47125Sbostic 	handler = &jmploc;
114*47125Sbostic #ifdef DEBUG
115*47125Sbostic 	opentrace();
116*47125Sbostic 	trputs("Shell args:  ");  trargs(argv);
117*47125Sbostic #endif
118*47125Sbostic 	rootpid = getpid();
119*47125Sbostic 	rootshell = 1;
120*47125Sbostic 	init();
121*47125Sbostic 	setstackmark(&smark);
122*47125Sbostic 	procargs(argc, argv);
123*47125Sbostic 	if (argv[0] && argv[0][0] == '-') {
124*47125Sbostic 		state = 1;
125*47125Sbostic 		read_profile("/etc/profile");
126*47125Sbostic state1:
127*47125Sbostic 		state = 2;
128*47125Sbostic 		read_profile(".profile");
129*47125Sbostic 	} else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) {
130*47125Sbostic 		state = 2;
131*47125Sbostic 		evalstring(shinit);
132*47125Sbostic 	}
133*47125Sbostic state2:
134*47125Sbostic 	state = 3;
135*47125Sbostic 	if (minusc) {
136*47125Sbostic 		evalstring(minusc);
137*47125Sbostic 	}
138*47125Sbostic 	if (sflag || minusc == NULL) {
139*47125Sbostic state3:
140*47125Sbostic 		cmdloop(1);
141*47125Sbostic 	}
142*47125Sbostic #if PROFILE
143*47125Sbostic 	monitor(0);
144*47125Sbostic #endif
145*47125Sbostic 	exitshell(exitstatus);
146*47125Sbostic }
147*47125Sbostic 
148*47125Sbostic 
149*47125Sbostic /*
150*47125Sbostic  * Read and execute commands.  "Top" is nonzero for the top level command
151*47125Sbostic  * loop; it turns on prompting if the shell is interactive.
152*47125Sbostic  */
153*47125Sbostic 
154*47125Sbostic void
155*47125Sbostic cmdloop(top) {
156*47125Sbostic 	union node *n;
157*47125Sbostic 	struct stackmark smark;
158*47125Sbostic 	int inter;
159*47125Sbostic 	int numeof;
160*47125Sbostic 
161*47125Sbostic 	TRACE(("cmdloop(%d) called\n", top));
162*47125Sbostic 	setstackmark(&smark);
163*47125Sbostic 	numeof = 0;
164*47125Sbostic 	for (;;) {
165*47125Sbostic 		if (pendingsigs)
166*47125Sbostic 			dotrap();
167*47125Sbostic 		inter = 0;
168*47125Sbostic 		if (iflag && top) {
169*47125Sbostic 			inter++;
170*47125Sbostic 			showjobs(1);
171*47125Sbostic 			chkmail(0);
172*47125Sbostic 			flushout(&output);
173*47125Sbostic 		}
174*47125Sbostic 		n = parsecmd(inter);
175*47125Sbostic #ifdef DEBUG
176*47125Sbostic 		/* BROKEN - FIX showtree(n); */
177*47125Sbostic #endif
178*47125Sbostic 		if (n == NEOF) {
179*47125Sbostic 			if (Iflag == 0 || numeof >= 50)
180*47125Sbostic 				break;
181*47125Sbostic 			out2str("\nUse \"exit\" to leave shell.\n");
182*47125Sbostic 			numeof++;
183*47125Sbostic 		} else if (n != NULL && nflag == 0) {
184*47125Sbostic 			if (inter) {
185*47125Sbostic 				INTOFF;
186*47125Sbostic 				if (prevcmd)
187*47125Sbostic 					freefunc(prevcmd);
188*47125Sbostic 				prevcmd = curcmd;
189*47125Sbostic 				curcmd = copyfunc(n);
190*47125Sbostic 				INTON;
191*47125Sbostic 			}
192*47125Sbostic 			evaltree(n, 0);
193*47125Sbostic #ifdef notdef
194*47125Sbostic 			if (exitstatus)				      /*DEBUG*/
195*47125Sbostic 				outfmt(&errout, "Exit status 0x%X\n", exitstatus);
196*47125Sbostic #endif
197*47125Sbostic 		}
198*47125Sbostic 		popstackmark(&smark);
199*47125Sbostic 	}
200*47125Sbostic 	popstackmark(&smark);		/* unnecessary */
201*47125Sbostic }
202*47125Sbostic 
203*47125Sbostic 
204*47125Sbostic 
205*47125Sbostic /*
206*47125Sbostic  * Read /etc/profile or .profile.  Return on error.
207*47125Sbostic  */
208*47125Sbostic 
209*47125Sbostic STATIC void
210*47125Sbostic read_profile(name)
211*47125Sbostic 	char *name;
212*47125Sbostic 	{
213*47125Sbostic 	int fd;
214*47125Sbostic 
215*47125Sbostic 	INTOFF;
216*47125Sbostic 	if ((fd = open(name, O_RDONLY)) >= 0)
217*47125Sbostic 		setinputfd(fd, 1);
218*47125Sbostic 	INTON;
219*47125Sbostic 	if (fd < 0)
220*47125Sbostic 		return;
221*47125Sbostic 	cmdloop(0);
222*47125Sbostic 	popfile();
223*47125Sbostic }
224*47125Sbostic 
225*47125Sbostic 
226*47125Sbostic 
227*47125Sbostic /*
228*47125Sbostic  * Read a file containing shell functions.
229*47125Sbostic  */
230*47125Sbostic 
231*47125Sbostic void
232*47125Sbostic readcmdfile(name)
233*47125Sbostic 	char *name;
234*47125Sbostic 	{
235*47125Sbostic 	int fd;
236*47125Sbostic 
237*47125Sbostic 	INTOFF;
238*47125Sbostic 	if ((fd = open(name, O_RDONLY)) >= 0)
239*47125Sbostic 		setinputfd(fd, 1);
240*47125Sbostic 	else
241*47125Sbostic 		error("Can't open %s", name);
242*47125Sbostic 	INTON;
243*47125Sbostic 	cmdloop(0);
244*47125Sbostic 	popfile();
245*47125Sbostic }
246*47125Sbostic 
247*47125Sbostic 
248*47125Sbostic 
249*47125Sbostic /*
250*47125Sbostic  * Take commands from a file.  To be compatable we should do a path
251*47125Sbostic  * search for the file, but a path search doesn't make any sense.
252*47125Sbostic  */
253*47125Sbostic 
254*47125Sbostic dotcmd(argc, argv)  char **argv; {
255*47125Sbostic 	exitstatus = 0;
256*47125Sbostic 	if (argc >= 2) {		/* That's what SVR2 does */
257*47125Sbostic 		setinputfile(argv[1], 1);
258*47125Sbostic 		commandname = argv[1];
259*47125Sbostic 		cmdloop(0);
260*47125Sbostic 		popfile();
261*47125Sbostic 	}
262*47125Sbostic 	return exitstatus;
263*47125Sbostic }
264*47125Sbostic 
265*47125Sbostic 
266*47125Sbostic exitcmd(argc, argv)  char **argv; {
267*47125Sbostic 	if (argc > 1)
268*47125Sbostic 		exitstatus = number(argv[1]);
269*47125Sbostic 	exitshell(exitstatus);
270*47125Sbostic }
271*47125Sbostic 
272*47125Sbostic 
273*47125Sbostic lccmd(argc, argv)  char **argv; {
274*47125Sbostic 	if (argc > 1) {
275*47125Sbostic 		defun(argv[1], prevcmd);
276*47125Sbostic 		return 0;
277*47125Sbostic 	} else {
278*47125Sbostic 		INTOFF;
279*47125Sbostic 		freefunc(curcmd);
280*47125Sbostic 		curcmd = prevcmd;
281*47125Sbostic 		prevcmd = NULL;
282*47125Sbostic 		INTON;
283*47125Sbostic 		evaltree(curcmd, 0);
284*47125Sbostic 		return exitstatus;
285*47125Sbostic 	}
286*47125Sbostic }
287*47125Sbostic 
288*47125Sbostic 
289*47125Sbostic 
290*47125Sbostic #ifdef notdef
291*47125Sbostic /*
292*47125Sbostic  * Should never be called.
293*47125Sbostic  */
294*47125Sbostic 
295*47125Sbostic void
296*47125Sbostic exit(exitstatus) {
297*47125Sbostic 	_exit(exitstatus);
298*47125Sbostic }
299*47125Sbostic #endif
300