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