📄 ash.c
字号:
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 voiderror(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 */ short 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 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 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(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 = xmalloc(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; 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){ 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++; INTOFF; jp = makejob(n, pipelen); prevfd = -1; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { /* * Search for a command. This is called before we fork so that the * location of the command will be available in the parent as well as * the child. The check for "goodname" is an overly conservative * check that the name will not be subject to expansion. */ struct cmdentry entry; union node *lpn = lp->n; if (lpn->type == NCMD && lpn->ncmd.args && goodname(lpn->ncmd.args->narg.text)) find_command(lpn->ncmd.args->narg.text, &entry, 0, pathval()); 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 (prevfd > 0) { close(0); dup_as_newfd(prevfd, 0); close(prevfd); if (pip[0] == 0) { pip[0] = -1; } } if (pip[1] >= 0) { if (pip[0] >= 0) { close(pip[0]); } if (pip[1] != 1) { close(1); dup_as_newfd(pip[1], 1); close(pip[1]);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -