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