📄 csh.c
字号:
(void) signal(SIGINT, pintr); (void) sigblock(sigmask(SIGINT)); (void) signal(SIGTERM, SIG_IGN); if (quitit == 0 && arginp == 0) { (void) signal(SIGTSTP, SIG_IGN); (void) signal(SIGTTIN, SIG_IGN); (void) 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(FSHERR)) f = FSHERR; else if (isatty(FSHOUT)) f = FSHOUT; else if (isatty(OLDSTD)) f = OLDSTD; else f = -1; retry: if ((tpgrp = tcgetpgrp(f)) != -1) { if (tpgrp != shpgrp) { sig_t old = signal(SIGTTIN, SIG_DFL); (void) kill(0, SIGTTIN); (void) signal(SIGTTIN, old); goto retry; } opgrp = shpgrp; shpgrp = getpid(); tpgrp = shpgrp; /* * Setpgid will fail if we are a session leader and * mypid == mypgrp (POSIX 4.3.3) */ if (opgrp != shpgrp) if (setpgid(0, shpgrp) == -1) goto notty; /* * We do that after we set our process group, to make sure * that the process group belongs to a process in the same * session as the tty (our process and our group) (POSIX 7.2.4) */ if (tcsetpgrp(f, shpgrp) == -1) goto notty; (void) ioctl(dcopy(f, FSHTTY), FIOCLEX, NULL); } if (tpgrp == -1) {notty: (void) fprintf(csherr, "Warning: no access to tty (%s).\n", strerror(errno)); (void) fprintf(csherr, "Thus no job control in this shell.\n"); } } } if ((setintr == 0) && (parintr == SIG_DFL)) setintr = 1; (void) signal(SIGCHLD, pchild); /* while signals not ready */ /* * Set an exit here in case of an interrupt or error reading the shell * start-up scripts. */ reenter = setexit(); /* PWP */ haderr = 0; /* In case second time through */ if (!fast && reenter == 0) { /* Will have value(STRhome) here because set fast if don't */ { int osetintr = setintr; sig_t oparintr = parintr; sigset_t omask = sigblock(sigmask(SIGINT)); setintr = 0; parintr = SIG_IGN; /* Disable onintr */#ifdef _PATH_DOTCSHRC (void) srcfile(_PATH_DOTCSHRC, 0, 0);#endif if (!fast && !arginp && !onelflg) dohash(NULL, NULL);#ifdef _PATH_DOTLOGIN if (loginsh) (void) srcfile(_PATH_DOTLOGIN, 0, 0);#endif (void) sigsetmask(omask); setintr = osetintr; parintr = oparintr; } (void) srccat(value(STRhome), STRsldotcshrc); if (!fast && !arginp && !onelflg && !havhash) dohash(NULL, NULL); /* * Source history before .login so that it is available in .login */ if ((cp = value(STRhistfile)) != STRNULL) loadhist[2] = cp; dosource(loadhist, NULL); if (loginsh) (void) srccat(value(STRhome), STRsldotlogin); } /* * Now are ready for the -v and -x flags */ if (nverbose) setNS(STRverbose); if (nexececho) setNS(STRecho); /* * All the rest of the world is inside this call. The argument to process * indicates whether it should catch "error unwinds". Thus if we are a * interactive shell our call here will never return by being blown past on * an error. */ process(setintr); /* * Mop-up. */ if (intty) { if (loginsh) { (void) fprintf(cshout, "logout\n"); (void) close(SHIN); child = 1; goodbye(); } else { (void) fprintf(cshout, "exit\n"); } } rechist(); exitstat(); return (0);}voiduntty(){ if (tpgrp > 0) { (void) setpgid(0, opgrp); (void) tcsetpgrp(FSHTTY, opgrp); }}voidimportpath(cp) Char *cp;{ register int i = 0; register Char *dp; register Char **pv; int c; 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 **) xcalloc((size_t) (i + 2), sizeof(Char **)); dp = cp; i = 0; if (*dp) for (;;) { if ((c = *dp) == ':' || c == 0) { *dp = 0; if ((*cp != '/' || *cp == '\0') && (euid == 0 || uid == 0)) (void) fprintf(csherr, "Warning: imported path contains relative components\n"); pv[i++] = Strsave(*cp ? cp : STRdot); if (c) { cp = dp + 1; *dp = ':'; } else break; } dp++; } pv[i] = 0; set1(STRpath, pv, &shvhed);}/* * Source to the file which is the catenation of the argument names. */static intsrccat(cp, dp) Char *cp, *dp;{ register Char *ep = Strspl(cp, dp); char *ptr = short2str(ep); xfree((ptr_t) ep); return srcfile(ptr, mflag ? 0 : 1, 0);}/* * Source to a file putting the file descriptor in a safe place (> 2). */static intsrcfile(f, onlyown, flag) char *f; bool onlyown, flag;{ register int unit; if ((unit = open(f, O_RDONLY)) == -1) return 0; unit = dmove(unit, -1); (void) ioctl(unit, FIOCLEX, NULL); srcunit(unit, onlyown, flag); return 1;}/* * 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. */int insource;static voidsrcunit(unit, onlyown, hflg) register int unit; bool onlyown, hflg;{ /* We have to push down a lot of state here */ /* All this could go into a structure */ int oSHIN = -1, oldintty = intty, oinsource = insource; struct whyle *oldwhyl = whyles; Char *ogointr = gointr, *oarginp = arginp; Char *oevalp = evalp, **oevalvec = evalvec; int oonelflg = onelflg; bool oenterhist = enterhist; char OHIST = HIST; bool otell = cantell; struct Bin saveB; volatile sigset_t omask; jmp_buf oldexit; /* The (few) real local variables */ int my_reenter; if (unit < 0) return; if (didfds) donefds(); if (onlyown) { struct stat stb; if (fstat(unit, &stb) < 0) { (void) close(unit); return; } } /* * There is a critical section here while we are pushing down the input * stream since we have stuff in different structures. If we weren't * careful an interrupt could corrupt SHIN's Bin structure and kill the * shell. * * We could avoid the critical region by grouping all the stuff in a single * structure and pointing at it to move it all at once. This is less * efficient globally on many variable references however. */ insource = 1; getexit(oldexit); omask = 0; if (setintr) omask = sigblock(sigmask(SIGINT)); /* Setup the new values of the state stuff saved above */ bcopy((char *) &B, (char *) &(saveB), sizeof(B)); fbuf = NULL; fseekp = feobp = fblocks = 0; oSHIN = SHIN, SHIN = unit, arginp = 0, onelflg = 0; intty = isatty(SHIN), whyles = 0, gointr = 0; evalvec = 0; evalp = 0; enterhist = hflg; if (enterhist) HIST = '\0'; /* * Now if we are allowing commands to be interrupted, we let ourselves be * interrupted. */ if (setintr) (void) sigsetmask(omask); settell(); if ((my_reenter = setexit()) == 0) process(0); /* 0 -> blow away on errors */ if (setintr) (void) sigsetmask(omask); if (oSHIN >= 0) { register int i; /* We made it to the new state... free up its storage */ /* This code could get run twice but xfree doesn't care */ for (i = 0; i < fblocks; i++) xfree((ptr_t) fbuf[i]); xfree((ptr_t) fbuf); /* Reset input arena */ bcopy((char *) &(saveB), (char *) &B, sizeof(B)); (void) close(SHIN), SHIN = oSHIN; arginp = oarginp, onelflg = oonelflg; evalp = oevalp, evalvec = oevalvec; intty = oldintty, whyles = oldwhyl, gointr = ogointr; if (enterhist) HIST = OHIST; enterhist = oenterhist; cantell = otell; } resexit(oldexit); /* * If process reset() (effectively an unwind) then we must also unwind. */ if (my_reenter) stderror(ERR_SILENT); insource = oinsource;}voidrechist(){ Char buf[BUFSIZ], hbuf[BUFSIZ], *hfile; int fp, ftmp, oldidfds; struct varent *shist; if (!fast) { /* * If $savehist is just set, we use the value of $history * else we use the value in $savehist */ if ((shist = adrof(STRsavehist)) != NULL) { if (shist->vec[0][0] != '\0') (void) Strcpy(hbuf, shist->vec[0]); else if ((shist = adrof(STRhistory)) && shist->vec[0][0] != '\0') (void) Strcpy(hbuf, shist->vec[0]); else return; } else return; if ((hfile = value(STRhistfile)) == STRNULL) { hfile = Strcpy(buf, value(STRhome)); (void) Strcat(buf, STRsldthist); } if ((fp = creat(short2str(hfile), 0600)) == -1) return; oldidfds = didfds; didfds = 0; ftmp = SHOUT; SHOUT = fp; dumphist[2] = hbuf; dohist(dumphist, NULL); SHOUT = ftmp; (void) close(fp); didfds = oldidfds; }}voidgoodbye(){ rechist(); if (loginsh) { (void) signal(SIGQUIT, SIG_IGN); (void) signal(SIGINT, SIG_IGN); (void) signal(SIGTERM, SIG_IGN); setintr = 0; /* No interrupts after "logout" */ if (!(adrof(STRlogout))) set(STRlogout, STRnormal);#ifdef _PATH_DOTLOGOUT (void) srcfile(_PATH_DOTLOGOUT, 0, 0);#endif if (adrof(STRhome)) (void) srccat(value(STRhome), STRsldtlogout); } exitstat();}voidexitstat(){ Char *s;#ifdef PROF monitor(0);#endif /* * Note that if STATUS is corrupted (i.e. getn bombs) then error will exit * directly because we poke child here. Otherwise we might continue * unwarrantedly (sic). */ child = 1; s = value(STRstatus); xexit(s ? getn(s) : 0);}/* * in the event of a HUP we want to save the history */static voidphup(sig)int sig;{ rechist(); /* * We kill the last foreground process group. It then becomes * responsible to propagate the SIGHUP to its progeny. */ { struct process *pp, *np; for (pp = proclist.p_next; pp; pp = pp->p_next) { np = pp; /* * Find if this job is in the foreground. It could be that * the process leader has exited and the foreground flag * is cleared for it. */ do /* * If a process is in the foreground; we try to kill * it's process group. If we succeed, then the * whole job is gone. Otherwise we keep going... * But avoid sending HUP to the shell again. */ if ((np->p_flags & PFOREGND) != 0 && np->p_jobid != shpgrp && killpg(np->p_jobid, SIGHUP) != -1) { /* In case the job was suspended... */ (void) killpg(np->p_jobid, SIGCONT); break; } while ((np = np->p_friends) != pp); } } _exit(sig);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -