main.c revision 245689
1125635Skientzle/*- 2133244Skientzle * Copyright (c) 1991, 1993 3151275Skientzle * The Regents of the University of California. All rights reserved. 4152285Sru * 5152285Sru * This code is derived from software contributed to Berkeley by 6133244Skientzle * Kenneth Almquist. 7156417Skientzle * 8156417Skientzle * Redistribution and use in source and binary forms, with or without 9164630Skientzle * modification, are permitted provided that the following conditions 10164630Skientzle * are met: 11156417Skientzle * 1. Redistributions of source code must retain the above copyright 12170079Skientzle * notice, this list of conditions and the following disclaimer. 13151275Skientzle * 2. Redistributions in binary form must reproduce the above copyright 14164630Skientzle * notice, this list of conditions and the following disclaimer in the 15164630Skientzle * documentation and/or other materials provided with the distribution. 16164630Skientzle * 4. Neither the name of the University nor the names of its contributors 17164013Skientzle * may be used to endorse or promote products derived from this software 18164013Skientzle * without specific prior written permission. 19167186Skientzle * 20151275Skientzle * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21133244Skientzle * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22133244Skientzle * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23168648Skientzle * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24133244Skientzle * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25133244Skientzle * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26133244Skientzle * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27133244Skientzle * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28151275Skientzle * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29133244Skientzle * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30133244Skientzle * SUCH DAMAGE. 31156417Skientzle */ 32162028Skientzle 33156417Skientzle#ifndef lint 34156417Skientzlestatic char const copyright[] = 35169201Scperciva"@(#) Copyright (c) 1991, 1993\n\ 36156417Skientzle The Regents of the University of California. All rights reserved.\n"; 37156417Skientzle#endif /* not lint */ 38156417Skientzle 39162028Skientzle#ifndef lint 40156417Skientzle#if 0 41156417Skientzlestatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 42156417Skientzle#endif 43156417Skientzle#endif /* not lint */ 44156417Skientzle#include <sys/cdefs.h> 45156417Skientzle__FBSDID("$FreeBSD: head/bin/sh/main.c 245689 2013-01-20 12:44:50Z jilles $"); 46156417Skientzle 47156417Skientzle#include <stdio.h> 48133244Skientzle#include <signal.h> 49170079Skientzle#include <sys/stat.h> 50170079Skientzle#include <unistd.h> 51133244Skientzle#include <fcntl.h> 52133244Skientzle#include <locale.h> 53133244Skientzle#include <errno.h> 54133244Skientzle 55164589Skientzle#include "shell.h" 56164448Skientzle#include "main.h" 57164589Skientzle#include "mail.h" 58133244Skientzle#include "options.h" 59133244Skientzle#include "output.h" 60133244Skientzle#include "parser.h" 61133244Skientzle#include "nodes.h" 62133244Skientzle#include "expand.h" 63170079Skientzle#include "eval.h" 64133244Skientzle#include "jobs.h" 65168740Skientzle#include "input.h" 66133244Skientzle#include "trap.h" 67166387Skientzle#include "var.h" 68139565Skientzle#include "show.h" 69133244Skientzle#include "memalloc.h" 70140790Skientzle#include "error.h" 71133244Skientzle#include "init.h" 72133244Skientzle#include "mystring.h" 73133244Skientzle#include "exec.h" 74167186Skientzle#include "cd.h" 75133244Skientzle#include "builtins.h" 76167186Skientzle 77167186Skientzleint rootpid; 78133244Skientzleint rootshell; 79164589Skientzlestruct jmploc main_handler; 80164448Skientzleint localeisutf8, initial_localeisutf8; 81164589Skientzle 82133244Skientzlestatic void cmdloop(int); 83133244Skientzlestatic void read_profile(char *); 84133244Skientzlestatic char *find_dot_file(char *); 85170079Skientzle 86133244Skientzle/* 87168453Skientzle * Main routine. We initialize things, parse the arguments, execute 88133244Skientzle * profiles if we're a login shell, and then call cmdloop to execute 89133244Skientzle * commands. The setjmp call sets up the location to jump to when an 90133244Skientzle * exception occurs. When an exception occurs the variable "state" 91133244Skientzle * is used to figure out how far we had gotten. 92170079Skientzle */ 93170079Skientzle 94133244Skientzleint 95151275Skientzlemain(int argc, char *argv[]) 96133244Skientzle{ 97133244Skientzle struct stackmark smark, smark2; 98133244Skientzle volatile int state; 99133244Skientzle char *shinit; 100167186Skientzle 101133244Skientzle (void) setlocale(LC_ALL, ""); 102133244Skientzle initcharset(); 103133244Skientzle state = 0; 104133244Skientzle if (setjmp(main_handler.loc)) { 105151275Skientzle switch (exception) { 106133244Skientzle case EXEXEC: 107133244Skientzle exitstatus = exerrno; 108133244Skientzle break; 109133244Skientzle 110133244Skientzle case EXERROR: 111133244Skientzle exitstatus = 2; 112133244Skientzle break; 113133244Skientzle 114133244Skientzle default: 115133244Skientzle break; 116133244Skientzle } 117133244Skientzle 118133244Skientzle if (state == 0 || iflag == 0 || ! rootshell || 119133244Skientzle exception == EXEXIT) 120133244Skientzle exitshell(exitstatus); 121133244Skientzle reset(); 122133244Skientzle if (exception == EXINT) 123170079Skientzle out2fmt_flush("\n"); 124170079Skientzle popstackmark(&smark); 125170079Skientzle FORCEINTON; /* enable interrupts */ 126170079Skientzle if (state == 1) 127133244Skientzle goto state1; 128133244Skientzle else if (state == 2) 129133244Skientzle goto state2; 130133244Skientzle else if (state == 3) 131133244Skientzle goto state3; 132133244Skientzle else 133133244Skientzle goto state4; 134133244Skientzle } 135133244Skientzle handler = &main_handler; 136133244Skientzle#ifdef DEBUG 137133244Skientzle opentrace(); 138170079Skientzle trputs("Shell args: "); trargs(argv); 139133244Skientzle#endif 140133244Skientzle rootpid = getpid(); 141133244Skientzle rootshell = 1; 142133244Skientzle initvar(); 143133244Skientzle setstackmark(&smark); 144133244Skientzle setstackmark(&smark2); 145170079Skientzle procargs(argc, argv); 146170079Skientzle pwd_init(iflag); 147170079Skientzle if (iflag) 148170079Skientzle chkmail(1); 149170079Skientzle if (argv[0] && argv[0][0] == '-') { 150133244Skientzle state = 1; 151133244Skientzle read_profile("/etc/profile"); 152133244Skientzlestate1: 153133244Skientzle state = 2; 154133244Skientzle if (privileged == 0) 155133244Skientzle read_profile("${HOME-}/.profile"); 156170079Skientzle else 157170079Skientzle read_profile("/etc/suid_profile"); 158133244Skientzle } 159170079Skientzlestate2: 160133244Skientzle state = 3; 161133244Skientzle if (!privileged && iflag) { 162133244Skientzle if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 163133244Skientzle state = 3; 164133244Skientzle read_profile(shinit); 165133244Skientzle } 166133244Skientzle } 167133244Skientzlestate3: 168133244Skientzle state = 4; 169133244Skientzle popstackmark(&smark2); 170133244Skientzle if (minusc) { 171133244Skientzle evalstring(minusc, sflag ? 0 : EV_EXIT); 172133244Skientzle } 173133244Skientzle if (sflag || minusc == NULL) { 174133244Skientzlestate4: /* XXX ??? - why isn't this before the "if" statement */ 175133244Skientzle cmdloop(1); 176133244Skientzle } 177133244Skientzle exitshell(exitstatus); 178133244Skientzle /*NOTREACHED*/ 179162028Skientzle return 0; 180133244Skientzle} 181133244Skientzle 182133244Skientzle 183133244Skientzle/* 184162028Skientzle * Read and execute commands. "Top" is nonzero for the top level command 185164589Skientzle * loop; it turns on prompting if the shell is interactive. 186133244Skientzle */ 187133244Skientzle 188164448Skientzlestatic void 189164589Skientzlecmdloop(int top) 190133244Skientzle{ 191133244Skientzle union node *n; 192133244Skientzle struct stackmark smark; 193133244Skientzle int inter; 194133244Skientzle int numeof = 0; 195170079Skientzle 196133244Skientzle TRACE(("cmdloop(%d) called\n", top)); 197133244Skientzle setstackmark(&smark); 198139913Skientzle for (;;) { 199133244Skientzle if (pendingsigs) 200140790Skientzle dotrap(); 201167186Skientzle inter = 0; 202133244Skientzle if (iflag && top) { 203133244Skientzle inter++; 204133244Skientzle showjobs(1, SHOWJOBS_DEFAULT); 205133244Skientzle chkmail(0); 206133244Skientzle flushout(&output); 207133244Skientzle } 208137240Skientzle n = parsecmd(inter); 209133244Skientzle /* showtree(n); DEBUG */ 210133244Skientzle if (n == NEOF) { 211164628Skientzle if (!top || numeof >= 50) 212164628Skientzle break; 213164628Skientzle if (!stoppedjobs()) { 214133244Skientzle if (!Iflag) 215133244Skientzle break; 216133244Skientzle out2fmt_flush("\nUse \"exit\" to leave shell.\n"); 217164589Skientzle } 218133244Skientzle numeof++; 219133244Skientzle } else if (n != NULL && nflag == 0) { 220164448Skientzle job_warning = (job_warning == 2) ? 1 : 0; 221164589Skientzle numeof = 0; 222164589Skientzle evaltree(n, 0); 223133244Skientzle } 224133244Skientzle popstackmark(&smark); 225133244Skientzle setstackmark(&smark); 226133244Skientzle if (evalskip != 0) { 227170079Skientzle if (evalskip == SKIPFILE) 228170079Skientzle evalskip = 0; 229133244Skientzle break; 230133244Skientzle } 231133244Skientzle } 232167186Skientzle popstackmark(&smark); 233167186Skientzle} 234167186Skientzle 235167186Skientzle 236167186Skientzle 237167186Skientzle/* 238133244Skientzle * Read /etc/profile or .profile. Return on error. 239133244Skientzle */ 240167186Skientzle 241167186Skientzlestatic void 242167186Skientzleread_profile(char *name) 243133244Skientzle{ 244 int fd; 245 const char *expandedname; 246 247 expandedname = expandstr(name); 248 if (expandedname == NULL) 249 return; 250 INTOFF; 251 if ((fd = open(expandedname, O_RDONLY)) >= 0) 252 setinputfd(fd, 1); 253 INTON; 254 if (fd < 0) 255 return; 256 cmdloop(0); 257 popfile(); 258} 259 260 261 262/* 263 * Read a file containing shell functions. 264 */ 265 266void 267readcmdfile(const char *name) 268{ 269 setinputfile(name, 1); 270 cmdloop(0); 271 popfile(); 272} 273 274 275 276/* 277 * Take commands from a file. To be compatible we should do a path 278 * search for the file, which is necessary to find sub-commands. 279 */ 280 281 282static char * 283find_dot_file(char *basename) 284{ 285 char *fullname; 286 const char *path = pathval(); 287 struct stat statb; 288 289 /* don't try this for absolute or relative paths */ 290 if( strchr(basename, '/')) 291 return basename; 292 293 while ((fullname = padvance(&path, basename)) != NULL) { 294 if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) { 295 /* 296 * Don't bother freeing here, since it will 297 * be freed by the caller. 298 */ 299 return fullname; 300 } 301 stunalloc(fullname); 302 } 303 return basename; 304} 305 306int 307dotcmd(int argc, char **argv) 308{ 309 char *filename, *fullname; 310 311 if (argc < 2) 312 error("missing filename"); 313 314 exitstatus = 0; 315 316 /* 317 * Because we have historically not supported any options, 318 * only treat "--" specially. 319 */ 320 filename = argc > 2 && strcmp(argv[1], "--") == 0 ? argv[2] : argv[1]; 321 322 fullname = find_dot_file(filename); 323 setinputfile(fullname, 1); 324 commandname = fullname; 325 cmdloop(0); 326 popfile(); 327 return exitstatus; 328} 329 330 331int 332exitcmd(int argc, char **argv) 333{ 334 if (stoppedjobs()) 335 return 0; 336 if (argc > 1) 337 exitshell(number(argv[1])); 338 else 339 exitshell_savedstatus(); 340} 341