main.c revision 199629
1251881Speter/*- 2251881Speter * Copyright (c) 1991, 1993 3251881Speter * The Regents of the University of California. All rights reserved. 4251881Speter * 5251881Speter * This code is derived from software contributed to Berkeley by 6251881Speter * Kenneth Almquist. 7251881Speter * 8251881Speter * Redistribution and use in source and binary forms, with or without 9251881Speter * modification, are permitted provided that the following conditions 10251881Speter * are met: 11251881Speter * 1. Redistributions of source code must retain the above copyright 12251881Speter * notice, this list of conditions and the following disclaimer. 13251881Speter * 2. Redistributions in binary form must reproduce the above copyright 14251881Speter * notice, this list of conditions and the following disclaimer in the 15251881Speter * documentation and/or other materials provided with the distribution. 16251881Speter * 4. Neither the name of the University nor the names of its contributors 17251881Speter * may be used to endorse or promote products derived from this software 18251881Speter * without specific prior written permission. 19251881Speter * 20251881Speter * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 21251881Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 22251881Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 23251881Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 24251881Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 25251881Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 26251881Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 27251881Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 28251881Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 29251881Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 30251881Speter * SUCH DAMAGE. 31251881Speter */ 32251881Speter 33289180Speter#ifndef lint 34251881Speterstatic char const copyright[] = 35251881Speter"@(#) Copyright (c) 1991, 1993\n\ 36251881Speter The Regents of the University of California. All rights reserved.\n"; 37286506Speter#endif /* not lint */ 38251881Speter 39251881Speter#ifndef lint 40251881Speter#if 0 41251881Speterstatic char sccsid[] = "@(#)main.c 8.6 (Berkeley) 5/28/95"; 42251881Speter#endif 43251881Speter#endif /* not lint */ 44251881Speter#include <sys/cdefs.h> 45251881Speter__FBSDID("$FreeBSD: head/bin/sh/main.c 199629 2009-11-21 14:28:32Z jilles $"); 46251881Speter 47251881Speter#include <stdio.h> 48251881Speter#include <signal.h> 49251881Speter#include <sys/stat.h> 50251881Speter#include <unistd.h> 51251881Speter#include <fcntl.h> 52251881Speter#include <locale.h> 53251881Speter#include <errno.h> 54251881Speter 55289180Speter#include "shell.h" 56251881Speter#include "main.h" 57251881Speter#include "mail.h" 58251881Speter#include "options.h" 59251881Speter#include "output.h" 60251881Speter#include "parser.h" 61251881Speter#include "nodes.h" 62251881Speter#include "expand.h" 63251881Speter#include "eval.h" 64251881Speter#include "jobs.h" 65251881Speter#include "input.h" 66251881Speter#include "trap.h" 67251881Speter#include "var.h" 68251881Speter#include "show.h" 69251881Speter#include "memalloc.h" 70251881Speter#include "error.h" 71251881Speter#include "init.h" 72251881Speter#include "mystring.h" 73251881Speter#include "exec.h" 74362181Sdim#include "cd.h" 75362181Sdim 76362181Sdimint rootpid; 77251881Speterint rootshell; 78251881Speter 79251881SpeterSTATIC void read_profile(char *); 80251881SpeterSTATIC char *find_dot_file(char *); 81251881Speter 82251881Speter/* 83251881Speter * Main routine. We initialize things, parse the arguments, execute 84251881Speter * profiles if we're a login shell, and then call cmdloop to execute 85251881Speter * commands. The setjmp call sets up the location to jump to when an 86251881Speter * exception occurs. When an exception occurs the variable "state" 87251881Speter * is used to figure out how far we had gotten. 88251881Speter */ 89251881Speter 90251881Speterint 91251881Spetermain(int argc, char *argv[]) 92251881Speter{ 93251881Speter struct jmploc jmploc; 94251881Speter struct stackmark smark; 95251881Speter volatile int state; 96251881Speter char *shinit; 97251881Speter 98251881Speter (void) setlocale(LC_ALL, ""); 99251881Speter state = 0; 100251881Speter if (setjmp(jmploc.loc)) { 101251881Speter /* 102251881Speter * When a shell procedure is executed, we raise the 103251881Speter * exception EXSHELLPROC to clean up before executing 104251881Speter * the shell procedure. 105251881Speter */ 106251881Speter switch (exception) { 107251881Speter case EXSHELLPROC: 108251881Speter rootpid = getpid(); 109251881Speter rootshell = 1; 110251881Speter minusc = NULL; 111251881Speter state = 3; 112251881Speter break; 113251881Speter 114251881Speter case EXEXEC: 115251881Speter exitstatus = exerrno; 116251881Speter break; 117251881Speter 118289180Speter case EXERROR: 119251881Speter exitstatus = 2; 120251881Speter break; 121251881Speter 122251881Speter default: 123289180Speter break; 124289180Speter } 125251881Speter 126251881Speter if (exception != EXSHELLPROC) { 127251881Speter if (state == 0 || iflag == 0 || ! rootshell) 128251881Speter exitshell(exitstatus); 129251881Speter } 130251881Speter reset(); 131289180Speter if (exception == EXINT) { 132251881Speter out2c('\n'); 133251881Speter flushout(&errout); 134251881Speter } 135251881Speter popstackmark(&smark); 136251881Speter FORCEINTON; /* enable interrupts */ 137251881Speter if (state == 1) 138251881Speter goto state1; 139251881Speter else if (state == 2) 140251881Speter goto state2; 141251881Speter else if (state == 3) 142251881Speter goto state3; 143251881Speter else 144251881Speter goto state4; 145251881Speter } 146251881Speter handler = &jmploc; 147251881Speter#ifdef DEBUG 148251881Speter opentrace(); 149251881Speter trputs("Shell args: "); trargs(argv); 150251881Speter#endif 151251881Speter rootpid = getpid(); 152251881Speter rootshell = 1; 153251881Speter init(); 154251881Speter setstackmark(&smark); 155251881Speter procargs(argc, argv); 156251881Speter if (getpwd() == NULL && iflag) 157251881Speter out2fmt_flush("sh: cannot determine working directory\n"); 158251881Speter if (getpwd() != NULL) 159251881Speter setvar ("PWD", getpwd(), VEXPORT); 160251881Speter if (argv[0] && argv[0][0] == '-') { 161251881Speter state = 1; 162251881Speter read_profile("/etc/profile"); 163251881Speterstate1: 164251881Speter state = 2; 165251881Speter if (privileged == 0) 166251881Speter read_profile(".profile"); 167251881Speter else 168251881Speter read_profile("/etc/suid_profile"); 169251881Speter } 170251881Speterstate2: 171362181Sdim state = 3; 172362181Sdim if (!privileged && iflag) { 173251881Speter if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { 174251881Speter state = 3; 175251881Speter read_profile(shinit); 176251881Speter } 177251881Speter } 178251881Speterstate3: 179251881Speter state = 4; 180251881Speter if (minusc) { 181251881Speter evalstring(minusc, sflag ? 0 : EV_EXIT); 182251881Speter } 183251881Speter if (sflag || minusc == NULL) { 184251881Speterstate4: /* XXX ??? - why isn't this before the "if" statement */ 185251881Speter cmdloop(1); 186251881Speter } 187251881Speter exitshell(exitstatus); 188251881Speter /*NOTREACHED*/ 189251881Speter return 0; 190251881Speter} 191251881Speter 192251881Speter 193251881Speter/* 194251881Speter * Read and execute commands. "Top" is nonzero for the top level command 195251881Speter * loop; it turns on prompting if the shell is interactive. 196251881Speter */ 197251881Speter 198251881Spetervoid 199251881Spetercmdloop(int top) 200251881Speter{ 201251881Speter union node *n; 202251881Speter struct stackmark smark; 203251881Speter int inter; 204251881Speter int numeof = 0; 205251881Speter 206251881Speter TRACE(("cmdloop(%d) called\n", top)); 207251881Speter setstackmark(&smark); 208251881Speter for (;;) { 209251881Speter if (pendingsigs) 210251881Speter dotrap(); 211251881Speter inter = 0; 212251881Speter if (iflag && top) { 213251881Speter inter++; 214251881Speter showjobs(1, SHOWJOBS_DEFAULT); 215251881Speter chkmail(0); 216251881Speter flushout(&output); 217251881Speter } 218251881Speter n = parsecmd(inter); 219251881Speter /* showtree(n); DEBUG */ 220251881Speter if (n == NEOF) { 221251881Speter if (!top || numeof >= 50) 222251881Speter break; 223251881Speter if (!stoppedjobs()) { 224251881Speter if (!Iflag) 225251881Speter break; 226251881Speter out2fmt_flush("\nUse \"exit\" to leave shell.\n"); 227251881Speter } 228251881Speter numeof++; 229251881Speter } else if (n != NULL && nflag == 0) { 230251881Speter job_warning = (job_warning == 2) ? 1 : 0; 231251881Speter numeof = 0; 232251881Speter evaltree(n, 0); 233251881Speter } 234362181Sdim popstackmark(&smark); 235362181Sdim setstackmark(&smark); 236362181Sdim if (evalskip == SKIPFILE) { 237362181Sdim evalskip = 0; 238362181Sdim break; 239362181Sdim } 240362181Sdim } 241362181Sdim popstackmark(&smark); 242362181Sdim} 243362181Sdim 244362181Sdim 245362181Sdim 246362181Sdim/* 247362181Sdim * Read /etc/profile or .profile. Return on error. 248362181Sdim */ 249362181Sdim 250362181SdimSTATIC void 251362181Sdimread_profile(char *name) 252362181Sdim{ 253362181Sdim int fd; 254251881Speter 255251881Speter INTOFF; 256251881Speter if ((fd = open(name, O_RDONLY)) >= 0) 257286506Speter setinputfd(fd, 1); 258286506Speter INTON; 259286506Speter if (fd < 0) 260251881Speter return; 261251881Speter cmdloop(0); 262251881Speter popfile(); 263251881Speter} 264251881Speter 265251881Speter 266251881Speter 267251881Speter/* 268251881Speter * Read a file containing shell functions. 269251881Speter */ 270251881Speter 271251881Spetervoid 272251881Speterreadcmdfile(char *name) 273251881Speter{ 274251881Speter int fd; 275251881Speter 276251881Speter INTOFF; 277251881Speter if ((fd = open(name, O_RDONLY)) >= 0) 278251881Speter setinputfd(fd, 1); 279251881Speter else 280251881Speter error("Can't open %s: %s", name, strerror(errno)); 281251881Speter INTON; 282251881Speter cmdloop(0); 283251881Speter popfile(); 284251881Speter} 285251881Speter 286251881Speter 287251881Speter 288251881Speter/* 289251881Speter * Take commands from a file. To be compatible we should do a path 290251881Speter * search for the file, which is necessary to find sub-commands. 291251881Speter */ 292251881Speter 293251881Speter 294251881SpeterSTATIC char * 295251881Speterfind_dot_file(char *basename) 296251881Speter{ 297251881Speter static char localname[FILENAME_MAX+1]; 298251881Speter char *fullname; 299251881Speter char *path = pathval(); 300251881Speter struct stat statb; 301251881Speter 302251881Speter /* don't try this for absolute or relative paths */ 303251881Speter if( strchr(basename, '/')) 304251881Speter return basename; 305251881Speter 306251881Speter while ((fullname = padvance(&path, basename)) != NULL) { 307251881Speter strcpy(localname, fullname); 308251881Speter stunalloc(fullname); 309251881Speter if ((stat(fullname, &statb) == 0) && S_ISREG(statb.st_mode)) 310251881Speter return localname; 311251881Speter } 312251881Speter return basename; 313251881Speter} 314251881Speter 315251881Speterint 316251881Speterdotcmd(int argc, char **argv) 317251881Speter{ 318251881Speter struct strlist *sp; 319251881Speter char *fullname; 320251881Speter 321251881Speter if (argc < 2) 322251881Speter error("missing filename"); 323251881Speter 324251881Speter exitstatus = 0; 325251881Speter 326251881Speter for (sp = cmdenviron; sp ; sp = sp->next) 327251881Speter setvareq(savestr(sp->text), VSTRFIXED|VTEXTFIXED); 328251881Speter 329251881Speter fullname = find_dot_file(argv[1]); 330251881Speter setinputfile(fullname, 1); 331251881Speter commandname = fullname; 332251881Speter cmdloop(0); 333251881Speter popfile(); 334269833Speter return exitstatus; 335251881Speter} 336251881Speter 337251881Speter 338251881Speterint 339251881Speterexitcmd(int argc, char **argv) 340251881Speter{ 341251881Speter extern int oexitstatus; 342251881Speter 343251881Speter if (stoppedjobs()) 344251881Speter return 0; 345251881Speter if (argc > 1) 346251881Speter exitstatus = number(argv[1]); 347251881Speter else 348251881Speter exitstatus = oexitstatus; 349251881Speter exitshell(exitstatus); 350251881Speter /*NOTREACHED*/ 351251881Speter return 0; 352251881Speter} 353251881Speter