|
|
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.