📄 ash.c
字号:
{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 CONFIG_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 int evalcmd(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 void evalstring(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 = xmalloc(funcblocksize + funcstringsize); funcstring = (char *) funcblock + funcblocksize; return copynode(n);}/* * Add a new command entry, replacing any existing command entry for * the same name. */static inline void addcmdentry(char *name, struct cmdentry *entry){ struct tblentry *cmdp; INTOFF; cmdp = cmdlookup(name, 1); if (cmdp->cmdtype == CMDFUNCTION) { free(cmdp->param.func); } cmdp->cmdtype = entry->cmdtype; cmdp->param = entry->u; INTON;}static inline void evalloop(const union node *n, int flags){ int status; loopnest++; status = 0; flags &= EV_TESTED; 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); status = exitstatus; if (evalskip) goto skipping; } loopnest--; exitstatus = status;}static void evalfor(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++; flags &= EV_TESTED; for (sp = arglist.list; sp; sp = sp->next) { setvar(n->nfor.var, sp->text, 0); evaltree(n->nfor.body, flags); if (evalskip) { if (evalskip == SKIPCONT && --skipcount <= 0) { evalskip = 0; continue; } if (evalskip == SKIPBREAK && --skipcount <= 0) evalskip = 0; break; } } loopnest--; out: popstackmark(&smark);}static inline void evalcase(const union node *n, int flags){ union node *cp; union node *patp; struct arglist arglist; struct stackmark smark; setstackmark(&smark); arglist.lastp = &arglist.list; oexitstatus = exitstatus; expandarg(n->ncase.expr, &arglist, EXP_TILDE); for (cp = n->ncase.cases; cp && evalskip == 0; cp = cp->nclist.next) { for (patp = cp->nclist.pattern; patp; patp = patp->narg.next) { if (casematch(patp, arglist.list->text)) { if (evalskip == 0) { evaltree(cp->nclist.body, flags); } goto out; } } } out: popstackmark(&smark);}/* * Evaluate a pipeline. All the processes in the pipeline are children * of the process creating the pipeline. (This differs from some versions * of the shell, which make the last process in a pipeline the parent * of all the rest.) */static inline void evalpipe(union node *n, int flags){ struct job *jp; struct nodelist *lp; int pipelen; int prevfd; int pip[2]; TRACE(("evalpipe(0x%lx) called\n", (long) n)); pipelen = 0; for (lp = n->npipe.cmdlist; lp; lp = lp->next) pipelen++; flags |= EV_EXIT; INTOFF; jp = makejob(n, pipelen); prevfd = -1; for (lp = n->npipe.cmdlist; lp; lp = lp->next) { prehash(lp->n); pip[1] = -1; if (lp->next) { if (pipe(pip) < 0) { close(prevfd); error("Pipe call failed"); } } if (forkshell(jp, lp->n, n->npipe.backgnd) == 0) { INTON; if (pip[1] >= 0) { close(pip[0]); } if (prevfd > 0) { dup2(prevfd, 0); close(prevfd); } if (pip[1] > 1) { dup2(pip[1], 1); close(pip[1]); } evaltree(lp->n, flags); } if (prevfd >= 0) close(prevfd); prevfd = pip[0]; close(pip[1]); } if (n->npipe.backgnd == 0) { exitstatus = waitforjob(jp); TRACE(("evalpipe: job done exit status %d\n", exitstatus)); } INTON;}static void find_command(const char *, struct cmdentry *, int, const char *);static int isassignment(const char *word){ if (!is_name(*word)) { return 0; } do { word++; } while (is_in_name(*word)); return *word == '=';}static void evalcommand(union node *cmd, int flags){ struct stackmark smark; union node *argp; struct arglist arglist; struct arglist varlist; char **argv; int argc; char **envp; struct strlist *sp; int mode; struct cmdentry cmdentry; struct job *jp; char *volatile savecmdname; volatile struct shparam saveparam; struct localvar *volatile savelocalvars; volatile int e; char *lastarg; const char *path; int spclbltin; struct jmploc *volatile savehandler; struct jmploc jmploc;#if __GNUC__ /* Avoid longjmp clobbering */ (void) &argv; (void) &argc; (void) &lastarg; (void) &flags; (void) &spclbltin;#endif /* First expand the arguments. */ TRACE(("evalcommand(0x%lx, %d) called\n", (long) cmd, flags)); setstackmark(&smark); arglist.lastp = &arglist.list; varlist.lastp = &varlist.list; arglist.list = 0; oexitstatus = exitstatus; exitstatus = 0; path = pathval(); for (argp = cmd->ncmd.assign; argp; argp = argp->narg.next) { expandarg(argp, &varlist, EXP_VARTILDE); } for (argp = cmd->ncmd.args; argp && !arglist.list; argp = argp->narg.next) { expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); } if (argp) { struct builtincmd *bcmd; int pseudovarflag; bcmd = find_builtin(arglist.list->text); pseudovarflag = bcmd && IS_BUILTIN_ASSIGN(bcmd); for (; argp; argp = argp->narg.next) { if (pseudovarflag && isassignment(argp->narg.text)) { expandarg(argp, &arglist, EXP_VARTILDE); continue; } expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); } } *arglist.lastp = NULL; *varlist.lastp = NULL; expredir(cmd->ncmd.redirect); argc = 0; for (sp = arglist.list; sp; sp = sp->next) argc++; argv = stalloc(sizeof(char *) * (argc + 1)); for (sp = arglist.list; sp; sp = sp->next) { TRACE(("evalcommand arg: %s\n", sp->text)); *argv++ = sp->text; } *argv = NULL; lastarg = NULL; if (iflag && funcnest == 0 && argc > 0) lastarg = argv[-1]; argv -= argc; /* Print the command if xflag is set. */ if (xflag) { out2c('+'); eprintlist(varlist.list); eprintlist(arglist.list); out2c('\n'); } /* Now locate the command. */ if (argc == 0) { cmdentry.cmdtype = CMDBUILTIN; cmdentry.u.cmd = BLTINCMD; spclbltin = 1; } else { const char *oldpath; int findflag = DO_ERR; int oldfindflag; /* * Modify the command lookup path, if a PATH= assignment * is present */ for (sp = varlist.list; sp; sp = sp->next) if (varequal(sp->text, defpathvar)) { path = sp->text + 5; findflag |= DO_BRUTE; } oldpath = path; oldfindflag = findflag; spclbltin = -1; for (;;) { find_command(argv[0], &cmdentry, findflag, path); if (cmdentry.cmdtype == CMD
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -