sh.c
来自「<B>Digital的Unix操作系统VAX 4.2源码</B>」· C语言 代码 · 共 1,098 行 · 第 1/2 页
C
1,098 行
#ifndef lintstatic char *sccsid = "@(#)sh.c 4.2 (ULTRIX) 8/13/90";#endif lint/************************************************************************ * * * Copyright (c) 1988 by * * Digital Equipment Corporation, Maynard, MA * * All rights reserved. * * * * This software is furnished under a license and may be used and * * copied only in accordance with the terms of such license and * * with the inclusion of the above copyright notice. This * * software or any other copies thereof may not be provided or * * otherwise made available to any other person. No title to and * * ownership of the software is hereby transferred. * * * * This software is derived from software received from the * * University of California, Berkeley, and from Bell * * Laboratories. Use, duplication, or disclosure is subject to * * restrictions under license agreements with University of * * California and with AT&T. * * * * The information in this software is subject to change without * * notice and should not be construed as a commitment by Digital * * Equipment Corporation. * * * * Digital assumes no responsibility for the use or reliability * * of its software on equipment which is not supplied by Digital. * * * ************************************************************************//* * C Shell * * Bill Joy, UC Berkeley, California, USA * October 1978, May 1980 * * Jim Kulp, IIASA, Laxenburg, Austria * April 1980 * * Modification History: * * 005 - Bob Fontaine - Thu Jun 21 10:22:20 EDT 1990 * change name of csh internal printf function to csh_printf to avoid * conflicts with printf function in stdio library. * * 004 - Bob Fontaine - Fri May 25 10:00:14 EDT 1990 * Stat argument to source command and make sure file exists and * that it is a regular file (ie that it is not a directory, pipe ...). * Fix for QAR# 3835 * * 003 - Gary A. Gaudet - Thu Dec 28 17:31:15 EST 1989 * Added comments; removed code not compiled. * * 02 12-Nov-88, Al Delorey (afd). * Use "ifdef CSHEDIT" around the cmd line edit code. * * 01 20-Sep-88, Al Delorey (afd) * Added command line edit capability (search for "edit" to find changes). * Deleted Mips tsh_init call. */#include "sh.h"#include <sys/ioctl.h>char *word();#ifdef CSHEDITchar *editword();#endifchar *pathlist[] = { ".", "/usr/ucb", "/bin", "/usr/bin", 0 };char *dumphist[] = { "history", "-h", 0, 0 };char *loadhist[] = { "source", "-h", "~/.history", 0 };char HIST = '!';char HISTSUB = '^';bool nofile;bool reenter;bool nverbose;bool nexececho;bool quitit;bool fast;bool batch;bool prompt = 1;bool enterhist = 0;extern gid_t getegid(), getgid();extern uid_t geteuid(), getuid();main(c, av) int c; char **av;{ register char **v, *cp; register int f; struct sigvec osv;/* * immediately establish a timing base */ settimes(); v = av;/* * a.out's are quittable */ if (eq(v[0], "a.out")) quitit = 1;/* * get user id */ uid = getuid();/* * login shell if "-csh" with no arguments */ loginsh = **v == '-' && c == 1; if (loginsh) (void) time(&chktim); /* * Move the descriptors to safe places. * The variable didfds is 0 while we have only FSH* to work with. * When didfds is true, we have 0,1,2 and prefer to use these. */ initdesc(); /* * Initialize the shell variables. * ARGV and PROMPT are initialized later. * STATUS is also munged in several places. * CHILD is munged when forking/waiting */ set("status", "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", 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 */ if ((cp = getenv("PATH")) == NOSTR) set1("path", saveblk(pathlist), &shvhed); else importpath(cp); set("shell", SHELLPATH); doldol = putn(getpid()); /* For $$ */ shtemp = strspl("/tmp/sh", doldol); /* For << */ /* * Record the interrupt states from the parent process. * If the parent is non-interruptible our hand must be forced * or we (and our children) won't be either. * Our children inherit termination from our parent. * We catch it only if we are the login shell. */ /* parents interruptibility */ (void) sigvec(SIGINT, (struct sigvec *)0, &osv); parintr = osv.sv_handler; /* parents terminability */ (void) sigvec(SIGTERM, (struct sigvec *)0, &osv); parterm = osv.sv_handler; if (loginsh) { (void) signal(SIGHUP, phup); /* exit processing on HUP */ (void) signal(SIGXCPU, phup); /* ...and on XCPU */ (void) signal(SIGXFSZ, phup); /* ...and on XFSZ */ } /* * Process the arguments. * * Note that processing of -v/-x is actually delayed till after * script processing. */ c--, v++; while (c > 0 && (cp = v[0])[0] == '-' && *++cp != '\0' && !batch) { do switch (*cp++) { case 'b': /* -b Next arg is input file */ batch++; break; case 'c': /* -c Command input from arg */ if (c == 1) { exit(0); } c--, v++; arginp = v[0]; prompt = 0; nofile++; break; case 'e': /* -e Exit on any error */ exiterr++; break; case 'f': /* -f Fast start */ fast++; break; case 'i': /* -i Interactive, even if !intty */ intact++; nofile++; break; case 'n': /* -n Don't execute */ noexec++; break; case 'q': /* -q (Undoc'd) ... die on quit */ quitit = 1; break; case 's': /* -s Read from std input */ nofile++; break; case 't': /* -t Read one line from input */ onelflg = 2; prompt = 0; nofile++; break; case 'v': /* -v Echo hist expanded input */ nverbose = 1; /* ... later */ break; case 'x': /* -x Echo just before execution */ nexececho = 1; /* ... later */ break; case 'V': /* -V Echo hist expanded input */ setNS("verbose"); /* NOW! */ break; case 'X': /* -X Echo just before execution */ setNS("echo"); /* NOW! */ break; } while (*cp); v++, c--; } if (quitit) /* With all due haste, for debugging */ (void) signal(SIGQUIT, SIG_DFL); /* * Unless prevented by -c, -i, -s, or -t, if there * are remaining arguments the first of them is the name * of a shell file from which to read commands. */ if (nofile == 0 && c > 0) { nofile = open(v[0], 0); if (nofile < 0) { child++; /* So this ... */ Perror(v[0]); /* ... doesn't return */ } file = v[0]; SHIN = dmove(nofile, FSHIN); /* Replace FSHIN */ prompt = 0; c--, v++; } if (!batch && (uid != geteuid() || getgid() != getegid())) { errno = EACCES; child++; /* So this ... */ Perror("csh"); /* ... doesn't return */ } /* * 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 /* * Save the remaining arguments in argv. */ setq("argv", v, &shvhed); /* * Set up the prompt. */ if (prompt) set("prompt", uid == 0 ? "# " : "% "); /* * If we are an interactive shell, then start fiddling * with the signals; this is a tricky game. */ shpgrp = getpgrp(0); opgrp = tpgrp = -1; oldisc = -1; if (setintr) { **av = '-'; if (!quitit) /* Wary! */ (void) signal(SIGQUIT, SIG_IGN); (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(FSHDIAG)) f = FSHDIAG; else if (isatty(FSHOUT)) f = FSHOUT; else if (isatty(OLDSTD)) f = OLDSTD; else f = -1;retry: if (ioctl(f, TIOCGPGRP, (char *)&tpgrp) == 0 && tpgrp != -1) { int ldisc; if (tpgrp != shpgrp) { void (*old)() = signal(SIGTTIN,SIG_DFL); (void) kill(0, SIGTTIN); (void) signal(SIGTTIN, old); goto retry; } if (ioctl(f, TIOCGETD, (char *)&oldisc) != 0) goto notty; if (oldisc != NTTYDISC) {#ifdef DEBUG csh_printf("Switching to new tty driver...\n"); /* 005 RNF */#endif DEBUG ldisc = NTTYDISC; (void) ioctl(f, TIOCSETD, (char *)&ldisc); } else oldisc = -1; opgrp = shpgrp; shpgrp = getpid(); tpgrp = shpgrp; (void) ioctl(f, TIOCSPGRP, (char *)&shpgrp); (void) setpgrp(0, shpgrp); dcopy(f, FSHTTY); ioctl(FSHTTY, FIOCLEX, 0); } else {notty: csh_printf("Warning: no access to tty; thus no job control in this shell...\n"); /* 005 RNF */ tpgrp = -1; } } } if (setintr == 0 && parintr == SIG_DFL) setintr++; (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. */ setexit(); haderr = 0; /* In case second time through */ if (!fast && reenter == 0) { reenter++; /* Will have value("home") here because set fast if don't */ srccat(value("home"), "/.cshrc"); if (!fast && !arginp && !onelflg && !havhash) dohash(); if (loginsh) { srccat(value("home"), "/.login"); } dosource(loadhist); } /* * Now are ready for the -v and -x flags */ if (nverbose) setNS("verbose"); if (nexececho) setNS("echo"); /* * 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 (loginsh) { csh_printf("logout\n"); /* 005 RNF */ (void) close(SHIN); child++; goodbye(); } rechist(); exitstat();}untty(){ if (tpgrp > 0) { (void) setpgrp(0, opgrp); (void) ioctl(FSHTTY, TIOCSPGRP, (char *)&opgrp); if (oldisc != -1 && oldisc != NTTYDISC) {#ifdef DEBUG csh_printf("\nReverting to old tty driver...\n"); /* 005 RNF */#endif DEBUG (void) ioctl(FSHTTY, TIOCSETD, (char *)&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((unsigned) (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. */srccat(cp, dp) char *cp, *dp;{ register char *ep = strspl(cp, dp); register int unit = dmove(open(ep, 0), -1); xfree(ep);/* * There is code here to prevent from automatically source'ing $home/.cshrc * and $home/.login if you don't own them. This probably isn't a good * idea in two cases: * * 1. A program may exist whose sole purpose is to change your uid * and groups without changing you to that user (for example, su -e * in some versions of Unix). * * 2. You may be sharing a home directory with someone else. This was * the case with a group I worked in once. */#ifdef notdef srcunit(unit, 1, 0);#else srcunit(unit, 0, 0);#endif}/* * 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, hflg) register int unit; bool onlyown; bool hflg;{ /* We have to push down a lot of state here */ /* All this could go into a structure */ int oSHIN = -1, oldintty = intty; struct whyle *oldwhyl = whyles; char *ogointr = gointr, *oarginp = arginp; char *oevalp = evalp, **oevalvec = evalvec; int oonelflg = onelflg; bool oenterhist = enterhist; char OHIST = HIST;#ifdef TELL bool otell = cantell;#endif struct Bin saveB; /* The (few) real local variables */ jmp_buf oldexit; int reenter, omask; if (unit < 0) return; if (didfds) donefds(); if (onlyown) { struct stat stb; if (fstat(unit, &stb) < 0 || (stb.st_uid != uid && stb.st_gid != getgid())) { (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. *
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?