📄 csh.c
字号:
/*- * Copyright (c) 1980, 1991, 1993 * The Regents of the University of California. All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. All advertising materials mentioning features or use of this software * must display the following acknowledgement: * This product includes software developed by the University of * California, Berkeley and its contributors. * 4. Neither the name of the University nor the names of its contributors * may be used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */#ifndef lintstatic char copyright[] ="@(#) Copyright (c) 1980, 1991, 1993\n\ The Regents of the University of California. All rights reserved.\n";#endif /* not lint */#ifndef lintstatic char sccsid[] = "@(#)csh.c 8.2 (Berkeley) 10/12/93";#endif /* not lint */#include <sys/types.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <fcntl.h>#include <errno.h>#include <pwd.h>#include <stdlib.h>#include <string.h>#include <locale.h>#include <unistd.h>#include <vis.h>#if __STDC__# include <stdarg.h>#else# include <varargs.h>#endif#include "csh.h"#include "proc.h"#include "extern.h"#include "pathnames.h"extern bool MapsAreInited;extern bool NLSMapsAreInited;/* * C Shell * * Bill Joy, UC Berkeley, California, USA * October 1978, May 1980 * * Jim Kulp, IIASA, Laxenburg, Austria * April 1980 * * Christos Zoulas, Cornell University * June, 1991 */Char *dumphist[] = {STRhistory, STRmh, 0, 0};Char *loadhist[] = {STRsource, STRmh, STRtildothist, 0};int nofile = 0;bool reenter = 0;bool nverbose = 0;bool nexececho = 0;bool quitit = 0;bool fast = 0;bool batch = 0;bool mflag = 0;bool prompt = 1;bool enterhist = 0;bool tellwhat = 0;extern char **environ;static int readf __P((void *, char *, int));static fpos_t seekf __P((void *, fpos_t, int));static int writef __P((void *, const char *, int));static int closef __P((void *));static int srccat __P((Char *, Char *));static int srcfile __P((char *, bool, bool));static void phup __P((int));static void srcunit __P((int, bool, bool));static void mailchk __P((void));static Char **defaultpath __P((void));intmain(argc, argv) int argc; char **argv;{ register Char *cp; register char *tcp; register int f; register char **tempv; struct sigvec osv; cshin = stdin; cshout = stdout; csherr = stderr; settimes(); /* Immed. estab. timing base */ /* * Initialize non constant strings */#ifdef _PATH_BSHELL STR_BSHELL = SAVE(_PATH_BSHELL);#endif#ifdef _PATH_CSHELL STR_SHELLPATH = SAVE(_PATH_CSHELL);#endif STR_environ = blk2short(environ); environ = short2blk(STR_environ); /* So that we can free it */ STR_WORD_CHARS = SAVE(WORD_CHARS); HIST = '!'; HISTSUB = '^'; word_chars = STR_WORD_CHARS; tempv = argv; if (eq(str2short(tempv[0]), STRaout)) /* A.out's are quittable */ quitit = 1; uid = getuid(); gid = getgid(); euid = geteuid(); egid = getegid(); /* * We are a login shell if: 1. we were invoked as -<something> and we had * no arguments 2. or we were invoked only with the -l flag */ loginsh = (**tempv == '-' && argc == 1) || (argc == 2 && tempv[1][0] == '-' && tempv[1][1] == 'l' && tempv[1][2] == '\0'); if (loginsh && **tempv != '-') { /* * Mangle the argv space */ tempv[1][0] = '\0'; tempv[1][1] = '\0'; tempv[1] = NULL; for (tcp = *tempv; *tcp++;) continue; for (tcp--; tcp >= *tempv; tcp--) tcp[1] = tcp[0]; *++tcp = '-'; argc--; } if (loginsh) (void) time(&chktim); AsciiOnly = 1;#ifdef NLS (void) setlocale(LC_ALL, ""); { int k; for (k = 0200; k <= 0377 && !Isprint(k); k++) continue; AsciiOnly = k > 0377; }#else AsciiOnly = getenv("LANG") == NULL && getenv("LC_CTYPE") == NULL;#endif /* NLS */ /* * 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(); /* * XXX: This is to keep programs that use stdio happy. * what we really want is freunopen() .... * Closing cshin cshout and csherr (which are really stdin stdout * and stderr at this point and then reopening them in the same order * gives us again stdin == cshin stdout == cshout and stderr == csherr. * If that was not the case builtins like printf that use stdio * would break. But in any case we could fix that with memcpy and * a bit of pointer manipulation... * Fortunately this is not needed under the current implementation * of stdio. */ (void) fclose(cshin); (void) fclose(cshout); (void) fclose(csherr); if (!(cshin = funopen((void *) &SHIN, readf, writef, seekf, closef))) exit(1); if (!(cshout = funopen((void *) &SHOUT, readf, writef, seekf, closef))) exit(1); if (!(csherr = funopen((void *) &SHERR, readf, writef, seekf, closef))) exit(1); (void) setvbuf(cshin, NULL, _IOLBF, 0); (void) setvbuf(cshout, NULL, _IOLBF, 0); (void) setvbuf(csherr, NULL, _IOLBF, 0); /* * Initialize the shell variables. ARGV and PROMPT are initialized later. * STATUS is also munged in several places. CHILD is munged when * forking/waiting */ set(STRstatus, Strsave(STR0)); if ((tcp = getenv("HOME")) != NULL) cp = SAVE(tcp); else cp = NULL; if (cp == NULL) fast = 1; /* No home -> can't read scripts */ else set(STRhome, cp); dinit(cp); /* dinit thinks that HOME == cwd in a login * shell */ /* * Grab other useful things from the environment. Should we grab * everything?? */ if ((tcp = getenv("LOGNAME")) != NULL || (tcp = getenv("USER")) != NULL) set(STRuser, SAVE(tcp)); if ((tcp = getenv("TERM")) != NULL) set(STRterm, SAVE(tcp)); /* * Re-initialize path if set in environment */ if ((tcp = getenv("PATH")) == NULL) set1(STRpath, defaultpath(), &shvhed); else importpath(SAVE(tcp)); set(STRshell, Strsave(STR_SHELLPATH)); doldol = putn((int) getpid()); /* For $$ */ shtemp = Strspl(STRtmpsh, 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, NULL, &osv); parintr = (void (*) ()) osv.sv_handler; (void) sigvec(SIGTERM, NULL, &osv); parterm = (void (*) ()) 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. * * We set the first character of our name to be '-' if we are a shell * running interruptible commands. Many programs which examine ps'es * use this to filter such shells out. */ argc--, tempv++; while (argc > 0 && (tcp = tempv[0])[0] == '-' && *++tcp != '\0' && !batch) { do switch (*tcp++) { case 0: /* - Interruptible, no prompt */ prompt = 0; setintr = 1; nofile = 1; break; case 'b': /* -b Next arg is input file */ batch = 1; break; case 'c': /* -c Command input from arg */ if (argc == 1) xexit(0); argc--, tempv++; arginp = SAVE(tempv[0]); prompt = 0; nofile = 1; break; case 'e': /* -e Exit on any error */ exiterr = 1; break; case 'f': /* -f Fast start */ fast = 1; break; case 'i': /* -i Interactive, even if !intty */ intact = 1; nofile = 1; break; case 'm': /* -m read .cshrc (from su) */ mflag = 1; break; case 'n': /* -n Don't execute */ noexec = 1; break; case 'q': /* -q (Undoc'd) ... die on quit */ quitit = 1; break; case 's': /* -s Read from std input */ nofile = 1; break; case 't': /* -t Read one line from input */ onelflg = 2; prompt = 0; nofile = 1; 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(STRverbose); /* NOW! */ break; case 'X': /* -X Echo just before execution */ setNS(STRecho); /* NOW! */ break; } while (*tcp); tempv++, argc--; } 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 && argc > 0) { nofile = open(tempv[0], O_RDONLY); if (nofile < 0) { child = 1; /* So this doesn't return */ stderror(ERR_SYSTEM, tempv[0], strerror(errno)); } ffile = SAVE(tempv[0]); /* * Replace FSHIN. Handle /dev/std{in,out,err} specially * since once they are closed we cannot open them again. * In that case we use our own saved descriptors */ if ((SHIN = dmove(nofile, FSHIN)) < 0) switch(nofile) { case 0: SHIN = FSHIN; break; case 1: SHIN = FSHOUT; break; case 2: SHIN = FSHERR; break; default: stderror(ERR_SYSTEM, tempv[0], strerror(errno)); break; } (void) ioctl(SHIN, FIOCLEX, NULL); prompt = 0; /* argc not used any more */ tempv++; } intty = isatty(SHIN); intty |= intact; if (intty || (intact && isatty(SHOUT))) { if (!batch && (uid != euid || gid != egid)) { errno = EACCES; child = 1; /* So this doesn't return */ stderror(ERR_SYSTEM, "csh", strerror(errno)); } } /* * 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; settell(); /* * Save the remaining arguments in argv. */ setq(STRargv, blk2short(tempv), &shvhed); /* * Set up the prompt. */ if (prompt) { set(STRprompt, Strsave(uid == 0 ? STRsymhash : STRsymcent)); /* that's a meta-questionmark */ set(STRprompt2, Strsave(STRmquestion)); } /* * If we are an interactive shell, then start fiddling with the signals; * this is a tricky game. */ shpgrp = getpgrp(); opgrp = tpgrp = -1; if (setintr) { **argv = '-'; if (!quitit) /* Wary! */ (void) signal(SIGQUIT, SIG_IGN);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -