main.c revision 17987
11556Srgrimes/*- 21556Srgrimes * Copyright (c) 1991, 1993 31556Srgrimes * The Regents of the University of California. All rights reserved. 41556Srgrimes * 51556Srgrimes * This code is derived from software contributed to Berkeley by 61556Srgrimes * Kenneth Almquist. 71556Srgrimes * 81556Srgrimes * Redistribution and use in source and binary forms, with or without 91556Srgrimes * modification, are permitted provided that the following conditions 101556Srgrimes * are met: 111556Srgrimes * 1. Redistributions of source code must retain the above copyright 121556Srgrimes * notice, this list of conditions and the following disclaimer. 131556Srgrimes * 2. Redistributions in binary form must reproduce the above copyright 141556Srgrimes * notice, this list of conditions and the following disclaimer in the 151556Srgrimes * documentation and/or other materials provided with the distribution. 161556Srgrimes * 3. All advertising materials mentioning features or use of this software 171556Srgrimes * must display the following acknowledgement: 181556Srgrimes * This product includes software developed by the University of 191556Srgrimes * California, Berkeley and its contributors. 201556Srgrimes * 4. Neither the name of the University nor the names of its contributors 211556Srgrimes * may be used to endorse or promote products derived from this software 221556Srgrimes * without specific prior written permission. 231556Srgrimes * 241556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 251556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 261556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 271556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 281556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 291556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 301556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 311556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 321556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 331556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 341556Srgrimes * SUCH DAMAGE. 353044Sdg * 3617987Speter * $Id: main.c,v 1.4 1996/08/11 22:50:58 ache Exp $ 371556Srgrimes */ 381556Srgrimes 391556Srgrimes#ifndef lint 401556Srgrimesstatic char copyright[] = 411556Srgrimes"@(#) Copyright (c) 1991, 1993\n\ 421556Srgrimes The Regents of the University of California. All rights reserved.\n"; 431556Srgrimes#endif /* not lint */ 441556Srgrimes 451556Srgrimes#ifndef lint 4617987Speterstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 471556Srgrimes#endif /* not lint */ 481556Srgrimes 4917987Speter#include <stdio.h> 501556Srgrimes#include <signal.h> 5117987Speter#include <sys/stat.h> 5217987Speter#include <unistd.h> 531556Srgrimes#include <fcntl.h> 5417525Sache#include <locale.h> 5517525Sache 5617987Speter 571556Srgrimes#include "shell.h" 581556Srgrimes#include "main.h" 591556Srgrimes#include "mail.h" 601556Srgrimes#include "options.h" 611556Srgrimes#include "output.h" 621556Srgrimes#include "parser.h" 631556Srgrimes#include "nodes.h" 6417987Speter#include "expand.h" 651556Srgrimes#include "eval.h" 661556Srgrimes#include "jobs.h" 671556Srgrimes#include "input.h" 681556Srgrimes#include "trap.h" 691556Srgrimes#include "var.h" 7017987Speter#include "show.h" 711556Srgrimes#include "memalloc.h" 721556Srgrimes#include "error.h" 731556Srgrimes#include "init.h" 741556Srgrimes#include "mystring.h" 7517987Speter#include "exec.h" 761556Srgrimes 771556Srgrimes#define PROFILE 0 781556Srgrimes 791556Srgrimesint rootpid; 801556Srgrimesint rootshell; 811556SrgrimesSTATIC union node *curcmd; 821556SrgrimesSTATIC union node *prevcmd; 831556Srgrimesextern int errno; 841556Srgrimes#if PROFILE 851556Srgrimesshort profile_buf[16384]; 861556Srgrimesextern int etext(); 871556Srgrimes#endif 881556Srgrimes 8917987SpeterSTATIC void read_profile __P((char *)); 9017987SpeterSTATIC char *find_dot_file __P((char *)); 911556Srgrimes 921556Srgrimes/* 931556Srgrimes * Main routine. We initialize things, parse the arguments, execute 941556Srgrimes * profiles if we're a login shell, and then call cmdloop to execute 951556Srgrimes * commands. The setjmp call sets up the location to jump to when an 961556Srgrimes * exception occurs. When an exception occurs the variable "state" 971556Srgrimes * is used to figure out how far we had gotten. 981556Srgrimes */ 991556Srgrimes 10017987Speterint 10117987Spetermain(argc, argv) 10217987Speter int argc; 10317987Speter char **argv; 10417987Speter{ 1051556Srgrimes struct jmploc jmploc; 1061556Srgrimes struct stackmark smark; 1071556Srgrimes volatile int state; 1081556Srgrimes char *shinit; 1091556Srgrimes 1101556Srgrimes#if PROFILE 1111556Srgrimes monitor(4, etext, profile_buf, sizeof profile_buf, 50); 1121556Srgrimes#endif 11317525Sache (void) setlocale(LC_ALL, ""); 1141556Srgrimes state = 0; 1151556Srgrimes if (setjmp(jmploc.loc)) { 1161556Srgrimes /* 1171556Srgrimes * When a shell procedure is executed, we raise the 1181556Srgrimes * exception EXSHELLPROC to clean up before executing 1191556Srgrimes * the shell procedure. 1201556Srgrimes */ 12117987Speter if (exception == EXERROR) 12217987Speter exitstatus = 2; 1231556Srgrimes if (exception == EXSHELLPROC) { 1241556Srgrimes rootpid = getpid(); 1251556Srgrimes rootshell = 1; 1261556Srgrimes minusc = NULL; 1271556Srgrimes state = 3; 1281556Srgrimes } else if (state == 0 || iflag == 0 || ! rootshell) 1291556Srgrimes exitshell(2); 1301556Srgrimes reset(); 1311556Srgrimes if (exception == EXINT 1321556Srgrimes#if ATTY 1331556Srgrimes && (! attyset() || equal(termval(), "emacs")) 1341556Srgrimes#endif 1351556Srgrimes ) { 1361556Srgrimes out2c('\n'); 1371556Srgrimes flushout(&errout); 1381556Srgrimes } 1391556Srgrimes popstackmark(&smark); 1401556Srgrimes FORCEINTON; /* enable interrupts */ 1411556Srgrimes if (state == 1) 1421556Srgrimes goto state1; 1431556Srgrimes else if (state == 2) 1441556Srgrimes goto state2; 1451556Srgrimes else if (state == 3) 1461556Srgrimes goto state3; 1471556Srgrimes else 1481556Srgrimes goto state4; 1491556Srgrimes } 1501556Srgrimes handler = &jmploc; 1511556Srgrimes#ifdef DEBUG 1521556Srgrimes opentrace(); 1531556Srgrimes trputs("Shell args: "); trargs(argv); 1541556Srgrimes#endif 1551556Srgrimes rootpid = getpid(); 1561556Srgrimes rootshell = 1; 1571556Srgrimes init(); 1581556Srgrimes setstackmark(&smark); 1591556Srgrimes procargs(argc, argv); 1601556Srgrimes if (argv[0] && argv[0][0] == '-') { 1611556Srgrimes state = 1; 1621556Srgrimes read_profile("/etc/profile"); 1631556Srgrimesstate1: 1641556Srgrimes state = 2; 1651556Srgrimes read_profile(".profile"); 1668855Srgrimes } 1671556Srgrimesstate2: 1681556Srgrimes state = 3; 16917987Speter if (getuid() == geteuid() && getgid() == getegid()) { 17017987Speter if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 17117987Speter state = 3; 17217987Speter read_profile(shinit); 17317987Speter } 1741556Srgrimes } 1751556Srgrimesstate3: 1761556Srgrimes state = 4; 1771556Srgrimes if (minusc) { 1781556Srgrimes evalstring(minusc); 1791556Srgrimes } 1801556Srgrimes if (sflag || minusc == NULL) { 1811556Srgrimesstate4: /* XXX ??? - why isn't this before the "if" statement */ 1821556Srgrimes cmdloop(1); 1831556Srgrimes } 1841556Srgrimes#if PROFILE 1851556Srgrimes monitor(0); 1861556Srgrimes#endif 1871556Srgrimes exitshell(exitstatus); 18817987Speter /*NOTREACHED*/ 18917987Speter return 0; 1901556Srgrimes} 1911556Srgrimes 1921556Srgrimes 1931556Srgrimes/* 1941556Srgrimes * Read and execute commands. "Top" is nonzero for the top level command 1951556Srgrimes * loop; it turns on prompting if the shell is interactive. 1961556Srgrimes */ 1971556Srgrimes 1981556Srgrimesvoid 19917987Spetercmdloop(top) 20017987Speter int top; 20117987Speter{ 2021556Srgrimes union node *n; 2031556Srgrimes struct stackmark smark; 2041556Srgrimes int inter; 2051556Srgrimes int numeof = 0; 2061556Srgrimes 2071556Srgrimes TRACE(("cmdloop(%d) called\n", top)); 2081556Srgrimes setstackmark(&smark); 2091556Srgrimes for (;;) { 2101556Srgrimes if (pendingsigs) 2111556Srgrimes dotrap(); 2121556Srgrimes inter = 0; 2131556Srgrimes if (iflag && top) { 2141556Srgrimes inter++; 2151556Srgrimes showjobs(1); 2161556Srgrimes chkmail(0); 2171556Srgrimes flushout(&output); 2181556Srgrimes } 2191556Srgrimes n = parsecmd(inter); 2201556Srgrimes /* showtree(n); DEBUG */ 2211556Srgrimes if (n == NEOF) { 2221556Srgrimes if (!top || numeof >= 50) 2231556Srgrimes break; 2241556Srgrimes if (!stoppedjobs()) { 2251556Srgrimes if (!Iflag) 2261556Srgrimes break; 2271556Srgrimes out2str("\nUse \"exit\" to leave shell.\n"); 2281556Srgrimes } 2291556Srgrimes numeof++; 2301556Srgrimes } else if (n != NULL && nflag == 0) { 2311556Srgrimes job_warning = (job_warning == 2) ? 1 : 0; 2321556Srgrimes numeof = 0; 2331556Srgrimes evaltree(n, 0); 2341556Srgrimes } 2351556Srgrimes popstackmark(&smark); 2361556Srgrimes } 2371556Srgrimes popstackmark(&smark); /* unnecessary */ 2381556Srgrimes} 2391556Srgrimes 2401556Srgrimes 2411556Srgrimes 2421556Srgrimes/* 2431556Srgrimes * Read /etc/profile or .profile. Return on error. 2441556Srgrimes */ 2451556Srgrimes 2461556SrgrimesSTATIC void 2471556Srgrimesread_profile(name) 2481556Srgrimes char *name; 2491556Srgrimes { 2501556Srgrimes int fd; 2511556Srgrimes 2521556Srgrimes INTOFF; 2531556Srgrimes if ((fd = open(name, O_RDONLY)) >= 0) 2541556Srgrimes setinputfd(fd, 1); 2551556Srgrimes INTON; 2561556Srgrimes if (fd < 0) 2571556Srgrimes return; 2581556Srgrimes cmdloop(0); 2591556Srgrimes popfile(); 2601556Srgrimes} 2611556Srgrimes 2621556Srgrimes 2631556Srgrimes 2641556Srgrimes/* 2651556Srgrimes * Read a file containing shell functions. 2661556Srgrimes */ 2671556Srgrimes 2681556Srgrimesvoid 2691556Srgrimesreadcmdfile(name) 2701556Srgrimes char *name; 27117987Speter{ 2721556Srgrimes int fd; 2731556Srgrimes 2741556Srgrimes INTOFF; 2751556Srgrimes if ((fd = open(name, O_RDONLY)) >= 0) 2761556Srgrimes setinputfd(fd, 1); 2771556Srgrimes else 2781556Srgrimes error("Can't open %s", name); 2791556Srgrimes INTON; 2801556Srgrimes cmdloop(0); 2811556Srgrimes popfile(); 2821556Srgrimes} 2831556Srgrimes 2841556Srgrimes 2851556Srgrimes 2861556Srgrimes/* 2871556Srgrimes * Take commands from a file. To be compatable we should do a path 28817987Speter * search for the file, which is necessary to find sub-commands. 2891556Srgrimes */ 2901556Srgrimes 29117987Speter 29217987SpeterSTATIC char * 29317987Speterfind_dot_file(basename) 29417987Speter char *basename; 29517987Speter{ 29617987Speter static char localname[FILENAME_MAX+1]; 29717987Speter char *fullname; 29817987Speter char *path = pathval(); 29917987Speter struct stat statb; 30017987Speter 30117987Speter /* don't try this for absolute or relative paths */ 30217987Speter if( strchr(basename, '/')) 30317987Speter return basename; 30417987Speter 30517987Speter while ((fullname = padvance(&path, basename)) != NULL) { 30617987Speter strcpy(localname, fullname); 30717987Speter stunalloc(fullname); 30817987Speter if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 30917987Speter return localname; 31017987Speter } 31117987Speter return basename; 31217987Speter} 31317987Speter 31417987Speterint 31517987Speterdotcmd(argc, argv) 31617987Speter int argc; 31717987Speter char **argv; 31817987Speter{ 31917987Speter struct strlist *sp; 3201556Srgrimes exitstatus = 0; 32117987Speter 32217987Speter for (sp = cmdenviron; sp ; sp = sp->next) 32317987Speter setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); 32417987Speter 3251556Srgrimes if (argc >= 2) { /* That's what SVR2 does */ 32617987Speter char *fullname = find_dot_file(argv[1]); 32717987Speter 32817987Speter setinputfile(fullname, 1); 32917987Speter commandname = fullname; 3301556Srgrimes cmdloop(0); 3311556Srgrimes popfile(); 3321556Srgrimes } 3331556Srgrimes return exitstatus; 3341556Srgrimes} 3351556Srgrimes 3361556Srgrimes 33717987Speterint 33817987Speterexitcmd(argc, argv) 33917987Speter int argc; 34017987Speter char **argv; 34117987Speter{ 3421556Srgrimes if (stoppedjobs()) 34317987Speter return 0; 3441556Srgrimes if (argc > 1) 3451556Srgrimes exitstatus = number(argv[1]); 3461556Srgrimes exitshell(exitstatus); 34717987Speter /*NOTREACHED*/ 34817987Speter return 0; 3491556Srgrimes} 3501556Srgrimes 3511556Srgrimes 3521556Srgrimes#ifdef notdef 3531556Srgrimes/* 3541556Srgrimes * Should never be called. 3551556Srgrimes */ 3561556Srgrimes 3571556Srgrimesvoid 3581556Srgrimesexit(exitstatus) { 3591556Srgrimes _exit(exitstatus); 3601556Srgrimes} 3611556Srgrimes#endif 362