Example #1
0
File: glom.c Project: muennich/rc3
static List *backq(Node *ifs, Node *n) {
	int p[2], sp;
	pid_t pid;
	List *bq;
	struct termios t;
	if (n == NULL)
		return NULL;
	if (pipe(p) < 0) {
		uerror("pipe");
		rc_error(NULL);
	}
	if (interactive)
		tcgetattr(0, &t);
	if ((pid = rc_fork()) == 0) {
		mvfd(p[1], 1);
		close(p[0]);
		redirq = NULL;
		walk(n, FALSE);
		exit(getstatus());
	}
	close(p[1]);
	bq = bqinput(glom(ifs), p[0]);
	close(p[0]);
	rc_wait4(pid, &sp, TRUE);
	if (interactive && WIFSIGNALED(sp))
		tcsetattr(0, TCSANOW, &t);
	statprint(-1, sp);
	varassign("bqstatus", word(strstatus(sp), NULL), FALSE);
	sigchk();
	return bq;
}
Example #2
0
File: system.c Project: borkovic/rc
extern void writeall(int fd, const char *buf, size_t remain) {
	int i = 0;

	for (; remain > 0; buf += i, remain -= i)
		if ((i = write(fd, buf, remain)) <= 0)
			break; /* abort silently on errors in write() */
	sigchk();
}
Example #3
0
static bool dofork(bool parent) {
	int pid, sp;

	if (!parent || (pid = rc_fork()) == 0)
		return TRUE;
	redirq = NULL; /* clear out the pre-redirection queue in the parent */
	rc_wait4(pid, &sp, TRUE);
	setstatus(-1, sp);
	sigchk();
	return FALSE;
}
Example #4
0
static void dopipe(Node *n) {
	int i, j, sp, pid, fd_prev, fd_out, pids[512], stats[512], p[2];
	bool intr;
	Node *r;

	fd_prev = fd_out = 1;
	for (r = n, i = 0; r != NULL && r->type == nPipe; r = r->u[2].p, i++) {
		if (i > 500) /* the only hard-wired limit in rc? */
			rc_error("pipe too long");
		if (pipe(p) < 0) {
			uerror("pipe");
			rc_error(NULL);
		}
		if ((pid = rc_fork()) == 0) {
			setsigdefaults(FALSE);
			redirq = NULL; /* clear preredir queue */
			mvfd(p[0], r->u[1].i);
			if (fd_prev != 1)
				mvfd(fd_prev, fd_out);
			close(p[1]);
			walk(r->u[3].p, FALSE);
			exit(getstatus());
		}
		if (fd_prev != 1)
			close(fd_prev); /* parent must close all pipe fd's */
		pids[i] = pid;
		fd_prev = p[1];
		fd_out = r->u[0].i;
		close(p[0]);
	}
	if ((pid = rc_fork()) == 0) {
		setsigdefaults(FALSE);
		mvfd(fd_prev, fd_out);
		walk(r, FALSE);
		exit(getstatus());
		/* NOTREACHED */
	}
	redirq = NULL; /* clear preredir queue */
	close(fd_prev);
	pids[i++] = pid;

	/* collect statuses */

	intr = FALSE;
	for (j = 0; j < i; j++) {
		rc_wait4(pids[j], &sp, TRUE);
		stats[j] = sp;
		intr |= (sp == SIGINT);
	}
	setpipestatus(stats, i);
	sigchk();
}
Example #5
0
static int readb(void)
{
	register FILE f = standin;
	register int len;

	do {
		if (trapnote & SIGSET) {
			newline();
			sigchk();
		}
	} while ((len = read(f->fdes, f->fbuf, f->fsiz)) < 0 && trapnote);
	return (len);
}
Example #6
0
static void b_wait(char **av) {
	int status;
	pid_t pid;
	if (av[1] == NULL) {
		waitforall();
		return;
	}
	if (av[2] != NULL) {
		arg_count("wait");
		return;
	}
	if ((pid = a2u(av[1])) < 0) {
		badnum(av[1]);
		return;
	}
	if (rc_wait4(pid, &status, FALSE) > 0)
		setstatus(pid, status);
	else
		set(FALSE);
	sigchk();
}
Example #7
0
void
printnam(struct namnod *n)
{
	register unsigned char	*s;

	sigchk();

	if (n->namflg & N_FUNCTN)
	{
		prs_buff(n->namid);
		prs_buff("(){\n");
		prf((struct trenod *)n->namenv);
		prs_buff("\n}\n");
	}
	else if (s = n->namval)
	{
		prs_buff(n->namid);
		prc_buff('=');
		prs_buff(s);
		prc_buff(NL);
	}
}
Example #8
0
File: glob.c Project: muennich/rc3
static List *doglob(char *w, char *m) {
    static char *dir = NULL, *pattern = NULL, *metadir = NULL, *metapattern = NULL;
    static size_t dsize = 0;
    char *d, *p, *md, *mp;
    size_t psize;
    char *s = w;
    List firstdir;
    List *matched;
    if ((psize = strlen(w) + 1) > dsize || dir == NULL) {
        efree(dir);
        efree(pattern);
        efree(metadir);
        efree(metapattern);
        dir = ealloc(psize);
        pattern = ealloc(psize);
        metadir = ealloc(psize);
        metapattern = ealloc(psize);
        dsize = psize;
    }
    d = dir;
    p = pattern;
    md = metadir;
    mp = metapattern;
    while (*s != '/' && *s != '\0') {
        *d++ = *s++; /* get first directory component */
        *md++ = *m++;
    }
    *d = '\0';
    /*
       Special case: no slashes in the pattern, i.e., open the current directory.
       Remember that w cannot consist of slashes alone (the other way *s could be
       zero) since doglob gets called iff there's a metacharacter to be matched
    */
    if (*s == '\0') {
        matched = dmatch(".", dir, metadir);
        goto end;
    }
    if (*w == '/') {
        firstdir.w = dir;
        firstdir.m = metadir;
        firstdir.n = NULL;
        matched = &firstdir;
    } else {
        /*
           we must glob against current directory,
           since the first character is not a slash.
        */
        matched = dmatch(".", dir, metadir);
    }
    do {
        size_t slashcount;
        sigchk();
        for (slashcount = 0; *s == '/'; s++, m++)
            slashcount++; /* skip slashes */
        while (*s != '/' && *s != '\0')
            *p++ = *s++, *mp++ = *m++; /* get pattern */
        *p = '\0';
        matched = lglob(matched, pattern, metapattern, slashcount);
        p = pattern, mp = metapattern;
    } while (*s != '\0');
end:
    if (matched == NULL) {
        matched = nnew(List);
        matched->w = w;
        matched->m = NULL;
        matched->n = NULL;
    }
    return matched;
}
Example #9
0
int
echo(int argc, unsigned char **argv)
{
	unsigned char	*cp;
	int	i, wd;
	int	nflg = 0;
	int	j;
	int	len;
	wchar_t	wc;

	if (ucb_builtins) {

		nflg = 0;
		if (argc > 1 && argv[1][0] == '-' &&
		    argv[1][1] == 'n' && !argv[1][2]) {
			nflg++;
			argc--;
			argv++;
		}

		for (i = 1; i < argc; i++) {
			sigchk();

			for (cp = argv[i]; *cp; cp++) {
				prc_buff(*cp);
			}

			if (i < argc-1)
				prc_buff(' ');
		}

		if (nflg == 0)
			prc_buff('\n');
		exit(0);
	} else {
		if (--argc == 0) {
			prc_buff('\n');
			exit(0);
		}

		for (i = 1; i <= argc; i++) {
			sigchk();
			for (cp = argv[i]; *cp; cp++) {
				if ((len = mbtowc(&wc, (char *)cp,
				    MB_LEN_MAX)) <= 0) {
					prc_buff(*cp);
					continue;
				}

				if (wc == '\\') {
					switch (*++cp) {
					case 'b':
						prc_buff('\b');
						continue;
					case 'c':
						exit(0);

					case 'f':
						prc_buff('\f');
						continue;

					case 'n':
						prc_buff('\n');
						continue;

					case 'r':
						prc_buff('\r');
						continue;

					case 't':
						prc_buff('\t');
						continue;

					case 'v':
						prc_buff('\v');
						continue;

					case '\\':
						prc_buff('\\');
						continue;
					case '0':
						j = wd = 0;
						while ((*++cp >= '0' &&
						    *cp <= '7') && j++ < 3) {
							wd <<= 3;
							wd |= (*cp - '0');
						}
						prc_buff(wd);
						--cp;
						continue;

					default:
						cp--;
					}
					prc_buff(*cp);
					continue;
				} else {
					for (; len > 0; len--)
						prc_buff(*cp++);
					cp--;
					continue;
				}
			}
			prc_buff(i == argc? '\n': ' ');
		}
		exit(0);
	}
}
Example #10
0
static int
readb(struct fileblk *f, int toread, int rest)
{
	int	len;
	int	fflags;

	if (rest) {
		/*
		 * copies the remaining 'rest' bytes from f->fnxt
		 * to f->fbuf
		 */
		memcpy(f->fbuf, f->fnxt, rest);
		f->fnxt = f->fbuf;
		f->fend = f->fnxt + rest;
		f->nxtoff = 0;
		f->endoff = rest;
		if (f->fbuf[rest - 1] == '\n') {
			/*
			 * if '\n' found, it should be
			 * a bondary of multibyte char.
			 */
			return (rest);
		}
	}
		
retry:
	do {
		if (trapnote & SIGSET) {
			newline();
			sigchk();
		} else if ((trapnote & TRAPSET) && (rwait > 0)) {
			newline();
			chktrap();
			clearup();
		}
	} while ((len = read(f->fdes, f->fbuf + rest, toread)) < 0 && trapnote);
	/*
	 * if child sets O_NDELAY or O_NONBLOCK on stdin
	 * and exited then turn the modes off and retry
	 */
	if (len == 0) {
		if (((flags & intflg) ||
		    ((flags & oneflg) == 0 && isatty(input) &&
		    (flags & stdflg))) &&
		    ((fflags = fcntl(f->fdes, F_GETFL, 0)) & O_NDELAY)) {
			fflags &= ~O_NDELAY;
			fcntl(f->fdes, F_SETFL, fflags);
			goto retry;
		}
	} else if (len < 0) {
		if (errno == EAGAIN) {
			fflags = fcntl(f->fdes, F_GETFL, 0);
			fflags &= ~O_NONBLOCK;
			fcntl(f->fdes, F_SETFL, fflags);
			goto retry;
		}
		len = 0;
	}
	f->fnxt = f->fbuf;
	f->fend = f->fnxt + (len + rest);
	f->nxtoff = 0;
	f->endoff = len + rest;
	return (len + rest);
}
Example #11
0
int execute(TREPTR argt, int execflg, int *pf1, int *pf2)
{
	/* `stakbot' is preserved by this routine */
	register TREPTR t;
	STKPTR sav = savstak();

	sigchk();

	if ((t = argt) && execbrk == 0) {
		register int treeflgs;
		int oldexit, type;
		register char **com;

		treeflgs = t->tretyp;
		type = treeflgs & COMMSK;
		oldexit = exitval;
		exitval = 0;

		switch (type) {

		case TCOM:
			{
				STRING a1;
				int argn, internal;
				ARGPTR schain = gchain;
				IOPTR io = t->treio;
				gchain = 0;
				argn = getarg((void *)t);/*FIXME*/
				com = scan(argn);
				a1 = com[1];
				gchain = schain;

				if ((internal = syslook(com[0], commands)) || argn == 0)
					setlist(((COMPTR) t)->comset, 0);

				if (argn && (flags & noexec) == 0) {	/* print command if execpr */
					if (flags & execpr) {
						argn = 0;
						prs(execpmsg);
						while (com[argn] != ENDARGS) {
							prs(com[argn++]);
							blank();
						}
						newline();
					}

					switch (internal) {

					case SYSDOT:
						if (a1) {
							register int f;

							if ((f = pathopen(getpath(a1), a1)) < 0)
								failed(a1, notfound);
							else
								execexp(0, f);
						}
						break;

					case SYSTIMES:
					{
						struct tms t;
						times(&t);
						prt(t.tms_cutime);
						blank();
						prt(t.tms_cstime);
						newline();
					}
					break;

					case SYSEXIT:
						exitsh(a1 ? stoi(a1) : oldexit);

					case SYSNULL:
						io = 0;
						break;

					case SYSCONT:
						execbrk = -loopcnt;
						break;

					case SYSBREAK:
						if ((execbrk = loopcnt) && a1)
							breakcnt = stoi(a1);
						break;

					case SYSTRAP:
						if (a1) {
							BOOL clear;
							if ((clear = digit(*a1)) == 0)
								++com;
							while (*++com) {
								int i;
								if ((i = stoi(*com)) >= MAXTRAP || i < MINTRAP)
									failed(*com, badtrap);
								else if (clear)
									clrsig(i);
								else {
									replace(&trapcom[i], a1);
									if (*a1)
										getsig(i);
									else
										ignsig(i);
								}
							}
						} else {	/* print out current traps */
							int i;

							for (i = 0; i < MAXTRAP; i++) {
								if (trapcom[i]) {
									prn(i);
									prs(colon);
									prs(trapcom[i]);
									newline();
								}
							}
						}
						break;

					case SYSEXEC:
						com++;
						initio(io);
						ioset = 0;
						io = 0;
						if (a1 == 0)
							break;

					case SYSLOGIN:
						flags |= forked;
						oldsigs();
						execa((const char **)com);
						done();

					case SYSCD:
						if (flags & rshflg)
							failed(com[0], restricted);
						else if ((a1 == 0 && (a1 = (char *)homenod.namval) == 0) || chdir(a1) < 0) /* FIXME */
							failed(a1, baddir);
						break;

					case SYSSHFT:
						if (dolc < 1)
							error(badshift);
						else {
							dolv++;
							dolc--;
						}
						assnum(&dolladr, dolc);
						break;

					case SYSWAIT:
						await(-1);
						break;

					case SYSREAD:
						exitval = readvar(&com[1]);
						break;

/*
				case SYSTST:
					exitval=testcmd(com);
					break;
*/

					case SYSSET:
						if (a1) {
							int argc;
							argc = options(argn, (const char **)com);
							if (argc > 1)
								setargs((const char **)com + argn - argc);
						} else if (((COMPTR) t)->comset == 0)
						        /* Scan name chain and print */
							namscan(printnam);
						break;

					case SYSRDONLY:
						exitval = N_RDONLY;
					case SYSXPORT:
						if (exitval == 0)
							exitval = N_EXPORT;;

						if (a1) {
							while (*++com)
								attrib(lookup(*com), exitval);
						} else {
							namscan(printflg);
						}
						exitval = 0;
						break;

					case SYSEVAL:
						if (a1)
							execexp(a1, (UFD)&com[2]);	/* FIXME */
						break;

					case SYSUMASK:
						if (a1) {
							int c, i;
							i = 0;
							while ((c = *a1++) >= '0' && c <= '7')
								i = (i << 3) + c - '0';
							umask(i);
						} else {
							int i, j;
							umask(i = umask(0));
							prc('0');
							for (j = 6; j >= 0; j -= 3)
								prc(((i >> j) & 07) + '0');
							newline();
						}
						break;

					default:
						internal = builtin(argn, com);

					}

					if (internal) {
						if (io)
							error(illegal);
						chktrap();
						break;
					}
				} else if (t->treio == 0)
					break;
			}

		case TFORK:
			if (execflg && (treeflgs & (FAMP | FPOU)) == 0)
				parent = 0;
			else {
				while ((parent = fork()) == -1) {
					sigchk();
					alarm(10);
					pause();
				}
			}

			if (parent) {	/* This is the parent branch of fork;    */
				/* it may or may not wait for the child. */
				if (treeflgs & FPRS && flags & ttyflg) {
					prn(parent);
					newline();
				}
				if (treeflgs & FPCL)
					closepipe(pf1);
				if ((treeflgs & (FAMP | FPOU)) == 0)
					await(parent);
				else if ((treeflgs & FAMP) == 0)
					post(parent);
				else
					assnum(&pcsadr, parent);

				chktrap();
				break;
			} else {	/* this is the forked branch (child) of execute */
				flags |= forked;
				iotemp = 0;
				postclr();
				settmp();

				/* Turn off INTR and QUIT if `FINT'  */
				/* Reset ramaining signals to parent */
				/* except for those `lost' by trap   */
				oldsigs();
				if (treeflgs & FINT) {
					signal(INTR, SIG_IGN);
					signal(QUIT, SIG_IGN);
				}

				/* pipe in or out */
				if (treeflgs & FPIN) {
					sh_rename(pf1[INPIPE], 0);
					close(pf1[OTPIPE]);
				}
				if (treeflgs & FPOU) {
					sh_rename(pf2[OTPIPE], 1);
					close(pf2[INPIPE]);
				}

				/* default std input for & */
				if (treeflgs & FINT && ioset == 0)
					sh_rename(chkopen(devnull), 0);

				/* io redirection */
				initio(t->treio);
				if (type != TCOM)
					execute(((FORKPTR) t)->forktre, 1, NULL, NULL);
				else if (com[0] != ENDARGS) {
					setlist(((COMPTR) t)->comset, N_EXPORT);
					execa((const char **)com);
				}
				done();
			}

		case TPAR:
			sh_rename(dup(2), output);
			execute(((PARPTR) t)->partre, execflg, NULL, NULL);
			done();

		case TFIL:
		{
			int pv[2];
			chkpipe(pv);
			if (execute(((LSTPTR) t)->lstlef, 0, pf1, pv) == 0)
				execute(((LSTPTR) t)->lstrit, execflg, pv, pf2);
			else
				closepipe(pv);
			break;
                }
		case TLST:
			execute(((LSTPTR) t)->lstlef, 0, NULL, NULL);
			execute(((LSTPTR) t)->lstrit, execflg, NULL, NULL);
			break;

		case TAND:
			if (execute(((LSTPTR) t)->lstlef, 0, NULL, NULL) == 0)
				execute(((LSTPTR) t)->lstrit, execflg, NULL, NULL);
			break;

		case TORF:
			if (execute(((LSTPTR) t)->lstlef, 0, NULL, NULL) != 0)
				execute(((LSTPTR) t)->lstrit, execflg, NULL, NULL);
			break;

		case TFOR:
		{
			NAMPTR n = lookup(((FORPTR) t)->fornam);
			char **args;
			DOLPTR argsav = 0;

			if (((FORPTR) t)->forlst == 0) {
				args = (char **)dolv + 1;
				argsav = useargs();
			} else {
				ARGPTR schain = gchain;
				gchain = 0;
				trim((args = scan(getarg(((FORPTR) t)->forlst)))[0]);
				gchain = schain;
			}
			loopcnt++;
			while (*args != ENDARGS && execbrk == 0) {
				assign(n, *args++);
				execute(((FORPTR) t)->fortre, 0, NULL, NULL);
				if (execbrk < 0) {
					execbrk = 0;
				}
			}
			if (breakcnt)
				breakcnt--;
			execbrk = breakcnt;
			loopcnt--;
			argfor = freeargs(argsav);
        		break;
		}

		case TWH:
		case TUN:
		{
			int i = 0;

			loopcnt++;
			while (execbrk == 0 && (execute(((WHPTR) t)->whtre, 0, NULL, NULL) == 0) == (type == TWH)) {
				i = execute(((WHPTR) t)->dotre, 0, NULL, NULL);
				if (execbrk < 0)
					execbrk = 0;
			}
			if (breakcnt)
				breakcnt--;

			execbrk = breakcnt;
			loopcnt--;
			exitval = i;
			break;
		}

		case TIF:
			if (execute(((IFPTR) t)->iftre, 0, NULL, NULL) == 0)
				execute(((IFPTR) t)->thtre, execflg, NULL, NULL);
			else
				execute(((IFPTR) t)->eltre, execflg, NULL, NULL);
			break;

		case TSW:
		{
			register char *r = mactrim(((SWPTR) t)->swarg);
			t = (TREPTR) ((SWPTR) t)->swlst;
			while (t) {
				ARGPTR rex = ((REGPTR) t)->regptr;
				while (rex) {
					register char *s;
					if (gmatch(r, s = macro(rex->argval)) || (trim(s), eq(r, s))) {
						execute(((REGPTR)t)->regcom, 0, NULL, NULL);
						t = 0;
						break;
					} else
						rex = ((ARGPTR)rex)->argnxt;
				}
				if (t)
					t = (TREPTR) ((REGPTR) t)->regnxt;
			}
		}
		break;

		}
		exitset();
	}
Example #12
0
void
prf(struct trenod *t)
{
	sigchk();

	if (t)
	{
		int	type;

		type = t->tretyp & COMMSK;

		switch(type)
		{
			case TFND:
			{
				struct fndnod *f = (struct fndnod *)t;

				prs_buff(f->fndnam);
				prs_buff("(){");
				prbgnlst();
				prf(f->fndval);
				prbgnlst();
				prs_buff("}");
				break;
			}

			case TCOM:
				if (comptr(t)->comset) {
					prarg(comptr(t)->comset);
					prc_buff(SPACE);
				}
				prarg(comptr(t)->comarg);
				prio(comptr(t)->comio);
				break;

			case TFORK:
				prf(forkptr(t)->forktre);
				prio(forkptr(t)->forkio);
				if (forkptr(t)->forktyp & FAMP)
					prs_buff(" &");
				break;

			case TPAR:
				prs_buff("(");
				prf(parptr(t)->partre);
				prs_buff(")");
				break;

			case TFIL:
				prf(lstptr(t)->lstlef);
				prs_buff(" | ");
				prf(lstptr(t)->lstrit);
				break;

			case TLST:
				prf(lstptr(t)->lstlef);
				prendlst();
				prf(lstptr(t)->lstrit);
				break;

			case TAND:
				prf(lstptr(t)->lstlef);
				prs_buff(" && ");
				prf(lstptr(t)->lstrit);
				break;

			case TORF:
				prf(lstptr(t)->lstlef);
				prs_buff(" || ");
				prf(lstptr(t)->lstrit);
				break;

			case TFOR:
				{
					struct argnod	*arg;
					struct fornod 	*f = (struct fornod *)t;

					prs_buff("for ");
					prs_buff(f->fornam);

					if (f->forlst)
					{
						arg = f->forlst->comarg;
						prs_buff(" in");

						while(arg != ENDARGS)
						{
							prc_buff(SPACE);
							prs_buff(arg->argval);
							arg = arg->argnxt;
						}
					}

					prendlst();
					prs_buff("do");
					prbgnlst();
					prf(f->fortre);
					prendlst();
					prs_buff("done");
				}
				break;

			case TWH:
			case TUN:
				if (type == TWH)
					prs_buff("while ");
				else
					prs_buff("until ");
				prf(whptr(t)->whtre);
				prendlst();
				prs_buff("do");
				prbgnlst();
				prf(whptr(t)->dotre);
				prendlst();
				prs_buff("done");
				break;

			case TIF:
			{
				struct ifnod *f = (struct ifnod *)t;

				prs_buff("if ");
				prf(f->iftre);
				prendlst();
				prs_buff("then");
				prendlst();
				prf(f->thtre);

				if (f->eltre)
				{
					prendlst();
					prs_buff("else");
					prendlst();
					prf(f->eltre);
				}

				prendlst();
				prs_buff("fi");
				break;
			}

			case TSW:
				{
					struct regnod 	*swl;

					prs_buff("case ");
					prs_buff(swptr(t)->swarg);

					swl = swptr(t)->swlst;
					while(swl)
					{
						struct argnod	*arg = swl->regptr;

						if (arg)
						{
							prs_buff(arg->argval);
							arg = arg->argnxt;
						}

						while(arg)
						{
							prs_buff(" | ");
							prs_buff(arg->argval);
							arg = arg->argnxt;
						}

						prs_buff(")");
						prf(swl->regcom);
						prs_buff(";;");
						swl = swl->regnxt;
					}
				}
				break;
			} 
		} 

	sigchk();
}
Example #13
0
extern bool walk(Node *n, bool parent) {
top:	sigchk();
	if (n == NULL) {
		if (!parent)
			exit(0);
		set(TRUE);
		return TRUE;
	}
	switch (n->type) {
	case nArgs: case nBackq: case nConcat: case nCount:
	case nFlat: case nLappend: case nRedir: case nVar:
	case nVarsub: case nWord:
		exec(glob(glom(n)), parent);	/* simple command */
		break;
	case nBody:
		walk(n->u[0].p, TRUE);
		WALK(n->u[1].p, parent);
		/* WALK doesn't fall through */
	case nNowait: {
		int pid;
		if ((pid = rc_fork()) == 0) {
#if defined(RC_JOB) && defined(SIGTTOU) && defined(SIGTTIN) && defined(SIGTSTP)
			setsigdefaults(FALSE);
			rc_signal(SIGTTOU, SIG_IGN);	/* Berkeleyized version: put it in a new pgroup. */
			rc_signal(SIGTTIN, SIG_IGN);
			rc_signal(SIGTSTP, SIG_IGN);
			setpgid(0, getpid());
#else
			setsigdefaults(TRUE);		/* ignore SIGINT, SIGQUIT, SIGTERM */
#endif
			mvfd(rc_open("/dev/null", rFrom), 0);
			walk(n->u[0].p, FALSE);
			exit(getstatus());
		}
		if (interactive)
			fprint(2, "%d\n", pid);
		varassign("apid", word(nprint("%d", pid), NULL), FALSE);
		redirq = NULL; /* kill pre-redir queue */
		break;
	}
	case nAndalso: {
		bool oldcond = cond;
		cond = TRUE;
		if (walk(n->u[0].p, TRUE)) {
			cond = oldcond;
			WALK(n->u[1].p, parent);
		} else
			cond = oldcond;
		break;
	}
	case nOrelse: {
		bool oldcond = cond;
		cond = TRUE;
		if (!walk(n->u[0].p, TRUE)) {
			cond = oldcond;
			WALK(n->u[1].p, parent);
		} else
			cond = oldcond;
		break;
	}
	case nBang:
		set(!walk(n->u[0].p, TRUE));
		break;
	case nIf: {
		bool oldcond = cond;
		Node *true_cmd = n->u[1].p, *false_cmd = NULL;
		if (true_cmd != NULL && true_cmd->type == nElse) {
			false_cmd = true_cmd->u[1].p;
			true_cmd = true_cmd->u[0].p;
		}
		cond = TRUE;
		if (!walk(n->u[0].p, TRUE))
			true_cmd = false_cmd; /* run the else clause */
		cond = oldcond;
		WALK(true_cmd, parent);
	}
	case nWhile: {
		Jbwrap j;
		Edata jbreak;
		Estack e1, e2;
		bool testtrue, oldcond = cond;
		cond = TRUE;
		if (!walk(n->u[0].p, TRUE)) { /* prevent spurious breaks inside test */
			cond = oldcond;
			break;
		}
		if (sigsetjmp(j.j, 1))
			break;
		jbreak.jb = &j;
		except(eBreak, jbreak, &e1);
		do {
			Edata block;
			block.b = newblock();
			cond = oldcond;
			except(eArena, block, &e2);
			walk(n->u[1].p, TRUE);
			testtrue = walk(n->u[0].p, TRUE);
			unexcept(); /* eArena */
			cond = TRUE;
		} while (testtrue);
		cond = oldcond;
		unexcept(); /* eBreak */
		break;
	}
	case nForin: {
		List *l, *var = glom(n->u[0].p);
		Jbwrap j;
		Estack e1, e2;
		Edata jbreak;
		if (sigsetjmp(j.j, 1))
			break;
		jbreak.jb = &j;
		except(eBreak, jbreak, &e1);
		for (l = listcpy(glob(glom(n->u[1].p)), nalloc); l != NULL; l = l->n) {
			Edata block;
			assign(var, word(l->w, NULL), FALSE);
			block.b = newblock();
			except(eArena, block, &e2);
			walk(n->u[2].p, TRUE);
			unexcept(); /* eArena */
		}
		unexcept(); /* eBreak */
		break;
	}
	case nSubshell:
		if (dofork(TRUE)) {
			setsigdefaults(FALSE);
			walk(n->u[0].p, FALSE);
			rc_exit(getstatus());
		}
		break;
	case nAssign:
		if (n->u[0].p == NULL)
			rc_error("null variable name");
		assign(glom(n->u[0].p), glob(glom(n->u[1].p)), FALSE);
		set(TRUE);
		break;
	case nPipe:
		dopipe(n);
		break;
	case nNewfn: {
		List *l = glom(n->u[0].p);
		if (l == NULL)
			rc_error("null function name");
		while (l != NULL) {
			if (dashex)
				prettyprint_fn(2, l->w, n->u[1].p);
			fnassign(l->w, n->u[1].p);
			l = l->n;
		}
		set(TRUE);
		break;
	}
	case nRmfn: {
		List *l = glom(n->u[0].p);
		while (l != NULL) {
			if (dashex)
				fprint(2, "fn %S\n", l->w);
			fnrm(l->w);
			l = l->n;
		}
		set(TRUE);
		break;
	}
	case nDup:
		redirq = NULL;
		break; /* Null command */
	case nMatch: {
		List *a = glob(glom(n->u[0].p)), *b = glom(n->u[1].p);
		if (dashex)
			fprint(2, (a != NULL && a->n != NULL) ? "~ (%L) %L\n" : "~ %L %L\n", a, " ", b, " ");
		set(lmatch(a, b));
		break;
	}
	case nSwitch: {
		List *v = glom(n->u[0].p);
		while (1) {
			do {
				n = n->u[1].p;
				if (n == NULL)
					return istrue();
			} while (n->u[0].p == NULL || n->u[0].p->type != nCase);
			if (lmatch(v, glom(n->u[0].p->u[0].p))) {
				for (n = n->u[1].p; n != NULL && (n->u[0].p == NULL || n->u[0].p->type != nCase); n = n->u[1].p)
					walk(n->u[0].p, TRUE);
				break;
			}
		}
		break;
	}
	case nPre: {
		List *v;
		if (n->u[0].p->type == nRedir || n->u[0].p->type == nDup) {
			if (redirq == NULL && !dofork(parent)) /* subshell on first preredir */
				break;
			setsigdefaults(FALSE);
			qredir(n->u[0].p);
			if (!haspreredir(n->u[1].p))
				doredirs(); /* no more preredirs, empty queue */
			walk(n->u[1].p, FALSE);
			rc_exit(getstatus());
			/* NOTREACHED */
		} else if (n->u[0].p->type == nAssign) {
			if (isallpre(n->u[1].p)) {
				walk(n->u[0].p, TRUE);
				WALK(n->u[1].p, parent);
			} else {
				Estack e;
				Edata var;
				v = glom(n->u[0].p->u[0].p);
				assign(v, glob(glom(n->u[0].p->u[1].p)), TRUE);
				var.name = v->w;
				except(eVarstack, var, &e);
				walk(n->u[1].p, parent);
				varrm(v->w, TRUE);
				unexcept(); /* eVarstack */
			}
		} else
			panic("unexpected node in preredir section of walk");
		break;
	}
	case nBrace:
		if (n->u[1].p == NULL) {
			WALK(n->u[0].p, parent);
		} else if (dofork(parent)) {
			setsigdefaults(FALSE);
			walk(n->u[1].p, TRUE); /* Do redirections */
			redirq = NULL;   /* Reset redirection queue */
			walk(n->u[0].p, FALSE); /* Do commands */
			rc_exit(getstatus());
			/* NOTREACHED */
		}
		break;
	case nEpilog:
		qredir(n->u[0].p);
		if (n->u[1].p != NULL) {
			WALK(n->u[1].p, parent); /* Do more redirections. */
		} else {
			doredirs();	/* Okay, we hit the bottom. */
		}
		break;
	case nNmpipe:
		rc_error("named pipes cannot be executed as commands");
		/* NOTREACHED */
	default:
		panic("unknown node in walk");
		/* NOTREACHED */
	}
	return istrue();
}