--- /dev/null Thu Jan 01 00:00:00 1970 +0000
+++ b/usr/src/cmd/sh/main.c Tue Jun 14 00:00:00 2005 -0700
@@ -0,0 +1,647 @@
+/*
+ * CDDL HEADER START
+ *
+ * The contents of this file are subject to the terms of the
+ * Common Development and Distribution License, Version 1.0 only
+ * (the "License"). You may not use this file except in compliance
+ * with the License.
+ *
+ * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
+ * or http://www.opensolaris.org/os/licensing.
+ * See the License for the specific language governing permissions
+ * and limitations under the License.
+ *
+ * When distributing Covered Code, include this CDDL HEADER in each
+ * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
+ * If applicable, add the following below this CDDL HEADER, with the
+ * fields enclosed by brackets "[]" replaced with your own identifying
+ * information: Portions Copyright [yyyy] [name of copyright owner]
+ *
+ * CDDL HEADER END
+ */
+/*
+ * Copyright 2004 Sun Microsystems, Inc. All rights reserved.
+ * Use is subject to license terms.
+ */
+
+/* Copyright (c) 1984, 1986, 1987, 1988, 1989 AT&T */
+/* All Rights Reserved */
+
+
+
+#pragma ident "%Z%%M% %I% %E% SMI"
+
+/*
+ * UNIX shell
+ */
+
+#include "defs.h"
+#include "sym.h"
+#include "timeout.h"
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/wait.h>
+#include "dup.h"
+#include "sh_policy.h"
+
+#ifdef RES
+#include <sgtty.h>
+#endif
+
+pid_t mypid, mypgid, mysid;
+
+static BOOL beenhere = FALSE;
+unsigned char tmpout[20] = "/tmp/sh-";
+struct fileblk stdfile;
+struct fileblk *standin = &stdfile;
+int mailchk = 0;
+
+static unsigned char *mailp;
+static long *mod_time = 0;
+static BOOL login_shell = FALSE;
+
+#if vax
+char **execargs = (char **)(0x7ffffffc);
+#endif
+
+#if pdp11
+char **execargs = (char **)(-2);
+#endif
+
+
+static int exfile();
+extern unsigned char *simple();
+
+
+main(c, v, e)
+int c;
+char *v[];
+char *e[];
+{
+ register int rflag = ttyflg;
+ int rsflag = 1; /* local restricted flag */
+ register unsigned char *flagc = flagadr;
+ struct namnod *n;
+
+ mypid = getpid();
+ mypgid = getpgid(mypid);
+ mysid = getsid(mypid);
+
+ /*
+ * Do locale processing only if /usr is mounted.
+ */
+ localedir_exists = (access(localedir, F_OK) == 0);
+
+ /*
+ * initialize storage allocation
+ */
+
+ if (stakbot == 0) {
+ addblok((unsigned)0);
+ }
+
+ /*
+ * If the first character of the last path element of v[0] is "-"
+ * (ex. -sh, or /bin/-sh), this is a login shell
+ */
+ if (*simple(v[0]) == '-') {
+ signal(SIGXCPU, SIG_DFL);
+ signal(SIGXFSZ, SIG_DFL);
+
+ /*
+ * As the previous comment states, this is a login shell.
+ * Therefore, we set the login_shell flag to explicitly
+ * indicate this condition.
+ */
+ login_shell = TRUE;
+ }
+
+ stdsigs();
+
+ /*
+ * set names from userenv
+ */
+
+ setup_env();
+
+ /*
+ * LC_MESSAGES is set here so that early error messages will
+ * come out in the right style.
+ * Note that LC_CTYPE is done later on and is *not*
+ * taken from the previous environ
+ */
+
+ /*
+ * Do locale processing only if /usr is mounted.
+ */
+ if (localedir_exists)
+ (void) setlocale(LC_ALL, "");
+#if !defined(TEXT_DOMAIN) /* Should be defined by cc -D */
+#define TEXT_DOMAIN "SYS_TEST" /* Use this only if it weren't */
+#endif
+ (void) textdomain(TEXT_DOMAIN);
+
+ /*
+ * This is a profile shell if the simple name of argv[0] is
+ * pfsh or -pfsh
+ */
+ if (c > 0 && (eq("pfsh", simple(*v)) || eq("-pfsh", simple(*v)))) {
+ flags |= pfshflg;
+ secpolicy_init();
+ }
+
+ /*
+ * 'rsflag' is zero if SHELL variable is
+ * set in environment and
+ * the simple file part of the value.
+ * is rsh
+ */
+ if (n = findnam("SHELL"))
+ {
+ if (eq("rsh", simple(n->namval)))
+ rsflag = 0;
+ }
+
+ /*
+ * a shell is also restricted if the simple name of argv(0) is
+ * rsh or -rsh in its simple name
+ */
+
+#ifndef RES
+
+ if (c > 0 && (eq("rsh", simple(*v)) || eq("-rsh", simple(*v))))
+ rflag = 0;
+
+#endif
+
+ if (eq("jsh", simple(*v)) || eq("-jsh", simple(*v)))
+ flags |= monitorflg;
+
+ hcreate();
+ set_dotpath();
+
+
+ /*
+ * look for options
+ * dolc is $#
+ */
+ dolc = options(c, v);
+
+ if (dolc < 2)
+ {
+ flags |= stdflg;
+ {
+
+ while (*flagc)
+ flagc++;
+ *flagc++ = STDFLG;
+ *flagc = 0;
+ }
+ }
+ if ((flags & stdflg) == 0)
+ dolc--;
+
+ if ((flags & privflg) == 0) {
+ register uid_t euid;
+ register gid_t egid;
+ register uid_t ruid;
+ register gid_t rgid;
+
+ /*
+ * Determine all of the user's id #'s for this process and
+ * then decide if this shell is being entered as a result
+ * of a fork/exec.
+ * If the effective uid/gid do NOT match and the euid/egid
+ * is < 100 and the egid is NOT 1, reset the uid and gid to
+ * the user originally calling this process.
+ */
+ euid = geteuid();
+ ruid = getuid();
+ egid = getegid();
+ rgid = getgid();
+ if ((euid != ruid) && (euid < 100))
+ setuid(ruid); /* reset the uid to the orig user */
+ if ((egid != rgid) && ((egid < 100) && (egid != 1)))
+ setgid(rgid); /* reset the gid to the orig user */
+ }
+
+ dolv = (unsigned char **)v + c - dolc;
+ dolc--;
+
+ /*
+ * return here for shell file execution
+ * but not for parenthesis subshells
+ */
+ if (setjmp(subshell)) {
+ freejobs();
+ flags |= subsh;
+ }
+
+ /*
+ * number of positional parameters
+ */
+ replace(&cmdadr, dolv[0]); /* cmdadr is $0 */
+
+ /*
+ * set pidname '$$'
+ */
+ assnum(&pidadr, (long)mypid);
+
+ /*
+ * set up temp file names
+ */
+ settmp();
+
+ /*
+ * default internal field separators
+ * Do not allow importing of IFS from parent shell.
+ * setup_env() may have set anything from parent shell to IFS.
+ * Always set the default ifs to IFS.
+ */
+ assign(&ifsnod, sptbnl);
+
+ dfault(&mchknod, MAILCHECK);
+ mailchk = stoi(mchknod.namval);
+
+ /* initialize OPTIND for getopt */
+
+ n = lookup("OPTIND");
+ assign(n, "1");
+ /*
+ * make sure that option parsing starts
+ * at first character
+ */
+ _sp = 1;
+
+ /* initialize multibyte information */
+ setwidth();
+
+ if ((beenhere++) == FALSE) /* ? profile */
+ {
+ if ((login_shell == TRUE) && (flags & privflg) == 0) {
+
+ /* system profile */
+
+#ifndef RES
+
+ if ((input = pathopen(nullstr, sysprofile)) >= 0)
+ exfile(rflag); /* file exists */
+
+#endif
+ /* user profile */
+
+ if ((input = pathopen(homenod.namval, profile)) >= 0)
+ {
+ exfile(rflag);
+ flags &= ~ttyflg;
+ }
+ }
+ if (rsflag == 0 || rflag == 0) {
+ if ((flags & rshflg) == 0) {
+ while (*flagc)
+ flagc++;
+ *flagc++ = 'r';
+ *flagc = '\0';
+ }
+ flags |= rshflg;
+ }
+
+ /*
+ * open input file if specified
+ */
+ if (comdiv)
+ {
+ estabf(comdiv);
+ input = -1;
+ }
+ else
+ {
+ if (flags & stdflg) {
+ input = 0;
+ } else {
+ /*
+ * If the command file specified by 'cmdadr'
+ * doesn't exist, chkopen() will fail calling
+ * exitsh(). If this is a login shell and
+ * the $HOME/.profile file does not exist, the
+ * above statement "flags &= ~ttyflg" does not
+ * get executed and this makes exitsh() call
+ * longjmp() instead of exiting. longjmp() will
+ * return to the location specified by the last
+ * active jmpbuffer, which is the one set up in
+ * the function exfile() called after the system
+ * profile file is executed (see lines above).
+ * This would cause an infinite loop, because
+ * chkopen() will continue to fail and exitsh()
+ * to call longjmp(). To make exitsh() exit instead
+ * of calling longjmp(), we then set the flag forcexit
+ * at this stage.
+ */
+
+ flags |= forcexit;
+ input = chkopen(cmdadr, 0);
+ flags &= ~forcexit;
+ }
+
+#ifdef ACCT
+ if (input != 0)
+ preacct(cmdadr);
+#endif
+ comdiv--;
+ }
+ }
+#ifdef pdp11
+ else
+ *execargs = (char *)dolv; /* for `ps' cmd */
+#endif
+
+
+ exfile(0);
+ done(0);
+}
+
+static int
+exfile(prof)
+BOOL prof;
+{
+ time_t mailtime = 0; /* Must not be a register variable */
+ time_t curtime = 0;
+
+ /*
+ * move input
+ */
+ if (input > 0)
+ {
+ Ldup(input, INIO);
+ input = INIO;
+ }
+
+
+ setmode(prof);
+
+ if (setjmp(errshell) && prof)
+ {
+ close(input);
+ (void) endjobs(0);
+ return;
+ }
+ /*
+ * error return here
+ */
+
+ loopcnt = peekc = peekn = 0;
+ fndef = 0;
+ nohash = 0;
+ iopend = 0;
+
+ if (input >= 0)
+ initf(input);
+ /*
+ * command loop
+ */
+ for (;;)
+ {
+ tdystak(0);
+ stakchk(); /* may reduce sbrk */
+ exitset();
+
+ if ((flags & prompt) && standin->fstak == 0 && !eof)
+ {
+
+ if (mailp)
+ {
+ time(&curtime);
+
+ if ((curtime - mailtime) >= mailchk)
+ {
+ chkmail();
+ mailtime = curtime;
+ }
+ }
+
+ /* necessary to print jobs in a timely manner */
+ if (trapnote & TRAPSET)
+ chktrap();
+
+ prs(ps1nod.namval);
+
+#ifdef TIME_OUT
+ alarm(TIMEOUT);
+#endif
+
+ }
+
+ trapnote = 0;
+ peekc = readwc();
+ if (eof) {
+ if (endjobs(JOB_STOPPED))
+ return;
+ eof = 0;
+ }
+
+#ifdef TIME_OUT
+ alarm(0);
+#endif
+
+ {
+ register struct trenod *t;
+ t = cmd(NL, MTFLG);
+ if (t == NULL && flags & ttyflg)
+ freejobs();
+ else
+ execute(t, 0, eflag);
+ }
+
+ eof |= (flags & oneflg);
+
+ }
+}
+
+chkpr()
+{
+ if ((flags & prompt) && standin->fstak == 0)
+ prs(ps2nod.namval);
+}
+
+settmp()
+{
+ int i;
+ i = ltos(mypid);
+ serial = 0;
+ tmpname = movstr(numbuf + i, &tmpout[TMPNAM]);
+}
+
+Ldup(fa, fb)
+register int fa, fb;
+{
+#ifdef RES
+
+ dup(fa | DUPFLG, fb);
+ close(fa);
+ ioctl(fb, FIOCLEX, 0);
+
+#else
+
+ if (fa >= 0) {
+ if (fa != fb)
+ {
+ close(fb);
+ fcntl(fa, 0, fb); /* normal dup */
+ close(fa);
+ }
+ fcntl(fb, 2, 1); /* autoclose for fb */
+ }
+
+#endif
+}
+
+
+chkmail()
+{
+ register unsigned char *s = mailp;
+ register unsigned char *save;
+
+ long *ptr = mod_time;
+ unsigned char *start;
+ BOOL flg;
+ struct stat statb;
+
+ while (*s) {
+ start = s;
+ save = 0;
+ flg = 0;
+
+ while (*s) {
+ if (*s != COLON) {
+ if (*s == '%' && save == 0)
+ save = s;
+
+ s++;
+ } else {
+ flg = 1;
+ *s = 0;
+ }
+ }
+
+ if (save)
+ *save = 0;
+
+ if (*start && stat((const char *)start, &statb) >= 0) {
+ if (statb.st_size && *ptr &&
+ statb.st_mtime != *ptr) {
+ if (save) {
+ prs(save+1);
+ newline();
+ }
+ else
+ prs(mailmsg);
+ }
+ *ptr = statb.st_mtime;
+ } else if (*ptr == 0)
+ *ptr = 1;
+
+ if (save)
+ *save = '%';
+
+ if (flg)
+ *s++ = COLON;
+
+ ptr++;
+ }
+}
+
+
+setmail(mailpath)
+ unsigned char *mailpath;
+{
+ register unsigned char *s = mailpath;
+ register int cnt = 1;
+
+ long *ptr;
+
+ free(mod_time);
+ if (mailp = mailpath)
+ {
+ while (*s)
+ {
+ if (*s == COLON)
+ cnt += 1;
+
+ s++;
+ }
+
+ ptr = mod_time = (long *)alloc(sizeof (long) * cnt);
+
+ while (cnt)
+ {
+ *ptr = 0;
+ ptr++;
+ cnt--;
+ }
+ }
+}
+
+void
+setwidth()
+{
+ unsigned char *name = lookup("LC_CTYPE")->namval;
+ if (!name || !*name)
+ name = lookup("LANG")->namval;
+ /*
+ * Do locale processing only if /usr is mounted.
+ */
+ if (localedir_exists) {
+ if (!name || !*name)
+ (void) setlocale(LC_CTYPE, "C");
+ else
+ (void) setlocale(LC_CTYPE, (const char *)name);
+ }
+}
+
+setmode(prof)
+{
+ /*
+ * decide whether interactive
+ */
+
+ if ((flags & intflg) ||
+ ((flags&oneflg) == 0 &&
+ isatty(output) &&
+ isatty(input)))
+
+ {
+ dfault(&ps1nod, (geteuid() ? stdprompt : supprompt));
+ dfault(&ps2nod, readmsg);
+ flags |= ttyflg | prompt;
+ if (mailpnod.namflg != N_DEFAULT)
+ setmail(mailpnod.namval);
+ else
+ setmail(mailnod.namval);
+ startjobs();
+ }
+ else
+ {
+ flags |= prof;
+ flags &= ~prompt;
+ }
+}
+
+/*
+ * A generic call back routine to output error messages from the
+ * policy backing functions called by pfsh.
+ *
+ * msg must contain '\n' if a new line is to be printed.
+ */
+void
+secpolicy_print(int level, const char *msg)
+{
+ switch (level) {
+ case SECPOLICY_WARN:
+ default:
+ prs(msg); /* prs() does gettext() */
+ return;
+ case SECPOLICY_ERROR:
+ error(msg);
+ break;
+ }
+}