msh: instead of fixing "ls | cd", "cd | ls" etc just disallow

builtins in pipes. They make no sense there anyway.
msh: shrink umask builtin.

function                                             old     new   delta
execute                                             2508    2509      +1
doset                                                326     317      -9
forkexec                                            1370    1345     -25
doumask                                              165     101     -64
------------------------------------------------------------------------------
(add/remove: 0/0 grow/shrink: 1/3 up/down: 1/-98)             Total: -97 bytes
This commit is contained in:
Denis Vlasenko 2008-02-12 09:51:03 +00:00
parent e26b2783a5
commit 7e497527ea

View File

@ -86,7 +86,7 @@ static char *itoa(int n)
# include "busybox.h" /* for applet_names */ # include "busybox.h" /* for applet_names */
#endif #endif
/*#define MSHDEBUG 1*/ //#define MSHDEBUG 4
#ifdef MSHDEBUG #ifdef MSHDEBUG
int mshdbg = MSHDEBUG; int mshdbg = MSHDEBUG;
@ -244,11 +244,6 @@ static const char *const T_CMD_NAMES[] = {
}; };
#endif #endif
/*
* actions determining the environment of a process
*/
#define FEXEC 1 /* execute without forking */
#define AREASIZE (90000) #define AREASIZE (90000)
/* /*
@ -402,8 +397,6 @@ struct var {
static int yyparse(void); static int yyparse(void);
static int execute(struct op *t, int *pin, int *pout, int act);
/* -------- io.h -------- */ /* -------- io.h -------- */
/* io buffer */ /* io buffer */
@ -495,7 +488,8 @@ static char **getwords(struct wdblock *wb);
/* -------- misc stuff -------- */ /* -------- misc stuff -------- */
static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp); static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp);
static int execute(struct op *t, int *pin, int *pout, int no_fork);
static int iosetup(struct ioword *iop, int pipein, int pipeout); static int iosetup(struct ioword *iop, int pipein, int pipeout);
static void brkset(struct brkcon *bc); static void brkset(struct brkcon *bc);
static int dolabel(struct op *t); static int dolabel(struct op *t);
@ -564,10 +558,13 @@ static const char *const signame[] = {
}; };
typedef int (*builtin_func_ptr)(struct op *);
struct builtincmd { struct builtincmd {
const char *name; const char *name;
int (*builtinfunc)(struct op *t); builtin_func_ptr builtinfunc;
}; };
static const struct builtincmd builtincmds[] = { static const struct builtincmd builtincmds[] = {
{ "." , dodot }, { "." , dodot },
{ ":" , dolabel }, { ":" , dolabel },
@ -1373,7 +1370,7 @@ static void onecommand(void)
if (!FLAG['n']) { if (!FLAG['n']) {
DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n", DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
outtree)); outtree));
execute(outtree, NOPIPE, NOPIPE, 0); execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
} }
if (!interactive && intr) { if (!interactive && intr) {
@ -2450,7 +2447,7 @@ static struct op *findcase(struct op *t, const char *w)
* execute tree * execute tree
*/ */
static int execute(struct op *t, int *pin, int *pout, int act) static int execute(struct op *t, int *pin, int *pout, int no_fork)
{ {
struct op *t1; struct op *t1;
volatile int i, rv, a; volatile int i, rv, a;
@ -2495,17 +2492,17 @@ static int execute(struct op *t, int *pin, int *pout, int act)
outtree = outtree_save; outtree = outtree_save;
if (t->left) if (t->left)
rv = execute(t->left, pin, pout, 0); rv = execute(t->left, pin, pout, /* no_fork: */ 0);
if (t->right) if (t->right)
rv = execute(t->right, pin, pout, 0); rv = execute(t->right, pin, pout, /* no_fork: */ 0);
break; break;
case TPAREN: case TPAREN:
rv = execute(t->left, pin, pout, 0); rv = execute(t->left, pin, pout, /* no_fork: */ 0);
break; break;
case TCOM: case TCOM:
rv = forkexec(t, pin, pout, act, wp); rv = forkexec(t, pin, pout, no_fork, wp);
break; break;
case TPIPE: case TPIPE:
@ -2517,14 +2514,14 @@ static int execute(struct op *t, int *pin, int *pout, int act)
break; break;
pv[0] = remap(pv[0]); pv[0] = remap(pv[0]);
pv[1] = remap(pv[1]); pv[1] = remap(pv[1]);
(void) execute(t->left, pin, pv, 0); (void) execute(t->left, pin, pv, /* no_fork: */ 0);
rv = execute(t->right, pv, pout, 0); rv = execute(t->right, pv, pout, /* no_fork: */ 0);
} }
break; break;
case TLIST: case TLIST:
(void) execute(t->left, pin, pout, 0); (void) execute(t->left, pin, pout, /* no_fork: */ 0);
rv = execute(t->right, pin, pout, 0); rv = execute(t->right, pin, pout, /* no_fork: */ 0);
break; break;
case TASYNC: case TASYNC:
@ -2544,7 +2541,7 @@ static int execute(struct op *t, int *pin, int *pout, int act)
close(0); close(0);
xopen(bb_dev_null, O_RDONLY); xopen(bb_dev_null, O_RDONLY);
} }
_exit(execute(t->left, pin, pout, FEXEC)); _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
} }
interactive = hinteractive; interactive = hinteractive;
if (i != -1) { if (i != -1) {
@ -2562,10 +2559,10 @@ static int execute(struct op *t, int *pin, int *pout, int act)
case TOR: case TOR:
case TAND: case TAND:
rv = execute(t->left, pin, pout, 0); rv = execute(t->left, pin, pout, /* no_fork: */ 0);
t1 = t->right; t1 = t->right;
if (t1 != NULL && (rv == 0) == (t->type == TAND)) if (t1 != NULL && (rv == 0) == (t->type == TAND))
rv = execute(t1, pin, pout, 0); rv = execute(t1, pin, pout, /* no_fork: */ 0);
break; break;
case TFOR: case TFOR:
@ -2585,7 +2582,7 @@ static int execute(struct op *t, int *pin, int *pout, int act)
brkset(&bc); brkset(&bc);
for (t1 = t->left; i-- && *wp != NULL;) { for (t1 = t->left; i-- && *wp != NULL;) {
setval(vp, *wp++); setval(vp, *wp++);
rv = execute(t1, pin, pout, 0); rv = execute(t1, pin, pout, /* no_fork: */ 0);
} }
brklist = brklist->nextlev; brklist = brklist->nextlev;
break; break;
@ -2597,17 +2594,17 @@ static int execute(struct op *t, int *pin, int *pout, int act)
goto broken; goto broken;
brkset(&bc); brkset(&bc);
t1 = t->left; t1 = t->left;
while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE)) while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
rv = execute(t->right, pin, pout, 0); rv = execute(t->right, pin, pout, /* no_fork: */ 0);
brklist = brklist->nextlev; brklist = brklist->nextlev;
break; break;
case TIF: case TIF:
case TELIF: case TELIF:
if (t->right != NULL) { if (t->right != NULL) {
rv = !execute(t->left, pin, pout, 0) ? rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
execute(t->right->left, pin, pout, 0) : execute(t->right->left, pin, pout, /* no_fork: */ 0) :
execute(t->right->right, pin, pout, 0); execute(t->right->right, pin, pout, /* no_fork: */ 0);
} }
break; break;
@ -2623,7 +2620,7 @@ static int execute(struct op *t, int *pin, int *pout, int act)
t1 = findcase(t->left, cp); t1 = findcase(t->left, cp);
if (t1 != NULL) { if (t1 != NULL) {
DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1)); DBGPRINTF7(("EXECUTE: TCASE, calling execute(t=%p, t1=%p)...\n", t, t1));
rv = execute(t1, pin, pout, 0); rv = execute(t1, pin, pout, /* no_fork: */ 0);
DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1)); DBGPRINTF7(("EXECUTE: TCASE, back from execute(t=%p, t1=%p)...\n", t, t1));
} }
break; break;
@ -2641,7 +2638,7 @@ static int execute(struct op *t, int *pin, int *pout, int act)
if (rv >= 0) { if (rv >= 0) {
t1 = t->left; t1 = t->left;
if (t1) { if (t1) {
rv = execute(t1, pin, pout, 0); rv = execute(t1, pin, pout, /* no_fork: */ 0);
} }
} }
break; break;
@ -2669,8 +2666,6 @@ static int execute(struct op *t, int *pin, int *pout, int act)
return rv; return rv;
} }
typedef int (*builtin_func_ptr)(struct op *);
static builtin_func_ptr inbuilt(const char *s) static builtin_func_ptr inbuilt(const char *s)
{ {
const struct builtincmd *bp; const struct builtincmd *bp;
@ -2681,17 +2676,17 @@ static builtin_func_ptr inbuilt(const char *s)
return NULL; return NULL;
} }
static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp) static int forkexec(struct op *t, int *pin, int *pout, int no_fork, char **wp)
{ {
pid_t newpid; pid_t newpid;
int i; int i;
builtin_func_ptr bltin = NULL; builtin_func_ptr bltin = NULL;
int f; const char *bltin_name = NULL;
const char *cp = NULL; const char *cp;
struct ioword **iopp; struct ioword **iopp;
int resetsig; int resetsig;
char **owp; char **owp;
int forked = 0; int forked;
int *hpin = pin; int *hpin = pin;
int *hpout = pout; int *hpout = pout;
@ -2712,11 +2707,10 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
(void) &owp; (void) &owp;
#endif #endif
DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin, DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
pout, act)); pout, no_fork));
DBGPRINTF7(("FORKEXEC: t->words is %s\n", DBGPRINTF7(("FORKEXEC: t->words is %s\n",
((t->words == NULL) ? "NULL" : t->words[0]))); ((t->words == NULL) ? "NULL" : t->words[0])));
owp = wp; owp = wp;
resetsig = 0; resetsig = 0;
if (t->type == TCOM) { if (t->type == TCOM) {
@ -2725,32 +2719,36 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
cp = *wp; cp = *wp;
/* strip all initial assignments */ /* strip all initial assignments */
/* not correct wrt PATH=yyy command etc */ /* FIXME: not correct wrt PATH=yyy command etc */
if (FLAG['x']) { if (FLAG['x']) {
DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n", DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
cp, wp, owp)); cp, wp, owp));
echo(cp ? wp : owp); echo(cp ? wp : owp);
} }
if (cp == NULL && t->ioact == NULL) { if (cp == NULL) {
if (t->ioact == NULL) {
while ((cp = *owp++) != NULL && assign(cp, COPYV)) while ((cp = *owp++) != NULL && assign(cp, COPYV))
continue; continue;
DBGPRINTF(("FORKEXEC: returning setstatus()\n")); DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
return setstatus(0); return setstatus(0);
} }
if (cp != NULL) { } else { /* cp != NULL */
bltin_name = cp;
bltin = inbuilt(cp); bltin = inbuilt(cp);
} }
} }
forked = 0;
t->words = wp; t->words = wp;
f = act; DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
no_fork, owp));
DBGPRINTF(("FORKEXEC: bltin %p, f&FEXEC 0x%x, owp %p\n", bltin, /* Don't fork if it is a lone builtin (not in pipe)
f & FEXEC, owp)); * OR we are told to _not_ fork */
if ((!bltin || pin || pout) /* not lone bltin AND */
if (!bltin && (f & FEXEC) == 0) { && !no_fork /* not told to avoid fork */
/* Save values in case the child process alters them */ ) {
/* Save values in case child alters them after vfork */
hpin = pin; hpin = pin;
hpout = pout; hpout = pout;
hwp = *wp; hwp = *wp;
@ -2760,9 +2758,7 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
hexecflg = execflg; hexecflg = execflg;
DBGPRINTF3(("FORKEXEC: calling vfork()...\n")); DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
newpid = vfork(); newpid = vfork();
if (newpid == -1) { if (newpid == -1) {
DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n")); DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
return -1; return -1;
@ -2783,8 +2779,7 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
} }
/* Child */ /* Child */
DBGPRINTF(("FORKEXEC: child process, bltin=%p\n", bltin)); DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
if (interactive) { if (interactive) {
signal(SIGINT, SIG_IGN); signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN); signal(SIGQUIT, SIG_IGN);
@ -2802,20 +2797,6 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
if (!bltin) if (!bltin)
export(lookup(cp)); export(lookup(cp));
#if 1
/* How to fix it:
* explicitly pass pin[0] and pout[1] to builtins
* instead of making them rely on fd 0/1,
* and do not xmove_fd(pin[0]/pout[1]) below if bltin != NULL.
*/
if ((pin || pout) && bltin && bltin != doexec) {
err("piping to/from shell builtins not yet done");
if (forked)
_exit(-1);
return -1;
}
#endif
if (pin) { if (pin) {
xmove_fd(pin[0], 0); xmove_fd(pin[0], 0);
if (pin[1] != 0) if (pin[1] != 0)
@ -2830,13 +2811,13 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
iopp = t->ioact; iopp = t->ioact;
if (iopp) { if (iopp) {
if (bltin && bltin != doexec) { if (bltin && bltin != doexec) {
prs(cp); prs(bltin_name);
err(": cannot redirect shell command"); err(": cannot redirect shell command");
if (forked) if (forked)
_exit(-1); _exit(-1);
return -1; return -1;
} }
while (*iopp) while (*iopp) {
if (iosetup(*iopp++, pin != NULL, pout != NULL)) { if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
/* system-detected error */ /* system-detected error */
if (forked) if (forked)
@ -2844,19 +2825,22 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
return -1; return -1;
} }
} }
}
if (bltin) { if (bltin) {
if (forked || pin || pout) {
/* Builtin in pipe: disallowed */
/* TODO: allow "exec"? */
prs(bltin_name);
err(": cannot run builtin as part of pipe");
if (forked)
_exit(-1);
return -1;
}
i = setstatus(bltin(t)); i = setstatus(bltin(t));
if (forked) if (forked)
_exit(i); _exit(i);
DBGPRINTF(("FORKEXEC: returning i=%d\n", i)); DBGPRINTF(("FORKEXEC: returning i=%d\n", i));
/* Builtins in pipes ("ls /dev/null | cd"):
* here "cd" (which is not a child) will return to main msh,
* and we will read from ls's output as if it is our next command!
* Result: "/dev/null: cannot execute"
* and then we reach EOF on stdin and exit.
* See above for possible way to fix this.
*/
return i; return i;
} }
@ -2869,7 +2853,7 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
} }
if (t->type == TPAREN) if (t->type == TPAREN)
_exit(execute(t->left, NOPIPE, NOPIPE, FEXEC)); _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
if (wp[0] == NULL) if (wp[0] == NULL)
_exit(0); _exit(0);
@ -2880,7 +2864,7 @@ static int forkexec(struct op *t, int *pin, int *pout, int act, char **wp)
if (!execflg) if (!execflg)
trap[0] = NULL; trap[0] = NULL;
DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid)); DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
leave(); leave();
/* NOTREACHED */ /* NOTREACHED */
@ -2927,6 +2911,7 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout)
iop->io_flag = IOCLOSE; iop->io_flag = IOCLOSE;
iop->io_flag &= ~(IOREAD | IOWRITE); iop->io_flag &= ~(IOREAD | IOWRITE);
} }
switch (iop->io_flag) { switch (iop->io_flag) {
case IOREAD: case IOREAD:
u = open(cp, O_RDONLY); u = open(cp, O_RDONLY);
@ -2944,6 +2929,8 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout)
lseek(u, (long) 0, SEEK_END); lseek(u, (long) 0, SEEK_END);
break; break;
} }
/* fall through to creation if >>file doesn't exist */
case IOWRITE: case IOWRITE:
u = creat(cp, 0666); u = creat(cp, 0666);
break; break;
@ -2956,6 +2943,7 @@ static int iosetup(struct ioword *iop, int pipein, int pipeout)
close(iop->io_unit); close(iop->io_unit);
return 0; return 0;
} }
if (u < 0) { if (u < 0) {
prs(cp); prs(cp);
prs(": cannot "); prs(": cannot ");
@ -3148,7 +3136,7 @@ static int run(struct ioarg *argp, int (*f) (struct ioarg *))
yynerrs = 0; yynerrs = 0;
failpt = rt; failpt = rt;
if (setjmp(failpt) == 0 && yyparse() == 0) if (setjmp(failpt) == 0 && yyparse() == 0)
rv = execute(outtree, NOPIPE, NOPIPE, 0); rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
quitenv(); quitenv();
} else { } else {
DBGPRINTF(("RUN: error from newenv()!\n")); DBGPRINTF(("RUN: error from newenv()!\n"));
@ -3267,20 +3255,21 @@ static int dologin(struct op *t)
static int doumask(struct op *t) static int doumask(struct op *t)
{ {
int i, n; int i;
char *cp; char *cp;
cp = t->words[1]; cp = t->words[1];
if (cp == NULL) { if (cp == NULL) {
i = umask(0); i = umask(0);
umask(i); umask(i);
for (n = 3 * 4; (n -= 3) >= 0;) printf("%04o\n", i);
fputc('0' + ((i >> n) & 07), stderr);
fputc('\n', stderr);
} else { } else {
for (n = 0; *cp >= '0' && *cp <= '7'; cp++) i = bb_strtou(cp, NULL, 8);
n = n * 8 + (*cp - '0'); if (errno) {
umask(n); err("umask: bad octal number");
return 1;
}
umask(i);
} }
return 0; return 0;
} }
@ -3292,14 +3281,15 @@ static int doexec(struct op *t)
xint *ofail; xint *ofail;
t->ioact = NULL; t->ioact = NULL;
for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++); for (i = 0; (t->words[i] = t->words[i + 1]) != NULL; i++)
continue;
if (i == 0) if (i == 0)
return 1; return 1;
execflg = 1; execflg = 1;
ofail = failpt; ofail = failpt;
failpt = ex; failpt = ex;
if (setjmp(failpt) == 0) if (setjmp(failpt) == 0)
execute(t, NOPIPE, NOPIPE, FEXEC); execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
failpt = ofail; failpt = ofail;
execflg = 0; execflg = 0;
return 1; return 1;