1*47125Sbostic /*- 2*47125Sbostic * Copyright (c) 1991 The Regents of the University of California. 3*47125Sbostic * All rights reserved. 4*47125Sbostic * 5*47125Sbostic * This code is derived from software contributed to Berkeley by 6*47125Sbostic * Kenneth Almquist. 7*47125Sbostic * 8*47125Sbostic * %sccs.include.redist.c% 9*47125Sbostic */ 10*47125Sbostic 11*47125Sbostic #ifndef lint 12*47125Sbostic char copyright[] = 13*47125Sbostic "@(#) Copyright (c) 1991 The Regents of the University of California.\n\ 14*47125Sbostic All rights reserved.\n"; 15*47125Sbostic #endif /* not lint */ 16*47125Sbostic 17*47125Sbostic #ifndef lint 18*47125Sbostic static char sccsid[] = "@(#)main.c 5.1 (Berkeley) 03/07/91"; 19*47125Sbostic #endif /* not lint */ 20*47125Sbostic 21*47125Sbostic #include <signal.h> 22*47125Sbostic #include <fcntl.h> 23*47125Sbostic #include "shell.h" 24*47125Sbostic #include "main.h" 25*47125Sbostic #include "mail.h" 26*47125Sbostic #include "options.h" 27*47125Sbostic #include "output.h" 28*47125Sbostic #include "parser.h" 29*47125Sbostic #include "nodes.h" 30*47125Sbostic #include "eval.h" 31*47125Sbostic #include "jobs.h" 32*47125Sbostic #include "input.h" 33*47125Sbostic #include "trap.h" 34*47125Sbostic #if ATTY 35*47125Sbostic #include "var.h" 36*47125Sbostic #endif 37*47125Sbostic #include "memalloc.h" 38*47125Sbostic #include "error.h" 39*47125Sbostic #include "init.h" 40*47125Sbostic #include "mystring.h" 41*47125Sbostic 42*47125Sbostic #define PROFILE 0 43*47125Sbostic 44*47125Sbostic int rootpid; 45*47125Sbostic int rootshell; 46*47125Sbostic STATIC union node *curcmd; 47*47125Sbostic STATIC union node *prevcmd; 48*47125Sbostic extern int errno; 49*47125Sbostic #if PROFILE 50*47125Sbostic short profile_buf[16384]; 51*47125Sbostic extern int etext(); 52*47125Sbostic #endif 53*47125Sbostic 54*47125Sbostic #ifdef __STDC__ 55*47125Sbostic STATIC void read_profile(char *); 56*47125Sbostic char *getenv(char *); 57*47125Sbostic #else 58*47125Sbostic STATIC void read_profile(); 59*47125Sbostic char *getenv(); 60*47125Sbostic #endif 61*47125Sbostic 62*47125Sbostic 63*47125Sbostic /* 64*47125Sbostic * Main routine. We initialize things, parse the arguments, execute 65*47125Sbostic * profiles if we're a login shell, and then call cmdloop to execute 66*47125Sbostic * commands. The setjmp call sets up the location to jump to when an 67*47125Sbostic * exception occurs. When an exception occurs the variable "state" 68*47125Sbostic * is used to figure out how far we had gotten. 69*47125Sbostic */ 70*47125Sbostic 71*47125Sbostic main(argc, argv) char **argv; { 72*47125Sbostic struct jmploc jmploc; 73*47125Sbostic struct stackmark smark; 74*47125Sbostic volatile int state; 75*47125Sbostic char *shinit; 76*47125Sbostic 77*47125Sbostic #if PROFILE 78*47125Sbostic monitor(4, etext, profile_buf, sizeof profile_buf, 50); 79*47125Sbostic #endif 80*47125Sbostic state = 0; 81*47125Sbostic if (setjmp(jmploc.loc)) { 82*47125Sbostic /* 83*47125Sbostic * When a shell procedure is executed, we raise the 84*47125Sbostic * exception EXSHELLPROC to clean up before executing 85*47125Sbostic * the shell procedure. 86*47125Sbostic */ 87*47125Sbostic if (exception == EXSHELLPROC) { 88*47125Sbostic rootpid = getpid(); 89*47125Sbostic rootshell = 1; 90*47125Sbostic minusc = NULL; 91*47125Sbostic state = 3; 92*47125Sbostic } else if (state == 0 || iflag == 0 || ! rootshell) 93*47125Sbostic exitshell(2); 94*47125Sbostic reset(); 95*47125Sbostic #if ATTY 96*47125Sbostic if (exception == EXINT 97*47125Sbostic && (! attyset() || equal(termval(), "emacs"))) { 98*47125Sbostic #else 99*47125Sbostic if (exception == EXINT) { 100*47125Sbostic #endif 101*47125Sbostic out2c('\n'); 102*47125Sbostic flushout(&errout); 103*47125Sbostic } 104*47125Sbostic popstackmark(&smark); 105*47125Sbostic FORCEINTON; /* enable interrupts */ 106*47125Sbostic if (state == 1) 107*47125Sbostic goto state1; 108*47125Sbostic else if (state == 2) 109*47125Sbostic goto state2; 110*47125Sbostic else 111*47125Sbostic goto state3; 112*47125Sbostic } 113*47125Sbostic handler = &jmploc; 114*47125Sbostic #ifdef DEBUG 115*47125Sbostic opentrace(); 116*47125Sbostic trputs("Shell args: "); trargs(argv); 117*47125Sbostic #endif 118*47125Sbostic rootpid = getpid(); 119*47125Sbostic rootshell = 1; 120*47125Sbostic init(); 121*47125Sbostic setstackmark(&smark); 122*47125Sbostic procargs(argc, argv); 123*47125Sbostic if (argv[0] && argv[0][0] == '-') { 124*47125Sbostic state = 1; 125*47125Sbostic read_profile("/etc/profile"); 126*47125Sbostic state1: 127*47125Sbostic state = 2; 128*47125Sbostic read_profile(".profile"); 129*47125Sbostic } else if ((sflag || minusc) && (shinit = getenv("SHINIT")) != NULL) { 130*47125Sbostic state = 2; 131*47125Sbostic evalstring(shinit); 132*47125Sbostic } 133*47125Sbostic state2: 134*47125Sbostic state = 3; 135*47125Sbostic if (minusc) { 136*47125Sbostic evalstring(minusc); 137*47125Sbostic } 138*47125Sbostic if (sflag || minusc == NULL) { 139*47125Sbostic state3: 140*47125Sbostic cmdloop(1); 141*47125Sbostic } 142*47125Sbostic #if PROFILE 143*47125Sbostic monitor(0); 144*47125Sbostic #endif 145*47125Sbostic exitshell(exitstatus); 146*47125Sbostic } 147*47125Sbostic 148*47125Sbostic 149*47125Sbostic /* 150*47125Sbostic * Read and execute commands. "Top" is nonzero for the top level command 151*47125Sbostic * loop; it turns on prompting if the shell is interactive. 152*47125Sbostic */ 153*47125Sbostic 154*47125Sbostic void 155*47125Sbostic cmdloop(top) { 156*47125Sbostic union node *n; 157*47125Sbostic struct stackmark smark; 158*47125Sbostic int inter; 159*47125Sbostic int numeof; 160*47125Sbostic 161*47125Sbostic TRACE(("cmdloop(%d) called\n", top)); 162*47125Sbostic setstackmark(&smark); 163*47125Sbostic numeof = 0; 164*47125Sbostic for (;;) { 165*47125Sbostic if (pendingsigs) 166*47125Sbostic dotrap(); 167*47125Sbostic inter = 0; 168*47125Sbostic if (iflag && top) { 169*47125Sbostic inter++; 170*47125Sbostic showjobs(1); 171*47125Sbostic chkmail(0); 172*47125Sbostic flushout(&output); 173*47125Sbostic } 174*47125Sbostic n = parsecmd(inter); 175*47125Sbostic #ifdef DEBUG 176*47125Sbostic /* BROKEN - FIX showtree(n); */ 177*47125Sbostic #endif 178*47125Sbostic if (n == NEOF) { 179*47125Sbostic if (Iflag == 0 || numeof >= 50) 180*47125Sbostic break; 181*47125Sbostic out2str("\nUse \"exit\" to leave shell.\n"); 182*47125Sbostic numeof++; 183*47125Sbostic } else if (n != NULL && nflag == 0) { 184*47125Sbostic if (inter) { 185*47125Sbostic INTOFF; 186*47125Sbostic if (prevcmd) 187*47125Sbostic freefunc(prevcmd); 188*47125Sbostic prevcmd = curcmd; 189*47125Sbostic curcmd = copyfunc(n); 190*47125Sbostic INTON; 191*47125Sbostic } 192*47125Sbostic evaltree(n, 0); 193*47125Sbostic #ifdef notdef 194*47125Sbostic if (exitstatus) /*DEBUG*/ 195*47125Sbostic outfmt(&errout, "Exit status 0x%X\n", exitstatus); 196*47125Sbostic #endif 197*47125Sbostic } 198*47125Sbostic popstackmark(&smark); 199*47125Sbostic } 200*47125Sbostic popstackmark(&smark); /* unnecessary */ 201*47125Sbostic } 202*47125Sbostic 203*47125Sbostic 204*47125Sbostic 205*47125Sbostic /* 206*47125Sbostic * Read /etc/profile or .profile. Return on error. 207*47125Sbostic */ 208*47125Sbostic 209*47125Sbostic STATIC void 210*47125Sbostic read_profile(name) 211*47125Sbostic char *name; 212*47125Sbostic { 213*47125Sbostic int fd; 214*47125Sbostic 215*47125Sbostic INTOFF; 216*47125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 217*47125Sbostic setinputfd(fd, 1); 218*47125Sbostic INTON; 219*47125Sbostic if (fd < 0) 220*47125Sbostic return; 221*47125Sbostic cmdloop(0); 222*47125Sbostic popfile(); 223*47125Sbostic } 224*47125Sbostic 225*47125Sbostic 226*47125Sbostic 227*47125Sbostic /* 228*47125Sbostic * Read a file containing shell functions. 229*47125Sbostic */ 230*47125Sbostic 231*47125Sbostic void 232*47125Sbostic readcmdfile(name) 233*47125Sbostic char *name; 234*47125Sbostic { 235*47125Sbostic int fd; 236*47125Sbostic 237*47125Sbostic INTOFF; 238*47125Sbostic if ((fd = open(name, O_RDONLY)) >= 0) 239*47125Sbostic setinputfd(fd, 1); 240*47125Sbostic else 241*47125Sbostic error("Can't open %s", name); 242*47125Sbostic INTON; 243*47125Sbostic cmdloop(0); 244*47125Sbostic popfile(); 245*47125Sbostic } 246*47125Sbostic 247*47125Sbostic 248*47125Sbostic 249*47125Sbostic /* 250*47125Sbostic * Take commands from a file. To be compatable we should do a path 251*47125Sbostic * search for the file, but a path search doesn't make any sense. 252*47125Sbostic */ 253*47125Sbostic 254*47125Sbostic dotcmd(argc, argv) char **argv; { 255*47125Sbostic exitstatus = 0; 256*47125Sbostic if (argc >= 2) { /* That's what SVR2 does */ 257*47125Sbostic setinputfile(argv[1], 1); 258*47125Sbostic commandname = argv[1]; 259*47125Sbostic cmdloop(0); 260*47125Sbostic popfile(); 261*47125Sbostic } 262*47125Sbostic return exitstatus; 263*47125Sbostic } 264*47125Sbostic 265*47125Sbostic 266*47125Sbostic exitcmd(argc, argv) char **argv; { 267*47125Sbostic if (argc > 1) 268*47125Sbostic exitstatus = number(argv[1]); 269*47125Sbostic exitshell(exitstatus); 270*47125Sbostic } 271*47125Sbostic 272*47125Sbostic 273*47125Sbostic lccmd(argc, argv) char **argv; { 274*47125Sbostic if (argc > 1) { 275*47125Sbostic defun(argv[1], prevcmd); 276*47125Sbostic return 0; 277*47125Sbostic } else { 278*47125Sbostic INTOFF; 279*47125Sbostic freefunc(curcmd); 280*47125Sbostic curcmd = prevcmd; 281*47125Sbostic prevcmd = NULL; 282*47125Sbostic INTON; 283*47125Sbostic evaltree(curcmd, 0); 284*47125Sbostic return exitstatus; 285*47125Sbostic } 286*47125Sbostic } 287*47125Sbostic 288*47125Sbostic 289*47125Sbostic 290*47125Sbostic #ifdef notdef 291*47125Sbostic /* 292*47125Sbostic * Should never be called. 293*47125Sbostic */ 294*47125Sbostic 295*47125Sbostic void 296*47125Sbostic exit(exitstatus) { 297*47125Sbostic _exit(exitstatus); 298*47125Sbostic } 299*47125Sbostic #endif 300