147125Sbostic /*- 260698Sbostic * Copyright (c) 1991, 1993 360698Sbostic * The Regents of the University of California. 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 1260698Sbostic static char copyright[] = 1360698Sbostic "@(#) Copyright (c) 1991, 1993\n\ 1460698Sbostic The Regents of the University of California. All rights reserved.\n"; 1547125Sbostic #endif /* not lint */ 1647125Sbostic 1747125Sbostic #ifndef lint 18*68931Sbostic static char sccsid[] = "@(#)main.c 8.3 (Berkeley) 04/27/95"; 1947125Sbostic #endif /* not lint */ 2047125Sbostic 2168926Sbostic #include <sys/stat.h> 2268926Sbostic #include <stdio.h> 2347125Sbostic #include <signal.h> 2447125Sbostic #include <fcntl.h> 2547125Sbostic #include "shell.h" 2647125Sbostic #include "main.h" 2747125Sbostic #include "mail.h" 2847125Sbostic #include "options.h" 2947125Sbostic #include "output.h" 3047125Sbostic #include "parser.h" 3147125Sbostic #include "nodes.h" 3247125Sbostic #include "eval.h" 3347125Sbostic #include "jobs.h" 3447125Sbostic #include "input.h" 3547125Sbostic #include "trap.h" 3647125Sbostic #include "var.h" 3747125Sbostic #include "memalloc.h" 3847125Sbostic #include "error.h" 3947125Sbostic #include "init.h" 4047125Sbostic #include "mystring.h" 4168926Sbostic #include "exec.h" 4247125Sbostic 4347125Sbostic #define PROFILE 0 4447125Sbostic 4547125Sbostic int rootpid; 4647125Sbostic int rootshell; 4747125Sbostic STATIC union node *curcmd; 4847125Sbostic STATIC union node *prevcmd; 4947125Sbostic extern int errno; 5047125Sbostic #if PROFILE 5147125Sbostic short profile_buf[16384]; 5247125Sbostic extern int etext(); 5347125Sbostic #endif 5447125Sbostic 5547125Sbostic #ifdef __STDC__ 5647125Sbostic STATIC void read_profile(char *); 5747125Sbostic char *getenv(char *); 5847125Sbostic #else 5947125Sbostic STATIC void read_profile(); 6047125Sbostic char *getenv(); 6147125Sbostic #endif 6247125Sbostic 6347125Sbostic 6447125Sbostic /* 6547125Sbostic * Main routine. We initialize things, parse the arguments, execute 6647125Sbostic * profiles if we're a login shell, and then call cmdloop to execute 6747125Sbostic * commands. The setjmp call sets up the location to jump to when an 6847125Sbostic * exception occurs. When an exception occurs the variable "state" 6947125Sbostic * is used to figure out how far we had gotten. 7047125Sbostic */ 7147125Sbostic 7247125Sbostic main(argc, argv) char **argv; { 7347125Sbostic struct jmploc jmploc; 7447125Sbostic struct stackmark smark; 7547125Sbostic volatile int state; 7647125Sbostic char *shinit; 7747125Sbostic 7847125Sbostic #if PROFILE 7947125Sbostic monitor(4, etext, profile_buf, sizeof profile_buf, 50); 8047125Sbostic #endif 8147125Sbostic state = 0; 8247125Sbostic if (setjmp(jmploc.loc)) { 8347125Sbostic /* 8447125Sbostic * When a shell procedure is executed, we raise the 8547125Sbostic * exception EXSHELLPROC to clean up before executing 8647125Sbostic * the shell procedure. 8747125Sbostic */ 8847125Sbostic if (exception == EXSHELLPROC) { 8947125Sbostic rootpid = getpid(); 9047125Sbostic rootshell = 1; 9147125Sbostic minusc = NULL; 9247125Sbostic state = 3; 9347125Sbostic } else if (state == 0 || iflag == 0 || ! rootshell) 9447125Sbostic exitshell(2); 9547125Sbostic reset(); 9656563Smarc if (exception == EXINT 9747125Sbostic #if ATTY 9856563Smarc && (! attyset() || equal(termval(), "emacs")) 9947125Sbostic #endif 10056563Smarc ) { 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; 11054316Smarc else if (state == 3) 11154316Smarc goto state3; 11247125Sbostic else 11354316Smarc 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"); 13154316Smarc } 13247125Sbostic state2: 13347125Sbostic state = 3; 134*68931Sbostic if (getuid() == geteuid() && getgid() == getegid()) { 135*68931Sbostic if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 136*68931Sbostic state = 3; 137*68931Sbostic read_profile(shinit); 138*68931Sbostic } 13954316Smarc } 14054316Smarc state3: 14154316Smarc state = 4; 14247125Sbostic if (minusc) { 14347125Sbostic evalstring(minusc); 14447125Sbostic } 14547125Sbostic if (sflag || minusc == NULL) { 14654316Smarc state4: /* XXX ??? - why isn't this before the "if" statement */ 14747125Sbostic cmdloop(1); 14847125Sbostic } 14947125Sbostic #if PROFILE 15047125Sbostic monitor(0); 15147125Sbostic #endif 15247125Sbostic exitshell(exitstatus); 15347125Sbostic } 15447125Sbostic 15547125Sbostic 15647125Sbostic /* 15747125Sbostic * Read and execute commands. "Top" is nonzero for the top level command 15847125Sbostic * loop; it turns on prompting if the shell is interactive. 15947125Sbostic */ 16047125Sbostic 16147125Sbostic void 16247125Sbostic cmdloop(top) { 16347125Sbostic union node *n; 16447125Sbostic struct stackmark smark; 16547125Sbostic int inter; 16655278Smarc int numeof = 0; 16747125Sbostic 16847125Sbostic TRACE(("cmdloop(%d) called\n", top)); 16947125Sbostic setstackmark(&smark); 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); 18155277Smarc /* showtree(n); DEBUG */ 18247125Sbostic if (n == NEOF) { 18355277Smarc if (!top || numeof >= 50) 18447125Sbostic break; 18555277Smarc if (!stoppedjobs()) { 18655277Smarc if (!Iflag) 18755277Smarc break; 18855277Smarc out2str("\nUse \"exit\" to leave shell.\n"); 18955277Smarc } 19047125Sbostic numeof++; 19147125Sbostic } else if (n != NULL && nflag == 0) { 19255277Smarc job_warning = (job_warning == 2) ? 1 : 0; 19355278Smarc numeof = 0; 19447125Sbostic evaltree(n, 0); 19547125Sbostic } 19647125Sbostic popstackmark(&smark); 19747125Sbostic } 19847125Sbostic popstackmark(&smark); /* unnecessary */ 19947125Sbostic } 20047125Sbostic 20147125Sbostic 20247125Sbostic 20347125Sbostic /* 20447125Sbostic * Read /etc/profile or .profile. Return on error. 20547125Sbostic */ 20647125Sbostic 20747125Sbostic STATIC void 20847125Sbostic read_profile(name) 20947125Sbostic char *name; 21047125Sbostic { 21147125Sbostic int fd; 21247125Sbostic 21347125Sbostic INTOFF; 21447125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 21547125Sbostic setinputfd(fd, 1); 21647125Sbostic INTON; 21747125Sbostic if (fd < 0) 21847125Sbostic return; 21947125Sbostic cmdloop(0); 22047125Sbostic popfile(); 22147125Sbostic } 22247125Sbostic 22347125Sbostic 22447125Sbostic 22547125Sbostic /* 22647125Sbostic * Read a file containing shell functions. 22747125Sbostic */ 22847125Sbostic 22947125Sbostic void 23047125Sbostic readcmdfile(name) 23147125Sbostic char *name; 23247125Sbostic { 23347125Sbostic int fd; 23447125Sbostic 23547125Sbostic INTOFF; 23647125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 23747125Sbostic setinputfd(fd, 1); 23847125Sbostic else 23947125Sbostic error("Can't open %s", name); 24047125Sbostic INTON; 24147125Sbostic cmdloop(0); 24247125Sbostic popfile(); 24347125Sbostic } 24447125Sbostic 24547125Sbostic 24647125Sbostic 24747125Sbostic /* 24847125Sbostic * Take commands from a file. To be compatable we should do a path 24968926Sbostic * search for the file, which is necessary to find sub-commands. 25047125Sbostic */ 25147125Sbostic 25268926Sbostic 25368926Sbostic static char * 25468926Sbostic find_dot_file(basename) char *basename; { 25568926Sbostic static char localname[FILENAME_MAX+1]; 25668926Sbostic char *fullname; 25768926Sbostic char *path = pathval(); 25868926Sbostic struct stat statb; 25968926Sbostic 26068926Sbostic /* don't try this for absolute or relative paths */ 26168926Sbostic if( strchr(basename, '/')) 26268926Sbostic return basename; 26368926Sbostic 26468926Sbostic while ((fullname = padvance(&path, basename)) != NULL) { 26568926Sbostic strcpy(localname, fullname); 26668926Sbostic stunalloc(fullname); 26768926Sbostic if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 26868926Sbostic return localname; 26968926Sbostic } 27068926Sbostic return basename; 27168926Sbostic } 27268926Sbostic 27347125Sbostic dotcmd(argc, argv) char **argv; { 27447125Sbostic exitstatus = 0; 27547125Sbostic if (argc >= 2) { /* That's what SVR2 does */ 27668926Sbostic char *fullname = find_dot_file(argv[1]); 27768926Sbostic setinputfile(fullname, 1); 27868926Sbostic commandname = fullname; 27947125Sbostic cmdloop(0); 28047125Sbostic popfile(); 28147125Sbostic } 28247125Sbostic return exitstatus; 28347125Sbostic } 28447125Sbostic 28547125Sbostic 28647125Sbostic exitcmd(argc, argv) char **argv; { 28755277Smarc if (stoppedjobs()) 28855277Smarc return; 28947125Sbostic if (argc > 1) 29047125Sbostic exitstatus = number(argv[1]); 29147125Sbostic exitshell(exitstatus); 29247125Sbostic } 29347125Sbostic 29447125Sbostic 29547125Sbostic #ifdef notdef 29647125Sbostic /* 29747125Sbostic * Should never be called. 29847125Sbostic */ 29947125Sbostic 30047125Sbostic void 30147125Sbostic exit(exitstatus) { 30247125Sbostic _exit(exitstatus); 30347125Sbostic } 30447125Sbostic #endif 305