📄 msh.c
字号:
/* 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 <andersen@codepoet.org> * * - backtick expansion did not work properly * Jonas Holmberg <jonas.holmberg@axis.com> * Robert Schwebel <r.schwebel@pengutronix.de> * Erik Andersen <andersen@codepoet.org> * * 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. */#include <ctype.h>#include <dirent.h>#include <errno.h>#include <fcntl.h>#include <limits.h>#include <setjmp.h>#include <signal.h>#include <stddef.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <time.h>#include <unistd.h>#include <sys/stat.h>#include <sys/times.h>#include <sys/types.h>#include <sys/wait.h>#include "cmdedit.h"#include "busybox.h"/* -------- sh.h -------- *//* * shell */#define LINELIM 2100#define NPUSH 8 /* limit to input nesting */#undef NOFILE#define NOFILE 20 /* Number of open files */#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; /* Is this an interactive shell */static int execflg;static int multiline; /* \n changed to ; */static struct op *outtree; /* result from parser */static xint *failpt;static xint *errpt;static struct brkcon *brklist;static int isbreak;static int newfile(char *s);static char *findeq(char *cp);static char *cclass(char *p, int sub);static void initarea(void);extern int msh_main(int argc, char **argv);struct brkcon { jmp_buf brkpt; struct brkcon *nextlev;} ;/* * 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 */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))(struct op *);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 (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 my_getc( int ec);static int subgetc (int ec, int quoted );static char **makenv (void);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 gmatch (char *s, char *p );/* * error handling */static void leave (void); /* 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 *//* -------- area stuff -------- */#define REGSIZE sizeof(struct region)#define GROWBY 256//#define SHRINKBY 64#undef SHRINKBY#define FREE 32767#define BUSY 0#define ALIGN (sizeof(int)-1)struct region { struct region *next; int area;};/* -------- grammar stuff -------- */typedef union { char *cp; char **wp; int i; struct op *o;} YYSTYPE;#define WORD 256#define LOGAND 257#define LOGOR 258#define BREAK 259#define IF 260#define THEN 261#define ELSE 262#define ELIF 263#define FI 264#define CASE 265#define ESAC 266#define FOR 267#define WHILE 268#define UNTIL 269#define DO 270#define DONE 271#define IN 272#define YYERRCODE 300/* flags to yylex */#define CONTIN 01 /* skip new lines to complete command */#define SYNTAXERR zzerr()static struct op *pipeline(int cf );static struct op *andor(void);static struct op *c_list(void);static int synio(int cf );static void musthave (int c, int cf );static struct op *simple(void);static struct op *nested(int type, int mark );static struct op *command(int cf );static struct op *dogroup(int onlydone );static struct op *thenpart(void);static struct op *elsepart(void);static struct op *caselist(void);static struct op *casepart(void);static char **pattern(void);static char **wordlist(void);static struct op *list(struct op *t1, struct op *t2 );static struct op *block(int type, struct op *t1, struct op *t2, char **wp );static struct op *newtp(void);static struct op *namelist(struct op *t );static char **copyw(void);static void word(char *cp );static struct ioword **copyio(void);static struct ioword *io (int u, int f, char *cp );static void zzerr(void);static void yyerror(char *s );static int yylex(int cf );static int collect(int c, int c1 );static int dual(int c );static void diag(int ec );static char *tree(unsigned size );/* -------- 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 *, struct io *); 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 *));/* * IO functions */static int eofc (void);static int readc (void);static void unget (int c );static void ioecho (int c );static void prs (char *s );static void prn (unsigned u );static void closef (int i );static void closeall (void);/* * IO control */static void pushio (struct ioarg *argp, int (*f)(struct ioarg *));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; /* 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 -------- */#define NSTART 16 /* default number of words to allow for initially */struct wdblock { short w_bsize; short w_nword; /* bounds are arbitrary */ char *w_words[1];};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 (char *cp );static int areanum; /* current allocation area */#define NEW(type) (type *)getcell(sizeof(type))#define DELETE(obj) freecell((char *)obj)/* -------- misc stuff -------- */static int forkexec (struct op *t, int *pin, int *pout, int act, char **wp, int *pforked );static int iosetup (struct ioword *iop, int pipein, int pipeout );static void echo(char **wp );static struct op **find1case (struct op *t, char *w );static struct op *findcase (struct op *t, char *w );static void brkset(struct brkcon *bc );static int dolabel(struct op *t );static int dohelp(struct op *t );static int dochdir(struct op *t );static int doshift(struct op *t );static int dologin(struct op *t );static int doumask(struct op *t );static int doexec(struct op *t );static int dodot(struct op *t );static int dowait(struct op *t );static int doread(struct op *t );static int doeval(struct op *t );static int dotrap(struct op *t );static int getsig(char *s );static void setsig (int n, sighandler_t f);static int getn(char *as );static int dobreak(struct op *t );static int docontinue(struct op *t );static int brkcontin (char *cp, int val );static int doexit(struct op *t );static int doexport(struct op *t );static int doreadonly(struct op *t );static void rdexp (char **wp, void (*f)(struct var *), int key);static void badid(char *s );static int doset(struct op *t );static void varput (char *s, int out );static int dotimes(struct op *t );static int expand (char *cp, struct wdblock **wbp, int f );static char *blank(int f );static int dollar(int quoted );static int grave(int quoted );static void globname (char *we, char *pp );static char *generate (char *start1, char *end1, char *middle, char *end );static int anyspcl(struct wdblock *wb );static int xstrcmp (char *p1, char *p2 );static void glob0 (char *a0, unsigned int a1, int a2, int (*a3)(char *, char *));static void glob1 (char *base, char *lim );static void glob2 (char *i, char *j );static void glob3 (char *i, char *j, char *k );static void readhere (char **name, char *s, int ec );static void pushio (struct ioarg *argp, int (*f)(struct ioarg *));static int xxchar(struct ioarg *ap );struct here { char *h_tag; int h_dosub; struct ioword *h_iop; struct here *h_next;};static char *signame[] = { "Signal 0", "Hangup", (char *)NULL, /* interrupt */ "Quit", "Illegal instruction", "Trace/BPT trap", "Abort", "Bus error", "Floating Point Exception", "Killed", "SIGUSR1", "SIGSEGV", "SIGUSR2", (char *)NULL, /* broken pipe */ "Alarm clock", "Terminated",};#define NSIGNAL (sizeof(signame)/sizeof(signame[0]))struct res { char *r_name; int r_val;};static struct res restab[] = { {"for", FOR}, {"case", CASE}, {"esac", ESAC}, {"while", WHILE}, {"do", DO}, {"done", DONE}, {"if", IF}, {"in", IN}, {"then", THEN}, {"else", ELSE}, {"elif", ELIF}, {"until", UNTIL}, {"fi", FI}, {";;", BREAK}, {"||", LOGOR}, {"&&", LOGAND}, {"{", '{'}, {"}", '}'}, {0, 0},};struct builtincmd { const char *name; int (*builtinfunc)(struct op *t);};static const struct builtincmd builtincmds[] = { {".", dodot}, {":", dolabel}, {"break", dobreak}, {"cd", dochdir}, {"continue",docontinue}, {"eval", doeval}, {"exec", doexec}, {"exit", doexit}, {"export", doexport}, {"help", dohelp}, {"login", dologin}, {"newgrp", dologin}, {"read", doread}, {"readonly",doreadonly}, {"set", doset}, {"shift", doshift}, {"times", dotimes}, {"trap", dotrap}, {"umask", doumask}, {"wait", dowait}, {0,0}};/* Globals */extern char **environ; /* environment pointer */static char **dolv;static int dolc;static int exstat;static char gflg;static int interactive; /* Is this an interactive shell */static int execflg;static int multiline; /* \n changed to ; */static struct op *outtree; /* result from parser */static xint *failpt;static xint *errpt;static struct brkcon *brklist;static int isbreak;static struct wdblock *wdlist;static struct wdblock *iolist;static char *trap[_NSIG+1];static char ourtrap[_NSIG+1];static int trapset; /* trap pending */static int yynerrs; /* yacc */static char line[LINELIM];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 struct ioarg ioargstack[NPUSH];static struct io iostack[NPUSH];static int areanum; /* current allocation area */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};static void (*qflag)(int) = SIG_IGN;static int startl;static int peeksym;static int nlseen;static int iounit = IODEFAULT;static YYSTYPE yylval;static struct iobuf sharedbuf = {AFID_NOBUF};static struct iobuf mainbuf = {AFID_NOBUF};static unsigned bufid = AFID_ID; /* buffer id counter */static struct ioarg temparg = {0, 0, 0, AFID_NOBUF, 0};static struct here *inhere; /* list of hear docs while parsing */static struct here *acthere; /* list of active here documents */static struct region *areabot; /* bottom of area */static struct region *areatop; /* top of area */static struct region *areanxt; /* starting point of scan */static void * brktop;static void * brkaddr;#ifdef CONFIG_FEATURE_COMMAND_EDITINGstatic char * current_prompt;#endif/* -------- sh.c -------- *//* * shell */extern int msh_main(int argc, char **argv){ register int f; register char *s; int cflag; char *name, **ap; int (*iof)(struct ioarg *); initarea(); if ((ap = environ) != NULL) { while (*ap) assign(*ap++, !COPYV); for (ap = environ; *ap;) export(lookup(*ap++)); } closeall(); areanum = 1; shell = lookup("SHELL");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -