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*69272Schristos static char sccsid[] = "@(#)main.c 8.4 (Berkeley) 05/04/95"; 1947125Sbostic #endif /* not lint */ 2047125Sbostic 2168926Sbostic #include <stdio.h> 2247125Sbostic #include <signal.h> 23*69272Schristos #include <sys/stat.h> 24*69272Schristos #include <unistd.h> 2547125Sbostic #include <fcntl.h> 26*69272Schristos 27*69272Schristos 2847125Sbostic #include "shell.h" 2947125Sbostic #include "main.h" 3047125Sbostic #include "mail.h" 3147125Sbostic #include "options.h" 3247125Sbostic #include "output.h" 3347125Sbostic #include "parser.h" 3447125Sbostic #include "nodes.h" 3547125Sbostic #include "eval.h" 3647125Sbostic #include "jobs.h" 3747125Sbostic #include "input.h" 3847125Sbostic #include "trap.h" 3947125Sbostic #include "var.h" 40*69272Schristos #include "show.h" 4147125Sbostic #include "memalloc.h" 4247125Sbostic #include "error.h" 4347125Sbostic #include "init.h" 4447125Sbostic #include "mystring.h" 4568926Sbostic #include "exec.h" 4647125Sbostic 4747125Sbostic #define PROFILE 0 4847125Sbostic 4947125Sbostic int rootpid; 5047125Sbostic int rootshell; 5147125Sbostic STATIC union node *curcmd; 5247125Sbostic STATIC union node *prevcmd; 5347125Sbostic extern int errno; 5447125Sbostic #if PROFILE 5547125Sbostic short profile_buf[16384]; 5647125Sbostic extern int etext(); 5747125Sbostic #endif 5847125Sbostic 59*69272Schristos STATIC void read_profile __P((char *)); 60*69272Schristos STATIC char *find_dot_file __P((char *)); 6147125Sbostic 6247125Sbostic /* 6347125Sbostic * Main routine. We initialize things, parse the arguments, execute 6447125Sbostic * profiles if we're a login shell, and then call cmdloop to execute 6547125Sbostic * commands. The setjmp call sets up the location to jump to when an 6647125Sbostic * exception occurs. When an exception occurs the variable "state" 6747125Sbostic * is used to figure out how far we had gotten. 6847125Sbostic */ 6947125Sbostic 70*69272Schristos int 71*69272Schristos main(argc, argv) 72*69272Schristos int argc; 73*69272Schristos char **argv; 74*69272Schristos { 7547125Sbostic struct jmploc jmploc; 7647125Sbostic struct stackmark smark; 7747125Sbostic volatile int state; 7847125Sbostic char *shinit; 7947125Sbostic 8047125Sbostic #if PROFILE 8147125Sbostic monitor(4, etext, profile_buf, sizeof profile_buf, 50); 8247125Sbostic #endif 8347125Sbostic state = 0; 8447125Sbostic if (setjmp(jmploc.loc)) { 8547125Sbostic /* 8647125Sbostic * When a shell procedure is executed, we raise the 8747125Sbostic * exception EXSHELLPROC to clean up before executing 8847125Sbostic * the shell procedure. 8947125Sbostic */ 9047125Sbostic if (exception == EXSHELLPROC) { 9147125Sbostic rootpid = getpid(); 9247125Sbostic rootshell = 1; 9347125Sbostic minusc = NULL; 9447125Sbostic state = 3; 9547125Sbostic } else if (state == 0 || iflag == 0 || ! rootshell) 9647125Sbostic exitshell(2); 9747125Sbostic reset(); 9856563Smarc if (exception == EXINT 9947125Sbostic #if ATTY 10056563Smarc && (! attyset() || equal(termval(), "emacs")) 10147125Sbostic #endif 10256563Smarc ) { 10347125Sbostic out2c('\n'); 10447125Sbostic flushout(&errout); 10547125Sbostic } 10647125Sbostic popstackmark(&smark); 10747125Sbostic FORCEINTON; /* enable interrupts */ 10847125Sbostic if (state == 1) 10947125Sbostic goto state1; 11047125Sbostic else if (state == 2) 11147125Sbostic goto state2; 11254316Smarc else if (state == 3) 11354316Smarc goto state3; 11447125Sbostic else 11554316Smarc goto state4; 11647125Sbostic } 11747125Sbostic handler = &jmploc; 11847125Sbostic #ifdef DEBUG 11947125Sbostic opentrace(); 12047125Sbostic trputs("Shell args: "); trargs(argv); 12147125Sbostic #endif 12247125Sbostic rootpid = getpid(); 12347125Sbostic rootshell = 1; 12447125Sbostic init(); 12547125Sbostic setstackmark(&smark); 12647125Sbostic procargs(argc, argv); 12747125Sbostic if (argv[0] && argv[0][0] == '-') { 12847125Sbostic state = 1; 12947125Sbostic read_profile("/etc/profile"); 13047125Sbostic state1: 13147125Sbostic state = 2; 13247125Sbostic read_profile(".profile"); 13354316Smarc } 13447125Sbostic state2: 13547125Sbostic state = 3; 13668931Sbostic if (getuid() == geteuid() && getgid() == getegid()) { 13768931Sbostic if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 13868931Sbostic state = 3; 13968931Sbostic read_profile(shinit); 14068931Sbostic } 14154316Smarc } 14254316Smarc state3: 14354316Smarc state = 4; 14447125Sbostic if (minusc) { 14547125Sbostic evalstring(minusc); 14647125Sbostic } 14747125Sbostic if (sflag || minusc == NULL) { 14854316Smarc state4: /* XXX ??? - why isn't this before the "if" statement */ 14947125Sbostic cmdloop(1); 15047125Sbostic } 15147125Sbostic #if PROFILE 15247125Sbostic monitor(0); 15347125Sbostic #endif 15447125Sbostic exitshell(exitstatus); 155*69272Schristos /*NOTREACHED*/ 156*69272Schristos return 0; 15747125Sbostic } 15847125Sbostic 15947125Sbostic 16047125Sbostic /* 16147125Sbostic * Read and execute commands. "Top" is nonzero for the top level command 16247125Sbostic * loop; it turns on prompting if the shell is interactive. 16347125Sbostic */ 16447125Sbostic 16547125Sbostic void 166*69272Schristos cmdloop(top) 167*69272Schristos int top; 168*69272Schristos { 16947125Sbostic union node *n; 17047125Sbostic struct stackmark smark; 17147125Sbostic int inter; 17255278Smarc int numeof = 0; 17347125Sbostic 17447125Sbostic TRACE(("cmdloop(%d) called\n", top)); 17547125Sbostic setstackmark(&smark); 17647125Sbostic for (;;) { 17747125Sbostic if (pendingsigs) 17847125Sbostic dotrap(); 17947125Sbostic inter = 0; 18047125Sbostic if (iflag && top) { 18147125Sbostic inter++; 18247125Sbostic showjobs(1); 18347125Sbostic chkmail(0); 18447125Sbostic flushout(&output); 18547125Sbostic } 18647125Sbostic n = parsecmd(inter); 18755277Smarc /* showtree(n); DEBUG */ 18847125Sbostic if (n == NEOF) { 18955277Smarc if (!top || numeof >= 50) 19047125Sbostic break; 19155277Smarc if (!stoppedjobs()) { 19255277Smarc if (!Iflag) 19355277Smarc break; 19455277Smarc out2str("\nUse \"exit\" to leave shell.\n"); 19555277Smarc } 19647125Sbostic numeof++; 19747125Sbostic } else if (n != NULL && nflag == 0) { 19855277Smarc job_warning = (job_warning == 2) ? 1 : 0; 19955278Smarc numeof = 0; 20047125Sbostic evaltree(n, 0); 20147125Sbostic } 20247125Sbostic popstackmark(&smark); 20347125Sbostic } 20447125Sbostic popstackmark(&smark); /* unnecessary */ 20547125Sbostic } 20647125Sbostic 20747125Sbostic 20847125Sbostic 20947125Sbostic /* 21047125Sbostic * Read /etc/profile or .profile. Return on error. 21147125Sbostic */ 21247125Sbostic 21347125Sbostic STATIC void 21447125Sbostic read_profile(name) 21547125Sbostic char *name; 21647125Sbostic { 21747125Sbostic int fd; 21847125Sbostic 21947125Sbostic INTOFF; 22047125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 22147125Sbostic setinputfd(fd, 1); 22247125Sbostic INTON; 22347125Sbostic if (fd < 0) 22447125Sbostic return; 22547125Sbostic cmdloop(0); 22647125Sbostic popfile(); 22747125Sbostic } 22847125Sbostic 22947125Sbostic 23047125Sbostic 23147125Sbostic /* 23247125Sbostic * Read a file containing shell functions. 23347125Sbostic */ 23447125Sbostic 23547125Sbostic void 23647125Sbostic readcmdfile(name) 23747125Sbostic char *name; 238*69272Schristos { 23947125Sbostic int fd; 24047125Sbostic 24147125Sbostic INTOFF; 24247125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 24347125Sbostic setinputfd(fd, 1); 24447125Sbostic else 24547125Sbostic error("Can't open %s", name); 24647125Sbostic INTON; 24747125Sbostic cmdloop(0); 24847125Sbostic popfile(); 24947125Sbostic } 25047125Sbostic 25147125Sbostic 25247125Sbostic 25347125Sbostic /* 25447125Sbostic * Take commands from a file. To be compatable we should do a path 25568926Sbostic * search for the file, which is necessary to find sub-commands. 25647125Sbostic */ 25747125Sbostic 25868926Sbostic 259*69272Schristos STATIC char * 260*69272Schristos find_dot_file(basename) 261*69272Schristos char *basename; 262*69272Schristos { 26368926Sbostic static char localname[FILENAME_MAX+1]; 26468926Sbostic char *fullname; 26568926Sbostic char *path = pathval(); 26668926Sbostic struct stat statb; 26768926Sbostic 26868926Sbostic /* don't try this for absolute or relative paths */ 26968926Sbostic if( strchr(basename, '/')) 27068926Sbostic return basename; 27168926Sbostic 27268926Sbostic while ((fullname = padvance(&path, basename)) != NULL) { 27368926Sbostic strcpy(localname, fullname); 27468926Sbostic stunalloc(fullname); 27568926Sbostic if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 27668926Sbostic return localname; 27768926Sbostic } 27868926Sbostic return basename; 27968926Sbostic } 28068926Sbostic 281*69272Schristos int 282*69272Schristos dotcmd(argc, argv) 283*69272Schristos int argc; 284*69272Schristos char **argv; 285*69272Schristos { 28647125Sbostic exitstatus = 0; 28747125Sbostic if (argc >= 2) { /* That's what SVR2 does */ 28868926Sbostic char *fullname = find_dot_file(argv[1]); 28968926Sbostic setinputfile(fullname, 1); 29068926Sbostic commandname = fullname; 29147125Sbostic cmdloop(0); 29247125Sbostic popfile(); 29347125Sbostic } 29447125Sbostic return exitstatus; 29547125Sbostic } 29647125Sbostic 29747125Sbostic 298*69272Schristos int 299*69272Schristos exitcmd(argc, argv) 300*69272Schristos int argc; 301*69272Schristos char **argv; 302*69272Schristos { 30355277Smarc if (stoppedjobs()) 304*69272Schristos return 0; 30547125Sbostic if (argc > 1) 30647125Sbostic exitstatus = number(argv[1]); 30747125Sbostic exitshell(exitstatus); 308*69272Schristos /*NOTREACHED*/ 309*69272Schristos return 0; 31047125Sbostic } 31147125Sbostic 31247125Sbostic 31347125Sbostic #ifdef notdef 31447125Sbostic /* 31547125Sbostic * Should never be called. 31647125Sbostic */ 31747125Sbostic 31847125Sbostic void 31947125Sbostic exit(exitstatus) { 32047125Sbostic _exit(exitstatus); 32147125Sbostic } 32247125Sbostic #endif 323