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 + -
显示快捷键?