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$"); 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 "mystring.h" 7217987Speter#include "exec.h" 7320425Ssteve#include "cd.h" 74253650Sjilles#include "redir.h" 75223060Sjilles#include "builtins.h" 761556Srgrimes 771556Srgrimesint rootpid; 781556Srgrimesint rootshell; 79200998Sjillesstruct jmploc main_handler; 80221669Sjillesint localeisutf8, initial_localeisutf8; 811556Srgrimes 82253650Sjillesstatic void reset(void); 83229220Sjillesstatic void cmdloop(int); 84248980Sjillesstatic void read_profile(const char *); 85213811Sobrienstatic char *find_dot_file(char *); 861556Srgrimes 871556Srgrimes/* 881556Srgrimes * Main routine. We initialize things, parse the arguments, execute 891556Srgrimes * profiles if we're a login shell, and then call cmdloop to execute 901556Srgrimes * commands. The setjmp call sets up the location to jump to when an 911556Srgrimes * exception occurs. When an exception occurs the variable "state" 921556Srgrimes * is used to figure out how far we had gotten. 931556Srgrimes */ 941556Srgrimes 9517987Speterint 9690111Simpmain(int argc, char *argv[]) 9717987Speter{ 98222957Sjilles struct stackmark smark, smark2; 991556Srgrimes volatile int state; 1001556Srgrimes char *shinit; 1011556Srgrimes 10217525Sache (void) setlocale(LC_ALL, ""); 103221669Sjilles initcharset(); 1041556Srgrimes state = 0; 105200998Sjilles if (setjmp(main_handler.loc)) { 10620425Ssteve switch (exception) { 10720425Ssteve case EXEXEC: 10820425Ssteve exitstatus = exerrno; 10920425Ssteve break; 11020425Ssteve 11120425Ssteve case EXERROR: 11220425Ssteve exitstatus = 2; 11320425Ssteve break; 11420425Ssteve 11520425Ssteve default: 11620425Ssteve break; 11720425Ssteve } 11820425Ssteve 119220978Sjilles if (state == 0 || iflag == 0 || ! rootshell || 120220978Sjilles exception == EXEXIT) 121218306Sjilles exitshell(exitstatus); 1221556Srgrimes reset(); 123215567Sjilles if (exception == EXINT) 124215567Sjilles out2fmt_flush("\n"); 1251556Srgrimes popstackmark(&smark); 1261556Srgrimes FORCEINTON; /* enable interrupts */ 1271556Srgrimes if (state == 1) 1281556Srgrimes goto state1; 1291556Srgrimes else if (state == 2) 1301556Srgrimes goto state2; 1311556Srgrimes else if (state == 3) 1321556Srgrimes goto state3; 1331556Srgrimes else 1341556Srgrimes goto state4; 1351556Srgrimes } 136200998Sjilles handler = &main_handler; 1371556Srgrimes#ifdef DEBUG 1381556Srgrimes opentrace(); 1391556Srgrimes trputs("Shell args: "); trargs(argv); 1401556Srgrimes#endif 1411556Srgrimes rootpid = getpid(); 1421556Srgrimes rootshell = 1; 143245689Sjilles initvar(); 1441556Srgrimes setstackmark(&smark); 145222957Sjilles setstackmark(&smark2); 1461556Srgrimes procargs(argc, argv); 147206759Sjilles pwd_init(iflag); 148203576Sjilles if (iflag) 149203576Sjilles chkmail(1); 1501556Srgrimes if (argv[0] && argv[0][0] == '-') { 1511556Srgrimes state = 1; 1521556Srgrimes read_profile("/etc/profile"); 1531556Srgrimesstate1: 1541556Srgrimes state = 2; 15519240Ssteve if (privileged == 0) 156223005Sjilles read_profile("${HOME-}/.profile"); 15719240Ssteve else 15819240Ssteve read_profile("/etc/suid_profile"); 1598855Srgrimes } 1601556Srgrimesstate2: 1611556Srgrimes state = 3; 16225471Ssteve if (!privileged && iflag) { 16317987Speter if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 16417987Speter state = 3; 16517987Speter read_profile(shinit); 16617987Speter } 1671556Srgrimes } 1681556Srgrimesstate3: 1691556Srgrimes state = 4; 170222957Sjilles popstackmark(&smark2); 1711556Srgrimes if (minusc) { 172194128Sjilles evalstring(minusc, sflag ? 0 : EV_EXIT); 1731556Srgrimes } 174253271Sjillesstate4: 1751556Srgrimes if (sflag || minusc == NULL) { 1761556Srgrimes cmdloop(1); 1771556Srgrimes } 1781556Srgrimes exitshell(exitstatus); 17917987Speter /*NOTREACHED*/ 18017987Speter return 0; 1811556Srgrimes} 1821556Srgrimes 183253650Sjillesstatic void 184253650Sjillesreset(void) 185253650Sjilles{ 186253650Sjilles reseteval(); 187253650Sjilles resetinput(); 188253650Sjilles} 1891556Srgrimes 1901556Srgrimes/* 1911556Srgrimes * Read and execute commands. "Top" is nonzero for the top level command 1921556Srgrimes * loop; it turns on prompting if the shell is interactive. 1931556Srgrimes */ 1941556Srgrimes 195229220Sjillesstatic void 19690111Simpcmdloop(int top) 19717987Speter{ 1981556Srgrimes union node *n; 1991556Srgrimes struct stackmark smark; 2001556Srgrimes int inter; 2011556Srgrimes int numeof = 0; 2021556Srgrimes 2031556Srgrimes TRACE(("cmdloop(%d) called\n", top)); 2041556Srgrimes setstackmark(&smark); 2051556Srgrimes for (;;) { 206247206Sjilles if (pendingsig) 2071556Srgrimes dotrap(); 2081556Srgrimes inter = 0; 2091556Srgrimes if (iflag && top) { 2101556Srgrimes inter++; 211163085Sstefanf showjobs(1, SHOWJOBS_DEFAULT); 2121556Srgrimes chkmail(0); 2131556Srgrimes flushout(&output); 2141556Srgrimes } 2151556Srgrimes n = parsecmd(inter); 2161556Srgrimes /* showtree(n); DEBUG */ 2171556Srgrimes if (n == NEOF) { 2181556Srgrimes if (!top || numeof >= 50) 2191556Srgrimes break; 2201556Srgrimes if (!stoppedjobs()) { 2211556Srgrimes if (!Iflag) 2221556Srgrimes break; 223199629Sjilles out2fmt_flush("\nUse \"exit\" to leave shell.\n"); 2241556Srgrimes } 2251556Srgrimes numeof++; 2261556Srgrimes } else if (n != NULL && nflag == 0) { 2271556Srgrimes job_warning = (job_warning == 2) ? 1 : 0; 2281556Srgrimes numeof = 0; 2291556Srgrimes evaltree(n, 0); 2301556Srgrimes } 2311556Srgrimes popstackmark(&smark); 23264702Scracauer setstackmark(&smark); 233211349Sjilles if (evalskip != 0) { 234255215Sjilles if (evalskip == SKIPRETURN) 235211349Sjilles evalskip = 0; 23620425Ssteve break; 23720425Ssteve } 2381556Srgrimes } 23964702Scracauer popstackmark(&smark); 2401556Srgrimes} 2411556Srgrimes 2421556Srgrimes 2431556Srgrimes 2441556Srgrimes/* 2451556Srgrimes * Read /etc/profile or .profile. Return on error. 2461556Srgrimes */ 2471556Srgrimes 248213811Sobrienstatic void 249248980Sjillesread_profile(const char *name) 25090111Simp{ 2511556Srgrimes int fd; 252222957Sjilles const char *expandedname; 2531556Srgrimes 254222957Sjilles expandedname = expandstr(name); 255222957Sjilles if (expandedname == NULL) 256222957Sjilles return; 2571556Srgrimes INTOFF; 258250267Sjilles if ((fd = open(expandedname, O_RDONLY | O_CLOEXEC)) >= 0) 2591556Srgrimes setinputfd(fd, 1); 2601556Srgrimes INTON; 2611556Srgrimes if (fd < 0) 2621556Srgrimes return; 2631556Srgrimes cmdloop(0); 2641556Srgrimes popfile(); 2651556Srgrimes} 2661556Srgrimes 2671556Srgrimes 2681556Srgrimes 2691556Srgrimes/* 2701556Srgrimes * Read a file containing shell functions. 2711556Srgrimes */ 2721556Srgrimes 2731556Srgrimesvoid 274200956Sjillesreadcmdfile(const char *name) 27517987Speter{ 276240505Sjilles setinputfile(name, 1); 2771556Srgrimes cmdloop(0); 2781556Srgrimes popfile(); 2791556Srgrimes} 2801556Srgrimes 2811556Srgrimes 2821556Srgrimes 2831556Srgrimes/* 28446684Skris * Take commands from a file. To be compatible we should do a path 28517987Speter * search for the file, which is necessary to find sub-commands. 2861556Srgrimes */ 2871556Srgrimes 28817987Speter 289213811Sobrienstatic char * 29090111Simpfind_dot_file(char *basename) 29117987Speter{ 29217987Speter char *fullname; 293200956Sjilles const char *path = pathval(); 29417987Speter struct stat statb; 29517987Speter 29617987Speter /* don't try this for absolute or relative paths */ 29717987Speter if( strchr(basename, '/')) 29817987Speter return basename; 29917987Speter 30017987Speter while ((fullname = padvance(&path, basename)) != NULL) { 301222173Sjilles if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 302222173Sjilles /* 303222173Sjilles * Don't bother freeing here, since it will 304222173Sjilles * be freed by the caller. 305222173Sjilles */ 306222173Sjilles return fullname; 307222173Sjilles } 30817987Speter stunalloc(fullname); 30917987Speter } 31017987Speter return basename; 31117987Speter} 31217987Speter 31317987Speterint 31490111Simpdotcmd(int argc, char **argv) 31517987Speter{ 316208630Sjilles char *filename, *fullname; 317157414Sstefanf 318157414Sstefanf if (argc < 2) 319157414Sstefanf error("missing filename"); 320157414Sstefanf 3211556Srgrimes exitstatus = 0; 32217987Speter 323208630Sjilles /* 324208630Sjilles * Because we have historically not supported any options, 325208630Sjilles * only treat "--" specially. 326208630Sjilles */ 327208630Sjilles filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1]; 328208630Sjilles 329208630Sjilles fullname = find_dot_file(filename); 330157414Sstefanf setinputfile(fullname, 1); 331157414Sstefanf commandname = fullname; 332157414Sstefanf cmdloop(0); 333157414Sstefanf popfile(); 3341556Srgrimes return exitstatus; 3351556Srgrimes} 3361556Srgrimes 3371556Srgrimes 33817987Speterint 33990111Simpexitcmd(int argc, char **argv) 34017987Speter{ 3411556Srgrimes if (stoppedjobs()) 34217987Speter return 0; 34320425Ssteve if (argc > 1) 344217175Sjilles exitshell(number(argv[1])); 34520425Ssteve else 346217175Sjilles exitshell_savedstatus(); 3471556Srgrimes} 348