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*56563Smarc static char sccsid[] = "@(#)main.c 5.8 (Berkeley) 10/15/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 #include "var.h" 3547125Sbostic #include "memalloc.h" 3647125Sbostic #include "error.h" 3747125Sbostic #include "init.h" 3847125Sbostic #include "mystring.h" 3947125Sbostic 4047125Sbostic #define PROFILE 0 4147125Sbostic 4247125Sbostic int rootpid; 4347125Sbostic int rootshell; 4447125Sbostic STATIC union node *curcmd; 4547125Sbostic STATIC union node *prevcmd; 4647125Sbostic extern int errno; 4747125Sbostic #if PROFILE 4847125Sbostic short profile_buf[16384]; 4947125Sbostic extern int etext(); 5047125Sbostic #endif 5147125Sbostic 5247125Sbostic #ifdef __STDC__ 5347125Sbostic STATIC void read_profile(char *); 5447125Sbostic char *getenv(char *); 5547125Sbostic #else 5647125Sbostic STATIC void read_profile(); 5747125Sbostic char *getenv(); 5847125Sbostic #endif 5947125Sbostic 6047125Sbostic 6147125Sbostic /* 6247125Sbostic * Main routine. We initialize things, parse the arguments, execute 6347125Sbostic * profiles if we're a login shell, and then call cmdloop to execute 6447125Sbostic * commands. The setjmp call sets up the location to jump to when an 6547125Sbostic * exception occurs. When an exception occurs the variable "state" 6647125Sbostic * is used to figure out how far we had gotten. 6747125Sbostic */ 6847125Sbostic 6947125Sbostic main(argc, argv) char **argv; { 7047125Sbostic struct jmploc jmploc; 7147125Sbostic struct stackmark smark; 7247125Sbostic volatile int state; 7347125Sbostic char *shinit; 7447125Sbostic 7547125Sbostic #if PROFILE 7647125Sbostic monitor(4, etext, profile_buf, sizeof profile_buf, 50); 7747125Sbostic #endif 7847125Sbostic state = 0; 7947125Sbostic if (setjmp(jmploc.loc)) { 8047125Sbostic /* 8147125Sbostic * When a shell procedure is executed, we raise the 8247125Sbostic * exception EXSHELLPROC to clean up before executing 8347125Sbostic * the shell procedure. 8447125Sbostic */ 8547125Sbostic if (exception == EXSHELLPROC) { 8647125Sbostic rootpid = getpid(); 8747125Sbostic rootshell = 1; 8847125Sbostic minusc = NULL; 8947125Sbostic state = 3; 9047125Sbostic } else if (state == 0 || iflag == 0 || ! rootshell) 9147125Sbostic exitshell(2); 9247125Sbostic reset(); 93*56563Smarc if (exception == EXINT 9447125Sbostic #if ATTY 95*56563Smarc && (! attyset() || equal(termval(), "emacs")) 9647125Sbostic #endif 97*56563Smarc ) { 9847125Sbostic out2c('\n'); 9947125Sbostic flushout(&errout); 10047125Sbostic } 10147125Sbostic popstackmark(&smark); 10247125Sbostic FORCEINTON; /* enable interrupts */ 10347125Sbostic if (state == 1) 10447125Sbostic goto state1; 10547125Sbostic else if (state == 2) 10647125Sbostic goto state2; 10754316Smarc else if (state == 3) 10854316Smarc goto state3; 10947125Sbostic else 11054316Smarc goto state4; 11147125Sbostic } 11247125Sbostic handler = &jmploc; 11347125Sbostic #ifdef DEBUG 11447125Sbostic opentrace(); 11547125Sbostic trputs("Shell args: "); trargs(argv); 11647125Sbostic #endif 11747125Sbostic rootpid = getpid(); 11847125Sbostic rootshell = 1; 11947125Sbostic init(); 12047125Sbostic setstackmark(&smark); 12147125Sbostic procargs(argc, argv); 12247125Sbostic if (argv[0] && argv[0][0] == '-') { 12347125Sbostic state = 1; 12447125Sbostic read_profile("/etc/profile"); 12547125Sbostic state1: 12647125Sbostic state = 2; 12747125Sbostic read_profile(".profile"); 12854316Smarc } 12947125Sbostic state2: 13047125Sbostic state = 3; 13155283Smarc if ((shinit = lookupvar("ENV")) != NULL && 13254316Smarc *shinit != '\0') { 13354316Smarc state = 3; 13454316Smarc read_profile(shinit); 13554316Smarc } 13654316Smarc state3: 13754316Smarc state = 4; 13847125Sbostic if (minusc) { 13947125Sbostic evalstring(minusc); 14047125Sbostic } 14147125Sbostic if (sflag || minusc == NULL) { 14254316Smarc state4: /* XXX ??? - why isn't this before the "if" statement */ 14347125Sbostic cmdloop(1); 14447125Sbostic } 14547125Sbostic #if PROFILE 14647125Sbostic monitor(0); 14747125Sbostic #endif 14847125Sbostic exitshell(exitstatus); 14947125Sbostic } 15047125Sbostic 15147125Sbostic 15247125Sbostic /* 15347125Sbostic * Read and execute commands. "Top" is nonzero for the top level command 15447125Sbostic * loop; it turns on prompting if the shell is interactive. 15547125Sbostic */ 15647125Sbostic 15747125Sbostic void 15847125Sbostic cmdloop(top) { 15947125Sbostic union node *n; 16047125Sbostic struct stackmark smark; 16147125Sbostic int inter; 16255278Smarc int numeof = 0; 16347125Sbostic 16447125Sbostic TRACE(("cmdloop(%d) called\n", top)); 16547125Sbostic setstackmark(&smark); 16647125Sbostic for (;;) { 16747125Sbostic if (pendingsigs) 16847125Sbostic dotrap(); 16947125Sbostic inter = 0; 17047125Sbostic if (iflag && top) { 17147125Sbostic inter++; 17247125Sbostic showjobs(1); 17347125Sbostic chkmail(0); 17447125Sbostic flushout(&output); 17547125Sbostic } 17647125Sbostic n = parsecmd(inter); 17755277Smarc /* showtree(n); DEBUG */ 17847125Sbostic if (n == NEOF) { 17955277Smarc if (!top || numeof >= 50) 18047125Sbostic break; 18155277Smarc if (!stoppedjobs()) { 18255277Smarc if (!Iflag) 18355277Smarc break; 18455277Smarc out2str("\nUse \"exit\" to leave shell.\n"); 18555277Smarc } 18647125Sbostic numeof++; 18747125Sbostic } else if (n != NULL && nflag == 0) { 18855277Smarc job_warning = (job_warning == 2) ? 1 : 0; 18955278Smarc numeof = 0; 19047125Sbostic evaltree(n, 0); 19147125Sbostic } 19247125Sbostic popstackmark(&smark); 19347125Sbostic } 19447125Sbostic popstackmark(&smark); /* unnecessary */ 19547125Sbostic } 19647125Sbostic 19747125Sbostic 19847125Sbostic 19947125Sbostic /* 20047125Sbostic * Read /etc/profile or .profile. Return on error. 20147125Sbostic */ 20247125Sbostic 20347125Sbostic STATIC void 20447125Sbostic read_profile(name) 20547125Sbostic char *name; 20647125Sbostic { 20747125Sbostic int fd; 20847125Sbostic 20947125Sbostic INTOFF; 21047125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 21147125Sbostic setinputfd(fd, 1); 21247125Sbostic INTON; 21347125Sbostic if (fd < 0) 21447125Sbostic return; 21547125Sbostic cmdloop(0); 21647125Sbostic popfile(); 21747125Sbostic } 21847125Sbostic 21947125Sbostic 22047125Sbostic 22147125Sbostic /* 22247125Sbostic * Read a file containing shell functions. 22347125Sbostic */ 22447125Sbostic 22547125Sbostic void 22647125Sbostic readcmdfile(name) 22747125Sbostic char *name; 22847125Sbostic { 22947125Sbostic int fd; 23047125Sbostic 23147125Sbostic INTOFF; 23247125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 23347125Sbostic setinputfd(fd, 1); 23447125Sbostic else 23547125Sbostic error("Can't open %s", name); 23647125Sbostic INTON; 23747125Sbostic cmdloop(0); 23847125Sbostic popfile(); 23947125Sbostic } 24047125Sbostic 24147125Sbostic 24247125Sbostic 24347125Sbostic /* 24447125Sbostic * Take commands from a file. To be compatable we should do a path 24547125Sbostic * search for the file, but a path search doesn't make any sense. 24647125Sbostic */ 24747125Sbostic 24847125Sbostic dotcmd(argc, argv) char **argv; { 24947125Sbostic exitstatus = 0; 25047125Sbostic if (argc >= 2) { /* That's what SVR2 does */ 25147125Sbostic setinputfile(argv[1], 1); 25247125Sbostic commandname = argv[1]; 25347125Sbostic cmdloop(0); 25447125Sbostic popfile(); 25547125Sbostic } 25647125Sbostic return exitstatus; 25747125Sbostic } 25847125Sbostic 25947125Sbostic 26047125Sbostic exitcmd(argc, argv) char **argv; { 26155277Smarc if (stoppedjobs()) 26255277Smarc return; 26347125Sbostic if (argc > 1) 26447125Sbostic exitstatus = number(argv[1]); 26547125Sbostic exitshell(exitstatus); 26647125Sbostic } 26747125Sbostic 26847125Sbostic 26947125Sbostic #ifdef notdef 27047125Sbostic /* 27147125Sbostic * Should never be called. 27247125Sbostic */ 27347125Sbostic 27447125Sbostic void 27547125Sbostic exit(exitstatus) { 27647125Sbostic _exit(exitstatus); 27747125Sbostic } 27847125Sbostic #endif 279