# include "busybox.h" /* for applet_names */
#endif
-/*#define MSHDEBUG 1*/
+//#define MSHDEBUG 4
#ifdef MSHDEBUG
int mshdbg = MSHDEBUG;
};
#endif
-/*
- * actions determining the environment of a process
- */
-#define FEXEC 1 /* execute without forking */
-
#define AREASIZE (90000)
/*
static int yyparse(void);
-static int execute(struct op *t, int *pin, int *pout, int act);
-
/* -------- io.h -------- */
/* io buffer */
/* -------- 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 void brkset(struct brkcon *bc);
static int dolabel(struct op *t);
};
+typedef int (*builtin_func_ptr)(struct op *);
+
struct builtincmd {
const char *name;
- int (*builtinfunc)(struct op *t);
+ builtin_func_ptr builtinfunc;
};
+
static const struct builtincmd builtincmds[] = {
{ "." , dodot },
{ ":" , dolabel },
if (!FLAG['n']) {
DBGPRINTF(("ONECOMMAND: calling execute, t=outtree=%p\n",
outtree));
- execute(outtree, NOPIPE, NOPIPE, 0);
+ execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
}
if (!interactive && intr) {
* 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;
volatile int i, rv, a;
outtree = outtree_save;
if (t->left)
- rv = execute(t->left, pin, pout, 0);
+ rv = execute(t->left, pin, pout, /* no_fork: */ 0);
if (t->right)
- rv = execute(t->right, pin, pout, 0);
+ rv = execute(t->right, pin, pout, /* no_fork: */ 0);
break;
case TPAREN:
- rv = execute(t->left, pin, pout, 0);
+ rv = execute(t->left, pin, pout, /* no_fork: */ 0);
break;
case TCOM:
- rv = forkexec(t, pin, pout, act, wp);
+ rv = forkexec(t, pin, pout, no_fork, wp);
break;
case TPIPE:
break;
pv[0] = remap(pv[0]);
pv[1] = remap(pv[1]);
- (void) execute(t->left, pin, pv, 0);
- rv = execute(t->right, pv, pout, 0);
+ (void) execute(t->left, pin, pv, /* no_fork: */ 0);
+ rv = execute(t->right, pv, pout, /* no_fork: */ 0);
}
break;
case TLIST:
- (void) execute(t->left, pin, pout, 0);
- rv = execute(t->right, pin, pout, 0);
+ (void) execute(t->left, pin, pout, /* no_fork: */ 0);
+ rv = execute(t->right, pin, pout, /* no_fork: */ 0);
break;
case TASYNC:
close(0);
xopen(bb_dev_null, O_RDONLY);
}
- _exit(execute(t->left, pin, pout, FEXEC));
+ _exit(execute(t->left, pin, pout, /* no_fork: */ 1));
}
interactive = hinteractive;
if (i != -1) {
case TOR:
case TAND:
- rv = execute(t->left, pin, pout, 0);
+ rv = execute(t->left, pin, pout, /* no_fork: */ 0);
t1 = t->right;
if (t1 != NULL && (rv == 0) == (t->type == TAND))
- rv = execute(t1, pin, pout, 0);
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
break;
case TFOR:
brkset(&bc);
for (t1 = t->left; i-- && *wp != NULL;) {
setval(vp, *wp++);
- rv = execute(t1, pin, pout, 0);
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
}
brklist = brklist->nextlev;
break;
goto broken;
brkset(&bc);
t1 = t->left;
- while ((execute(t1, pin, pout, 0) == 0) == (t->type == TWHILE))
- rv = execute(t->right, pin, pout, 0);
+ while ((execute(t1, pin, pout, /* no_fork: */ 0) == 0) == (t->type == TWHILE))
+ rv = execute(t->right, pin, pout, /* no_fork: */ 0);
brklist = brklist->nextlev;
break;
case TIF:
case TELIF:
if (t->right != NULL) {
- rv = !execute(t->left, pin, pout, 0) ?
- execute(t->right->left, pin, pout, 0) :
- execute(t->right->right, pin, pout, 0);
+ rv = !execute(t->left, pin, pout, /* no_fork: */ 0) ?
+ execute(t->right->left, pin, pout, /* no_fork: */ 0) :
+ execute(t->right->right, pin, pout, /* no_fork: */ 0);
}
break;
t1 = findcase(t->left, cp);
if (t1 != NULL) {
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));
}
break;
if (rv >= 0) {
t1 = t->left;
if (t1) {
- rv = execute(t1, pin, pout, 0);
+ rv = execute(t1, pin, pout, /* no_fork: */ 0);
}
}
break;
return rv;
}
-typedef int (*builtin_func_ptr)(struct op *);
-
static builtin_func_ptr inbuilt(const char *s)
{
const struct builtincmd *bp;
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;
int i;
builtin_func_ptr bltin = NULL;
- int f;
- const char *cp = NULL;
+ const char *bltin_name = NULL;
+ const char *cp;
struct ioword **iopp;
int resetsig;
char **owp;
- int forked = 0;
+ int forked;
int *hpin = pin;
int *hpout = pout;
(void) &owp;
#endif
- DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, act %d\n", t, pin,
- pout, act));
+ DBGPRINTF(("FORKEXEC: t=%p, pin %p, pout %p, no_fork %d\n", t, pin,
+ pout, no_fork));
DBGPRINTF7(("FORKEXEC: t->words is %s\n",
- ((t->words == NULL) ? "NULL" : t->words[0])));
-
+ ((t->words == NULL) ? "NULL" : t->words[0])));
owp = wp;
resetsig = 0;
if (t->type == TCOM) {
cp = *wp;
/* strip all initial assignments */
- /* not correct wrt PATH=yyy command etc */
+ /* FIXME: not correct wrt PATH=yyy command etc */
if (FLAG['x']) {
DBGPRINTF9(("FORKEXEC: echo'ing, cp=%p, wp=%p, owp=%p\n",
cp, wp, owp));
echo(cp ? wp : owp);
}
- if (cp == NULL && t->ioact == NULL) {
- while ((cp = *owp++) != NULL && assign(cp, COPYV))
- continue;
- DBGPRINTF(("FORKEXEC: returning setstatus()\n"));
- return setstatus(0);
- }
- if (cp != NULL) {
+ if (cp == NULL) {
+ if (t->ioact == NULL) {
+ while ((cp = *owp++) != NULL && assign(cp, COPYV))
+ continue;
+ DBGPRINTF(("FORKEXEC: returning setstatus(0)\n"));
+ return setstatus(0);
+ }
+ } else { /* cp != NULL */
+ bltin_name = cp;
bltin = inbuilt(cp);
}
}
+ forked = 0;
t->words = wp;
- f = act;
-
- DBGPRINTF(("FORKEXEC: bltin %p, f&FEXEC 0x%x, owp %p\n", bltin,
- f & FEXEC, owp));
-
- if (!bltin && (f & FEXEC) == 0) {
- /* Save values in case the child process alters them */
+ DBGPRINTF(("FORKEXEC: bltin %p, no_fork %d, owp %p\n", bltin,
+ no_fork, owp));
+ /* Don't fork if it is a lone builtin (not in pipe)
+ * OR we are told to _not_ fork */
+ if ((!bltin || pin || pout) /* not lone bltin AND */
+ && !no_fork /* not told to avoid fork */
+ ) {
+ /* Save values in case child alters them after vfork */
hpin = pin;
hpout = pout;
hwp = *wp;
hexecflg = execflg;
DBGPRINTF3(("FORKEXEC: calling vfork()...\n"));
-
newpid = vfork();
-
if (newpid == -1) {
DBGPRINTF(("FORKEXEC: ERROR, cannot vfork()!\n"));
return -1;
}
/* Child */
- DBGPRINTF(("FORKEXEC: child process, bltin=%p\n", bltin));
-
+ DBGPRINTF(("FORKEXEC: child process, bltin=%p (%s)\n", bltin, bltin_name));
if (interactive) {
signal(SIGINT, SIG_IGN);
signal(SIGQUIT, SIG_IGN);
if (!bltin)
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) {
xmove_fd(pin[0], 0);
if (pin[1] != 0)
iopp = t->ioact;
if (iopp) {
if (bltin && bltin != doexec) {
- prs(cp);
+ prs(bltin_name);
err(": cannot redirect shell command");
if (forked)
_exit(-1);
return -1;
}
- while (*iopp)
+ while (*iopp) {
if (iosetup(*iopp++, pin != NULL, pout != NULL)) {
/* system-detected error */
if (forked)
_exit(-1);
return -1;
}
+ }
}
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));
if (forked)
_exit(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;
}
}
if (t->type == TPAREN)
- _exit(execute(t->left, NOPIPE, NOPIPE, FEXEC));
+ _exit(execute(t->left, NOPIPE, NOPIPE, /* no_fork: */ 1));
if (wp[0] == NULL)
_exit(0);
if (!execflg)
trap[0] = NULL;
- DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", newpid));
+ DBGPRINTF(("FORKEXEC: calling leave(), pid=%d\n", getpid()));
leave();
/* NOTREACHED */
iop->io_flag = IOCLOSE;
iop->io_flag &= ~(IOREAD | IOWRITE);
}
+
switch (iop->io_flag) {
case IOREAD:
u = open(cp, O_RDONLY);
lseek(u, (long) 0, SEEK_END);
break;
}
+ /* fall through to creation if >>file doesn't exist */
+
case IOWRITE:
u = creat(cp, 0666);
break;
close(iop->io_unit);
return 0;
}
+
if (u < 0) {
prs(cp);
prs(": cannot ");
yynerrs = 0;
failpt = rt;
if (setjmp(failpt) == 0 && yyparse() == 0)
- rv = execute(outtree, NOPIPE, NOPIPE, 0);
+ rv = execute(outtree, NOPIPE, NOPIPE, /* no_fork: */ 0);
quitenv();
} else {
DBGPRINTF(("RUN: error from newenv()!\n"));
static int doumask(struct op *t)
{
- int i, n;
+ int i;
char *cp;
cp = t->words[1];
if (cp == NULL) {
i = umask(0);
umask(i);
- for (n = 3 * 4; (n -= 3) >= 0;)
- fputc('0' + ((i >> n) & 07), stderr);
- fputc('\n', stderr);
+ printf("%04o\n", i);
} else {
- for (n = 0; *cp >= '0' && *cp <= '7'; cp++)
- n = n * 8 + (*cp - '0');
- umask(n);
+ i = bb_strtou(cp, NULL, 8);
+ if (errno) {
+ err("umask: bad octal number");
+ return 1;
+ }
+ umask(i);
}
return 0;
}
xint *ofail;
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)
return 1;
execflg = 1;
ofail = failpt;
failpt = ex;
if (setjmp(failpt) == 0)
- execute(t, NOPIPE, NOPIPE, FEXEC);
+ execute(t, NOPIPE, NOPIPE, /* no_fork: */ 1);
failpt = ofail;
execflg = 0;
return 1;