main.c revision 22988
1235911Smav/*- 2235911Smav * Copyright (c) 1991, 1993 3235911Smav * The Regents of the University of California. All rights reserved. 4235911Smav * 5235911Smav * This code is derived from software contributed to Berkeley by 6235911Smav * Kenneth Almquist. 7235911Smav * 8235911Smav * Redistribution and use in source and binary forms, with or without 9235911Smav * modification, are permitted provided that the following conditions 10235911Smav * are met: 11235911Smav * 1. Redistributions of source code must retain the above copyright 12235911Smav * notice, this list of conditions and the following disclaimer. 13235911Smav * 2. Redistributions in binary form must reproduce the above copyright 14235911Smav * notice, this list of conditions and the following disclaimer in the 15235911Smav * documentation and/or other materials provided with the distribution. 16235911Smav * 3. All advertising materials mentioning features or use of this software 17235911Smav * must display the following acknowledgement: 18235911Smav * This product includes software developed by the University of 19235911Smav * California, Berkeley and its contributors. 20235911Smav * 4. Neither the name of the University nor the names of its contributors 21235911Smav * may be used to endorse or promote products derived from this software 22235911Smav * without specific prior written permission. 23235911Smav * 24235911Smav * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25235911Smav * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26235911Smav * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27235911Smav * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28235911Smav * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29235911Smav * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 30235911Smav * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31235911Smav * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32235911Smav * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33235911Smav * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34235911Smav * SUCH DAMAGE. 35235911Smav * 36235911Smav * $Id$ 37235911Smav */ 38235911Smav 39235911Smav#ifndef lint 40235911Smavstatic char const copyright[] = 41235911Smav"@(#) Copyright (c) 1991, 1993\n\ 42235911Smav The Regents of the University of California. All rights reserved.\n"; 43235911Smav#endif /* not lint */ 44235911Smav 45235911Smav#ifndef lint 46235911Smavstatic char const sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 47235911Smav#endif /* not lint */ 48235911Smav 49235911Smav#include <stdio.h> 50235911Smav#include <signal.h> 51235911Smav#include <sys/stat.h> 52235911Smav#include <unistd.h> 53235911Smav#include <fcntl.h> 54235911Smav#include <locale.h> 55235911Smav 56235911Smav 57235911Smav#include "shell.h" 58235911Smav#include "main.h" 59235911Smav#include "mail.h" 60235911Smav#include "options.h" 61235911Smav#include "output.h" 62235911Smav#include "parser.h" 63235911Smav#include "nodes.h" 64235911Smav#include "expand.h" 65235911Smav#include "eval.h" 66235911Smav#include "jobs.h" 67235911Smav#include "input.h" 68235911Smav#include "trap.h" 69235911Smav#include "var.h" 70235911Smav#include "show.h" 71235911Smav#include "memalloc.h" 72235911Smav#include "error.h" 73235911Smav#include "init.h" 74235911Smav#include "mystring.h" 75235911Smav#include "exec.h" 76235911Smav#include "cd.h" 77235911Smav 78235911Smav#define PROFILE 0 79235911Smav 80235911Smavint rootpid; 81235911Smavint rootshell; 82235911Smavextern int errno; 83235911Smav#if PROFILE 84235911Smavshort profile_buf[16384]; 85235911Smavextern int etext(); 86235911Smav#endif 87235911Smav 88235911SmavSTATIC void read_profile __P((char *)); 89235911SmavSTATIC char *find_dot_file __P((char *)); 90235911Smav 91235911Smav/* 92235911Smav * Main routine. We initialize things, parse the arguments, execute 93235911Smav * profiles if we're a login shell, and then call cmdloop to execute 94235911Smav * commands. The setjmp call sets up the location to jump to when an 95235911Smav * exception occurs. When an exception occurs the variable "state" 96235911Smav * is used to figure out how far we had gotten. 97235911Smav */ 98235911Smav 99235911Smavint 100235911Smavmain(argc, argv) 101235911Smav int argc; 102235911Smav char **argv; 103235911Smav{ 104235911Smav struct jmploc jmploc; 105235911Smav struct stackmark smark; 106235911Smav volatile int state; 107235911Smav char *shinit; 108235911Smav 109235911Smav#if PROFILE 110235911Smav monitor(4, etext, profile_buf, sizeof profile_buf, 50); 111235911Smav#endif 112235911Smav (void) setlocale(LC_ALL, ""); 113235911Smav state = 0; 114235911Smav if (setjmp(jmploc.loc)) { 115235911Smav /* 116235911Smav * When a shell procedure is executed, we raise the 117235911Smav * exception EXSHELLPROC to clean up before executing 118235911Smav * the shell procedure. 119235911Smav */ 120235911Smav switch (exception) { 121235911Smav case EXSHELLPROC: 122235911Smav rootpid = getpid(); 123235911Smav rootshell = 1; 124235911Smav minusc = NULL; 125235911Smav state = 3; 126235911Smav break; 127235911Smav 128235911Smav case EXEXEC: 129235911Smav exitstatus = exerrno; 130235911Smav break; 131235911Smav 132235911Smav case EXERROR: 133235911Smav exitstatus = 2; 134235911Smav break; 135235911Smav 136235911Smav default: 137235911Smav break; 138235911Smav } 139235911Smav 140235911Smav if (exception != EXSHELLPROC) { 141235911Smav if (state == 0 || iflag == 0 || ! rootshell) 142235911Smav exitshell(exitstatus); 143235911Smav } 144235911Smav reset(); 145235911Smav if (exception == EXINT 146235911Smav#if ATTY 147235911Smav && (! attyset() || equal(termval(), "emacs")) 148235911Smav#endif 149235911Smav ) { 150235911Smav out2c('\n'); 151235911Smav flushout(&errout); 152235911Smav } 153235911Smav popstackmark(&smark); 154235911Smav FORCEINTON; /* enable interrupts */ 155235911Smav if (state == 1) 156235911Smav goto state1; 157235911Smav else if (state == 2) 158235911Smav goto state2; 159235911Smav else if (state == 3) 160235911Smav goto state3; 161235911Smav else 162235911Smav goto state4; 163235911Smav } 164235911Smav handler = &jmploc; 165235911Smav#ifdef DEBUG 166235911Smav opentrace(); 167235911Smav trputs("Shell args: "); trargs(argv); 168235911Smav#endif 169235911Smav rootpid = getpid(); 170235911Smav rootshell = 1; 171235911Smav init(); 172235911Smav setstackmark(&smark); 173235911Smav procargs(argc, argv); 174235911Smav if (getpwd() == NULL && iflag) 175235911Smav out2str("sh: cannot determine working directory\n"); 176235911Smav if (argv[0] && argv[0][0] == '-') { 177235911Smav state = 1; 178235911Smav read_profile("/etc/profile"); 179235911Smavstate1: 180235911Smav state = 2; 181235911Smav if (privileged == 0) 182235911Smav read_profile(".profile"); 183235911Smav else 184235911Smav read_profile("/etc/suid_profile"); 185235911Smav } 186235911Smavstate2: 187235911Smav state = 3; 188235911Smav if (privileged == 0) { 189235911Smav if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 190235911Smav state = 3; 191235911Smav read_profile(shinit); 192235911Smav } 193235911Smav } 194235911Smavstate3: 195235911Smav state = 4; 196235911Smav if (minusc) { 197235911Smav evalstring(minusc); 198235911Smav } 199235911Smav if (sflag || minusc == NULL) { 200235911Smavstate4: /* XXX ??? - why isn't this before the "if" statement */ 201235911Smav cmdloop(1); 202235911Smav } 203235911Smav#if PROFILE 204235911Smav monitor(0); 205235911Smav#endif 206235911Smav exitshell(exitstatus); 207235911Smav /*NOTREACHED*/ 208235911Smav return 0; 209235911Smav} 210235911Smav 211235911Smav 212235911Smav/* 213235911Smav * Read and execute commands. "Top" is nonzero for the top level command 214235911Smav * loop; it turns on prompting if the shell is interactive. 215235911Smav */ 216235911Smav 217235911Smavvoid 218235911Smavcmdloop(top) 219235911Smav int top; 220235911Smav{ 221235911Smav union node *n; 222235911Smav struct stackmark smark; 223239213Smjacob int inter; 224235911Smav int numeof = 0; 225235911Smav 226235911Smav TRACE(("cmdloop(%d) called\n", top)); 227235911Smav setstackmark(&smark); 228235911Smav for (;;) { 229235911Smav if (pendingsigs) 230235911Smav dotrap(); 231235911Smav inter = 0; 232235911Smav if (iflag && top) { 233235911Smav inter++; 234235911Smav showjobs(1); 235235911Smav chkmail(0); 236235911Smav flushout(&output); 237235911Smav } 238235911Smav n = parsecmd(inter); 239235911Smav /* showtree(n); DEBUG */ 240235911Smav if (n == NEOF) { 241235911Smav if (!top || numeof >= 50) 242235911Smav break; 243235911Smav if (!stoppedjobs()) { 244235911Smav if (!Iflag) 245235911Smav break; 246260387Sscottl out2str("\nUse \"exit\" to leave shell.\n"); 247235911Smav } 248235911Smav numeof++; 249235911Smav } else if (n != NULL && nflag == 0) { 250235911Smav job_warning = (job_warning == 2) ? 1 : 0; 251260387Sscottl numeof = 0; 252235911Smav evaltree(n, 0); 253235911Smav } 254235911Smav popstackmark(&smark); 255235911Smav if (evalskip == SKIPFILE) { 256235911Smav evalskip = 0; 257235911Smav break; 258235911Smav } 259235911Smav } 260235911Smav popstackmark(&smark); /* unnecessary */ 261235911Smav} 262235911Smav 263235911Smav 264235911Smav 265235911Smav/* 266235911Smav * Read /etc/profile or .profile. Return on error. 267235911Smav */ 268235911Smav 269235911SmavSTATIC void 270235911Smavread_profile(name) 271235911Smav char *name; 272239213Smjacob { 273235911Smav int fd; 274235911Smav 275235911Smav INTOFF; 276235911Smav if ((fd = open(name, O_RDONLY)) >= 0) 277235911Smav setinputfd(fd, 1); 278235911Smav INTON; 279235911Smav if (fd < 0) 280235911Smav return; 281235911Smav cmdloop(0); 282235911Smav popfile(); 283235911Smav} 284235911Smav 285235911Smav 286235911Smav 287235911Smav/* 288235911Smav * Read a file containing shell functions. 289235911Smav */ 290235911Smav 291235911Smavvoid 292235911Smavreadcmdfile(name) 293235911Smav char *name; 294235911Smav{ 295235911Smav int fd; 296235911Smav 297235911Smav INTOFF; 298235911Smav if ((fd = open(name, O_RDONLY)) >= 0) 299235911Smav setinputfd(fd, 1); 300235911Smav else 301235911Smav error("Can't open %s", name); 302235911Smav INTON; 303235911Smav cmdloop(0); 304235911Smav popfile(); 305235911Smav} 306235911Smav 307235911Smav 308235911Smav 309235911Smav/* 310235911Smav * Take commands from a file. To be compatable we should do a path 311235911Smav * search for the file, which is necessary to find sub-commands. 312235911Smav */ 313235911Smav 314235911Smav 315235911SmavSTATIC char * 316235911Smavfind_dot_file(basename) 317235911Smav char *basename; 318235911Smav{ 319235911Smav static char localname[FILENAME_MAX+1]; 320235911Smav char *fullname; 321235911Smav char *path = pathval(); 322235911Smav struct stat statb; 323235911Smav 324235911Smav /* don't try this for absolute or relative paths */ 325235911Smav if( strchr(basename, '/')) 326235911Smav return basename; 327235911Smav 328235911Smav while ((fullname = padvance(&path, basename)) != NULL) { 329235911Smav strcpy(localname, fullname); 330235911Smav stunalloc(fullname); 331235911Smav if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 332235911Smav return localname; 333235911Smav } 334235911Smav return basename; 335235911Smav} 336235911Smav 337235911Smavint 338235911Smavdotcmd(argc, argv) 339235911Smav int argc; 340235911Smav char **argv; 341235911Smav{ 342235911Smav struct strlist *sp; 343235911Smav exitstatus = 0; 344235911Smav 345235911Smav for (sp = cmdenviron; sp ; sp = sp->next) 346235911Smav setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); 347235911Smav 348235911Smav if (argc >= 2) { /* That's what SVR2 does */ 349235911Smav char *fullname = find_dot_file(argv[1]); 350235911Smav 351235911Smav setinputfile(fullname, 1); 352235911Smav commandname = fullname; 353235911Smav cmdloop(0); 354235911Smav popfile(); 355235911Smav } 356235911Smav return exitstatus; 357235911Smav} 358235911Smav 359235911Smav 360235911Smavint 361235911Smavexitcmd(argc, argv) 362235911Smav int argc; 363235911Smav char **argv; 364235911Smav{ 365235911Smav extern int oexitstatus; 366235911Smav 367235911Smav if (stoppedjobs()) 368235911Smav return 0; 369235911Smav if (argc > 1) 370235911Smav exitstatus = number(argv[1]); 371235911Smav else 372235911Smav exitstatus = oexitstatus; 373235911Smav exitshell(exitstatus); 374235911Smav /*NOTREACHED*/ 375235911Smav return 0; 376235911Smav} 377235911Smav 378235911Smav 379235911Smav#ifdef notdef 380235911Smav/* 381235911Smav * Should never be called. 382235911Smav */ 383235911Smav 384235911Smavvoid 385235911Smavexit(exitstatus) { 386235911Smav _exit(exitstatus); 387235911Smav} 388235911Smav#endif 389235911Smav