main.c revision 20425
1/*- 2 * Copyright (c) 1991, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * This code is derived from software contributed to Berkeley by 6 * Kenneth Almquist. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 1. Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * 2. Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in the 15 * documentation and/or other materials provided with the distribution. 16 * 3. All advertising materials mentioning features or use of this software 17 * must display the following acknowledgement: 18 * This product includes software developed by the University of 19 * California, Berkeley and its contributors. 20 * 4. Neither the name of the University nor the names of its contributors 21 * may be used to endorse or promote products derived from this software 22 * without specific prior written permission. 23 * 24 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34 * SUCH DAMAGE. 35 * 36 * $Id: main.c,v 1.9 1996/10/29 03:12:47 steve Exp $ 37 */ 38 39#ifndef lint 40static char const copyright[] = 41"@(#) Copyright (c) 1991, 1993\n\ 42 The Regents of the University of California. All rights reserved.\n"; 43#endif /* not lint */ 44 45#ifndef lint 46static char const sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 47#endif /* not lint */ 48 49#include <stdio.h> 50#include <signal.h> 51#include <sys/stat.h> 52#include <unistd.h> 53#include <fcntl.h> 54#include <locale.h> 55 56 57#include "shell.h" 58#include "main.h" 59#include "mail.h" 60#include "options.h" 61#include "output.h" 62#include "parser.h" 63#include "nodes.h" 64#include "expand.h" 65#include "eval.h" 66#include "jobs.h" 67#include "input.h" 68#include "trap.h" 69#include "var.h" 70#include "show.h" 71#include "memalloc.h" 72#include "error.h" 73#include "init.h" 74#include "mystring.h" 75#include "exec.h" 76#include "cd.h" 77 78#define PROFILE 0 79 80int rootpid; 81int rootshell; 82extern int errno; 83#if PROFILE 84short profile_buf[16384]; 85extern int etext(); 86#endif 87 88STATIC void read_profile __P((char *)); 89STATIC char *find_dot_file __P((char *)); 90 91/* 92 * Main routine. We initialize things, parse the arguments, execute 93 * profiles if we're a login shell, and then call cmdloop to execute 94 * commands. The setjmp call sets up the location to jump to when an 95 * exception occurs. When an exception occurs the variable "state" 96 * is used to figure out how far we had gotten. 97 */ 98 99int 100main(argc, argv) 101 int argc; 102 char **argv; 103{ 104 struct jmploc jmploc; 105 struct stackmark smark; 106 volatile int state; 107 char *shinit; 108 109#if PROFILE 110 monitor(4, etext, profile_buf, sizeof profile_buf, 50); 111#endif 112 (void) setlocale(LC_ALL, ""); 113 state = 0; 114 if (setjmp(jmploc.loc)) { 115 /* 116 * When a shell procedure is executed, we raise the 117 * exception EXSHELLPROC to clean up before executing 118 * the shell procedure. 119 */ 120 switch (exception) { 121 case EXSHELLPROC: 122 rootpid = getpid(); 123 rootshell = 1; 124 minusc = NULL; 125 state = 3; 126 break; 127 128 case EXEXEC: 129 exitstatus = exerrno; 130 break; 131 132 case EXERROR: 133 exitstatus = 2; 134 break; 135 136 default: 137 break; 138 } 139 140 if (exception != EXSHELLPROC) { 141 if (state == 0 || iflag == 0 || ! rootshell) 142 exitshell(exitstatus); 143 } 144 reset(); 145 if (exception == EXINT 146#if ATTY 147 && (! attyset() || equal(termval(), "emacs")) 148#endif 149 ) { 150 out2c('\n'); 151 flushout(&errout); 152 } 153 popstackmark(&smark); 154 FORCEINTON; /* enable interrupts */ 155 if (state == 1) 156 goto state1; 157 else if (state == 2) 158 goto state2; 159 else if (state == 3) 160 goto state3; 161 else 162 goto state4; 163 } 164 handler = &jmploc; 165#ifdef DEBUG 166 opentrace(); 167 trputs("Shell args: "); trargs(argv); 168#endif 169 rootpid = getpid(); 170 rootshell = 1; 171 init(); 172 setstackmark(&smark); 173 procargs(argc, argv); 174 getpwd(); 175 if (argv[0] && argv[0][0] == '-') { 176 state = 1; 177 read_profile("/etc/profile"); 178state1: 179 state = 2; 180 if (privileged == 0) 181 read_profile(".profile"); 182 else 183 read_profile("/etc/suid_profile"); 184 } 185state2: 186 state = 3; 187 if (privileged == 0) { 188 if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 189 state = 3; 190 read_profile(shinit); 191 } 192 } 193state3: 194 state = 4; 195 if (minusc) { 196 evalstring(minusc); 197 } 198 if (sflag || minusc == NULL) { 199state4: /* XXX ??? - why isn't this before the "if" statement */ 200 cmdloop(1); 201 } 202#if PROFILE 203 monitor(0); 204#endif 205 exitshell(exitstatus); 206 /*NOTREACHED*/ 207 return 0; 208} 209 210 211/* 212 * Read and execute commands. "Top" is nonzero for the top level command 213 * loop; it turns on prompting if the shell is interactive. 214 */ 215 216void 217cmdloop(top) 218 int top; 219{ 220 union node *n; 221 struct stackmark smark; 222 int inter; 223 int numeof = 0; 224 225 TRACE(("cmdloop(%d) called\n", top)); 226 setstackmark(&smark); 227 for (;;) { 228 if (pendingsigs) 229 dotrap(); 230 inter = 0; 231 if (iflag && top) { 232 inter++; 233 showjobs(1); 234 chkmail(0); 235 flushout(&output); 236 } 237 n = parsecmd(inter); 238 /* showtree(n); DEBUG */ 239 if (n == NEOF) { 240 if (!top || numeof >= 50) 241 break; 242 if (!stoppedjobs()) { 243 if (!Iflag) 244 break; 245 out2str("\nUse \"exit\" to leave shell.\n"); 246 } 247 numeof++; 248 } else if (n != NULL && nflag == 0) { 249 job_warning = (job_warning == 2) ? 1 : 0; 250 numeof = 0; 251 evaltree(n, 0); 252 } 253 popstackmark(&smark); 254 if (evalskip == SKIPFILE) { 255 evalskip = 0; 256 break; 257 } 258 } 259 popstackmark(&smark); /* unnecessary */ 260} 261 262 263 264/* 265 * Read /etc/profile or .profile. Return on error. 266 */ 267 268STATIC void 269read_profile(name) 270 char *name; 271 { 272 int fd; 273 274 INTOFF; 275 if ((fd = open(name, O_RDONLY)) >= 0) 276 setinputfd(fd, 1); 277 INTON; 278 if (fd < 0) 279 return; 280 cmdloop(0); 281 popfile(); 282} 283 284 285 286/* 287 * Read a file containing shell functions. 288 */ 289 290void 291readcmdfile(name) 292 char *name; 293{ 294 int fd; 295 296 INTOFF; 297 if ((fd = open(name, O_RDONLY)) >= 0) 298 setinputfd(fd, 1); 299 else 300 error("Can't open %s", name); 301 INTON; 302 cmdloop(0); 303 popfile(); 304} 305 306 307 308/* 309 * Take commands from a file. To be compatable we should do a path 310 * search for the file, which is necessary to find sub-commands. 311 */ 312 313 314STATIC char * 315find_dot_file(basename) 316 char *basename; 317{ 318 static char localname[FILENAME_MAX+1]; 319 char *fullname; 320 char *path = pathval(); 321 struct stat statb; 322 323 /* don't try this for absolute or relative paths */ 324 if( strchr(basename, '/')) 325 return basename; 326 327 while ((fullname = padvance(&path, basename)) != NULL) { 328 strcpy(localname, fullname); 329 stunalloc(fullname); 330 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 331 return localname; 332 } 333 return basename; 334} 335 336int 337dotcmd(argc, argv) 338 int argc; 339 char **argv; 340{ 341 struct strlist *sp; 342 exitstatus = 0; 343 344 for (sp = cmdenviron; sp ; sp = sp->next) 345 setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); 346 347 if (argc >= 2) { /* That's what SVR2 does */ 348 char *fullname = find_dot_file(argv[1]); 349 350 setinputfile(fullname, 1); 351 commandname = fullname; 352 cmdloop(0); 353 popfile(); 354 } 355 return exitstatus; 356} 357 358 359int 360exitcmd(argc, argv) 361 int argc; 362 char **argv; 363{ 364 extern int oexitstatus; 365 366 if (stoppedjobs()) 367 return 0; 368 if (argc > 1) 369 exitstatus = number(argv[1]); 370 else 371 exitstatus = oexitstatus; 372 exitshell(exitstatus); 373 /*NOTREACHED*/ 374 return 0; 375} 376 377 378#ifdef notdef 379/* 380 * Should never be called. 381 */ 382 383void 384exit(exitstatus) { 385 _exit(exitstatus); 386} 387#endif 388