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*69749Schristos static char sccsid[] = "@(#)main.c 8.6 (Berkeley) 05/28/95";
1947125Sbostic #endif /* not lint */
2047125Sbostic
2168926Sbostic #include <stdio.h>
2247125Sbostic #include <signal.h>
2369272Schristos #include <sys/stat.h>
2469272Schristos #include <unistd.h>
2547125Sbostic #include <fcntl.h>
2669272Schristos
2769272Schristos
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"
35*69749Schristos #include "expand.h"
3647125Sbostic #include "eval.h"
3747125Sbostic #include "jobs.h"
3847125Sbostic #include "input.h"
3947125Sbostic #include "trap.h"
4047125Sbostic #include "var.h"
4169272Schristos #include "show.h"
4247125Sbostic #include "memalloc.h"
4347125Sbostic #include "error.h"
4447125Sbostic #include "init.h"
4547125Sbostic #include "mystring.h"
4668926Sbostic #include "exec.h"
4747125Sbostic
4847125Sbostic #define PROFILE 0
4947125Sbostic
5047125Sbostic int rootpid;
5147125Sbostic int rootshell;
5247125Sbostic STATIC union node *curcmd;
5347125Sbostic STATIC union node *prevcmd;
5447125Sbostic extern int errno;
5547125Sbostic #if PROFILE
5647125Sbostic short profile_buf[16384];
5747125Sbostic extern int etext();
5847125Sbostic #endif
5947125Sbostic
6069272Schristos STATIC void read_profile __P((char *));
6169272Schristos STATIC char *find_dot_file __P((char *));
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
7169272Schristos int
main(argc,argv)7269272Schristos main(argc, argv)
7369272Schristos int argc;
7469272Schristos char **argv;
7569272Schristos {
7647125Sbostic struct jmploc jmploc;
7747125Sbostic struct stackmark smark;
7847125Sbostic volatile int state;
7947125Sbostic char *shinit;
8047125Sbostic
8147125Sbostic #if PROFILE
8247125Sbostic monitor(4, etext, profile_buf, sizeof profile_buf, 50);
8347125Sbostic #endif
8447125Sbostic state = 0;
8547125Sbostic if (setjmp(jmploc.loc)) {
8647125Sbostic /*
8747125Sbostic * When a shell procedure is executed, we raise the
8847125Sbostic * exception EXSHELLPROC to clean up before executing
8947125Sbostic * the shell procedure.
9047125Sbostic */
9169549Schristos if (exception == EXERROR)
9269549Schristos exitstatus = 2;
9347125Sbostic if (exception == EXSHELLPROC) {
9447125Sbostic rootpid = getpid();
9547125Sbostic rootshell = 1;
9647125Sbostic minusc = NULL;
9747125Sbostic state = 3;
9847125Sbostic } else if (state == 0 || iflag == 0 || ! rootshell)
9947125Sbostic exitshell(2);
10047125Sbostic reset();
10156563Smarc if (exception == EXINT
10247125Sbostic #if ATTY
10356563Smarc && (! attyset() || equal(termval(), "emacs"))
10447125Sbostic #endif
10556563Smarc ) {
10647125Sbostic out2c('\n');
10747125Sbostic flushout(&errout);
10847125Sbostic }
10947125Sbostic popstackmark(&smark);
11047125Sbostic FORCEINTON; /* enable interrupts */
11147125Sbostic if (state == 1)
11247125Sbostic goto state1;
11347125Sbostic else if (state == 2)
11447125Sbostic goto state2;
11554316Smarc else if (state == 3)
11654316Smarc goto state3;
11747125Sbostic else
11854316Smarc goto state4;
11947125Sbostic }
12047125Sbostic handler = &jmploc;
12147125Sbostic #ifdef DEBUG
12247125Sbostic opentrace();
12347125Sbostic trputs("Shell args: "); trargs(argv);
12447125Sbostic #endif
12547125Sbostic rootpid = getpid();
12647125Sbostic rootshell = 1;
12747125Sbostic init();
12847125Sbostic setstackmark(&smark);
12947125Sbostic procargs(argc, argv);
13047125Sbostic if (argv[0] && argv[0][0] == '-') {
13147125Sbostic state = 1;
13247125Sbostic read_profile("/etc/profile");
13347125Sbostic state1:
13447125Sbostic state = 2;
13547125Sbostic read_profile(".profile");
13654316Smarc }
13747125Sbostic state2:
13847125Sbostic state = 3;
13968931Sbostic if (getuid() == geteuid() && getgid() == getegid()) {
14068931Sbostic if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') {
14168931Sbostic state = 3;
14268931Sbostic read_profile(shinit);
14368931Sbostic }
14454316Smarc }
14554316Smarc state3:
14654316Smarc state = 4;
14747125Sbostic if (minusc) {
14847125Sbostic evalstring(minusc);
14947125Sbostic }
15047125Sbostic if (sflag || minusc == NULL) {
15154316Smarc state4: /* XXX ??? - why isn't this before the "if" statement */
15247125Sbostic cmdloop(1);
15347125Sbostic }
15447125Sbostic #if PROFILE
15547125Sbostic monitor(0);
15647125Sbostic #endif
15747125Sbostic exitshell(exitstatus);
15869272Schristos /*NOTREACHED*/
15969272Schristos return 0;
16047125Sbostic }
16147125Sbostic
16247125Sbostic
16347125Sbostic /*
16447125Sbostic * Read and execute commands. "Top" is nonzero for the top level command
16547125Sbostic * loop; it turns on prompting if the shell is interactive.
16647125Sbostic */
16747125Sbostic
16847125Sbostic void
cmdloop(top)16969272Schristos cmdloop(top)
17069272Schristos int top;
17169272Schristos {
17247125Sbostic union node *n;
17347125Sbostic struct stackmark smark;
17447125Sbostic int inter;
17555278Smarc int numeof = 0;
17647125Sbostic
17747125Sbostic TRACE(("cmdloop(%d) called\n", top));
17847125Sbostic setstackmark(&smark);
17947125Sbostic for (;;) {
18047125Sbostic if (pendingsigs)
18147125Sbostic dotrap();
18247125Sbostic inter = 0;
18347125Sbostic if (iflag && top) {
18447125Sbostic inter++;
18547125Sbostic showjobs(1);
18647125Sbostic chkmail(0);
18747125Sbostic flushout(&output);
18847125Sbostic }
18947125Sbostic n = parsecmd(inter);
19055277Smarc /* showtree(n); DEBUG */
19147125Sbostic if (n == NEOF) {
19255277Smarc if (!top || numeof >= 50)
19347125Sbostic break;
19455277Smarc if (!stoppedjobs()) {
19555277Smarc if (!Iflag)
19655277Smarc break;
19755277Smarc out2str("\nUse \"exit\" to leave shell.\n");
19855277Smarc }
19947125Sbostic numeof++;
20047125Sbostic } else if (n != NULL && nflag == 0) {
20155277Smarc job_warning = (job_warning == 2) ? 1 : 0;
20255278Smarc numeof = 0;
20347125Sbostic evaltree(n, 0);
20447125Sbostic }
20547125Sbostic popstackmark(&smark);
20647125Sbostic }
20747125Sbostic popstackmark(&smark); /* unnecessary */
20847125Sbostic }
20947125Sbostic
21047125Sbostic
21147125Sbostic
21247125Sbostic /*
21347125Sbostic * Read /etc/profile or .profile. Return on error.
21447125Sbostic */
21547125Sbostic
21647125Sbostic STATIC void
read_profile(name)21747125Sbostic read_profile(name)
21847125Sbostic char *name;
21947125Sbostic {
22047125Sbostic int fd;
22147125Sbostic
22247125Sbostic INTOFF;
22347125Sbostic if ((fd = open(name, O_RDONLY)) >= 0)
22447125Sbostic setinputfd(fd, 1);
22547125Sbostic INTON;
22647125Sbostic if (fd < 0)
22747125Sbostic return;
22847125Sbostic cmdloop(0);
22947125Sbostic popfile();
23047125Sbostic }
23147125Sbostic
23247125Sbostic
23347125Sbostic
23447125Sbostic /*
23547125Sbostic * Read a file containing shell functions.
23647125Sbostic */
23747125Sbostic
23847125Sbostic void
readcmdfile(name)23947125Sbostic readcmdfile(name)
24047125Sbostic char *name;
24169272Schristos {
24247125Sbostic int fd;
24347125Sbostic
24447125Sbostic INTOFF;
24547125Sbostic if ((fd = open(name, O_RDONLY)) >= 0)
24647125Sbostic setinputfd(fd, 1);
24747125Sbostic else
24847125Sbostic error("Can't open %s", name);
24947125Sbostic INTON;
25047125Sbostic cmdloop(0);
25147125Sbostic popfile();
25247125Sbostic }
25347125Sbostic
25447125Sbostic
25547125Sbostic
25647125Sbostic /*
25747125Sbostic * Take commands from a file. To be compatable we should do a path
25868926Sbostic * search for the file, which is necessary to find sub-commands.
25947125Sbostic */
26047125Sbostic
26168926Sbostic
26269272Schristos STATIC char *
find_dot_file(basename)26369272Schristos find_dot_file(basename)
26469272Schristos char *basename;
26569272Schristos {
26668926Sbostic static char localname[FILENAME_MAX+1];
26768926Sbostic char *fullname;
26868926Sbostic char *path = pathval();
26968926Sbostic struct stat statb;
27068926Sbostic
27168926Sbostic /* don't try this for absolute or relative paths */
27268926Sbostic if( strchr(basename, '/'))
27368926Sbostic return basename;
27468926Sbostic
27568926Sbostic while ((fullname = padvance(&path, basename)) != NULL) {
27668926Sbostic strcpy(localname, fullname);
27768926Sbostic stunalloc(fullname);
27868926Sbostic if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode))
27968926Sbostic return localname;
28068926Sbostic }
28168926Sbostic return basename;
28268926Sbostic }
28368926Sbostic
28469272Schristos int
dotcmd(argc,argv)28569272Schristos dotcmd(argc, argv)
28669272Schristos int argc;
28769272Schristos char **argv;
28869272Schristos {
289*69749Schristos struct strlist *sp;
29047125Sbostic exitstatus = 0;
291*69749Schristos
292*69749Schristos for (sp = cmdenviron; sp ; sp = sp->next)
293*69749Schristos setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED);
294*69749Schristos
29547125Sbostic if (argc >= 2) { /* That's what SVR2 does */
29668926Sbostic char *fullname = find_dot_file(argv[1]);
297*69749Schristos
29868926Sbostic setinputfile(fullname, 1);
29968926Sbostic commandname = fullname;
30047125Sbostic cmdloop(0);
30147125Sbostic popfile();
30247125Sbostic }
30347125Sbostic return exitstatus;
30447125Sbostic }
30547125Sbostic
30647125Sbostic
30769272Schristos int
exitcmd(argc,argv)30869272Schristos exitcmd(argc, argv)
30969272Schristos int argc;
31069272Schristos char **argv;
31169272Schristos {
31255277Smarc if (stoppedjobs())
31369272Schristos return 0;
31447125Sbostic if (argc > 1)
31547125Sbostic exitstatus = number(argv[1]);
31647125Sbostic exitshell(exitstatus);
31769272Schristos /*NOTREACHED*/
31869272Schristos return 0;
31947125Sbostic }
32047125Sbostic
32147125Sbostic
32247125Sbostic #ifdef notdef
32347125Sbostic /*
32447125Sbostic * Should never be called.
32547125Sbostic */
32647125Sbostic
32747125Sbostic void
exit(exitstatus)32847125Sbostic exit(exitstatus) {
32947125Sbostic _exit(exitstatus);
33047125Sbostic }
33147125Sbostic #endif
332