-/* Copyright (c) 1979 Regents of the University of California */
-#include "sh.h"
+static char *sccsid = "@(#)sh.c 4.1 10/9/80";
+#include "sh.h"
+#include <sys/ioctl.h>
/*
* C Shell
*
- * Bill Joy, UC Berkeley
- * October, 1978
+ * Bill Joy, UC Berkeley, California, USA
+ * October 1978, May 1980
+ *
+ * Jim Kulp, IIASA, Laxenburg, Austria
+ * April 1980
*/
-char *pathlist[] = { SRCHPATH, 0 };
+char *pathlist[] = { ".", "/usr/ucb", "/bin", "/usr/bin", 0 };
+char HIST = '!';
+char HISTSUB = '^';
+bool nofile;
+bool reenter;
+bool nverbose;
+bool nexececho;
+bool quitit;
+bool fast;
+bool prompt = 1;
main(c, av)
int c;
char **av;
{
register char **v, *cp;
- int nofile = 0;
- int reenter = 0;
- bool nverbose = 0, nexececho = 0, quitit = 0, fast = 0, prompt = 1;
- char *hp;
+ register int f;
settimes(); /* Immed. estab. timing base */
- hp = getenv("HOME");
v = av;
if (eq(v[0], "a.out")) /* A.out's are quittable */
quitit = 1;
uid = getuid();
-#ifdef V6
- loginsh = eq(*v, "-"); /* To do .login/.logout */
-#else
loginsh = **v == '-';
-#endif
if (loginsh)
time(&chktim);
*/
set("status", "0");
- if (hp == 0)
+ dinit(cp = getenv("HOME")); /* dinit thinks that HOME == cwd in a
+ * login shell */
+ if (cp == NOSTR)
fast++; /* No home -> can't read scripts */
else
- set("home", hp);
- if (uid == 0)
- pathlist[0] = "/etc";
- set1("path", saveblk(pathlist), &shvhed);
+ set("home", savestr(cp));
+ /*
+ * Grab other useful things from the environment.
+ * Should we grab everything??
+ */
+ if ((cp = getenv("USER")) != NOSTR)
+ set("user", savestr(cp));
+ if ((cp = getenv("TERM")) != NOSTR)
+ set("term", savestr(cp));
/*
* Re-initialize path if set in environment
- *
- cp = getenv("PATH");
- if (cp != 0) {
- register int i = 0;
+ */
+ if ((cp = getenv("PATH")) == NOSTR)
+ set1("path", saveblk(pathlist), &shvhed);
+ else {
+ register unsigned i = 0;
register char *dp;
register char **pv;
for (dp = cp; *dp; dp++)
if (*dp == ':')
i++;
- pv = calloc(i+1, sizeof (char **));
- dp = cp;
- i = 0;
- while (*dp) {
+ pv = (char **)calloc(i+2, sizeof (char **));
+ for (dp = cp, i = 0; ;)
if (*dp == ':') {
*dp = 0;
- pv[i++] = savestr(cp);
- *dp = ':';
- } else if (*dp == 0) {
- pv[i++] = savestr(cp);
+ pv[i++] = savestr(*cp ? cp : ".");
+ *dp++ = ':';
+ cp = dp;
+ } else if (*dp++ == 0) {
+ pv[i++] = savestr(*cp ? cp : ".");
break;
}
- dp++;
- }
pv[i] = 0;
set1("path", pv, &shvhed);
}
-*/
set("shell", SHELLPATH);
doldol = putn(getpid()); /* For $$ */
* We catch it only if we are the login shell.
*/
parintr = signal(SIGINT, SIG_IGN); /* parents interruptibility */
- signal(SIGINT, parintr); /* ... restore */
+ sigset(SIGINT, parintr); /* ... restore */
parterm = signal(SIGTERM, SIG_IGN); /* parents terminability */
signal(SIGTERM, parterm); /* ... restore */
case 0: /* - Interruptible, no prompt */
prompt = 0;
- **av = '-';
+ setintr++;
nofile++;
break;
case 'i': /* -i Interactive, even if !intty */
intact++;
- **av = '-';
nofile++;
break;
case 's': /* -s Read from std input */
nofile++;
- if (isatty(SHIN))
- **v = '-';
break;
case 't': /* -t Read one line from input */
onelflg = 2;
- if (isatty(SHIN))
- **v = '-';
prompt = 0;
nofile++;
break;
prompt = 0;
c--, v++;
}
-
/*
* Consider input a tty if it really is or we are interactive.
*/
intty = intact || isatty(SHIN);
+ /*
+ * Decide whether we should play with signals or not.
+ * If we are explicitly told (via -i, or -) or we are a login
+ * shell (arg0 starts with -) or the input and output are both
+ * the ttys("csh", or "csh</dev/ttyx>/dev/ttyx")
+ * Note that in only the login shell is it likely that parent
+ * may have set signals to be ignored
+ */
+ if (loginsh || intact || intty && isatty(SHOUT))
+ setintr = 1;
#ifdef TELL
settell();
#endif
/*
- * Commands are interruptible if we are interactive
- * or the process which created us was.
- */
- if (intact || parintr == SIG_DFL)
- **av = '-';
-
- /*
- * Save the remaining arguments in ARGV.
- * Normally the system-supplied argument list is ok as
- * a zero terminated value block.
- * On some version 6 systems, it is -1 terminated and setting it
- * to zero messes up "ps" so we change it to zero, copy
- * the block of pointers, and put it back the way it was.
+ * Save the remaining arguments in argv.
*/
-/*
- if (c == 0)
- set("argv", 0);
- else
- */
- if ((int) v[c] == -1) {
- /* ick */
- v[c] = 0, setq("argv", copyblk(v), &shvhed), v[c] = (char *) -1;
- } else
- setq("argv", v, &shvhed);
+ setq("argv", v, &shvhed);
/*
* Set up the prompt.
* If we are an interactive shell, then start fiddling
* with the signals; this is a tricky game.
*/
- if (**av == '-') {
- setintr++;
+ shpgrp = getpgrp(0);
+ opgrp = tpgrp = -1;
+ oldisc = -1;
+ if (setintr) {
+ **av = '-';
if (!quitit) /* Wary! */
signal(SIGQUIT, SIG_IGN);
- signal(SIGINT, SIG_IGN);
+ sigset(SIGINT, pintr);
+ sighold(SIGINT);
signal(SIGTERM, SIG_IGN);
+ if (quitit == 0 && arginp == 0) {
+ signal(SIGTSTP, SIG_IGN);
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ /*
+ * Wait till in foreground, in case someone
+ * stupidly runs
+ * csh &
+ * dont want to try to grab away the tty.
+ */
+ if (isatty(FSHDIAG))
+ f = FSHDIAG;
+ else if (isatty(FSHOUT))
+ f = FSHOUT;
+ else if (isatty(OLDSTD))
+ f = OLDSTD;
+ else
+ f = -1;
+retry:
+ if (ioctl(f, TIOCGPGRP, &tpgrp) == 0 && tpgrp != -1) {
+ int ldisc;
+ if (tpgrp != shpgrp) {
+ int old = sigsys(SIGTTIN, SIG_DFL);
+ kill(0, SIGTTIN);
+ sigsys(SIGTTIN, old);
+ goto retry;
+ }
+ if (ioctl(f, TIOCGETD, &oldisc) != 0)
+ goto notty;
+ if (oldisc != NTTYDISC) {
+ printf("Switching to new tty driver...\n");
+ ldisc = NTTYDISC;
+ ioctl(f, TIOCSETD, &ldisc);
+ } else
+ oldisc = -1;
+ opgrp = shpgrp;
+ shpgrp = getpid();
+ tpgrp = shpgrp;
+ ioctl(f, TIOCSPGRP, &shpgrp);
+ setpgrp(0, shpgrp);
+ dcopy(f, FSHTTY);
+ ioctl(FSHTTY, FIOCLEX, 0);
+ } else {
+notty:
+ printf("Warning: no access to tty; thus no job control in this shell...\n");
+ tpgrp = -1;
+ }
+ }
}
+ sigset(SIGCHLD, pchild); /* while signals not ready */
/*
* Set an exit here in case of an interrupt or error reading
srccat(value("home"), "/.cshrc");
if (!fast && !arginp && !onelflg)
dohash();
- if (loginsh)
-#ifdef NOHELP
- srccat("", ".login");
-#else
+ if (loginsh) {
+ int ldisc;
srccat(value("home"), "/.login");
-#endif
+ }
}
/*
exitstat();
}
+untty()
+{
+
+ if (tpgrp > 0) {
+ setpgrp(0, opgrp);
+ ioctl(FSHTTY, TIOCSPGRP, &opgrp);
+ if (oldisc != -1 && oldisc != NTTYDISC) {
+ printf("\nReverting to old tty driver...\n");
+ ioctl(FSHTTY, TIOCSETD, &oldisc);
+ }
+ }
+}
+
+importpath(cp)
+char *cp;
+{
+ register int i = 0;
+ register char *dp;
+ register char **pv;
+ int c;
+ static char dot[2] = {'.', 0};
+
+ for (dp = cp; *dp; dp++)
+ if (*dp == ':')
+ i++;
+ /*
+ * i+2 where i is the number of colons in the path.
+ * There are i+1 directories in the path plus we need
+ * room for a zero terminator.
+ */
+ pv = (char **) calloc(i+2, sizeof (char **));
+ dp = cp;
+ i = 0;
+ if (*dp)
+ for (;;) {
+ if ((c = *dp) == ':' || c == 0) {
+ *dp = 0;
+ pv[i++] = savestr(*cp ? cp : dot);
+ if (c) {
+ cp = dp + 1;
+ *dp = ':';
+ } else
+ break;
+ }
+ dp++;
+ }
+ pv[i] = 0;
+ set1("path", pv, &shvhed);
+}
+
/*
* Source to the file which is the catenation of the argument names.
*/
/* ioctl(unit, FIOCLEX, NULL); */
xfree(ep);
+#ifdef INGRES
srcunit(unit, 0);
+#else
+ srcunit(unit, 1);
+#endif
}
/*
- * Source to a unit. If onlyown it must be our file or
+ * Source to a unit. If onlyown it must be our file or our group or
* we don't chance it. This occurs on ".cshrc"s and the like.
*/
srcunit(unit, onlyown)
int oSHIN = -1, oldintty = intty;
struct whyle *oldwhyl = whyles;
char *ogointr = gointr, *oarginp = arginp;
+ char *oevalp = evalp, **oevalvec = evalvec;
int oonelflg = onelflg;
#ifdef TELL
bool otell = cantell;
/* The (few) real local variables */
jmp_buf oldexit;
int reenter;
- register int (*oldint)();
if (unit < 0)
return;
+ if (didfds)
+ donefds();
if (onlyown) {
struct stat stb;
-#ifdef CC
- if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_uid != (uid &~ 0377))) {
-#endif
-#ifdef CORY
- if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_uid != (uid &~ 0377))) {
-#endif
-#ifndef CC
-#ifndef CORY
- if (fstat(unit, &stb) < 0 || stb.st_uid != uid) {
-#endif
-#endif
+ if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_gid != getgid())) {
close(unit);
return;
}
*/
getexit(oldexit);
reenter = 0;
- oldint = signal(SIGINT, SIG_IGN);
+ if (setintr)
+ sighold(SIGINT);
setexit();
reenter++;
if (reenter == 1) {
/* Setup the new values of the state stuff saved above */
- copy(&saveB, &B, sizeof saveB);
+ copy((char *)&saveB, (char *)&B, sizeof saveB);
fbuf = (char **) 0;
fseekp = feobp = fblocks = 0;
oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0;
intty = isatty(SHIN), whyles = 0, gointr = 0;
+ evalvec = 0; evalp = 0;
/*
* Now if we are allowing commands to be interrupted,
* we let ourselves be interrupted.
*/
- signal(SIGINT, setintr ? pintr : oldint);
+ if (setintr)
+ sigrelse(SIGINT);
#ifdef TELL
settell();
#endif
process(0); /* 0 -> blow away on errors */
}
- signal(SIGINT, oldint);
+ if (setintr)
+ sigrelse(SIGINT);
if (oSHIN >= 0) {
register int i;
/* This code could get run twice but xfree doesn't care */
for (i = 0; i < fblocks; i++)
xfree(fbuf[i]);
- xfree(fbuf);
+ xfree((char *)fbuf);
/* Reset input arena */
- copy(&B, &saveB, sizeof B);
+ copy((char *)&B, (char *)&saveB, sizeof B);
close(SHIN), SHIN = oSHIN;
arginp = oarginp, onelflg = oonelflg;
+ evalp = oevalp, evalvec = oevalvec;
intty = oldintty, whyles = oldwhyl, gointr = ogointr;
#ifdef TELL
cantell = otell;
* we must also unwind.
*/
if (reenter >= 2)
- error(0);
+ error(NOSTR);
}
goodbye()
if (loginsh) {
signal(SIGQUIT, SIG_IGN);
- signal(SIGINT, SIG_IGN);
+ sigset(SIGINT, SIG_IGN);
signal(SIGTERM, SIG_IGN);
setintr = 0; /* No interrupts after "logout" */
if (adrof("home"))
exit(getn(value("status")));
}
+char *jobargv[2] = { "jobs", 0 };
/*
* Catch an interrupt, e.g. during lexical input.
* If we are an interactive shell, we reset the interrupt catch
{
register char **v;
+ if (setintr) {
+ sigrelse(SIGINT);
+ if (pjobs) {
+ pjobs = 0;
+ printf("\n");
+ dojobs(jobargv);
+ bferr("Interrupted");
+ }
+ }
if (setintr)
- signal(SIGINT, SIG_IGN);
+ sighold(SIGINT);
+ sigrelse(SIGCHLD);
draino();
/*
reset();
} else if (intty)
printf("\n"); /* Some like this, others don't */
- error(0);
+ error(NOSTR);
}
/*
* if this is ignored.
*
* Note that if catch is not set then we will unwind on any error.
- * In an end-of-file occurs, we return.
+ * If an end-of-file occurs, we return.
*/
process(catch)
bool catch;
{
register char *cp;
jmp_buf osetexit;
- struct wordent paraml;
struct command *t;
getexit(osetexit);
for (;;) {
+ pendjob();
paraml.next = paraml.prev = ¶ml;
paraml.word = "";
t = 0;
* Interruptible during interactive reads
*/
if (setintr)
- signal(SIGINT, pintr);
+ sigrelse(SIGINT);
/*
* For the sake of reset()
doneinp = 0;
break;
}
- if (intty) {
+ if (chkstop)
+ chkstop--;
+ if (neednote)
+ pnote();
+ if (intty && evalvec == 0) {
mailchk();
/*
* If we are at the end of the input buffer
if (fseekp == feobp)
if (!whyles)
for (cp = value("prompt"); *cp; cp++)
- if (*cp == '!')
+ if (*cp == HIST)
printf("%d", eventno + 1);
else {
- if (*cp == '\\' && cp[1] == '!')
+ if (*cp == '\\' && cp[1] == HIST)
cp++;
putchar(*cp | QUOTE);
}
* The parser may lose space if interrupted.
*/
if (setintr)
- signal(SIGINT, SIG_IGN);
+ sighold(SIGINT);
/*
* Save input text on the history list if it
/*
* Parse the words of the input into a parse tree.
*/
- t = syntax(paraml.next, ¶ml);
+ t = syntax(paraml.next, ¶ml, 0);
if (err)
error(err);
/*
* Execute the parse tree
*/
- execute(t);
+ execute(t, tpgrp);
/*
* Made it!
xfree(f);
if (u < 0)
Perror(f);
- didfds = 0;
srcunit(u, 0);
}
* about any mail file unless its been modified
* after the time we started.
* This prevents us from telling the user things he already
- * knows, since the login program insist on saying
+ * knows, since the login program insists on saying
* "You have mail."
*/
mailchk()
register char **vp;
time_t t;
int intvl, cnt;
+ struct stat stb;
+ bool new;
v = adrof("mail");
if (v == 0)
if (chktim + intvl > t)
return;
for (; *vp; vp++) {
- bool new;
- struct stat stb;
-
if (stat(*vp, &stb) < 0)
continue;
- /*
- * We assume that a file has been read if the access time is
- * greater than the mod time.
- */
-#ifndef CORY
- if (stb.st_size == 0)
- continue;
-#endif
- if (stb.st_atime > stb.st_mtime || stb.st_atime < chktim)
- continue;
new = stb.st_mtime > time0;
- if (loginsh && !new)
+ if (stb.st_size == 0 || stb.st_atime > stb.st_mtime ||
+ (stb.st_atime < chktim && stb.st_mtime < chktim) ||
+ loginsh && !new)
continue;
if (cnt == 1)
printf("You have %smail.\n", new ? "new " : "");
closem();
}
-#ifndef V6
exit(i)
int i;
{
+ untty();
+#ifdef PROF
+ IEH3exit(i);
+#else
_exit(i);
-}
#endif
+}