main.c revision 200956
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 * 4. Neither the name of the University nor the names of its contributors 171556Srgrimes * may be used to endorse or promote products derived from this software 181556Srgrimes * without specific prior written permission. 191556Srgrimes * 201556Srgrimes * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 211556Srgrimes * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 221556Srgrimes * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 231556Srgrimes * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 241556Srgrimes * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 251556Srgrimes * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 261556Srgrimes * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 271556Srgrimes * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 281556Srgrimes * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 291556Srgrimes * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 301556Srgrimes * SUCH DAMAGE. 311556Srgrimes */ 321556Srgrimes 331556Srgrimes#ifndef lint 3420425Sstevestatic char const copyright[] = 351556Srgrimes"@(#) Copyright (c) 1991, 1993\n\ 361556Srgrimes The Regents of the University of California. All rights reserved.\n"; 371556Srgrimes#endif /* not lint */ 381556Srgrimes 391556Srgrimes#ifndef lint 4036150Scharnier#if 0 4136150Scharnierstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 4236150Scharnier#endif 431556Srgrimes#endif /* not lint */ 4499110Sobrien#include <sys/cdefs.h> 4599110Sobrien__FBSDID("$FreeBSD: head/bin/sh/main.c 200956 2009-12-24 18:41:14Z jilles $"); 461556Srgrimes 4717987Speter#include <stdio.h> 481556Srgrimes#include <signal.h> 4917987Speter#include <sys/stat.h> 5017987Speter#include <unistd.h> 511556Srgrimes#include <fcntl.h> 5217525Sache#include <locale.h> 5359214Simp#include <errno.h> 5417525Sache 551556Srgrimes#include "shell.h" 561556Srgrimes#include "main.h" 571556Srgrimes#include "mail.h" 581556Srgrimes#include "options.h" 591556Srgrimes#include "output.h" 601556Srgrimes#include "parser.h" 611556Srgrimes#include "nodes.h" 6217987Speter#include "expand.h" 631556Srgrimes#include "eval.h" 641556Srgrimes#include "jobs.h" 651556Srgrimes#include "input.h" 661556Srgrimes#include "trap.h" 671556Srgrimes#include "var.h" 6817987Speter#include "show.h" 691556Srgrimes#include "memalloc.h" 701556Srgrimes#include "error.h" 711556Srgrimes#include "init.h" 721556Srgrimes#include "mystring.h" 7317987Speter#include "exec.h" 7420425Ssteve#include "cd.h" 751556Srgrimes 761556Srgrimesint rootpid; 771556Srgrimesint rootshell; 781556Srgrimes 7990111SimpSTATIC void read_profile(char *); 8090111SimpSTATIC char *find_dot_file(char *); 811556Srgrimes 821556Srgrimes/* 831556Srgrimes * Main routine. We initialize things, parse the arguments, execute 841556Srgrimes * profiles if we're a login shell, and then call cmdloop to execute 851556Srgrimes * commands. The setjmp call sets up the location to jump to when an 861556Srgrimes * exception occurs. When an exception occurs the variable "state" 871556Srgrimes * is used to figure out how far we had gotten. 881556Srgrimes */ 891556Srgrimes 9017987Speterint 9190111Simpmain(int argc, char *argv[]) 9217987Speter{ 931556Srgrimes struct jmploc jmploc; 941556Srgrimes struct stackmark smark; 951556Srgrimes volatile int state; 961556Srgrimes char *shinit; 971556Srgrimes 9817525Sache (void) setlocale(LC_ALL, ""); 991556Srgrimes state = 0; 1001556Srgrimes if (setjmp(jmploc.loc)) { 1011556Srgrimes /* 1021556Srgrimes * When a shell procedure is executed, we raise the 1031556Srgrimes * exception EXSHELLPROC to clean up before executing 1041556Srgrimes * the shell procedure. 1051556Srgrimes */ 10620425Ssteve switch (exception) { 10720425Ssteve case EXSHELLPROC: 1081556Srgrimes rootpid = getpid(); 1091556Srgrimes rootshell = 1; 1101556Srgrimes minusc = NULL; 1111556Srgrimes state = 3; 11220425Ssteve break; 11320425Ssteve 11420425Ssteve case EXEXEC: 11520425Ssteve exitstatus = exerrno; 11620425Ssteve break; 11720425Ssteve 11820425Ssteve case EXERROR: 11920425Ssteve exitstatus = 2; 12020425Ssteve break; 12120425Ssteve 12220425Ssteve default: 12320425Ssteve break; 12420425Ssteve } 12520425Ssteve 12620425Ssteve if (exception != EXSHELLPROC) { 12720425Ssteve if (state == 0 || iflag == 0 || ! rootshell) 12820425Ssteve exitshell(exitstatus); 12920425Ssteve } 1301556Srgrimes reset(); 131104255Stjr if (exception == EXINT) { 1321556Srgrimes out2c('\n'); 1331556Srgrimes flushout(&errout); 1341556Srgrimes } 1351556Srgrimes popstackmark(&smark); 1361556Srgrimes FORCEINTON; /* enable interrupts */ 1371556Srgrimes if (state == 1) 1381556Srgrimes goto state1; 1391556Srgrimes else if (state == 2) 1401556Srgrimes goto state2; 1411556Srgrimes else if (state == 3) 1421556Srgrimes goto state3; 1431556Srgrimes else 1441556Srgrimes goto state4; 1451556Srgrimes } 1461556Srgrimes handler = &jmploc; 1471556Srgrimes#ifdef DEBUG 1481556Srgrimes opentrace(); 1491556Srgrimes trputs("Shell args: "); trargs(argv); 1501556Srgrimes#endif 1511556Srgrimes rootpid = getpid(); 1521556Srgrimes rootshell = 1; 1531556Srgrimes init(); 1541556Srgrimes setstackmark(&smark); 1551556Srgrimes procargs(argc, argv); 15620774Ssteve if (getpwd() == NULL && iflag) 157199629Sjilles out2fmt_flush("sh: cannot determine working directory\n"); 158155304Sschweikh if (getpwd() != NULL) 159155304Sschweikh setvar ("PWD", getpwd(), VEXPORT); 1601556Srgrimes if (argv[0] && argv[0][0] == '-') { 1611556Srgrimes state = 1; 1621556Srgrimes read_profile("/etc/profile"); 1631556Srgrimesstate1: 1641556Srgrimes state = 2; 16519240Ssteve if (privileged == 0) 16619240Ssteve read_profile(".profile"); 16719240Ssteve else 16819240Ssteve read_profile("/etc/suid_profile"); 1698855Srgrimes } 1701556Srgrimesstate2: 1711556Srgrimes state = 3; 17225471Ssteve if (!privileged && iflag) { 17317987Speter if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 17417987Speter state = 3; 17517987Speter read_profile(shinit); 17617987Speter } 1771556Srgrimes } 1781556Srgrimesstate3: 1791556Srgrimes state = 4; 1801556Srgrimes if (minusc) { 181194128Sjilles evalstring(minusc, sflag ? 0 : EV_EXIT); 1821556Srgrimes } 1831556Srgrimes if (sflag || minusc == NULL) { 1841556Srgrimesstate4: /* XXX ??? - why isn't this before the "if" statement */ 1851556Srgrimes cmdloop(1); 1861556Srgrimes } 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 19990111Simpcmdloop(int top) 20017987Speter{ 2011556Srgrimes union node *n; 2021556Srgrimes struct stackmark smark; 2031556Srgrimes int inter; 2041556Srgrimes int numeof = 0; 2051556Srgrimes 2061556Srgrimes TRACE(("cmdloop(%d) called\n", top)); 2071556Srgrimes setstackmark(&smark); 2081556Srgrimes for (;;) { 2091556Srgrimes if (pendingsigs) 2101556Srgrimes dotrap(); 2111556Srgrimes inter = 0; 2121556Srgrimes if (iflag && top) { 2131556Srgrimes inter++; 214163085Sstefanf showjobs(1, SHOWJOBS_DEFAULT); 2151556Srgrimes chkmail(0); 2161556Srgrimes flushout(&output); 2171556Srgrimes } 2181556Srgrimes n = parsecmd(inter); 2191556Srgrimes /* showtree(n); DEBUG */ 2201556Srgrimes if (n == NEOF) { 2211556Srgrimes if (!top || numeof >= 50) 2221556Srgrimes break; 2231556Srgrimes if (!stoppedjobs()) { 2241556Srgrimes if (!Iflag) 2251556Srgrimes break; 226199629Sjilles out2fmt_flush("\nUse \"exit\" to leave shell.\n"); 2271556Srgrimes } 2281556Srgrimes numeof++; 2291556Srgrimes } else if (n != NULL && nflag == 0) { 2301556Srgrimes job_warning = (job_warning == 2) ? 1 : 0; 2311556Srgrimes numeof = 0; 2321556Srgrimes evaltree(n, 0); 2331556Srgrimes } 2341556Srgrimes popstackmark(&smark); 23564702Scracauer setstackmark(&smark); 23620425Ssteve if (evalskip == SKIPFILE) { 23720425Ssteve evalskip = 0; 23820425Ssteve break; 23920425Ssteve } 2401556Srgrimes } 24164702Scracauer popstackmark(&smark); 2421556Srgrimes} 2431556Srgrimes 2441556Srgrimes 2451556Srgrimes 2461556Srgrimes/* 2471556Srgrimes * Read /etc/profile or .profile. Return on error. 2481556Srgrimes */ 2491556Srgrimes 2501556SrgrimesSTATIC void 25190111Simpread_profile(char *name) 25290111Simp{ 2531556Srgrimes int fd; 2541556Srgrimes 2551556Srgrimes INTOFF; 2561556Srgrimes if ((fd = open(name, O_RDONLY)) >= 0) 2571556Srgrimes setinputfd(fd, 1); 2581556Srgrimes INTON; 2591556Srgrimes if (fd < 0) 2601556Srgrimes return; 2611556Srgrimes cmdloop(0); 2621556Srgrimes popfile(); 2631556Srgrimes} 2641556Srgrimes 2651556Srgrimes 2661556Srgrimes 2671556Srgrimes/* 2681556Srgrimes * Read a file containing shell functions. 2691556Srgrimes */ 2701556Srgrimes 2711556Srgrimesvoid 272200956Sjillesreadcmdfile(const char *name) 27317987Speter{ 2741556Srgrimes int fd; 2751556Srgrimes 2761556Srgrimes INTOFF; 2771556Srgrimes if ((fd = open(name, O_RDONLY)) >= 0) 2781556Srgrimes setinputfd(fd, 1); 2791556Srgrimes else 28053891Scracauer error("Can't open %s: %s", name, strerror(errno)); 2811556Srgrimes INTON; 2821556Srgrimes cmdloop(0); 2831556Srgrimes popfile(); 2841556Srgrimes} 2851556Srgrimes 2861556Srgrimes 2871556Srgrimes 2881556Srgrimes/* 28946684Skris * Take commands from a file. To be compatible we should do a path 29017987Speter * search for the file, which is necessary to find sub-commands. 2911556Srgrimes */ 2921556Srgrimes 29317987Speter 29417987SpeterSTATIC char * 29590111Simpfind_dot_file(char *basename) 29617987Speter{ 29717987Speter static char localname[FILENAME_MAX+1]; 29817987Speter char *fullname; 299200956Sjilles const char *path = pathval(); 30017987Speter struct stat statb; 30117987Speter 30217987Speter /* don't try this for absolute or relative paths */ 30317987Speter if( strchr(basename, '/')) 30417987Speter return basename; 30517987Speter 30617987Speter while ((fullname = padvance(&path, basename)) != NULL) { 30717987Speter strcpy(localname, fullname); 30817987Speter stunalloc(fullname); 30917987Speter if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 31017987Speter return localname; 31117987Speter } 31217987Speter return basename; 31317987Speter} 31417987Speter 31517987Speterint 31690111Simpdotcmd(int argc, char **argv) 31717987Speter{ 318157414Sstefanf char *fullname; 319157414Sstefanf 320157414Sstefanf if (argc < 2) 321157414Sstefanf error("missing filename"); 322157414Sstefanf 3231556Srgrimes exitstatus = 0; 32417987Speter 325157414Sstefanf fullname = find_dot_file(argv[1]); 326157414Sstefanf setinputfile(fullname, 1); 327157414Sstefanf commandname = fullname; 328157414Sstefanf cmdloop(0); 329157414Sstefanf popfile(); 3301556Srgrimes return exitstatus; 3311556Srgrimes} 3321556Srgrimes 3331556Srgrimes 33417987Speterint 33590111Simpexitcmd(int argc, char **argv) 33617987Speter{ 33718267Sadam extern int oexitstatus; 33818267Sadam 3391556Srgrimes if (stoppedjobs()) 34017987Speter return 0; 34120425Ssteve if (argc > 1) 34220425Ssteve exitstatus = number(argv[1]); 34320425Ssteve else 34420425Ssteve exitstatus = oexitstatus; 34518254Sbde exitshell(exitstatus); 34617987Speter /*NOTREACHED*/ 34717987Speter return 0; 3481556Srgrimes} 349