📄 ash.c
字号:
i = 1; } } return (i);}static struct alias **hashalias(const char *p){ unsigned int hashval; hashval = *p << 4; while (*p) hashval+= *p++; return &atab[hashval % ATABSIZE];}static struct alias *freealias(struct alias *ap){ struct alias *next; if (ap->flag & ALIASINUSE) { ap->flag |= ALIASDEAD; return ap; } next = ap->next; ckfree(ap->name); ckfree(ap->val); ckfree(ap); return next;}static struct alias **__lookupalias(const char *name){ struct alias **app = hashalias(name); for (; *app; app = &(*app)->next) { if (equal(name, (*app)->name)) { break; } } return app;}#endif#ifdef CONFIG_ASH_MATH_SUPPORT/* The generated file arith.c has been replaced with a custom hand * written implementation written by Aaron Lehmann <aaronl@vitelus.com>. * This is now part of libbb, so that it can be used by all the shells * in busybox. */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 CONFIG_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 CONFIG_TRUEstatic int true_main (int, char **);#endif#ifndef CONFIG_FALSEstatic 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 CONFIG_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 CONFIG_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 CONFIG_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 CONFIG_ASH_JOB_CONTROLTOPPED 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 CONFIG_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 CONFIG_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 CONFIG_ASH_JOB_CONTROLstatic int initialpgrp; /* pgrp of shell on invocation */static int curjob; /* current job */static int jobctl;#endifstatic int intreceived;static 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 intcdcmd(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 */}/* * Actually do the chdir. In an interactive shell, print the * directory name if "print" is nonzero. */static intdocd(char *dest, int print){ TRACE(("docd(\"%s\", %d) called\n", dest, print)); INTOFF; if (chdir(dest) < 0) { INTON; return -1; } hashcd(); /* * 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. */ /* If dest is NULL, we don't know the current directory */ if (dest == NULL || curdir == nullstr) setpwd(0, 1); else setpwd(dest, 1); INTON; if (print && iflag) puts(curdir); return 0;}static intpwdcmd(int argc, char **argv){ puts(curdir); return 0;}/* Ask system the current directory */static voidgetpwd(void){ curdir = xgetcwd(0); if(curdir==0) curdir = nullstr;}static voidsetpwd(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 */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);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -