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.4 (Berkeley) 07/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 ATTY 94 if (exception == EXINT 95 && (! attyset() || equal(termval(), "emacs"))) { 96 #else 97 if (exception == EXINT) { 98 #endif 99 out2c('\n'); 100 flushout(&errout); 101 } 102 popstackmark(&smark); 103 FORCEINTON; /* enable interrupts */ 104 if (state == 1) 105 goto state1; 106 else if (state == 2) 107 goto state2; 108 else if (state == 3) 109 goto state3; 110 else 111 goto state4; 112 } 113 handler = &jmploc; 114 #ifdef DEBUG 115 opentrace(); 116 trputs("Shell args: "); trargs(argv); 117 #endif 118 rootpid = getpid(); 119 rootshell = 1; 120 init(); 121 setstackmark(&smark); 122 procargs(argc, argv); 123 if (argv[0] && argv[0][0] == '-') { 124 state = 1; 125 read_profile("/etc/profile"); 126 state1: 127 state = 2; 128 read_profile(".profile"); 129 } 130 state2: 131 state = 3; 132 if ((sflag || minusc) && (shinit = lookupvar("ENV")) != NULL && 133 *shinit != '\0') { 134 state = 3; 135 read_profile(shinit); 136 } 137 state3: 138 state = 4; 139 if (minusc) { 140 evalstring(minusc); 141 } 142 if (sflag || minusc == NULL) { 143 state4: /* XXX ??? - why isn't this before the "if" statement */ 144 cmdloop(1); 145 } 146 #if PROFILE 147 monitor(0); 148 #endif 149 exitshell(exitstatus); 150 } 151 152 153 /* 154 * Read and execute commands. "Top" is nonzero for the top level command 155 * loop; it turns on prompting if the shell is interactive. 156 */ 157 158 void 159 cmdloop(top) { 160 union node *n; 161 struct stackmark smark; 162 int inter; 163 int numeof; 164 165 TRACE(("cmdloop(%d) called\n", top)); 166 setstackmark(&smark); 167 numeof = 0; 168 for (;;) { 169 if (pendingsigs) 170 dotrap(); 171 inter = 0; 172 if (iflag && top) { 173 inter++; 174 showjobs(1); 175 chkmail(0); 176 flushout(&output); 177 } 178 n = parsecmd(inter); 179 #ifdef DEBUG 180 /* showtree(n); */ 181 #endif 182 if (n == NEOF) { 183 if (Iflag == 0 || !top || numeof >= 50) 184 break; 185 out2str("\nUse \"exit\" to leave shell.\n"); 186 numeof++; 187 } else if (n != NULL && nflag == 0) { 188 if (inter) { 189 INTOFF; 190 if (prevcmd) 191 freefunc(prevcmd); 192 prevcmd = curcmd; 193 curcmd = copyfunc(n); 194 INTON; 195 } 196 evaltree(n, 0); 197 #ifdef notdef 198 if (exitstatus) /*DEBUG*/ 199 outfmt(&errout, "Exit status 0x%X\n", exitstatus); 200 #endif 201 } 202 popstackmark(&smark); 203 } 204 popstackmark(&smark); /* unnecessary */ 205 } 206 207 208 209 /* 210 * Read /etc/profile or .profile. Return on error. 211 */ 212 213 STATIC void 214 read_profile(name) 215 char *name; 216 { 217 int fd; 218 219 INTOFF; 220 if ((fd = open(name, O_RDONLY)) >= 0) 221 setinputfd(fd, 1); 222 INTON; 223 if (fd < 0) 224 return; 225 cmdloop(0); 226 popfile(); 227 } 228 229 230 231 /* 232 * Read a file containing shell functions. 233 */ 234 235 void 236 readcmdfile(name) 237 char *name; 238 { 239 int fd; 240 241 INTOFF; 242 if ((fd = open(name, O_RDONLY)) >= 0) 243 setinputfd(fd, 1); 244 else 245 error("Can't open %s", name); 246 INTON; 247 cmdloop(0); 248 popfile(); 249 } 250 251 252 253 /* 254 * Take commands from a file. To be compatable we should do a path 255 * search for the file, but a path search doesn't make any sense. 256 */ 257 258 dotcmd(argc, argv) char **argv; { 259 exitstatus = 0; 260 if (argc >= 2) { /* That's what SVR2 does */ 261 setinputfile(argv[1], 1); 262 commandname = argv[1]; 263 cmdloop(0); 264 popfile(); 265 } 266 return exitstatus; 267 } 268 269 270 exitcmd(argc, argv) char **argv; { 271 if (argc > 1) 272 exitstatus = number(argv[1]); 273 exitshell(exitstatus); 274 } 275 276 277 lccmd(argc, argv) char **argv; { 278 if (argc > 1) { 279 defun(argv[1], prevcmd); 280 return 0; 281 } else { 282 INTOFF; 283 freefunc(curcmd); 284 curcmd = prevcmd; 285 prevcmd = NULL; 286 INTON; 287 evaltree(curcmd, 0); 288 return exitstatus; 289 } 290 } 291 292 293 294 #ifdef notdef 295 /* 296 * Should never be called. 297 */ 298 299 void 300 exit(exitstatus) { 301 _exit(exitstatus); 302 } 303 #endif 304