main.c revision 1.7 1 /*-
2 * Copyright (c) 1991 The Regents of the University of California.
3 * All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Kenneth Almquist.
7 *
8 * Redistribution and use in source and binary forms, with or without
9 * modification, are permitted provided that the following conditions
10 * are met:
11 * 1. Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * 2. Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * 3. All advertising materials mentioning features or use of this software
17 * must display the following acknowledgement:
18 * This product includes software developed by the University of
19 * California, Berkeley and its contributors.
20 * 4. Neither the name of the University nor the names of its contributors
21 * may be used to endorse or promote products derived from this software
22 * without specific prior written permission.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37 #ifndef lint
38 char copyright[] =
39 "@(#) Copyright (c) 1991 The Regents of the University of California.\n\
40 All rights reserved.\n";
41 #endif /* not lint */
42
43 #ifndef lint
44 /*static char sccsid[] = "from: @(#)main.c 5.2 (Berkeley) 3/13/91";*/
45 static char rcsid[] = "$Id: main.c,v 1.7 1994/01/25 21:05:34 deraadt Exp $";
46 #endif /* not lint */
47
48 #include <stdio.h>
49 #include <signal.h>
50 #include <fcntl.h>
51 #include <sys/stat.h>
52 #include "shell.h"
53 #include "main.h"
54 #include "mail.h"
55 #include "options.h"
56 #include "output.h"
57 #include "parser.h"
58 #include "nodes.h"
59 #include "eval.h"
60 #include "jobs.h"
61 #include "input.h"
62 #include "trap.h"
63 #include "exec.h"
64 #include "var.h"
65 #include "memalloc.h"
66 #include "error.h"
67 #include "init.h"
68 #include "mystring.h"
69
70 #define PROFILE 0
71
72 int rootpid;
73 int rootshell;
74 STATIC union node *curcmd;
75 STATIC union node *prevcmd;
76 extern int errno;
77 #if PROFILE
78 short profile_buf[16384];
79 extern int etext();
80 #endif
81
82 #ifdef __STDC__
83 STATIC void read_profile(char *);
84 char *getenv(char *);
85 #else
86 STATIC void read_profile();
87 char *getenv();
88 #endif
89
90
91 /*
92 * Main routine. We initialize things, parse the arguments, execute
93 * profiles if we're a login shell, and then call cmdloop to execute
94 * commands. The setjmp call sets up the location to jump to when an
95 * exception occurs. When an exception occurs the variable "state"
96 * is used to figure out how far we had gotten.
97 */
98
99 main(argc, argv) char **argv; {
100 struct jmploc jmploc;
101 struct stackmark smark;
102 volatile int state;
103 char *shinit;
104
105 #if PROFILE
106 monitor(4, etext, profile_buf, sizeof profile_buf, 50);
107 #endif
108 state = 0;
109 if (setjmp(jmploc.loc)) {
110 /*
111 * When a shell procedure is executed, we raise the
112 * exception EXSHELLPROC to clean up before executing
113 * the shell procedure.
114 */
115 if (exception == EXSHELLPROC) {
116 rootpid = getpid();
117 rootshell = 1;
118 minusc = NULL;
119 state = 3;
120 } else if (state == 0 || iflag == 0 || ! rootshell)
121 exitshell(2);
122 reset();
123 #if ATTY
124 if (exception == EXINT
125 && (! attyset() || equal(termval(), "emacs"))) {
126 #else
127 if (exception == EXINT) {
128 #endif
129 out2c('\n');
130 flushout(&errout);
131 }
132 popstackmark(&smark);
133 FORCEINTON; /* enable interrupts */
134 if (state == 1)
135 goto state1;
136 else if (state == 2)
137 goto state2;
138 else
139 goto state3;
140 }
141 handler = &jmploc;
142 #ifdef DEBUG
143 opentrace();
144 trputs("Shell args: "); trargs(argv);
145 #endif
146 rootpid = getpid();
147 rootshell = 1;
148 init();
149 setstackmark(&smark);
150 procargs(argc, argv);
151 if (argv[0] && argv[0][0] == '-') {
152 state = 1;
153 read_profile("/etc/profile");
154 state1:
155 state = 2;
156 read_profile(".profile");
157 } else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) {
158 state = 2;
159 evalstring(shinit);
160 }
161 state2:
162 state = 3;
163 if (minusc) {
164 evalstring(minusc);
165 }
166 if (sflag || minusc == NULL) {
167 state3:
168 cmdloop(1);
169 }
170 #if PROFILE
171 monitor(0);
172 #endif
173 exitshell(exitstatus);
174 }
175
176
177 /*
178 * Read and execute commands. "Top" is nonzero for the top level command
179 * loop; it turns on prompting if the shell is interactive.
180 */
181
182 void
183 cmdloop(top) {
184 union node *n;
185 struct stackmark smark;
186 int inter;
187 int numeof;
188
189 TRACE(("cmdloop(%d) called\n", top));
190 setstackmark(&smark);
191 numeof = 0;
192 for (;;) {
193 if (pendingsigs)
194 dotrap();
195 inter = 0;
196 if (iflag && top) {
197 inter++;
198 showjobs(1);
199 chkmail(0);
200 flushout(&output);
201 }
202 n = parsecmd(inter);
203 #ifdef DEBUG
204 /* showtree(n); */
205 #endif
206 if (n == NEOF) {
207 if (Iflag == 0 || numeof >= 50)
208 break;
209 out2str("\nUse \"exit\" to leave shell.\n");
210 numeof++;
211 } else if (n != NULL && nflag == 0) {
212 if (inter) {
213 INTOFF;
214 if (prevcmd)
215 freefunc(prevcmd);
216 prevcmd = curcmd;
217 curcmd = copyfunc(n);
218 INTON;
219 }
220 evaltree(n, 0);
221 #ifdef notdef
222 if (exitstatus) /*DEBUG*/
223 outfmt(&errout, "Exit status 0x%X\n", exitstatus);
224 #endif
225 }
226 popstackmark(&smark);
227 }
228 popstackmark(&smark); /* unnecessary */
229 }
230
231
232
233 /*
234 * Read /etc/profile or .profile. Return on error.
235 */
236
237 STATIC void
238 read_profile(name)
239 char *name;
240 {
241 int fd;
242
243 INTOFF;
244 if ((fd = open(name, O_RDONLY)) >= 0)
245 setinputfd(fd, 1);
246 INTON;
247 if (fd < 0)
248 return;
249 cmdloop(0);
250 popfile();
251 }
252
253
254
255 /*
256 * Read a file containing shell functions.
257 */
258
259 void
260 readcmdfile(name)
261 char *name;
262 {
263 int fd;
264
265 INTOFF;
266 if ((fd = open(name, O_RDONLY)) >= 0)
267 setinputfd(fd, 1);
268 else
269 error("Can't open %s", name);
270 INTON;
271 cmdloop(0);
272 popfile();
273 }
274
275
276
277 /*
278 * Take commands from a file. To be compatable we should do a path
279 * search for the file, which is necessary to find sub-commands.
280 */
281
282
283 static char *
284 find_dot_file(basename) char *basename; {
285 static char localname[FILENAME_MAX+1];
286 char *fullname;
287 char *path = pathval();
288 struct stat statb;
289
290 /* don't try this for absolute or relative paths */
291 if( strchr(basename, '/'))
292 return basename;
293
294 while ((fullname = padvance(&path, basename)) != NULL) {
295 strcpy(localname, fullname);
296 stunalloc(fullname);
297 if ((stat(fullname, &statb) == 0) &&
298 (S_ISREG(statb.st_mode) || S_ISLNK(statb.st_mode)))
299 return localname;
300 }
301 return basename;
302 }
303
304 dotcmd(argc, argv) char **argv; {
305 exitstatus = 0;
306 if (argc >= 2) { /* That's what SVR2 does */
307 char *fullname = find_dot_file(argv[1]);
308 setinputfile(fullname, 1);
309 commandname = fullname;
310 cmdloop(0);
311 popfile();
312 }
313 return exitstatus;
314 }
315
316
317 exitcmd(argc, argv) char **argv; {
318 if (argc > 1)
319 exitstatus = number(argv[1]);
320 exitshell(exitstatus);
321 }
322
323
324 lccmd(argc, argv) char **argv; {
325 if (argc > 1) {
326 defun(argv[1], prevcmd);
327 return 0;
328 } else {
329 INTOFF;
330 freefunc(curcmd);
331 curcmd = prevcmd;
332 prevcmd = NULL;
333 INTON;
334 evaltree(curcmd, 0);
335 return exitstatus;
336 }
337 }
338
339
340
341 #ifdef notdef
342 /*
343 * Should never be called.
344 */
345
346 void
347 exit(exitstatus) {
348 _exit(exitstatus);
349 }
350 #endif
351