main.c revision 25471
1327Sjkh/*- 2327Sjkh * Copyright (c) 1991, 1993 3327Sjkh * The Regents of the University of California. All rights reserved. 4327Sjkh * 5327Sjkh * This code is derived from software contributed to Berkeley by 6327Sjkh * Kenneth Almquist. 7327Sjkh * 8327Sjkh * Redistribution and use in source and binary forms, with or without 9327Sjkh * modification, are permitted provided that the following conditions 10327Sjkh * are met: 11327Sjkh * 1. Redistributions of source code must retain the above copyright 12327Sjkh * notice, this list of conditions and the following disclaimer. 13327Sjkh * 2. Redistributions in binary form must reproduce the above copyright 14327Sjkh * notice, this list of conditions and the following disclaimer in the 15327Sjkh * documentation and/or other materials provided with the distribution. 16327Sjkh * 3. All advertising materials mentioning features or use of this software 17327Sjkh * must display the following acknowledgement: 18327Sjkh * This product includes software developed by the University of 19327Sjkh * California, Berkeley and its contributors. 20327Sjkh * 4. Neither the name of the University nor the names of its contributors 2193520Sobrien * may be used to endorse or promote products derived from this software 2293520Sobrien * without specific prior written permission. 2393520Sobrien * 2430221Scharnier * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 25222035Sflz * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 26327Sjkh * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 27327Sjkh * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 28327Sjkh * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 29327Sjkh * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 3096613Ssobomax * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 31327Sjkh * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 32327Sjkh * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 33327Sjkh * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 34327Sjkh * SUCH DAMAGE. 35327Sjkh * 36327Sjkh * $Id: main.c,v 1.13 1997/02/22 13:58:33 peter Exp $ 3783663Ssobomax */ 3883663Ssobomax 3972694Ssobomax#ifndef lint 4083663Ssobomaxstatic char const copyright[] = 4183663Ssobomax"@(#) Copyright (c) 1991, 1993\n\ 42327Sjkh The Regents of the University of California. All rights reserved.\n"; 4373134Ssobomax#endif /* not lint */ 4473134Ssobomax 4573134Ssobomax#ifndef lint 4673134Ssobomaxstatic char const sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 4773134Ssobomax#endif /* not lint */ 4873134Ssobomax 4996613Ssobomax#include <stdio.h> 5096613Ssobomax#include <signal.h> 5196613Ssobomax#include <sys/stat.h> 5296613Ssobomax#include <unistd.h> 5396613Ssobomax#include <fcntl.h> 5496613Ssobomax#include <locale.h> 5596613Ssobomax 5696613Ssobomax 5796613Ssobomax#include "shell.h" 5896613Ssobomax#include "main.h" 5996613Ssobomax#include "mail.h" 6096613Ssobomax#include "options.h" 6173134Ssobomax#include "output.h" 6273134Ssobomax#include "parser.h" 6373134Ssobomax#include "nodes.h" 6473134Ssobomax#include "expand.h" 6573134Ssobomax#include "eval.h" 6673134Ssobomax#include "jobs.h" 67131275Seik#include "input.h" 6873134Ssobomax#include "trap.h" 6973134Ssobomax#include "var.h" 7073134Ssobomax#include "show.h" 7173134Ssobomax#include "memalloc.h" 7273134Ssobomax#include "error.h" 7373134Ssobomax#include "init.h" 7473134Ssobomax#include "mystring.h" 7573134Ssobomax#include "exec.h" 7674295Ssobomax#include "cd.h" 7772694Ssobomax 7883663Ssobomax#define PROFILE 0 7983663Ssobomax 8083663Ssobomaxint rootpid; 8183663Ssobomaxint rootshell; 8283663Ssobomaxextern int errno; 8383663Ssobomax#if PROFILE 8483663Ssobomaxshort profile_buf[16384]; 8583663Ssobomaxextern int etext(); 8683663Ssobomax#endif 8783663Ssobomax 8883663SsobomaxSTATIC void read_profile __P((char *)); 8983663SsobomaxSTATIC char *find_dot_file __P((char *)); 9083663Ssobomax 9196392Salfred/* 9283663Ssobomax * Main routine. We initialize things, parse the arguments, execute 9383663Ssobomax * profiles if we're a login shell, and then call cmdloop to execute 9483663Ssobomax * commands. The setjmp call sets up the location to jump to when an 9583663Ssobomax * exception occurs. When an exception occurs the variable "state" 9683663Ssobomax * is used to figure out how far we had gotten. 9783663Ssobomax */ 9896392Salfred 9983663Ssobomaxint 10083663Ssobomaxmain(argc, argv) 10183663Ssobomax int argc; 10283663Ssobomax char **argv; 10383663Ssobomax{ 10483663Ssobomax struct jmploc jmploc; 10583663Ssobomax struct stackmark smark; 10683663Ssobomax volatile int state; 10783663Ssobomax char *shinit; 10883663Ssobomax 10983663Ssobomax#if PROFILE 11083663Ssobomax monitor(4, etext, profile_buf, sizeof profile_buf, 50); 11183663Ssobomax#endif 112327Sjkh (void) setlocale(LC_ALL, ""); 11372694Ssobomax state = 0; 11472694Ssobomax if (setjmp(jmploc.loc)) { 115327Sjkh /* 116327Sjkh * When a shell procedure is executed, we raise the 117327Sjkh * exception EXSHELLPROC to clean up before executing 118327Sjkh * the shell procedure. 119327Sjkh */ 120327Sjkh switch (exception) { 121327Sjkh case EXSHELLPROC: 122327Sjkh rootpid = getpid(); 123327Sjkh rootshell = 1; 124327Sjkh minusc = NULL; 125178753Spav state = 3; 1261550Sasami break; 12796613Ssobomax 128131280Seik case EXEXEC: 12941866Sjkh exitstatus = exerrno; 130178103Spav break; 131111486Sdes 132111486Sdes case EXERROR: 13383663Ssobomax exitstatus = 2; 13483663Ssobomax break; 135206043Sflz 136206043Sflz default: 137327Sjkh break; 13841080Sjkh } 13941080Sjkh 14041080Sjkh if (exception != EXSHELLPROC) { 14141080Sjkh if (state == 0 || iflag == 0 || ! rootshell) 14241080Sjkh exitshell(exitstatus); 143327Sjkh } 144327Sjkh reset(); 145327Sjkh if (exception == EXINT 146327Sjkh#if ATTY 147131280Seik && (! attyset() || equal(termval(), "emacs")) 148131280Seik#endif 149131280Seik ) { 150131280Seik out2c('\n'); 15130221Scharnier flushout(&errout); 152327Sjkh } 153131280Seik popstackmark(&smark); 154131280Seik FORCEINTON; /* enable interrupts */ 155131280Seik if (state == 1) 156131280Seik goto state1; 157131280Seik else if (state == 2) 158131280Seik goto state2; 159131280Seik else if (state == 3) 160131280Seik goto state3; 161131280Seik else 162131280Seik goto state4; 163131280Seik } 164131280Seik handler = &jmploc; 165131280Seik#ifdef DEBUG 166131280Seik opentrace(); 167327Sjkh trputs("Shell args: "); trargs(argv); 16841866Sjkh#endif 16939068Sjkh rootpid = getpid(); 17039068Sjkh rootshell = 1; 17196392Salfred init(); 17239068Sjkh setstackmark(&smark); 17341866Sjkh procargs(argc, argv); 174327Sjkh if (getpwd() == NULL && iflag) 17530221Scharnier out2str("sh: cannot determine working directory\n"); 176327Sjkh if (argv[0] && argv[0][0] == '-') { 177327Sjkh state = 1; 17841866Sjkh read_profile("/etc/profile"); 17973134Ssobomaxstate1: 18073134Ssobomax state = 2; 18173134Ssobomax if (privileged == 0) 18273134Ssobomax read_profile(".profile"); 18373134Ssobomax else 18473134Ssobomax read_profile("/etc/suid_profile"); 18573134Ssobomax } 18673134Ssobomaxstate2: 18773134Ssobomax state = 3; 18873134Ssobomax if (!privileged && iflag) { 18973134Ssobomax if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 19073134Ssobomax state = 3; 19173134Ssobomax read_profile(shinit); 19283663Ssobomax } 19383663Ssobomax } 19483663Ssobomaxstate3: 19581046Ssobomax state = 4; 19683663Ssobomax if (minusc) { 19783663Ssobomax evalstring(minusc); 19883663Ssobomax } 19983663Ssobomax if (sflag || minusc == NULL) { 2004996Sjkhstate4: /* XXX ??? - why isn't this before the "if" statement */ 2014996Sjkh cmdloop(1); 2024996Sjkh } 20341866Sjkh#if PROFILE 204327Sjkh monitor(0); 205327Sjkh#endif 20641866Sjkh exitshell(exitstatus); 207327Sjkh /*NOTREACHED*/ 20830221Scharnier return 0; 209327Sjkh} 210327Sjkh 21141866Sjkh 212327Sjkh/* 213327Sjkh * Read and execute commands. "Top" is nonzero for the top level command 214327Sjkh * loop; it turns on prompting if the shell is interactive. 215327Sjkh */ 216327Sjkh 21723442Sjkhvoid 21841866Sjkhcmdloop(top) 21923442Sjkh int top; 22030221Scharnier{ 22123442Sjkh union node *n; 22223442Sjkh struct stackmark smark; 22341866Sjkh int inter; 22423442Sjkh int numeof = 0; 22541866Sjkh 226206043Sflz TRACE(("cmdloop(%d) called\n", top)); 227206043Sflz setstackmark(&smark); 228206043Sflz for (;;) { 229206043Sflz if (pendingsigs) 2301550Sasami dotrap(); 2311550Sasami inter = 0; 2321550Sasami if (iflag && top) { 23330221Scharnier inter++; 23430221Scharnier showjobs(1); 2354996Sjkh chkmail(0); 2364996Sjkh flushout(&output); 2371550Sasami } 2381550Sasami n = parsecmd(inter); 23941866Sjkh /* showtree(n); DEBUG */ 24076739Ssobomax if (n == NEOF) { 24176739Ssobomax if (!top || numeof >= 50) 24241866Sjkh break; 24341866Sjkh if (!stoppedjobs()) { 24441866Sjkh if (!Iflag) 24541866Sjkh break; 24641866Sjkh out2str("\nUse \"exit\" to leave shell.\n"); 247111486Sdes } 248111486Sdes numeof++; 249111486Sdes } else if (n != NULL && nflag == 0) { 250111486Sdes job_warning = (job_warning == 2) ? 1 : 0; 251111486Sdes numeof = 0; 252111486Sdes evaltree(n, 0); 25341866Sjkh } 254111486Sdes popstackmark(&smark); 25541866Sjkh if (evalskip == SKIPFILE) { 25641866Sjkh evalskip = 0; 257206043Sflz break; 258327Sjkh } 259327Sjkh } 260327Sjkh popstackmark(&smark); /* unnecessary */ 261206043Sflz} 262206043Sflz 263206043Sflz 26441866Sjkh 26530221Scharnier/* 2664996Sjkh * Read /etc/profile or .profile. Return on error. 2674996Sjkh */ 268327Sjkh 269327SjkhSTATIC void 270327Sjkhread_profile(name) 27141866Sjkh char *name; 272131280Seik { 273131280Seik int fd; 274131280Seik 275173533Skrion INTOFF; 276131280Seik if ((fd = open(name, O_RDONLY)) >= 0) 277131280Seik setinputfd(fd, 1); 278131280Seik INTON; 279131280Seik if (fd < 0) 280131280Seik return; 281131280Seik cmdloop(0); 282131280Seik popfile(); 283131280Seik} 284178103Spav 285178103Spav 286178103Spav 287178103Spav/* 288178103Spav * Read a file containing shell functions. 289178103Spav */ 290178103Spav 291178103Spavvoid 292178103Spavreadcmdfile(name) 293131280Seik char *name; 294131280Seik{ 295131280Seik int fd; 296131280Seik 297178103Spav INTOFF; 298178103Spav if ((fd = open(name, O_RDONLY)) >= 0) 299178103Spav setinputfd(fd, 1); 300178103Spav else 301178103Spav error("Can't open %s", name); 302178103Spav INTON; 303178103Spav cmdloop(0); 304178753Spav popfile(); 305178753Spav} 306178753Spav 307178753Spav 308178103Spav 309178103Spav/* 310178103Spav * Take commands from a file. To be compatable we should do a path 311178103Spav * search for the file, which is necessary to find sub-commands. 312178103Spav */ 313178103Spav 314178103Spav 31539068SjkhSTATIC char * 31639068Sjkhfind_dot_file(basename) 31796392Salfred char *basename; 31896388Salfred{ 31939068Sjkh static char localname[FILENAME_MAX+1]; 32041866Sjkh char *fullname; 32176739Ssobomax char *path = pathval(); 32276739Ssobomax struct stat statb; 32376739Ssobomax 32476739Ssobomax /* don't try this for absolute or relative paths */ 32573525Sroberto if( strchr(basename, '/')) 32673525Sroberto return basename; 327225610Spluknet 328225610Spluknet while ((fullname = padvance(&path, basename)) != NULL) { 32941866Sjkh strcpy(localname, fullname); 33041866Sjkh stunalloc(fullname); 33141866Sjkh if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 33241866Sjkh return localname; 33341866Sjkh } 33441866Sjkh return basename; 335206043Sflz} 33641866Sjkh 33741866Sjkhint 33841866Sjkhdotcmd(argc, argv) 339206043Sflz int argc; 340206043Sflz char **argv; 341206043Sflz{ 34241866Sjkh struct strlist *sp; 34341866Sjkh exitstatus = 0; 34441866Sjkh 34541866Sjkh for (sp = cmdenviron; sp ; sp = sp->next) 34641866Sjkh setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); 34741866Sjkh 34841866Sjkh if (argc >= 2) { /* That's what SVR2 does */ 34941866Sjkh char *fullname = find_dot_file(argv[1]); 35041866Sjkh 35141866Sjkh setinputfile(fullname, 1); 35296392Salfred commandname = fullname; 35396388Salfred cmdloop(0); 35441866Sjkh popfile(); 35541866Sjkh } 35641866Sjkh return exitstatus; 35761171Shoek} 35830221Scharnier 35917338Sjkh 36017338Sjkhint 36112219Sjkhexitcmd(argc, argv) 362327Sjkh int argc; 363327Sjkh char **argv; 364327Sjkh{ 365327Sjkh extern int oexitstatus; 366327Sjkh 367327Sjkh if (stoppedjobs()) 368327Sjkh return 0; 36939068Sjkh if (argc > 1) 37039068Sjkh exitstatus = number(argv[1]); 37196392Salfred else 37296388Salfred exitstatus = oexitstatus; 37339068Sjkh exitshell(exitstatus); 374327Sjkh /*NOTREACHED*/ 375327Sjkh return 0; 376327Sjkh} 377327Sjkh 378327Sjkh 37939068Sjkh#ifdef notdef 38039068Sjkh/* 381327Sjkh * Should never be called. 3824996Sjkh */ 3834996Sjkh 38496613Ssobomaxvoid 3854996Sjkhexit(exitstatus) { 38683663Ssobomax _exit(exitstatus); 38783663Ssobomax} 38883663Ssobomax#endif 38983663Ssobomax