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(); }
static List *mkcmdarg(Node *n) { int fd; char *name; Edata efifo; Estack *e = enew(Estack); List *ret = nnew(List); static int fifonumber = 0; name = nprint("/tmp/rc%d.%d", getpid(), fifonumber++); if (mkfifo(name, 0666) < 0) { uerror("mkfifo"); return NULL; } if (rc_fork() == 0) { setsigdefaults(FALSE); fd = rc_open(name, (n->u[0].i != rFrom) ? rFrom : rCreate); /* stupid hack */ if (fd < 0) { uerror("open"); exit(1); } if (mvfd(fd, (n->u[0].i == rFrom)) < 0) /* same stupid hack */ exit(1); redirq = NULL; walk(n->u[2].p, FALSE); exit(getstatus()); } efifo.name = name; except(eFifo, efifo, e); ret->w = name; ret->m = NULL; ret->n = NULL; return ret; }
static List *mkcmdarg(Node *n) { char *name; List *ret = nnew(List); Estack *e = nnew(Estack); Edata efd; int p[2]; if (pipe(p) < 0) { uerror("pipe"); return NULL; } if (rc_fork() == 0) { setsigdefaults(FALSE); if (mvfd(p[n->u[0].i == rFrom], n->u[0].i == rFrom) < 0) /* stupid hack */ exit(1); close(p[n->u[0].i != rFrom]); redirq = NULL; walk(n->u[2].p, FALSE); exit(getstatus()); } #if HAVE_DEV_FD name = nprint("/dev/fd/%d", p[n->u[0].i != rFrom]); #else name = nprint("/proc/self/fd/%d", p[n->u[0].i != rFrom]); #endif efd.fd = p[n->u[0].i != rFrom]; except(eFd, efd, e); close(p[n->u[0].i == rFrom]); ret->w = name; ret->m = NULL; ret->n = NULL; return ret; }
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; }
extern void doredirs() { List *fname; int fd, p[2]; Rq *r; for (r = redirq; r != NULL; r = r->n) { switch(r->r->type) { default: panic("unexpected node in doredirs"); /* NOTREACHED */ case nRedir: if (r->r->u[0].i == rHerestring) { fname = flatten(glom(r->r->u[2].p)); /* fname is really a string */ if (pipe(p) < 0) { uerror("pipe"); rc_error(NULL); } if (rc_fork() == 0) { /* child writes to pipe */ setsigdefaults(FALSE); close(p[0]); if (fname != NULL) writeall(p[1], fname->w, strlen(fname->w)); exit(0); } else { close(p[1]); if (mvfd(p[0], r->r->u[1].i) < 0) rc_error(NULL); } } else { fname = glob(glom(r->r->u[2].p)); if (fname == NULL) rc_error("null filename in redirection"); if (fname->n != NULL) rc_error("multi-word filename in redirection"); switch (r->r->u[0].i) { default: panic("unexpected node in doredirs"); /* NOTREACHED */ case rCreate: case rAppend: case rFrom: fd = rc_open(fname->w, r->r->u[0].i); break; } if (fd < 0) { uerror(fname->w); rc_error(NULL); } if (mvfd(fd, r->r->u[1].i) < 0) rc_error(NULL); } break; case nDup: if (r->r->u[2].i == -1) close(r->r->u[1].i); else if (r->r->u[2].i != r->r->u[1].i) { if (dup2(r->r->u[2].i, r->r->u[1].i) < 0) { uerror("dup2"); rc_error(NULL); } } } } redirq = NULL; }
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(); }