msh.c
来自「手机嵌入式Linux下可用的busybox源码」· C语言 代码 · 共 3,606 行 · 第 1/5 页
C
3,606 行
/* vi: set sw=4 ts=4: *//* * Minix shell port for busybox * * This version of the Minix shell was adapted for use in busybox * by Erik Andersen <andersee@debian.org> and * Vladimir Oleynik <dzo@simtreas.ru> * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; either version 2 of the License, or * (at your option) any later version. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program; if not, write to the Free Software * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA * * Original copyright notice is retained at the end of this file. *//* -------- sh.h -------- */#include <stdlib.h>#include <stdio.h>#include <string.h>#include <unistd.h>#include <fcntl.h>#include <sys/types.h>#include <signal.h>#include <errno.h>#include <setjmp.h>#include <stddef.h>#include <time.h>#include <sys/times.h>#include <sys/stat.h>#include <sys/wait.h>#include <sys/dir.h>#include <limits.h>#include "cmdedit.h"#include "busybox.h"/* define this to use fork on MMU-systems instead of vfork */#if defined(__uClinux__)#undef USE_FORK#else#define USE_FORK#endif#ifdef test//#undef BB_FEATURE_COMMAND_EDITINGconst char *applet_name = "msh";#define TEST_NEW_VERSION#define Abort() { fprintf(stderr, "Abort %d\n", __LINE__); abort(); }#else#undef TEST_NEW_VERSION#define Abort() abort()#endif/* * shell */#define LINELIM 4096#define NPUSH 8 /* limit to input nesting */#ifndef NOFILE#define NOFILE 20 /* Number of open files */#endif#define NUFILE 10 /* Number of user-accessible files */#define FDBASE 10 /* First file usable by Shell *//* * values returned by wait */#define WAITSIG(s) ((s)&0177)#define WAITVAL(s) (((s)>>8)&0377)#define WAITCORE(s) (((s)&0200)!=0)/* * library and system defintions */typedef void xint; /* base type of jmp_buf, for not broken compilers *//* * shell components */#define QUOTE 0200#define NOBLOCK ((struct op *)NULL)#define NOWORD ((char *)NULL)#define NOWORDS ((char **)NULL)#define NOPIPE ((int *)NULL)/* * Description of a command or an operation on commands. * Might eventually use a union. */struct op { int type; /* operation type, see below */ char **words; /* arguments to a command */ struct ioword **ioact; /* IO actions (eg, < > >>) */ struct op *left; struct op *right; char *str; /* identifier for case and for */};#define TCOM 1 /* command */#define TPAREN 2 /* (c-list) */#define TPIPE 3 /* a | b */#define TLIST 4 /* a [&;] b */#define TOR 5 /* || */#define TAND 6 /* && */#define TFOR 7#define TDO 8#define TCASE 9#define TIF 10#define TWHILE 11#define TUNTIL 12#define TELIF 13#define TPAT 14 /* pattern in case */#define TBRACE 15 /* {c-list} */#define TASYNC 16 /* c & *//* * actions determining the environment of a process */#define BIT(i) (1<<(i))#define FEXEC BIT(0) /* execute without forking *//* * flags to control evaluation of words */#define DOSUB 1 /* interpret $, `, and quotes */#define DOBLANK 2 /* perform blank interpretation */#define DOGLOB 4 /* interpret [?* */#define DOKEY 8 /* move words with `=' to 2nd arg. list */#define DOTRIM 16 /* trim resulting string */#define DOALL (DOSUB|DOBLANK|DOGLOB|DOKEY|DOTRIM)static char **dolv;static int dolc;static int exstat;static char gflg;static int interactive; /* interactive (interactive-type wireless) */static int execflg;static int multiline; /* \n changed to ; */static struct op *outtree; /* result from parser */static xint *failpt;static xint *errpt;struct brkcon { jmp_buf brkpt; struct brkcon *nextlev;};static struct brkcon *brklist;static int isbreak;/* * redirection */struct ioword { short io_unit; /* unit affected */ short io_flag; /* action (below) */ char *io_name; /* file name */};#define IOREAD 1 /* < */#define IOHERE 2 /* << (here file) */#define IOWRITE 4 /* > */#define IOCAT 8 /* >> */#define IOXHERE 16 /* ${}, ` in << */#define IODUP 32 /* >&digit */#define IOCLOSE 64 /* >&- */#define IODEFAULT (-1) /* token for default IO unit */struct wdblock { short w_bsize; short w_nword; /* bounds are arbitrary */ char *w_words[1];};static struct wdblock *wdlist;static struct wdblock *iolist;/* * parsing & execution environment */static struct env { char *linep; struct io *iobase; struct io *iop; xint *errpt; int iofd; struct env *oenv;} e;/* * flags: * -e: quit on error * -k: look for name=value everywhere on command line * -n: no execution * -t: exit after reading and executing one command * -v: echo as read * -x: trace * -u: unset variables net diagnostic */static char *flag;static char *null; /* null value for variable */static int intr; /* interrupt pending */static char *trap[_NSIG + 1];static char ourtrap[_NSIG + 1];static int trapset; /* trap pending */static int heedint; /* heed interrupt signals */static int yynerrs; /* yacc */static char line[LINELIM];static char *elinep;/* * other functions */static int (*inbuilt(char *s)) (void);static char *rexecve(char *c, char **v, char **envp);static char *space(int n);static char *strsave(char *s, int a);static char *evalstr(char *cp, int f);static char *putn(int n);static char *itoa(unsigned u, int n);static char *unquote(char *as);static struct var *lookup(char *n);static int rlookup(char *n);static struct wdblock *glob(char *cp, struct wdblock *wb);static int subgetc(int ec, int quoted);static char **makenv(int all);static char **eval(char **ap, int f);static int setstatus(int s);static int waitfor(int lastpid, int canintr);static void onintr(int s); /* SIGINT handler */static int newenv(int f);static void quitenv(void);static void err(char *s);static int anys(char *s1, char *s2);static int any(int c, char *s);static void next(int f);static void setdash(void);static void onecommand(void);static void runtrap(int i);static int letter(int c);static int digit(int c);static int letnum(int c);static int gmatch(char *s, char *p);/* * error handling */static void leave(void) __attribute__ ((noreturn)); /* abort shell (or fail in subshell) */static void fail(void); /* fail but return to process next command */static void warn(char *s);static void sig(int i); /* default signal handler *//* -------- var.h -------- */struct var { char *value; char *name; struct var *next; char status;};#define COPYV 1 /* flag to setval, suggesting copy */#define RONLY 01 /* variable is read-only */#define EXPORT 02 /* variable is to be exported */#define GETCELL 04 /* name & value space was got with getcell */static struct var *vlist; /* dictionary */static struct var *homedir; /* home directory */static struct var *prompt; /* main prompt */static struct var *cprompt; /* continuation prompt */static struct var *path; /* search path for commands */static struct var *shell; /* shell to interpret command files */static struct var *ifs; /* field separators */static int yyparse(void);static struct var *lookup(char *n);static void setval(struct var *vp, char *val);static void nameval(struct var *vp, char *val, char *name);static void export(struct var *vp);static void ronly(struct var *vp);static int isassign(char *s);static int checkname(char *cp);static int assign(char *s, int cf);static void putvlist(int f, int out);static int eqname(char *n1, char *n2);static int execute(struct op *t, int *pin, int *pout, int act);/* -------- io.h -------- *//* io buffer */struct iobuf { unsigned id; /* buffer id */ char buf[512]; /* buffer */ char *bufp; /* pointer into buffer */ char *ebufp; /* pointer to end of buffer */};/* possible arguments to an IO function */struct ioarg { char *aword; char **awordlist; int afile; /* file descriptor */ unsigned afid; /* buffer id */ long afpos; /* file position */ struct iobuf *afbuf; /* buffer for this file */};static struct ioarg ioargstack[NPUSH];#define AFID_NOBUF (~0)#define AFID_ID 0/* an input generator's state */struct io { int (*iofn) (); struct ioarg *argp; int peekc; char prev; /* previous character read by readc() */ char nlcount; /* for `'s */ char xchar; /* for `'s */ char task; /* reason for pushed IO */};static struct io iostack[NPUSH];#define XOTHER 0 /* none of the below */#define XDOLL 1 /* expanding ${} */#define XGRAVE 2 /* expanding `'s */#define XIO 3 /* file IO *//* in substitution */#define INSUB() (e.iop->task == XGRAVE || e.iop->task == XDOLL)/* * input generators for IO structure */static int nlchar(struct ioarg *ap);static int strchar(struct ioarg *ap);static int qstrchar(struct ioarg *ap);static int filechar(struct ioarg *ap);static int herechar(struct ioarg *ap);static int linechar(struct ioarg *ap);static int gravechar(struct ioarg *ap, struct io *iop);static int qgravechar(struct ioarg *ap, struct io *iop);static int dolchar(struct ioarg *ap);static int wdchar(struct ioarg *ap);static void scraphere(void);static void freehere(int area);static void gethere(void);static void markhere(char *s, struct ioword *iop);static int herein(char *hname, int xdoll);static int run(struct ioarg *argp, int (*f) (struct ioarg * ap));/* * IO functions */static int eofc(void);static int getqc(int ec);static int readc(void);static void unget(int c);static void ioecho(int c);static void prs(char *s);static void put1c(int c);static void prn(unsigned u);static void closef(int i);static void closeall(void);/* * IO control */static void pushio(struct ioarg *argp, int (*fn) ());static int remap(int fd);static int openpipe(int *pv);static void closepipe(int *pv);static struct io *setbase(struct io *ip);static struct ioarg temparg = { 0, 0, 0, AFID_NOBUF, 0 }; /* temporary for PUSHIO */#define PUSHIO(what,arg,gen) ((temparg.what = (arg)),pushio(&temparg,(gen)))#define RUN(what,arg,gen) ((temparg.what = (arg)), run(&temparg,(gen)))/* -------- word.h -------- */static struct wdblock *addword(char *wd, struct wdblock *wb);static struct wdblock *newword(int nw);static char **getwords(struct wdblock *wb);/* -------- area.h -------- *//* * storage allocation */static char *getcell(unsigned nbytes);static void garbage(void);static void setarea(char *cp, int a);static int getarea(char *cp);static void freearea(int a);static void freecell(void *cp);static int areanum; /* current allocation area */#define NEW(type) (type *)getcell(sizeof(type))/* -------- sh.c -------- *//* * shell */static int intr;static int inparse;static char flags['z' - 'a' + 1];static char *flag = flags - 'a';static char *elinep = line + sizeof(line) - 5;static char *null = "";static int heedint = 1;static struct env e = { line, iostack, iostack - 1, (xint *) NULL, FDBASE, (struct env *) NULL};extern char **environ; /* environment pointer *//* * default shell, search rules */static char shellname[] = "/bin/sh";static char search[] = ":/bin:/usr/bin";static void (*qflag) (int) = SIG_IGN;static int newfile(char *s);static char *findeq(char *cp);static char *cclass(char *p, int sub);static void initarea(void);struct here { char *h_tag; int h_dosub; struct ioword *h_iop; struct here *h_next;};static struct here *inhere; /* list of hear docs while parsing */static struct here *acthere; /* list of active here documents */#ifdef BB_FEATURE_COMMAND_EDITINGstatic char *current_prompt;#endif#ifdef testint main(int argc, char **argv)#elseint msh_main(int argc, char **argv)#endif{ register int f; register char *s; int cflag; char *name, **ap; int (*iof) (); initarea(); if ((ap = environ) != NULL) { while (*ap) assign(*ap++, !COPYV); for (ap = environ; *ap;) export(lookup(*ap++)); } closeall(); areanum = 1; shell = lookup("SHELL"); if (shell->value == null) setval(shell, shellname); export(shell); homedir = lookup("HOME"); if (homedir->value == null) setval(homedir, "/"); export(homedir);#ifdef TEST_NEW_VERSION#ifdef BB_FEATURE_SH_FANCY_PROMPT cwd = xgetcwd(0); if (cwd == 0) cwd = (char *) unknown;#endif#endif setval(lookup("$"), itoa(getpid(), 5)); path = lookup("PATH"); if (path->value == null) setval(path, search); export(path); ifs = lookup("IFS"); if (ifs->value == null) setval(ifs, " \t\n"); prompt = lookup("PS1");#ifdef BB_FEATURE_SH_FANCY_PROMPT if (prompt->value == null)#endif setval(prompt, "$ "); if (geteuid() == 0) { setval(prompt, "# "); prompt->status &= ~EXPORT; } cprompt = lookup("PS2");#ifdef BB_FEATURE_SH_FANCY_PROMPT if (cprompt->value == null)#endif setval(cprompt, "> "); iof = filechar; cflag = 0; name = *argv++; if (--argc >= 1) { if (argv[0][0] == '-' && argv[0][1] != '\0') { for (s = argv[0] + 1; *s; s++) switch (*s) { case 'c': prompt->status &= ~EXPORT; cprompt->status &= ~EXPORT; setval(prompt, ""); setval(cprompt, ""); cflag = 1; if (--argc > 0) PUSHIO(aword, *++argv, iof = nlchar); break; case 'q': qflag = SIG_DFL; break; case 's': /* standard input */ break; case 't': prompt->status &= ~EXPORT; setval(prompt, ""); iof = linechar; break; case 'i': interactive++; default: if (*s >= 'a' && *s <= 'z') flag[(int) *s]++; } } else { argv--; argc++; } if (iof == filechar && --argc > 0) { setval(prompt, ""); setval(cprompt, ""); prompt->status &= ~EXPORT; cprompt->status &= ~EXPORT; if (newfile(name = *++argv)) exit(1); } } setdash(); if (e.iop < iostack) { PUSHIO(afile, 0, iof); if (isatty(0) && isatty(1) && !cflag) { interactive++; printf( "\n\n" BB_BANNER " Built-in shell (msh)\n"); printf( "Enter 'help' for a list of built-in commands.\n\n"); } } signal(SIGQUIT, qflag); if (name && name[0] == '-') { interactive++; if ((f = open(".profile", 0)) >= 0) next(remap(f)); if ((f = open("/etc/profile", 0)) >= 0) next(remap(f)); } if (interactive) signal(SIGTERM, sig); if (signal(SIGINT, SIG_IGN) != SIG_IGN) signal(SIGINT, onintr); dolv = argv; dolc = argc; dolv[0] = name; if (dolc > 1) for (ap = ++argv; --argc > 0;) { if (assign(*ap = *argv++, !COPYV)) dolc--; /* keyword */ else ap++; } setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc)); for (;;) { if (interactive && e.iop <= iostack)#ifdef BB_FEATURE_COMMAND_EDITING current_prompt = prompt->value;#else prs(prompt->value);#endif onecommand(); /* Ensure that getenv("PATH") stays current */ setenv("PATH", path->value, 1); }}void setdash(){ register char *cp, c; char m['z' - 'a' + 1]; cp = m; for (c = 'a'; c <= 'z'; c++) if (flag[(int) c]) *cp++ = c; *cp = 0; setval(lookup("-"), m);}int newfile(s)register char *s;{ int f; if (strcmp(s, "-") != 0) { f = open(s, 0); if (f < 0) { prs(s); err(": cannot open"); return (1); } } else f = 0; next(remap(f)); return (0);}void onecommand(){ int i; jmp_buf m1; while (e.oenv) quitenv(); areanum = 1; freehere(areanum); freearea(areanum); garbage(); wdlist = 0; iolist = 0; e.errpt = 0; e.linep = line; yynerrs = 0; multiline = 0; inparse = 1; intr = 0; execflg = 0; setjmp(failpt = m1); /* Bruce Evans' fix */ if (setjmp(failpt = m1) || yyparse() || intr) { while (e.oenv) quitenv(); scraphere(); if (!interactive && intr) leave(); inparse = 0; intr = 0; return; } inparse = 0; brklist = 0; intr = 0; execflg = 0; if (!flag['n']) execute(outtree, NOPIPE, NOPIPE, 0); if (!interactive && intr) { execflg = 0; leave(); } if ((i = trapset) != 0) { trapset = 0; runtrap(i); }}void fail(){ longjmp(failpt, 1); /* NOTREACHED */}void leave(){ if (execflg)
⌨️ 快捷键说明
复制代码Ctrl + C
搜索代码Ctrl + F
全屏模式F11
增大字号Ctrl + =
减小字号Ctrl + -
显示快捷键?