X-Git-Url: https://git.subgeniuskitty.com/unix-history/.git/blobdiff_plain/2b84abb596f52ab2068d52108adc96838ad4340a..31cef89cb428866f787983e68246030321893df4:/usr/src/cmd/csh/sh.c diff --git a/usr/src/cmd/csh/sh.c b/usr/src/cmd/csh/sh.c index 17168f88ee..dea30dddcf 100644 --- a/usr/src/cmd/csh/sh.c +++ b/usr/src/cmd/csh/sh.c @@ -1,36 +1,41 @@ -/* 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 /* * 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); @@ -49,43 +54,47 @@ main(c, av) */ 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 $$ */ @@ -99,7 +108,7 @@ main(c, av) * 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 */ @@ -119,7 +128,7 @@ main(c, av) case 0: /* - Interruptible, no prompt */ prompt = 0; - **av = '-'; + setintr++; nofile++; break; @@ -142,7 +151,6 @@ main(c, av) case 'i': /* -i Interactive, even if !intty */ intact++; - **av = '-'; nofile++; break; @@ -156,14 +164,10 @@ main(c, av) 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; @@ -207,39 +211,27 @@ main(c, av) 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") + * 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. @@ -251,13 +243,66 @@ main(c, av) * 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 @@ -271,12 +316,10 @@ main(c, av) 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 + } } /* @@ -307,6 +350,56 @@ main(c, av) 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. */ @@ -318,11 +411,15 @@ srccat(cp, dp) /* 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) @@ -334,6 +431,7 @@ 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; @@ -343,24 +441,15 @@ srcunit(unit, onlyown) /* 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; } @@ -379,27 +468,31 @@ srcunit(unit, onlyown) */ 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; @@ -407,13 +500,14 @@ srcunit(unit, onlyown) /* 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; @@ -426,7 +520,7 @@ srcunit(unit, onlyown) * we must also unwind. */ if (reenter >= 2) - error(0); + error(NOSTR); } goodbye() @@ -434,7 +528,7 @@ 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")) @@ -455,6 +549,7 @@ exitstat() 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 @@ -466,8 +561,18 @@ pintr() { 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(); /* @@ -485,7 +590,7 @@ pintr() reset(); } else if (intty) printf("\n"); /* Some like this, others don't */ - error(0); + error(NOSTR); } /* @@ -500,18 +605,18 @@ pintr() * 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; @@ -522,7 +627,7 @@ process(catch) * Interruptible during interactive reads */ if (setintr) - signal(SIGINT, pintr); + sigrelse(SIGINT); /* * For the sake of reset() @@ -553,7 +658,11 @@ process(catch) 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 @@ -564,10 +673,10 @@ process(catch) 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); } @@ -595,7 +704,7 @@ process(catch) * The parser may lose space if interrupted. */ if (setintr) - signal(SIGINT, SIG_IGN); + sighold(SIGINT); /* * Save input text on the history list if it @@ -623,14 +732,14 @@ process(catch) /* * 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! @@ -652,7 +761,6 @@ dosource(t) xfree(f); if (u < 0) Perror(f); - didfds = 0; srcunit(u, 0); } @@ -662,7 +770,7 @@ dosource(t) * 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() @@ -671,6 +779,8 @@ mailchk() register char **vp; time_t t; int intvl, cnt; + struct stat stb; + bool new; v = adrof("mail"); if (v == 0) @@ -684,23 +794,12 @@ mailchk() 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 " : ""); @@ -744,11 +843,14 @@ initdesc() closem(); } -#ifndef V6 exit(i) int i; { + untty(); +#ifdef PROF + IEH3exit(i); +#else _exit(i); -} #endif +}