diff options
Diffstat (limited to 'bin/sh/main.c')
-rw-r--r-- | bin/sh/main.c | 393 |
1 files changed, 393 insertions, 0 deletions
diff --git a/bin/sh/main.c b/bin/sh/main.c new file mode 100644 index 0000000..a023611 --- /dev/null +++ b/bin/sh/main.c @@ -0,0 +1,393 @@ +/* $NetBSD: main.c,v 1.80 2019/01/19 14:20:22 kre Exp $ */ + +/*- + * Copyright (c) 1991, 1993 + * The Regents of the University of California. All rights reserved. + * + * This code is derived from software contributed to Berkeley by + * Kenneth Almquist. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions + * are met: + * 1. Redistributions of source code must retain the above copyright + * notice, this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright + * notice, this list of conditions and the following disclaimer in the + * documentation and/or other materials provided with the distribution. + * 3. Neither the name of the University nor the names of its contributors + * may be used to endorse or promote products derived from this software + * without specific prior written permission. + * + * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND + * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE + * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL + * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS + * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT + * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY + * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF + * SUCH DAMAGE. + */ + +#include <sys/cdefs.h> +#ifndef lint +__COPYRIGHT("@(#) Copyright (c) 1991, 1993\ + The Regents of the University of California. All rights reserved."); +#endif /* not lint */ + +#ifndef lint +#if 0 +static char sccsid[] = "@(#)main.c 8.7 (Berkeley) 7/19/95"; +#else +__RCSID("$NetBSD: main.c,v 1.80 2019/01/19 14:20:22 kre Exp $"); +#endif +#endif /* not lint */ + +#include <errno.h> +#include <stdio.h> +#include <signal.h> +#include <sys/stat.h> +#include <unistd.h> +#include <stdlib.h> +#include <locale.h> +#include <fcntl.h> + + +#include "shell.h" +#include "main.h" +#include "mail.h" +#include "options.h" +#include "builtins.h" +#include "output.h" +#include "parser.h" +#include "nodes.h" +#include "expand.h" +#include "eval.h" +#include "jobs.h" +#include "input.h" +#include "trap.h" +#include "var.h" +#include "show.h" +#include "memalloc.h" +#include "error.h" +#include "init.h" +#include "mystring.h" +#include "exec.h" +#include "cd.h" +#include "redir.h" + +#define PROFILE 0 + +int rootpid; +int rootshell; +struct jmploc main_handler; +int max_user_fd; +#if PROFILE +short profile_buf[16384]; +extern int etext(); +#endif + +STATIC void read_profile(const char *); + +/* + * Main routine. We initialize things, parse the arguments, execute + * profiles if we're a login shell, and then call cmdloop to execute + * commands. The setjmp call sets up the location to jump to when an + * exception occurs. When an exception occurs the variable "state" + * is used to figure out how far we had gotten. + */ + +int +main(int argc, char **argv) +{ + struct stackmark smark; + volatile int state; + char *shinit; + uid_t uid; + gid_t gid; + + uid = getuid(); + gid = getgid(); + + max_user_fd = fcntl(0, F_MAXFD); + if (max_user_fd < 2) + max_user_fd = 2; + + setlocale(LC_ALL, ""); + + posix = getenv("POSIXLY_CORRECT") != NULL; +#if PROFILE + monitor(4, etext, profile_buf, sizeof profile_buf, 50); +#endif + state = 0; + if (setjmp(main_handler.loc)) { + /* + * When a shell procedure is executed, we raise the + * exception EXSHELLPROC to clean up before executing + * the shell procedure. + */ + switch (exception) { + case EXSHELLPROC: + rootpid = getpid(); + rootshell = 1; + minusc = NULL; + state = 3; + break; + + case EXEXEC: + exitstatus = exerrno; + break; + + case EXERROR: + exitstatus = 2; + break; + + default: + break; + } + + if (exception != EXSHELLPROC) { + if (state == 0 || iflag == 0 || ! rootshell || + exception == EXEXIT) + exitshell(exitstatus); + } + reset(); + if (exception == EXINT) { + out2c('\n'); + flushout(&errout); + } + popstackmark(&smark); + FORCEINTON; /* enable interrupts */ + if (state == 1) + goto state1; + else if (state == 2) + goto state2; + else if (state == 3) + goto state3; + else + goto state4; + } + handler = &main_handler; +#ifdef DEBUG +#if DEBUG >= 2 + debug = 1; /* this may be reset by procargs() later */ +#endif + opentrace(); + trputs("Shell args: "); trargs(argv); +#if DEBUG >= 3 + set_debug(((DEBUG)==3 ? "_@" : "++"), 1); +#endif +#endif + rootpid = getpid(); + rootshell = 1; + init(); + initpwd(); + setstackmark(&smark); + procargs(argc, argv); + + /* + * Limit bogus system(3) or popen(3) calls in setuid binaries, + * by requiring the -p flag + */ + if (!pflag && (uid != geteuid() || gid != getegid())) { + setuid(uid); + setgid(gid); + /* PS1 might need to be changed accordingly. */ + choose_ps1(); + } + + if (argv[0] && argv[0][0] == '-') { + state = 1; + read_profile("/etc/profile"); + state1: + state = 2; + read_profile(".profile"); + } + state2: + state = 3; + if ((iflag || !posix) && + getuid() == geteuid() && getgid() == getegid()) { + struct stackmark env_smark; + + setstackmark(&env_smark); + if ((shinit = lookupvar("ENV")) != NULL && *shinit != '\0') { + state = 3; + read_profile(expandenv(shinit)); + } + popstackmark(&env_smark); + } + state3: + state = 4; + line_number = 1; /* undo anything from profile files */ + + if (sflag == 0 || minusc) { + static int sigs[] = { + SIGINT, SIGQUIT, SIGHUP, +#ifdef SIGTSTP + SIGTSTP, +#endif + SIGPIPE + }; +#define SIGSSIZE (sizeof(sigs)/sizeof(sigs[0])) + size_t i; + + for (i = 0; i < SIGSSIZE; i++) + setsignal(sigs[i], 0); + } + + if (minusc) + evalstring(minusc, sflag ? 0 : EV_EXIT); + + if (sflag || minusc == NULL) { + state4: /* XXX ??? - why isn't this before the "if" statement */ + cmdloop(1); + } +#if PROFILE + monitor(0); +#endif + line_number = plinno; + exitshell(exitstatus); + /* NOTREACHED */ +} + + +/* + * Read and execute commands. "Top" is nonzero for the top level command + * loop; it turns on prompting if the shell is interactive. + */ + +void +cmdloop(int top) +{ + union node *n; + struct stackmark smark; + int inter; + int numeof = 0; + enum skipstate skip; + + CTRACE(DBG_ALWAYS, ("cmdloop(%d) called\n", top)); + setstackmark(&smark); + for (;;) { + if (pendingsigs) + dotrap(); + inter = 0; + if (iflag == 1 && top) { + inter = 1; + showjobs(out2, SHOW_CHANGED); + chkmail(0); + flushout(&errout); + nflag = 0; + } + n = parsecmd(inter); + VXTRACE(DBG_PARSE|DBG_EVAL|DBG_CMDS,("cmdloop: "),showtree(n)); + if (n == NEOF) { + if (!top || numeof >= 50) + break; + if (nflag) + break; + if (!stoppedjobs()) { + if (!iflag || !Iflag) + break; + out2str("\nUse \"exit\" to leave shell.\n"); + } + numeof++; + } else if (n != NULL && nflag == 0) { + job_warning = (job_warning == 2) ? 1 : 0; + numeof = 0; + evaltree(n, 0); + } + rststackmark(&smark); + + /* + * Any SKIP* can occur here! SKIP(FUNC|BREAK|CONT) occur when + * a dotcmd is in a loop or a function body and appropriate + * built-ins occurs in file scope in the sourced file. Values + * other than SKIPFILE are reset by the appropriate eval*() + * that contained the dotcmd() call. + */ + skip = current_skipstate(); + if (skip != SKIPNONE) { + if (skip == SKIPFILE) + stop_skipping(); + break; + } + } + popstackmark(&smark); +} + + + +/* + * Read /etc/profile or .profile. Return on error. + */ + +STATIC void +read_profile(const char *name) +{ + int fd; + int xflag_set = 0; + int vflag_set = 0; + + if (*name == '\0') + return; + + INTOFF; + if ((fd = open(name, O_RDONLY)) >= 0) + setinputfd(fd, 1); + INTON; + if (fd < 0) + return; + /* -q turns off -x and -v just when executing init files */ + if (qflag) { + if (xflag) + xflag = 0, xflag_set = 1; + if (vflag) + vflag = 0, vflag_set = 1; + } + cmdloop(0); + if (qflag) { + if (xflag_set) + xflag = 1; + if (vflag_set) + vflag = 1; + } + popfile(); +} + + + +/* + * Read a file containing shell functions. + */ + +void +readcmdfile(char *name) +{ + int fd; + + INTOFF; + if ((fd = open(name, O_RDONLY)) >= 0) + setinputfd(fd, 1); + else + error("Can't open %s", name); + INTON; + cmdloop(0); + popfile(); +} + + + +int +exitcmd(int argc, char **argv) +{ + if (stoppedjobs()) + return 0; + if (argc > 1) + exitshell(number(argv[1])); + else + exitshell_savedstatus(); + /* NOTREACHED */ +} |