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