|
|
1.1 root 1: /*
2: * startup, main loop, enviroments and error handling
3: */
4:
5: static char *RCSid = "$Header: main.c,v 3.1 88/11/03 09:17:04 egisin Exp $";
6:
7: #define Extern
8:
9: #include <stddef.h>
10: #include <stdlib.h>
11: #include <stdio.h>
12: #include <string.h>
13: #include <unistd.h>
14: #include <fcntl.h>
15: #include <signal.h>
16: #include <errno.h>
17: #include <setjmp.h>
18: #include "sh.h"
19: #include "lex.h"
20: #include "tree.h"
21: #include "table.h"
22:
23: /*
24: * global data
25: */
26:
27: Area aperm;
28:
29: static void reclaim ARGS((void));
30:
31: /*
32: * shell initialization
33: */
34:
35: static char initifs [] = "IFS= \t\n"; /* must be R/W */
36:
37: static Const char initsubs [] =
38: "${SHELL:=/bin/sh} ${PATH:=/bin:/usr/bin:.} ${HOME:=/} ${PS1:=$ } ${PS2:=> }";
39:
40: static Const char *initcoms [] = {
41: "cd", ".", NULL, /* set up $PWD */
42: "typeset", "-x", "SHELL", "PATH", "HOME", NULL,
43: "typeset", "-r", "PWD", "OLDPWD", NULL,
44: "typeset", "-i", "SECONDS=0", "OPTIND", NULL,
45: "alias",
46: "integer=typeset -i", "pwd=print -r \"$PWD\"",
47: "history=fc -l", "r=fc -s",
48: #if !COHERENT
49: "nohup=nohup ",
50: #endif
51: "login=exec login", "newgrp=exec newgrp",
52: "type=whence -v", "functions=typeset -f",
53: "echo=print", "true=:", "false=let", "[=\\[", NULL,
54: NULL
55: };
56:
57: main(argc, argv, envp)
58: int argc;
59: register char **argv;
60: char **envp;
61: {
62: register int i;
63: register char *arg;
64: int cflag = 0, qflag = 0;
65: char *name;
66: register Source *s;
67: register struct block *l = &globals;
68: register char **wp0, **wp;
69: extern char ksh_version [];
70:
71: ainit(&aperm); /* initialize permanent Area */
72:
73: /* set up base enviroment */
74: e.type = E_NONE;
75: ainit(&e.area);
76: e.loc = l;
77: e.savefd = NULL;
78: e.oenv = NULL;
79:
80: initctypes();
81:
82: /* open file streams for fd's 0,1,2 */
83: fopenshf(0); fopenshf(1); fopenshf(2);
84:
85: /* set up variable and command dictionaries */
86: newblock(); /* set up global l->vars and l->funs */
87: tinit(&commands, APERM);
88: tinit(&builtins, APERM);
89: tinit(&lexicals, APERM);
90: tinit(&homedirs, APERM);
91:
92: /* import enviroment */
93: if (envp != NULL)
94: for (wp = envp; *wp != NULL; wp++)
95: import(*wp);
96:
97: typeset(initifs, 0, 0); /* for security */
98: typeset(ksh_version, 0, 0); /* RDONLY */
99:
100: /* define shell keywords */
101: keywords();
102:
103: /* define built-in commands */
104: for (i = 0; shbuiltins[i].name != NULL; i++)
105: builtin(shbuiltins[i].name, shbuiltins[i].func);
106: for (i = 0; kshbuiltins[i].name != NULL; i++)
107: builtin(kshbuiltins[i].name, kshbuiltins[i].func);
108:
109: /* assign default shell variable values */
110: substitute(initsubs, 0);
111: /* execute initialization statements */
112: for (wp0 = (char**) initcoms; *wp0 != NULL; wp0 = wp+1) {
113: /* copy because the alias initializers are readonly */
114: for (wp = wp0; *wp != NULL; wp++)
115: *wp = strsave(*wp, ATEMP);
116: shcomexec(wp0);
117: }
118: afreeall(ATEMP);
119:
120: if (geteuid() == 0)
121: setstr(global("PS1"), "# ");
122:
123: s = pushs(SFILE);
124: s->u.file = stdin;
125: cflag = 0;
126: name = *argv++;
127:
128: /* what a bloody mess */
129: if (--argc >= 1) {
130: if (argv[0][0] == '-' && argv[0][1] != '\0') {
131: for (arg = argv[0]+1; *arg; arg++)
132: switch (*arg) {
133: case 'c':
134: cflag = 1;
135: if (--argc > 0) {
136: s->type = SSTRING;
137: s->str = *++argv;
138: }
139: break;
140:
141: case 'q':
142: qflag = 1;
143: break;
144:
145: default:
146: if (*arg>='a' && *arg<='z')
147: flag[FLAG(*arg)]++;
148: }
149: } else {
150: argv--;
151: argc++;
152: }
153: if (s->type == SFILE && --argc > 0) {
154: if ((s->u.file = fopen(*++argv, "r")) == NULL)
155: errorf("%s: cannot open\n", *argv);
156: s->file = *argv;
157: fileno(s->u.file) = savefd(fileno(s->u.file));
158: setvbuf(s->u.file, (char *)NULL, _IOFBF, BUFSIZ);
159: }
160: }
161:
162: if (s->type == SFILE) {
163: if (fileno(s->u.file) == 0)
164: flag[FSTDIN] = 1;
165: if (isatty(0) && isatty(1) && !cflag)
166: flag[FTALKING] = 1;
167: if (flag[FTALKING] && flag[FSTDIN])
168: s->type = STTY;
169: }
170: if (s->type == STTY) {
171: ttyfd = fcntl(0, F_DUPFD, FDBASE);
172: #if !COHERENT
173: (void) fcntl(ttyfd, F_SETFD, FD_CLEXEC);
174: #endif
175: #if EDIT
176: x_init();
177: #endif
178: }
179:
180: /* initialize job control */
181: j_init();
182:
183: if (!qflag)
184: ignoresig(SIGQUIT);
185:
186: if (name[0] == '-') {
187: flag[FTALKING] = 1;
188: #if !COHERENT
189: (void) include("/etc/profile");
190: #endif
191: (void) include(".profile");
192: }
193:
194: /* include $ENV */
195: arg = substitute(strval(global("ENV")), DOTILDE);
196: if (*arg != '\0')
197: (void) include(arg);
198:
199: if (flag[FTALKING]) {
200: signal(SIGTERM, trapsig);
201: ignoresig(SIGINT);
202: } else
203: flag[FHASHALL] = 1;
204:
205: #if JOBS /* todo: could go before includes? */
206: if (s->type == STTY) {
207: flag[FMONITOR] = 1;
208: j_change();
209: }
210: #endif
211:
212: l->argv = argv;
213: l->argc = argc;
214: l->argv[0] = name;
215: resetopts();
216:
217: argc = shell(s);
218: leave(argc);
219: }
220:
221: int
222: include(name)
223: register char *name;
224: {
225: register FILE *f;
226: register Source *s;
227:
228: if (strcmp(name, "-") != 0) {
229: f = fopen(name, "r");
230: if (f == NULL)
231: return 0;
232: /* todo: the savefd doesn't get popped */
233: fileno(f) = savefd(fileno(f)); /* questionable */
234: setvbuf(f, (char *)NULL, _IOFBF, BUFSIZ);
235: } else
236: f = stdin;
237: s = pushs(SFILE);
238: s->u.file = f;
239: s->file = name;
240: /*return*/ shell(s);
241: if (f != stdin)
242: fclose(f);
243: return 1;
244: }
245:
246: int
247: command(comm)
248: register char *comm;
249: {
250: register Source *s;
251:
252: s = pushs(SSTRING);
253: s->str = comm;
254: return shell(s);
255: }
256:
257: /*
258: * run the commands from the input source, returning status.
259: */
260: int
261: shell(s)
262: Source *s; /* input source */
263: {
264: struct op *t;
265: Volatile int attempts = 13;
266:
267: newenv(E_PARSE);
268: e.interactive = 1;
269: exstat = 0;
270: if (setjmp(e.jbuf)) {
271: /*shellf("<unwind>");*/
272: if (trap) /* pending SIGINT */
273: shellf("\n");
274: sigtraps[SIGINT].set = 0;
275: }
276:
277: while (1) {
278: if (trap)
279: runtraps();
280: if (flag[FTALKING])
281: signal(SIGINT, trapsig);
282:
283: if (s->next == NULL)
284: s->echo = flag[FVERBOSE];
285:
286: j_notify();
287:
288: if (s->type == STTY)
289: prompt = substitute(strval(global("PS1")), 0);
290:
291: t = compile(s);
292: if (t != NULL && t->type == TEOF)
293: if (s->type == SEOF && flag[FIGNEOF] && --attempts > 0) {
294: s->type = STTY;
295: shellf("Use `exit'\n");
296: } else
297: break;
298: flushshf(2); /* flush -v output */
299:
300: if (!flag[FNOEXEC] || s->type == STTY)
301: execute(t, 0);
302:
303: reclaim();
304: }
305: Error:
306: quitenv();
307: return exstat;
308: }
309:
310: void
311: leave(rv)
312: int rv;
313: {
314: if (e.type == E_TCOM && e.oenv != NULL) /* exec'd command */
315: unwind();
316: runtrap(&sigtraps[0]);
317: j_exit();
318: exit(rv);
319: /* NOTREACHED */
320: }
321:
322: error()
323: {
324: if (flag[FERREXIT] || !flag[FTALKING])
325: leave(1);
326: unwind();
327: }
328:
329: /* return to closest error handler or shell(), exit if none found */
330: unwind()
331: {
332: while (1)
333: switch (e.type) {
334: case E_NONE:
335: leave(1);
336: /* NOTREACHED */
337: case E_PARSE:
338: longjmp(e.jbuf, 1);
339: /* NOTREACHED */
340: case E_ERRH:
341: longjmp(e.jbuf, 1);
342: /* NOTREACHED */
343: default:
344: quitenv();
345: break;
346: }
347: }
348:
349: newenv(type)
350: {
351: register struct env *ep;
352:
353: ep = (struct env *) alloc(sizeof(*ep), ATEMP);
354: *ep = e;
355: ainit(&e.area);
356: e.type = type;
357: e.oenv = ep;
358: e.savefd = NULL;
359: e.temps = NULL;
360: }
361:
362: quitenv()
363: {
364: register struct env *ep;
365: register int fd;
366:
367: if ((ep = e.oenv) == NULL)
368: exit(exstat); /* exit child */
369: if (e.loc != ep->loc)
370: popblock();
371: if (e.savefd != NULL)
372: for (fd = 0; fd < NUFILE; fd++)
373: restfd(fd, e.savefd[fd]);
374: reclaim();
375: e = *ep;
376: }
377:
378: /* remove temp files and free ATEMP Area */
379: static void
380: reclaim()
381: {
382: register struct temp *tp;
383:
384: for (tp = e.temps; tp != NULL; tp = tp->next)
385: remove(tp->name);
386: e.temps = NULL;
387: afreeall(&e.area);
388: }
389:
390: void
391: aerror(ap, msg)
392: Area *ap;
393: Const char *msg;
394: {
395: errorf("alloc internal error: %s\n", msg);
396: }
397:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.