📄 ash.c
字号:
static void expari(int);#endifstatic char *trap[NSIG]; /* trap handler commands */static char sigmode[NSIG - 1]; /* current value of signal */static char gotsig[NSIG - 1]; /* indicates specified signal received */static int pendingsigs; /* indicates some signal received *//* * This file was generated by the mkbuiltins program. */#ifdef BB_FEATURE_ASH_JOB_CONTROLstatic int bgcmd(int, char **);static int fgcmd(int, char **);static int killcmd(int, char **);#endifstatic int bltincmd(int, char **);static int cdcmd(int, char **);static int breakcmd(int, char **);#ifdef CONFIG_ASH_CMDCMDstatic int commandcmd(int, char **);#endifstatic int dotcmd(int, char **);static int evalcmd(int, char **);static int execcmd(int, char **);static int exitcmd(int, char **);static int exportcmd(int, char **);static int histcmd(int, char **);static int hashcmd(int, char **);static int helpcmd(int, char **);static int jobscmd(int, char **);static int localcmd(int, char **);static int pwdcmd(int, char **);static int readcmd(int, char **);static int returncmd(int, char **);static int setcmd(int, char **);static int setvarcmd(int, char **);static int shiftcmd(int, char **);static int trapcmd(int, char **);static int umaskcmd(int, char **);#ifdef CONFIG_ASH_ALIASstatic int aliascmd(int, char **);static int unaliascmd(int, char **);#endifstatic int unsetcmd(int, char **);static int waitcmd(int, char **);static int ulimitcmd(int, char **);static int timescmd(int, char **);#ifdef CONFIG_ASH_MATH_SUPPORTstatic int letcmd(int, char **);#endifstatic int typecmd(int, char **);#ifdef CONFIG_ASH_GETOPTSstatic int getoptscmd(int, char **);#endif#ifndef BB_TRUE_FALSEstatic int true_main(int, char **);static int false_main(int, char **);#endifstatic void setpwd(const char *, int);#define BUILTIN_NOSPEC "0"#define BUILTIN_SPECIAL "1"#define BUILTIN_REGULAR "2"#define BUILTIN_ASSIGN "4"#define BUILTIN_SPEC_ASSG "5"#define BUILTIN_REG_ASSG "6"#define IS_BUILTIN_SPECIAL(builtincmd) ((builtincmd)->name[0] & 1)#define IS_BUILTIN_REGULAR(builtincmd) ((builtincmd)->name[0] & 2)#define IS_BUILTIN_ASSIGN(builtincmd) ((builtincmd)->name[0] & 4)struct builtincmd { const char *name; int (*const builtinfunc) (int, char **); //unsigned flags;};/* It is CRUCIAL that this listing be kept in ascii order, otherwise * the binary search in find_builtin() will stop working. If you value * your kneecaps, you'll be sure to *make sure* that any changes made * to this array result in the listing remaining in ascii order. You * have been warned. */static const struct builtincmd builtincmds[] = { {BUILTIN_SPECIAL ".", dotcmd}, /* first, see declare DOTCMD */ {BUILTIN_SPECIAL ":", true_main},#ifdef CONFIG_ASH_ALIAS {BUILTIN_REG_ASSG "alias", aliascmd},#endif#ifdef BB_FEATURE_ASH_JOB_CONTROL {BUILTIN_REGULAR "bg", bgcmd},#endif {BUILTIN_SPECIAL "break", breakcmd}, {BUILTIN_SPECIAL "builtin", bltincmd}, {BUILTIN_REGULAR "cd", cdcmd}, {BUILTIN_NOSPEC "chdir", cdcmd},#ifdef CONFIG_ASH_CMDCMD {BUILTIN_REGULAR "command", commandcmd},#endif {BUILTIN_SPECIAL "continue", breakcmd}, {BUILTIN_SPECIAL "eval", evalcmd}, {BUILTIN_SPECIAL "exec", execcmd}, {BUILTIN_SPECIAL "exit", exitcmd}, {BUILTIN_SPEC_ASSG "export", exportcmd}, {BUILTIN_REGULAR "false", false_main}, {BUILTIN_REGULAR "fc", histcmd},#ifdef BB_FEATURE_ASH_JOB_CONTROL {BUILTIN_REGULAR "fg", fgcmd},#endif#ifdef CONFIG_ASH_GETOPTS {BUILTIN_REGULAR "getopts", getoptscmd},#endif {BUILTIN_NOSPEC "hash", hashcmd}, {BUILTIN_NOSPEC "help", helpcmd}, {BUILTIN_REGULAR "jobs", jobscmd},#ifdef BB_FEATURE_ASH_JOB_CONTROL {BUILTIN_REGULAR "kill", killcmd},#endif#ifdef CONFIG_ASH_MATH_SUPPORT {BUILTIN_REGULAR "let", letcmd},#endif {BUILTIN_ASSIGN "local", localcmd}, {BUILTIN_NOSPEC "pwd", pwdcmd}, {BUILTIN_REGULAR "read", readcmd}, {BUILTIN_SPEC_ASSG "readonly", exportcmd}, {BUILTIN_SPECIAL "return", returncmd}, {BUILTIN_SPECIAL "set", setcmd}, {BUILTIN_NOSPEC "setvar", setvarcmd}, {BUILTIN_SPECIAL "shift", shiftcmd}, {BUILTIN_SPECIAL "times", timescmd}, {BUILTIN_SPECIAL "trap", trapcmd}, {BUILTIN_REGULAR "true", true_main}, {BUILTIN_NOSPEC "type", typecmd}, {BUILTIN_NOSPEC "ulimit", ulimitcmd}, {BUILTIN_REGULAR "umask", umaskcmd},#ifdef CONFIG_ASH_ALIAS {BUILTIN_REGULAR "unalias", unaliascmd},#endif {BUILTIN_SPECIAL "unset", unsetcmd}, {BUILTIN_REGULAR "wait", waitcmd},};#define NUMBUILTINS (sizeof (builtincmds) / sizeof (struct builtincmd) )#define DOTCMD &builtincmds[0]static struct builtincmd *BLTINCMD;static struct builtincmd *EXECCMD;static struct builtincmd *EVALCMD;/* states */#define JOBSTOPPED 1 /* all procs are stopped */#define JOBDONE 2 /* all procs are completed *//* * A job structure contains information about a job. A job is either a * single process or a set of processes contained in a pipeline. In the * latter case, pidlist will be non-NULL, and will point to a -1 terminated * array of pids. */struct procstat { pid_t pid; /* process id */ int status; /* status flags (defined above) */ char *cmd; /* text of command being run */};static int job_warning; /* user was warned about stopped jobs */#ifdef BB_FEATURE_ASH_JOB_CONTROLstatic void setjobctl(int enable);#else#define setjobctl(on) /* do nothing */#endifstruct job { struct procstat ps0; /* status of process */ struct procstat *ps; /* status or processes when more than one */ short nprocs; /* number of processes */ short pgrp; /* process group of this job */ char state; /* true if job is finished */ char used; /* true if this entry is in used */ char changed; /* true if status has changed */#ifdef BB_FEATURE_ASH_JOB_CONTROL char jobctl; /* job running under job control */#endif};static struct job *jobtab; /* array of jobs */static int njobs; /* size of array */static int backgndpid = -1; /* pid of last background process */#ifdef BB_FEATURE_ASH_JOB_CONTROLstatic int initialpgrp; /* pgrp of shell on invocation */static int curjob; /* current job */static int jobctl;#endifstatic struct job *makejob(const union node *, int);static int forkshell(struct job *, const union node *, int);static int waitforjob(struct job *);static int docd(char *, int);static void getpwd(void);static char *padvance(const char **, const char *);static char nullstr[1]; /* zero length string */static char *curdir = nullstr; /* current working directory */static int cdcmd(int argc, char **argv){ const char *dest; const char *path; char *p; struct stat statb; int print = 0; nextopt(nullstr); if ((dest = *argptr) == NULL && (dest = bltinlookup("HOME")) == NULL) error("HOME not set"); if (*dest == '\0') dest = "."; if (dest[0] == '-' && dest[1] == '\0') { dest = bltinlookup("OLDPWD"); if (!dest || !*dest) { dest = curdir; } print = 1; if (dest) print = 1; else dest = "."; } if (*dest == '/' || (path = bltinlookup("CDPATH")) == NULL) path = nullstr; while ((p = padvance(&path, dest)) != NULL) { if (stat(p, &statb) >= 0 && S_ISDIR(statb.st_mode)) { if (!print) { /* * XXX - rethink */ if (p[0] == '.' && p[1] == '/' && p[2] != '\0') p += 2; print = strcmp(p, dest); } if (docd(p, print) >= 0) return 0; } } error("can't cd to %s", dest); /* NOTREACHED */}/* * Update curdir (the name of the current directory) in response to a * cd command. We also call hashcd to let the routines in exec.c know * that the current directory has changed. */static void hashcd(void);static inline void updatepwd(const char *dir){ hashcd(); /* update command hash table */ /* * If our argument is NULL, we don't know the current directory */ if (dir == NULL || curdir == nullstr) { setpwd(0, 1); } else { setpwd(dir, 1); }}/* * Actually do the chdir. In an interactive shell, print the * directory name if "print" is nonzero. */static int docd(char *dest, int print){ TRACE(("docd(\"%s\", %d) called\n", dest, print)); INTOFF; if (chdir(dest) < 0) { INTON; return -1; } updatepwd(dest); INTON; if (print && iflag) puts(curdir); return 0;}static int pwdcmd(int argc, char **argv){ puts(curdir); return 0;}/* Ask system the current directory */static void getpwd(void){ curdir = xgetcwd(0); if (curdir == 0) curdir = nullstr;}static void setpwd(const char *val, int setold){ char *cated = NULL; if (setold) { setvar("OLDPWD", curdir, VEXPORT); } INTOFF; if (curdir != nullstr) { if (val != NULL && *val != '/') val = cated = concat_path_file(curdir, val); free(curdir); } if (!val) getpwd(); else curdir = simplify_path(val); free(cated); 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 */#define EXREDIR 4 /* redirection error */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 void exraise(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 void onint(void){ sigset_t mysigset; if (suppressint) { intpending++; return; } intpending = 0; sigemptyset(&mysigset); sigprocmask(SIG_SETMASK, &mysigset, NULL); if (!(rootshell && iflag)) { signal(SIGINT, SIG_DFL); raise(SIGINT); } exraise(EXINT); /* 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 void exverror(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 void exerror(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[] = {
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -