📄 ash.c
字号:
*/static voidgetpwd(void){ curdir = xgetcwd(0); if(curdir==0) curdir = nullstr;}static voidsetpwd(const char *val, int setold){ if (setold) { setvar("OLDPWD", curdir, VEXPORT); } INTOFF; if (curdir != nullstr) { free(curdir); curdir = nullstr; } if (!val) { getpwd(); } else { curdir = savestr(val); } INTON; setvar("PWD", curdir, VEXPORT);}/* * Errors and exceptions. *//* * Code to handle exceptions in C. *//* * We enclose jmp_buf in a structure so that we can declare pointers to * jump locations. The global variable handler contains the location to * jump to when an exception occurs, and the global variable exception * contains a code identifying the exeception. To implement nested * exception handlers, the user should save the value of handler on entry * to an inner scope, set handler to point to a jmploc structure for the * inner scope, and restore handler on exit from the scope. */struct jmploc { jmp_buf loc;};/* exceptions */#define EXINT 0 /* SIGINT received */#define EXERROR 1 /* a generic error */#define EXSHELLPROC 2 /* execute a shell procedure */#define EXEXEC 3 /* command execution failed */static struct jmploc *handler;static int exception;static void exverror (int, const char *, va_list) __attribute__((__noreturn__));/* * Called to raise an exception. Since C doesn't include exceptions, we * just do a longjmp to the exception handler. The type of exception is * stored in the global variable "exception". */static void exraise (int) __attribute__((__noreturn__));static voidexraise(int e){#ifdef DEBUG if (handler == NULL) abort();#endif flushall(); exception = e; longjmp(handler->loc, 1);}/* * Called from trap.c when a SIGINT is received. (If the user specifies * that SIGINT is to be trapped or ignored using the trap builtin, then * this routine is not called.) Suppressint is nonzero when interrupts * are held using the INTOFF macro. The call to _exit is necessary because * there is a short period after a fork before the signal handlers are * set to the appropriate value for the child. (The test for iflag is * just defensive programming.) */static voidonint(void) { sigset_t mysigset; if (suppressint) { intpending++; return; } intpending = 0; sigemptyset(&mysigset); sigprocmask(SIG_SETMASK, &mysigset, NULL); if (rootshell && iflag) exraise(EXINT); else { signal(SIGINT, SIG_DFL); raise(SIGINT); } /* NOTREACHED */}static char *commandname; /* currently executing command *//* * Exverror is called to raise the error exception. If the first argument * is not NULL then error prints an error message using printf style * formatting. It then raises the error exception. */static voidexverror(int cond, const char *msg, va_list ap){ CLEAR_PENDING_INT; INTOFF;#ifdef DEBUG if (msg) TRACE(("exverror(%d, \"%s\") pid=%d\n", cond, msg, getpid())); else TRACE(("exverror(%d, NULL) pid=%d\n", cond, getpid()));#endif if (msg) { if (commandname) out2fmt("%s: ", commandname); vfprintf(stderr, msg, ap); out2c('\n'); } exraise(cond); /* NOTREACHED */}static void error(const char *msg, ...){ va_list ap; va_start(ap, msg); exverror(EXERROR, msg, ap); /* NOTREACHED */ va_end(ap);}static voidexerror(int cond, const char *msg, ...){ va_list ap; va_start(ap, msg); exverror(cond, msg, ap); /* NOTREACHED */ va_end(ap);}/* * Table of error messages. */struct errname { short errcode; /* error number */ char action; /* operation which encountered the error */};/* * Types of operations (passed to the errmsg routine). */#define E_OPEN 01 /* opening a file */#define E_CREAT 02 /* creating a file */#define E_EXEC 04 /* executing a program */#define ALL (E_OPEN|E_CREAT|E_EXEC)static const struct errname errormsg[] = { { EINTR, ALL }, { EACCES, ALL }, { EIO, ALL }, { ENOENT, E_OPEN }, { ENOENT, E_CREAT }, { ENOENT, E_EXEC }, { ENOTDIR, E_OPEN }, { ENOTDIR, E_CREAT }, { ENOTDIR, E_EXEC }, { EISDIR, ALL }, { EEXIST, E_CREAT },#ifdef EMFILE { EMFILE, ALL },#endif { ENFILE, ALL }, { ENOSPC, ALL },#ifdef EDQUOT { EDQUOT, ALL },#endif#ifdef ENOSR { ENOSR, ALL },#endif { ENXIO, ALL }, { EROFS, ALL }, { ETXTBSY, ALL },#ifdef EAGAIN { EAGAIN, E_EXEC },#endif { ENOMEM, ALL },#ifdef ENOLINK { ENOLINK, ALL },#endif#ifdef EMULTIHOP { EMULTIHOP, ALL },#endif#ifdef ECOMM { ECOMM, ALL },#endif#ifdef ESTALE { ESTALE, ALL },#endif#ifdef ETIMEDOUT { ETIMEDOUT, ALL },#endif#ifdef ELOOP { ELOOP, ALL },#endif { E2BIG, E_EXEC },#ifdef ELIBACC { ELIBACC, E_EXEC },#endif};#define ERRNAME_SIZE (sizeof(errormsg)/sizeof(struct errname))/* * Return a string describing an error. The returned string may be a * pointer to a static buffer that will be overwritten on the next call. * Action describes the operation that got the error. */static const char *errmsg(int e, int action){ struct errname const *ep; static char buf[12]; for (ep = errormsg ; ep < errormsg+ERRNAME_SIZE; ep++) { if (ep->errcode == e && (ep->action & action) != 0) return strerror(e); } snprintf(buf, sizeof buf, "error %d", e); return buf;}#ifdef ASH_OPTIMIZE_FOR_SIZEstatic void__inton() { if (--suppressint == 0 && intpending) { onint(); }}static void forceinton (void) { suppressint = 0; if (intpending) onint();}#endif/* flags in argument to evaltree */#define EV_EXIT 01 /* exit after evaluating tree */#define EV_TESTED 02 /* exit status is checked; ignore -e flag */#define EV_BACKCMD 04 /* command executing within back quotes */static int evalskip; /* set if we are skipping commands */static int skipcount; /* number of levels to skip */static int loopnest; /* current loop nesting level */static int funcnest; /* depth of function calls */static struct strlist *cmdenviron; /* environment for builtin command */static int exitstatus; /* exit status of last command */static int oexitstatus; /* saved exit status */static void evalsubshell (const union node *, int);static void expredir (union node *);static void prehash (union node *);static void eprintlist (struct strlist *);static union node *parsecmd(int);/* * Called to reset things after an exception. *//* * The eval commmand. */static void evalstring (char *, int);static intevalcmd(argc, argv) int argc; char **argv;{ char *p; char *concat; char **ap; if (argc > 1) { p = argv[1]; if (argc > 2) { STARTSTACKSTR(concat); ap = argv + 2; for (;;) { while (*p) STPUTC(*p++, concat); if ((p = *ap++) == NULL) break; STPUTC(' ', concat); } STPUTC('\0', concat); p = grabstackstr(concat); } evalstring(p, EV_TESTED); } return exitstatus;}/* * Execute a command or commands contained in a string. */static void evaltree (union node *, int);static void setinputstring (char *);static void popfile (void);static void setstackmark(struct stackmark *mark);static void popstackmark(struct stackmark *mark);static voidevalstring(char *s, int flag){ union node *n; struct stackmark smark; setstackmark(&smark); setinputstring(s); while ((n = parsecmd(0)) != NEOF) { evaltree(n, flag); popstackmark(&smark); } popfile(); popstackmark(&smark);}static struct builtincmd *find_builtin (const char *);static void expandarg (union node *, struct arglist *, int);static void calcsize (const union node *);static union node *copynode (const union node *);/* * Make a copy of a parse tree. */static int funcblocksize; /* size of structures in function */static int funcstringsize; /* size of strings in node */static pointer funcblock; /* block to allocate function from */static char *funcstring; /* block to allocate strings from */static inline union node *copyfunc(union node *n){ if (n == NULL) return NULL; funcblocksize = 0; funcstringsize = 0; calcsize(n); funcblock = ckmalloc(funcblocksize + funcstringsize); funcstring = (char *) funcblock + funcblocksize; return copynode(n);}/* * Free a parse tree. */static voidfreefunc(union node *n){ if (n) ckfree(n);}/* * Add a new command entry, replacing any existing command entry for * the same name. */static inline voidaddcmdentry(char *name, struct cmdentry *entry){ struct tblentry *cmdp; INTOFF; cmdp = cmdlookup(name, 1); if (cmdp->cmdtype == CMDFUNCTION) { freefunc(cmdp->param.func); } cmdp->cmdtype = entry->cmdtype; cmdp->param = entry->u; INTON;}static inline voidevalloop(const union node *n, int flags){ int status; loopnest++; status = 0; for (;;) { evaltree(n->nbinary.ch1, EV_TESTED); if (evalskip) {skipping: if (evalskip == SKIPCONT && --skipcount <= 0) { evalskip = 0; continue; } if (evalskip == SKIPBREAK && --skipcount <= 0) evalskip = 0; break; } if (n->type == NWHILE) { if (exitstatus != 0) break; } else { if (exitstatus == 0) break; } evaltree(n->nbinary.ch2, flags & EV_TESTED); status = exitstatus; if (evalskip) goto skipping; } loopnest--; exitstatus = status;}static voidevalfor(const union node *n, int flags){ struct arglist arglist; union node *argp; struct strlist *sp; struct stackmark smark; setstackmark(&smark); arglist.lastp = &arglist.list; for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { oexitstatus = exitstatus; expandarg(argp, &arglist, EXP_FULL | EXP_TILDE | EXP_RECORD); if (evalskip) goto out; } *arglist.lastp = NULL; exitstatus = 0; loopnest++; for (sp = arglist.list ; sp ; sp = sp->next) { setvar(n->nfor.var, sp->text, 0); evaltree(n->nfor.body, flags & EV_TESTED); if (evalskip) { if (evalskip == SKIPCONT && --skipcount <= 0) { evalskip = 0; continue; } if (evalskip == SKIPBREAK && --skipcount <= 0) evalskip = 0; break; } } loopnest--;out: popstackmark(&smark);}static inline voidevalcase(const union node *n, int flags){ union node *cp; union node *patp; struct arglist arglist; struct stackmark smark; setstac
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -