147125Sbostic /*- 247125Sbostic * Copyright (c) 1991 The Regents of the University of California. 347125Sbostic * All rights reserved. 447125Sbostic * 547125Sbostic * This code is derived from software contributed to Berkeley by 647125Sbostic * Kenneth Almquist. 747125Sbostic * 847125Sbostic * %sccs.include.redist.c% 947125Sbostic */ 1047125Sbostic 1147125Sbostic #ifndef lint 1247125Sbostic char copyright[] = 1347125Sbostic "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 1447125Sbostic All rights reserved.\n"; 1547125Sbostic #endif /* not lint */ 1647125Sbostic 1747125Sbostic #ifndef lint 18*54316Smarc static char sccsid[] = "@(#)main.c 5.3 (Berkeley) 06/23/92"; 1947125Sbostic #endif /* not lint */ 2047125Sbostic 2147125Sbostic #include <signal.h> 2247125Sbostic #include <fcntl.h> 2347125Sbostic #include "shell.h" 2447125Sbostic #include "main.h" 2547125Sbostic #include "mail.h" 2647125Sbostic #include "options.h" 2747125Sbostic #include "output.h" 2847125Sbostic #include "parser.h" 2947125Sbostic #include "nodes.h" 3047125Sbostic #include "eval.h" 3147125Sbostic #include "jobs.h" 3247125Sbostic #include "input.h" 3347125Sbostic #include "trap.h" 3447125Sbostic #if ATTY 3547125Sbostic #include "var.h" 3647125Sbostic #endif 3747125Sbostic #include "memalloc.h" 3847125Sbostic #include "error.h" 3947125Sbostic #include "init.h" 4047125Sbostic #include "mystring.h" 4147125Sbostic 4247125Sbostic #define PROFILE 0 4347125Sbostic 4447125Sbostic int rootpid; 4547125Sbostic int rootshell; 4647125Sbostic STATIC union node *curcmd; 4747125Sbostic STATIC union node *prevcmd; 4847125Sbostic extern int errno; 4947125Sbostic #if PROFILE 5047125Sbostic short profile_buf[16384]; 5147125Sbostic extern int etext(); 5247125Sbostic #endif 5347125Sbostic 5447125Sbostic #ifdef __STDC__ 5547125Sbostic STATIC void read_profile(char *); 5647125Sbostic char *getenv(char *); 5747125Sbostic #else 5847125Sbostic STATIC void read_profile(); 5947125Sbostic char *getenv(); 6047125Sbostic #endif 6147125Sbostic 6247125Sbostic 6347125Sbostic /* 6447125Sbostic * Main routine. We initialize things, parse the arguments, execute 6547125Sbostic * profiles if we're a login shell, and then call cmdloop to execute 6647125Sbostic * commands. The setjmp call sets up the location to jump to when an 6747125Sbostic * exception occurs. When an exception occurs the variable "state" 6847125Sbostic * is used to figure out how far we had gotten. 6947125Sbostic */ 7047125Sbostic 7147125Sbostic main(argc, argv) char **argv; { 7247125Sbostic struct jmploc jmploc; 7347125Sbostic struct stackmark smark; 7447125Sbostic volatile int state; 7547125Sbostic char *shinit; 7647125Sbostic 7747125Sbostic #if PROFILE 7847125Sbostic monitor(4, etext, profile_buf, sizeof profile_buf, 50); 7947125Sbostic #endif 8047125Sbostic state = 0; 8147125Sbostic if (setjmp(jmploc.loc)) { 8247125Sbostic /* 8347125Sbostic * When a shell procedure is executed, we raise the 8447125Sbostic * exception EXSHELLPROC to clean up before executing 8547125Sbostic * the shell procedure. 8647125Sbostic */ 8747125Sbostic if (exception == EXSHELLPROC) { 8847125Sbostic rootpid = getpid(); 8947125Sbostic rootshell = 1; 9047125Sbostic minusc = NULL; 9147125Sbostic state = 3; 9247125Sbostic } else if (state == 0 || iflag == 0 || ! rootshell) 9347125Sbostic exitshell(2); 9447125Sbostic reset(); 9547125Sbostic #if ATTY 9647125Sbostic if (exception == EXINT 9747125Sbostic && (! attyset() || equal(termval(), "emacs"))) { 9847125Sbostic #else 9947125Sbostic if (exception == EXINT) { 10047125Sbostic #endif 10147125Sbostic out2c('\n'); 10247125Sbostic flushout(&errout); 10347125Sbostic } 10447125Sbostic popstackmark(&smark); 10547125Sbostic FORCEINTON; /* enable interrupts */ 10647125Sbostic if (state == 1) 10747125Sbostic goto state1; 10847125Sbostic else if (state == 2) 10947125Sbostic goto state2; 110*54316Smarc else if (state == 3) 111*54316Smarc goto state3; 11247125Sbostic else 113*54316Smarc goto state4; 11447125Sbostic } 11547125Sbostic handler = &jmploc; 11647125Sbostic #ifdef DEBUG 11747125Sbostic opentrace(); 11847125Sbostic trputs("Shell args: "); trargs(argv); 11947125Sbostic #endif 12047125Sbostic rootpid = getpid(); 12147125Sbostic rootshell = 1; 12247125Sbostic init(); 12347125Sbostic setstackmark(&smark); 12447125Sbostic procargs(argc, argv); 12547125Sbostic if (argv[0] && argv[0][0] == '-') { 12647125Sbostic state = 1; 12747125Sbostic read_profile("/etc/profile"); 12847125Sbostic state1: 12947125Sbostic state = 2; 13047125Sbostic read_profile(".profile"); 131*54316Smarc } 13247125Sbostic state2: 13347125Sbostic state = 3; 134*54316Smarc if ((sflag || minusc) && (shinit = lookupvar("ENV")) != NULL && 135*54316Smarc *shinit != '\0') { 136*54316Smarc state = 3; 137*54316Smarc read_profile(shinit); 138*54316Smarc } 139*54316Smarc state3: 140*54316Smarc state = 4; 14147125Sbostic if (minusc) { 14247125Sbostic evalstring(minusc); 14347125Sbostic } 14447125Sbostic if (sflag || minusc == NULL) { 145*54316Smarc state4: /* XXX ??? - why isn't this before the "if" statement */ 14647125Sbostic cmdloop(1); 14747125Sbostic } 14847125Sbostic #if PROFILE 14947125Sbostic monitor(0); 15047125Sbostic #endif 15147125Sbostic exitshell(exitstatus); 15247125Sbostic } 15347125Sbostic 15447125Sbostic 15547125Sbostic /* 15647125Sbostic * Read and execute commands. "Top" is nonzero for the top level command 15747125Sbostic * loop; it turns on prompting if the shell is interactive. 15847125Sbostic */ 15947125Sbostic 16047125Sbostic void 16147125Sbostic cmdloop(top) { 16247125Sbostic union node *n; 16347125Sbostic struct stackmark smark; 16447125Sbostic int inter; 16547125Sbostic int numeof; 16647125Sbostic 16747125Sbostic TRACE(("cmdloop(%d) called\n", top)); 16847125Sbostic setstackmark(&smark); 16947125Sbostic numeof = 0; 17047125Sbostic for (;;) { 17147125Sbostic if (pendingsigs) 17247125Sbostic dotrap(); 17347125Sbostic inter = 0; 17447125Sbostic if (iflag && top) { 17547125Sbostic inter++; 17647125Sbostic showjobs(1); 17747125Sbostic chkmail(0); 17847125Sbostic flushout(&output); 17947125Sbostic } 18047125Sbostic n = parsecmd(inter); 18147125Sbostic #ifdef DEBUG 18247295Smarc /* showtree(n); */ 18347125Sbostic #endif 18447125Sbostic if (n == NEOF) { 185*54316Smarc if (Iflag == 0 || !top || numeof >= 50) 18647125Sbostic break; 18747125Sbostic out2str("\nUse \"exit\" to leave shell.\n"); 18847125Sbostic numeof++; 18947125Sbostic } else if (n != NULL && nflag == 0) { 19047125Sbostic if (inter) { 19147125Sbostic INTOFF; 19247125Sbostic if (prevcmd) 19347125Sbostic freefunc(prevcmd); 19447125Sbostic prevcmd = curcmd; 19547125Sbostic curcmd = copyfunc(n); 19647125Sbostic INTON; 19747125Sbostic } 19847125Sbostic evaltree(n, 0); 19947125Sbostic #ifdef notdef 20047125Sbostic if (exitstatus) /*DEBUG*/ 20147125Sbostic outfmt(&errout, "Exit status 0x%X\n", exitstatus); 20247125Sbostic #endif 20347125Sbostic } 20447125Sbostic popstackmark(&smark); 20547125Sbostic } 20647125Sbostic popstackmark(&smark); /* unnecessary */ 20747125Sbostic } 20847125Sbostic 20947125Sbostic 21047125Sbostic 21147125Sbostic /* 21247125Sbostic * Read /etc/profile or .profile. Return on error. 21347125Sbostic */ 21447125Sbostic 21547125Sbostic STATIC void 21647125Sbostic read_profile(name) 21747125Sbostic char *name; 21847125Sbostic { 21947125Sbostic int fd; 22047125Sbostic 22147125Sbostic INTOFF; 22247125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 22347125Sbostic setinputfd(fd, 1); 22447125Sbostic INTON; 22547125Sbostic if (fd < 0) 22647125Sbostic return; 22747125Sbostic cmdloop(0); 22847125Sbostic popfile(); 22947125Sbostic } 23047125Sbostic 23147125Sbostic 23247125Sbostic 23347125Sbostic /* 23447125Sbostic * Read a file containing shell functions. 23547125Sbostic */ 23647125Sbostic 23747125Sbostic void 23847125Sbostic readcmdfile(name) 23947125Sbostic char *name; 24047125Sbostic { 24147125Sbostic int fd; 24247125Sbostic 24347125Sbostic INTOFF; 24447125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 24547125Sbostic setinputfd(fd, 1); 24647125Sbostic else 24747125Sbostic error("Can't open %s", name); 24847125Sbostic INTON; 24947125Sbostic cmdloop(0); 25047125Sbostic popfile(); 25147125Sbostic } 25247125Sbostic 25347125Sbostic 25447125Sbostic 25547125Sbostic /* 25647125Sbostic * Take commands from a file. To be compatable we should do a path 25747125Sbostic * search for the file, but a path search doesn't make any sense. 25847125Sbostic */ 25947125Sbostic 26047125Sbostic dotcmd(argc, argv) char **argv; { 26147125Sbostic exitstatus = 0; 26247125Sbostic if (argc >= 2) { /* That's what SVR2 does */ 26347125Sbostic setinputfile(argv[1], 1); 26447125Sbostic commandname = argv[1]; 26547125Sbostic cmdloop(0); 26647125Sbostic popfile(); 26747125Sbostic } 26847125Sbostic return exitstatus; 26947125Sbostic } 27047125Sbostic 27147125Sbostic 27247125Sbostic exitcmd(argc, argv) char **argv; { 27347125Sbostic if (argc > 1) 27447125Sbostic exitstatus = number(argv[1]); 27547125Sbostic exitshell(exitstatus); 27647125Sbostic } 27747125Sbostic 27847125Sbostic 27947125Sbostic lccmd(argc, argv) char **argv; { 28047125Sbostic if (argc > 1) { 28147125Sbostic defun(argv[1], prevcmd); 28247125Sbostic return 0; 28347125Sbostic } else { 28447125Sbostic INTOFF; 28547125Sbostic freefunc(curcmd); 28647125Sbostic curcmd = prevcmd; 28747125Sbostic prevcmd = NULL; 28847125Sbostic INTON; 28947125Sbostic evaltree(curcmd, 0); 29047125Sbostic return exitstatus; 29147125Sbostic } 29247125Sbostic } 29347125Sbostic 29447125Sbostic 29547125Sbostic 29647125Sbostic #ifdef notdef 29747125Sbostic /* 29847125Sbostic * Should never be called. 29947125Sbostic */ 30047125Sbostic 30147125Sbostic void 30247125Sbostic exit(exitstatus) { 30347125Sbostic _exit(exitstatus); 30447125Sbostic } 30547125Sbostic #endif 306