|
|
1.1 ! root 1: /* ! 2: * sh/main.c ! 3: * The Bourne shell. ! 4: * Main program, initialization and miscellaneous routines. ! 5: */ ! 6: ! 7: #include <assert.h> ! 8: #include <stdarg.h> ! 9: #include "sh.h" ! 10: #include <fcntl.h> ! 11: ! 12: void fakearg (); ! 13: void reset (); ! 14: void ecantopen (); ! 15: void panic (); ! 16: void printe (); ! 17: void syntax (); ! 18: ! 19: ! 20: int ! 21: main(argc, argv, envp) ! 22: char *argv[]; ! 23: char *envp[]; ! 24: { ! 25: ! 26: sarg0 = argc > 0 ? argv [0] : ""; ! 27: fakearg (0, argc, argv, envp); ! 28: ! 29: if (argc > 0 && argv [0][0] == '-') { ! 30: lgnflag = 1; ! 31: umask (ufmask = 022); ! 32: } else if (argc > 0 && argv [0][0] == '+') { ! 33: lgnflag = 2; ! 34: umask (ufmask = 022); ! 35: } else ! 36: umask (ufmask = umask (ufmask)); ! 37: ! 38: /* ! 39: * NIGEL: we must *force* stdin to be unbuffered to defeat some ! 40: * excessive cleverness in the stdio library. Note that line-buffering ! 41: * is a mode that only applies to output. ! 42: */ ! 43: ! 44: if (setvbuf (stdin, NULL, _IONBF, BUFSIZ) != 0) ! 45: printe ("Cannot set stdin buffering\n"); ! 46: ! 47: if (setjmp (restart) != 0) { ! 48: /* reentry for shell command file execution */ ! 49: fakearg (1, nargc, nargv, nenvp); ! 50: argc = nargc; ! 51: argv = nargv; ! 52: envp = nenvp; ! 53: cmdflag ++; ! 54: nllflag = 0; ! 55: } ! 56: ! 57: shpid = getpid (); ! 58: initvar (envp); ! 59: ! 60: if (set (argc, argv, 1)) ! 61: return 1; ! 62: ! 63: if (cflag) { ! 64: if (sargp [0] == NULL) { ! 65: printe ("No string for -c?"); ! 66: return 1; ! 67: } ! 68: -- sargc; ! 69: session (SARGS, * sargp ++); ! 70: } else if (! sflag && ! iflag && sargc != 0) { ! 71: sarg0 = * sargp ++; ! 72: --sargc; ! 73: if (scmdp == NULL) ! 74: scmdp = sarg0; ! 75: session (SFILE, scmdp); ! 76: } else ! 77: session (SSTR, stdin); ! 78: ! 79: cleanup_shell_fns (); ! 80: unlink_temp (capture_temp ()); ! 81: return slret; ! 82: } ! 83: ! 84: ! 85: /* ! 86: * Make the arg listing of ps come out right. ! 87: * f == 0, first entry, determine buffer limits. ! 88: * f != 0, later entry, fill buffer with lies. ! 89: */ ! 90: ! 91: void ! 92: fakearg(f, argc, argv, envp) ! 93: int f, argc; ! 94: char **argv, **envp; ! 95: { ! 96: static char *fbuf; ! 97: static int nbuf; ! 98: register int n; ! 99: ! 100: if (f == 0) { ! 101: fbuf = argv [0]; ! 102: nbuf = 0; ! 103: if (envp != NULL && envp [0] != NULL) { ! 104: while (envp [1] != NULL) ! 105: envp += 1; ! 106: nbuf = envp [0] - fbuf + strlen (envp [0]) - 1; ! 107: } else if (argc > 0) ! 108: nbuf = argv [argc - 1] - fbuf + ! 109: strlen (argv [argc - 1]) - 1; ! 110: } else { ! 111: if (fbuf == NULL || nbuf == 0) ! 112: return; ! 113: n = 0; ! 114: fbuf [0] = 0; ! 115: while (-- argc > 0) { ! 116: argv += 1; ! 117: n += strlen (argv [0]) + 1; ! 118: if (n >= nbuf) ! 119: break; ! 120: strcat (fbuf, argv [0]); ! 121: strcat (fbuf, " "); ! 122: } ! 123: strcat (fbuf, "\1"); /* non-ascii terminator */ ! 124: } ! 125: } ! 126: ! 127: ! 128: /* ! 129: * Push a session of the indicated type. A non-zero return value is the ! 130: * appropriate return value for the session, but offset by one. ! 131: */ ! 132: ! 133: int ! 134: push_session (type, info, session) ! 135: int type; ! 136: __VOID__ * info; ! 137: SES * session; ! 138: { ! 139: session->s_next = sesp; ! 140: sesp = session; ! 141: session->s_bpp = savebuf (); ! 142: ! 143: switch (session->s_type = type) { ! 144: case SARGS: ! 145: session->s_strp = (char *) info; ! 146: session->s_flag = 0; ! 147: break; ! 148: ! 149: case SARGV: ! 150: session->s_argv = (char **) info; ! 151: if ((session->s_strp = session->s_argv [0]) == NULL) ! 152: return 1; ! 153: session->s_flag = 0; ! 154: break; ! 155: ! 156: case SFILE: ! 157: session->s_strp = (char *) info; ! 158: ! 159: /* ! 160: * NIGEL: We should take steps to ensure that the file ! 161: * descriptors created for these input files lie above the ! 162: * range that can be redirected in scripts! ! 163: */ ! 164: ! 165: if ((type = open (session->s_strp, O_RDONLY)) < 0) { ! 166: ecantopen (session->s_strp); ! 167: return 2; ! 168: } ! 169: if (type > 9) { ! 170: int scan; ! 171: for (scan = 10 ; scan < FOPEN_MAX ; scan ++) { ! 172: if (fcntl (scan, F_GETFD) == -1) { ! 173: /* ! 174: * Move the new FD to the new place. ! 175: */ ! 176: ! 177: dup2 (type, scan); ! 178: close (type); ! 179: type = scan; ! 180: ! 181: break; ! 182: } ! 183: } ! 184: } ! 185: if ((session->s_ifp = fdopen (type, "r")) == NULL) { ! 186: ecantopen (session->s_strp); ! 187: return 2; ! 188: } ! 189: session->s_flag = isatty (fileno (session->s_ifp)) && ! 190: isatty (2); ! 191: break; ! 192: ! 193: case SSTR: ! 194: session->s_strp = NULL; ! 195: session->s_ifp = (FILE *) info; ! 196: session->s_flag = isatty (fileno (session->s_ifp)) && ! 197: isatty (2); ! 198: break; ! 199: } ! 200: ! 201: return 0; ! 202: } ! 203: ! 204: ! 205: /* ! 206: * Pop the passed-in session, which must be the current session. ! 207: */ ! 208: ! 209: void ! 210: pop_session (session) ! 211: SES * session; ! 212: { ! 213: assert (sesp == session); ! 214: ! 215: freebuf (session->s_bpp); ! 216: ! 217: if (session->s_type == SFILE) ! 218: fclose (session->s_ifp); ! 219: ! 220: if (session->s_next == NULL) { ! 221: sigintr (0); ! 222: recover (IRDY); ! 223: } ! 224: ! 225: sesp = session->s_next; ! 226: } ! 227: ! 228: ! 229: /* ! 230: * Loop on input. ! 231: */ ! 232: ! 233: int ! 234: session(t, p) ! 235: register char *p; ! 236: { ! 237: SES s; ! 238: register int rcode; ! 239: ! 240: if ((rcode = push_session (t, p, & s)) > 0) ! 241: return rcode - 1; ! 242: ! 243: if (s.s_next == NULL) { /* Initial entry */ ! 244: if (iflag) ! 245: s.s_flag = iflag; ! 246: else ! 247: iflag = s.s_flag; ! 248: dflttrp (IRDY); ! 249: } ! 250: ! 251: /* Loop on input */ ! 252: for (;;) { ! 253: unlink_temp (capture_temp ()); ! 254: ! 255: rcode = setjmp (s.s_envl); ! 256: switch (rcode) { ! 257: case RSET: /* initial setjmp call */ ! 258: switch (lgnflag) { ! 259: case 1: /* - sign invocation */ ! 260: lgnflag = 0; ! 261: if (ffind ("/etc", "profile", 4)) ! 262: session (SFILE, duplstr (strt, 0)); ! 263: recover (IPROF); ! 264: if (* vhome && ffind (vhome, ".profile", 4)) ! 265: session (SFILE, duplstr (strt, 0)); ! 266: break; ! 267: ! 268: case 2: /* + sign invocation */ ! 269: lgnflag = 0; ! 270: if (ffind ("/etc", "profile", 4)) ! 271: session (SFILE, duplstr (strt, 0)); ! 272: recover (IPROF); ! 273: return exshell (findvar ("SHELL")); ! 274: } ! 275: checkmail (); ! 276: comflag = 1; ! 277: errflag = 0; ! 278: recover (IRDY); ! 279: freebuf (s.s_bpp); ! 280: s.s_bpp = savebuf (); ! 281: if (yyparse () != 0) ! 282: syntax (); ! 283: ! 284: case REOF: ! 285: recover (IRDY); ! 286: break; ! 287: ! 288: case RCMD: ! 289: recover (IRDY); ! 290: s.s_con = NULL; ! 291: command (s.s_node); ! 292: if (tflag && tflag ++ >= 2) ! 293: break; ! 294: continue; ! 295: ! 296: case RERR: ! 297: recover (IRDY); ! 298: if (! errflag) ! 299: syntax (); ! 300: if (! iflag || (tflag && tflag ++ >= 2)) ! 301: break; ! 302: continue; ! 303: ! 304: case RINT: ! 305: if (s.s_next != NULL) { ! 306: sesp = s.s_next; ! 307: reset (RINT); ! 308: NOTREACHED; ! 309: } ! 310: prpflag = 2; ! 311: if (! iflag || (tflag && tflag ++ >= 2)) ! 312: break; ! 313: continue; ! 314: ! 315: case RUEXITS: ! 316: case RUABORT: ! 317: if (s.s_next != NULL) { ! 318: sesp = s.s_next; ! 319: reset (rcode); ! 320: NOTREACHED; ! 321: } ! 322: if (rcode == RUEXITS || ! iflag || ! 323: (tflag && tflag ++ >= 2)) ! 324: break; ! 325: continue; ! 326: ! 327: case RNOSBRK: ! 328: case RSYSER: ! 329: case RBRKCON: ! 330: case RNOWAY: ! 331: default: ! 332: if (s.s_next != NULL) ! 333: break; ! 334: if (! iflag || (tflag && tflag ++ >= 2)) ! 335: break; ! 336: continue; ! 337: } ! 338: break; ! 339: } ! 340: ! 341: pop_session (& s); ! 342: return (slret); ! 343: } ! 344: ! 345: ! 346: void ! 347: reset (f) ! 348: { ! 349: longjmp (sesp->s_envl, f); ! 350: NOTREACHED; ! 351: } ! 352: ! 353: ! 354: /* ! 355: * Global head of list of temporary files. ! 356: */ ! 357: ! 358: static TEMP_FILE * temp_list; ! 359: ! 360: ALLOC_COUNT (temp) ! 361: ! 362: /* ! 363: * Remember the name of a temporary file. ! 364: */ ! 365: ! 366: void ! 367: remember_temp (filename) ! 368: char * filename; ! 369: { ! 370: TEMP_FILE * temp = (TEMP_FILE *) salloc (sizeof (* temp)); ! 371: ! 372: temp->tf_name = duplstr (filename, 1); ! 373: temp->tf_next = temp_list; ! 374: temp_list = temp; ! 375: ! 376: ALLOC_ALLOC (temp) ! 377: } ! 378: ! 379: ! 380: /* ! 381: * Return a pointer to the current global list of temporary files and clear ! 382: * the global pointer to that list. ! 383: */ ! 384: ! 385: TEMP_FILE * ! 386: capture_temp () ! 387: { ! 388: TEMP_FILE * temp = temp_list; ! 389: ! 390: temp_list = NULL; ! 391: return temp; ! 392: } ! 393: ! 394: ! 395: /* ! 396: * Deallocate a list of temporary files. ! 397: */ ! 398: ! 399: void ! 400: forget_temp (templist) ! 401: TEMP_FILE * templist; ! 402: { ! 403: TEMP_FILE * temp; ! 404: ! 405: while ((temp = templist) != NULL) { ! 406: ! 407: templist = temp->tf_next; ! 408: ! 409: ALLOC_FREE (temp); ! 410: sfree (temp->tf_name); ! 411: sfree (temp); ! 412: } ! 413: } ! 414: ! 415: ! 416: /* ! 417: * Walk over a list of temporary files, unlinking the files and deallocating ! 418: * the list nodes. ! 419: */ ! 420: ! 421: void ! 422: unlink_temp (templist) ! 423: TEMP_FILE * templist; ! 424: { ! 425: TEMP_FILE * temp; ! 426: ! 427: while ((temp = templist) != NULL) { ! 428: ! 429: templist = temp->tf_next; ! 430: unlink (temp->tf_name); ! 431: ! 432: ALLOC_FREE (temp) ! 433: sfree (temp->tf_name); ! 434: sfree (temp); ! 435: } ! 436: } ! 437: ! 438: ! 439: /* ! 440: * Make a temp file name. ! 441: */ ! 442: ! 443: char * ! 444: shtmp () ! 445: { ! 446: static char tmpfile [] = "/tmp/shXXXXXXX"; ! 447: static int tmpflag = 0; ! 448: ! 449: tmpflag ++; ! 450: sprintf (tmpfile + 6, "%05d%c%c", shpid, tmpflag % 26 + 'a', ! 451: (tmpflag / 26) % 26 + 'a'); ! 452: return tmpfile; ! 453: } ! 454: ! 455: ! 456: /* ! 457: * Print formatted. ! 458: */ ! 459: ! 460: void ! 461: prints (format /* , ... */) ! 462: char * format; ! 463: { ! 464: va_list args; ! 465: ! 466: va_start (args, format); ! 467: vfprintf (stderr, format, args); ! 468: va_end (args); ! 469: } ! 470: ! 471: ! 472: /* ! 473: * Make a core dump in /tmp and longjmp back to session - ! 474: * there's a possibility we'll die horribly. ! 475: */ ! 476: ! 477: void ! 478: panic (i) ! 479: int i; ! 480: { ! 481: #ifdef PARANOID ! 482: register int f; ! 483: ! 484: if ((f = fork ()) == 0) { ! 485: abort (); ! 486: NOTREACHED; ! 487: } ! 488: waitc (f); ! 489: #endif ! 490: printe ("Internal shell assertion %d failed", i); ! 491: reset (RNOWAY); ! 492: NOTREACHED; ! 493: } ! 494: ! 495: ! 496: /* ! 497: * Print out an error message. ! 498: */ ! 499: ! 500: void ! 501: printe (format /* , ... */) ! 502: char * format; ! 503: { ! 504: errflag += 1; ! 505: if (! noeflag) { ! 506: va_list args; ! 507: ! 508: va_start (args, format); ! 509: vfprintf (stderr, format, args); ! 510: va_end (args); ! 511: fprintf (stderr, "\n"); ! 512: } ! 513: } ! 514: ! 515: /* ! 516: * Some familiar errors. ! 517: */ ! 518: ! 519: void ecantopen(s) char *s; { printe ("Cannot open %s", s); } ! 520: void ecantfind(s) char *s; { printe ("Cannot find %s", s); } ! 521: void e2big(s) char *s; { printe ("File to big to execute: %s", s); } ! 522: void ecantmake(s) char *s; { printe ("Cannot create %s", s); } ! 523: void emisschar(c) { printe ("Missing `%c'", c); } ! 524: void ecantfdop() { printe ("Fdopen failed"); } ! 525: void enotdef(s) char *s; { printe ("Cannot find variable %s", s); } ! 526: void eillvar(s) char *s; { printe ("Illegal variable name: %s", s); } ! 527: void eredir() { printe ("Illegal redirection"); } ! 528: void etoolong(s) char *s; { ! 529: printe ("Argument too long %s: %.*s", s, STRSIZE, strt); ! 530: } ! 531: void eredirundo() { ! 532: printe ("Unable to preserve redirection state when redirecting builtin"); ! 533: } ! 534: ! 535: ! 536: /* ! 537: * Don't print out an error message. ! 538: */ ! 539: ! 540: void ! 541: yyerror() ! 542: { ! 543: } ! 544: ! 545: ! 546: /* ! 547: * print out the prompt given the prompt to write ! 548: */ ! 549: ! 550: void ! 551: prompt(vps) ! 552: char *vps; ! 553: { ! 554: prints ("%s", vps); ! 555: #if RSX ! 556: fflush (stdout); ! 557: #endif ! 558: } ! 559: ! 560: ! 561: /* ! 562: * Syntax error message - print line number and file if ! 563: * not interactive. ! 564: */ ! 565: ! 566: void ! 567: syntax() ! 568: { ! 569: if (sesp->s_type == SFILE) { ! 570: if (feof (sesp->s_ifp)) ! 571: printe ("%s: Syntax error at EOF", sesp->s_strp); ! 572: else ! 573: printe ("%s: Syntax error in line %d", sesp->s_strp, ! 574: yyline); ! 575: } else ! 576: printe ("Syntax error"); ! 577: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.