STATIC void evalpipe(union node *n) { struct job *jp; struct nodelist *lp; int pipelen; int prevfd; int pip[2]; TRACE(("evalpipe(0x%lx) called\n", (long)n)); pipelen = 0; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) pipelen++; INTOFF; jp = makejob(n, pipelen); prevfd = -1; for (lp = n->npipe.cmdlist ; lp ; lp = lp->next) { prehash(lp->n); pip[1] = -1; if (lp->next) { if (sh_pipe(pip) < 0) { if (prevfd >= 0) close(prevfd); error("Pipe call failed"); } } if (forkshell(jp, lp->n, n->npipe.backgnd ? FORK_BG : FORK_FG) == 0) { INTON; if (prevfd > 0) { close(0); copyfd(prevfd, 0, 1, 0); close(prevfd); } if (pip[1] >= 0) { close(pip[0]); if (pip[1] != 1) { close(1); copyfd(pip[1], 1, 1, 0); close(pip[1]); } } evaltree(lp->n, EV_EXIT); } if (prevfd >= 0) close(prevfd); prevfd = pip[0]; close(pip[1]); } if (n->npipe.backgnd == 0) { exitstatus = waitforjob(jp); TRACE(("evalpipe: job done exit status %d\n", exitstatus)); } else exitstatus = 0; INTON; }
static void runbenchn(Benchmark *b, int n) { int outfd = tmpfd(); int durfd = tmpfd(); strcpy(b->dir, TmpDirPat); mktemp(b->dir); int pid = fork(); if (pid < 0) { die(1, errno, "fork"); } else if (!pid) { setpgid(0, 0); if (dup2(outfd, 1) == -1) { die(3, errno, "dup2"); } if (close(outfd) == -1) { die(3, errno, "fclose"); } if (dup2(1, 2) == -1) { die(3, errno, "dup2"); } curdir = b->dir; ctstarttimer(); b->f(n); ctstoptimer(); write(durfd, &bdur, sizeof bdur); write(durfd, &bbytes, sizeof bbytes); _exit(0); } setpgid(pid, pid); pid = waitpid(pid, &b->status, 0); if (pid == -1) { die(3, errno, "wait"); } killpg(pid, 9); rmtree(b->dir); if (b->status != 0) { putchar('\n'); lseek(outfd, 0, SEEK_SET); copyfd(stdout, outfd); return; } lseek(durfd, 0, SEEK_SET); int r = read(durfd, &b->dur, sizeof b->dur); if (r != sizeof b->dur) { perror("read"); b->status = 1; } r = read(durfd, &b->bytes, sizeof b->bytes); if (r != sizeof b->bytes) { perror("read"); b->status = 1; } }
void evalbackcmd(union node *n, struct backcmd *result) { int pip[2]; struct job *jp; struct stackmark smark; /* unnecessary */ setstackmark(&smark); result->fd = -1; result->buf = NULL; result->nleft = 0; result->jp = NULL; if (nflag || n == NULL) { goto out; } #ifdef notyet /* * For now we disable executing builtins in the same * context as the shell, because we are not keeping * enough state to recover from changes that are * supposed only to affect subshells. eg. echo "`cd /`" */ if (n->type == NCMD) { exitstatus = oexitstatus; evalcommand(n, EV_BACKCMD, result); } else #endif { INTOFF; if (sh_pipe(pip) < 0) error("Pipe call failed"); jp = makejob(n, 1); if (forkshell(jp, n, FORK_NOJOB) == 0) { FORCEINTON; close(pip[0]); if (pip[1] != 1) { close(1); copyfd(pip[1], 1, 1, 0); close(pip[1]); } eflag = 0; evaltree(n, EV_EXIT); /* NOTREACHED */ } close(pip[1]); result->fd = pip[0]; result->jp = jp; INTON; } out: popstackmark(&smark); TRACE(("evalbackcmd done: fd=%d buf=0x%x nleft=%d jp=0x%x\n", result->fd, result->buf, result->nleft, result->jp)); }
/* * rename fd from to be fd to (closing from). * close-on-exec is never set on 'to' (unless * from==to and it was set on from) - ie: a no-op * returns to (or errors() if an error occurs). * * This is mostly used for rearranging the * results from pipe(). */ int movefd(int from, int to) { if (from == to) return to; (void) close(to); if (copyfd(from, to, 0) != to) { int e = errno; (void) close(from); error("Unable to make fd %d: %s", to, strerror(e)); } (void) close(from); return to; }
static int report(Test *t) { int nfail = 0, nerr = 0; putchar('\n'); for (; t->f; t++) { rmtree(t->dir); if (!t->status) { continue; } printf("\n%s: ", t->name); if (failed(t->status)) { nfail++; printf("failure"); } else { nerr++; printf("error"); if (WIFEXITED(t->status)) { printf(" (exit status %d)", WEXITSTATUS(t->status)); } if (WIFSIGNALED(t->status)) { printf(" (signal %d)", WTERMSIG(t->status)); } } putchar('\n'); lseek(t->fd, 0, SEEK_SET); copyfd(stdout, t->fd); } if (nfail || nerr) { printf("\n%d failures; %d errors.\n", nfail, nerr); } else { printf("\nPASS\n"); } return nfail || nerr; }
void popredir(void) { struct redirtab *rp = redirlist; int i; for (i = 0 ; i < 10 ; i++) { if (rp->renamed[i] != EMPTY) { if (i == 0) fd0_redirected--; close(i); if (rp->renamed[i] >= 0) { copyfd(rp->renamed[i], i, 1); close(rp->renamed[i]); } } } INTOFF; redirlist = rp->next; ckfree(rp); INTON; }
extern void print_file(FILE *file) { fflush(stdout); copyfd(fileno(file), fileno(stdout)); fclose(file); }
STATIC void openredirect(union node *redir, char memory[10], int flags) { struct stat sb; int fd = redir->nfile.fd; char *fname; int f; int eflags, cloexec; /* * We suppress interrupts so that we won't leave open file * descriptors around. This may not be such a good idea because * an open of a device or a fifo can block indefinitely. */ INTOFF; if (fd < 10) memory[fd] = 0; switch (redir->nfile.type) { case NFROM: fname = redir->nfile.expfname; if (flags & REDIR_VFORK) eflags = O_NONBLOCK; else eflags = 0; if ((f = open(fname, O_RDONLY|eflags)) < 0) goto eopen; if (eflags) (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags); break; case NFROMTO: fname = redir->nfile.expfname; if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) goto ecreate; break; case NTO: if (Cflag) { fname = redir->nfile.expfname; if ((f = open(fname, O_WRONLY)) == -1) { if ((f = open(fname, O_WRONLY|O_CREAT|O_EXCL, 0666)) < 0) goto ecreate; } else if (fstat(f, &sb) == -1) { int serrno = errno; close(f); errno = serrno; goto ecreate; } else if (S_ISREG(sb.st_mode)) { close(f); errno = EEXIST; goto ecreate; } break; } /* FALLTHROUGH */ case NCLOBBER: fname = redir->nfile.expfname; if ((f = open(fname, O_WRONLY|O_CREAT|O_TRUNC, 0666)) < 0) goto ecreate; break; case NAPPEND: fname = redir->nfile.expfname; if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) goto ecreate; break; case NTOFD: case NFROMFD: if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ if (fd < 10 && redir->ndup.dupfd < 10 && memory[redir->ndup.dupfd]) memory[fd] = 1; else if (copyfd(redir->ndup.dupfd, fd, (flags & REDIR_KEEP) == 0) < 0) error("Redirect (from %d to %d) failed: %s", redir->ndup.dupfd, fd, strerror(errno)); } else (void) close(fd); INTON; return; case NHERE: case NXHERE: f = openhere(redir); break; default: abort(); } cloexec = fd > 2 && (flags & REDIR_KEEP) == 0; if (f != fd) { if (copyfd(f, fd, cloexec) < 0) { int e = errno; close(f); error("redirect reassignment (fd %d) failed: %s", fd, strerror(e)); } close(f); } else if (cloexec) (void)fcntl(f, F_SETFD, FD_CLOEXEC); INTON; return; ecreate: exerrno = 1; error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); eopen: exerrno = 1; error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); }
/* * Process I/O control requests. */ static int vnd_ioctl(devminor_t UNUSED(minor), unsigned long request, endpoint_t endpt, cp_grant_id_t grant, endpoint_t user_endpt) { struct vnd_ioctl vnd; struct vnd_user vnu; struct stat st; int r; switch (request) { case VNDIOCSET: /* * The VND must not be busy. Note that the caller has the * device open to perform the IOCTL request. */ if (state.fd != -1 || state.openct != 1) return EBUSY; if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &vnd, sizeof(vnd))) != OK) return r; /* * Issue a special VFS backcall that copies a file descriptor * to the current process, from the user process ultimately * making the IOCTL call. The result is either a newly * allocated file descriptor or an error. */ if ((r = copyfd(user_endpt, vnd.vnd_fildes, COPYFD_FROM)) < 0) return r; state.fd = r; /* The target file must be regular. */ if (fstat(state.fd, &st) == -1) { printf("VND%u: fstat failed (%d)\n", instance, -errno); r = -errno; } if (r == OK && !S_ISREG(st.st_mode)) r = EINVAL; /* * Allocate memory for an intermediate I/O transfer buffer. In * order to save on memory in the common case, the buffer is * only allocated when the vnd is in use. We use mmap instead * of malloc to allow the memory to be actually freed later. */ if (r == OK) { state.buf = mmap(NULL, VND_BUF_SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0); if (state.buf == MAP_FAILED) r = ENOMEM; } if (r != OK) { close(state.fd); state.fd = -1; return r; } /* Set various device state fields. */ state.dev = st.st_dev; state.ino = st.st_ino; state.rdonly = !!(vnd.vnd_flags & VNDIOF_READONLY); r = vnd_layout(st.st_size, &vnd); /* Upon success, return the device size to userland. */ if (r == OK) { vnd.vnd_size = state.geom.size; r = sys_safecopyto(endpt, grant, 0, (vir_bytes) &vnd, sizeof(vnd)); } if (r != OK) { munmap(state.buf, VND_BUF_SIZE); close(state.fd); state.fd = -1; } return r; case VNDIOCCLR: /* The VND can only be cleared if it has been configured. */ if (state.fd == -1) return ENXIO; if ((r = sys_safecopyfrom(endpt, grant, 0, (vir_bytes) &vnd, sizeof(vnd))) != OK) return r; /* The caller has the device open to do the IOCTL request. */ if (!(vnd.vnd_flags & VNDIOF_FORCE) && state.openct != 1) return EBUSY; /* * Close the associated file descriptor immediately, but do not * allow reuse until the device has been closed by the other * users. */ munmap(state.buf, VND_BUF_SIZE); close(state.fd); state.fd = -1; return OK; case VNDIOCGET: /* * We need not copy in the given structure. It would contain * the requested unit number, but each driver instance provides * only one unit anyway. */ memset(&vnu, 0, sizeof(vnu)); vnu.vnu_unit = instance; /* Leave these fields zeroed if the device is not in use. */ if (state.fd != -1) { vnu.vnu_dev = state.dev; vnu.vnu_ino = state.ino; } return sys_safecopyto(endpt, grant, 0, (vir_bytes) &vnu, sizeof(vnu)); case DIOCOPENCT: return sys_safecopyto(endpt, grant, 0, (vir_bytes) &state.openct, sizeof(state.openct)); case DIOCFLUSH: if (state.fd == -1) return ENXIO; fsync(state.fd); return OK; } return ENOTTY; }
STATIC void evalcommand(union node *cmd, int flgs, struct backcmd *backcmd) { struct stackmark smark; union node *argp; struct arglist arglist; struct arglist varlist; volatile int flags = flgs; char ** volatile argv; volatile int argc; char **envp; int varflag; struct strlist *sp; volatile int mode; int pip[2]; struct cmdentry cmdentry; struct job * volatile jp; struct jmploc jmploc; struct jmploc *volatile savehandler = NULL; const char *volatile savecmdname; volatile struct shparam saveparam; struct localvar *volatile savelocalvars; volatile int e; char * volatile lastarg; const char * volatile path = pathval(); volatile int temp_path; vforked = 0; /* First expand the arguments. */ TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); setstackmark(&smark); back_exitstatus = 0; arglist.lastp = &arglist.list; varflag = 1; /* Expand arguments, ignoring the initial 'name=value' ones */ for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { char *p = argp->narg.text; if (varflag && is_name(*p)) { do { p++; } while (is_in_name(*p)); if (*p == '=') continue; } expandarg(argp, &arglist, EXP_FULL | EXP_TILDE); varflag = 0; } *arglist.lastp = NULL; expredir(cmd->ncmd.redirect); /* Now do the initial 'name=value' ones we skipped above */ varlist.lastp = &varlist.list; for (argp = cmd->ncmd.args ; argp ; argp = argp->narg.next) { char *p = argp->narg.text; if (!is_name(*p)) break; do p++; while (is_in_name(*p)); if (*p != '=') break; expandarg(argp, &varlist, EXP_VARTILDE); } *varlist.lastp = NULL; argc = 0; for (sp = arglist.list ; sp ; sp = sp->next) argc++; argv = stalloc(sizeof (char *) * (argc + 1)); for (sp = arglist.list ; sp ; sp = sp->next) { TRACE(("evalcommand arg: %s\n", sp->text)); *argv++ = sp->text; } *argv = NULL; lastarg = NULL; if (iflag && funcnest == 0 && argc > 0) lastarg = argv[-1]; argv -= argc; /* Print the command if xflag is set. */ if (xflag) { char sep = 0; out2str(ps4val()); for (sp = varlist.list ; sp ; sp = sp->next) { char *p; if (sep != 0) outc(sep, &errout); /* * The "var=" part should not be quoted, regardless * of the value, or it would not represent an * assignment, but rather a command */ p = strchr(sp->text, '='); if (p != NULL) { *p = '\0'; /*XXX*/ out2shstr(sp->text); out2c('='); *p++ = '='; /*XXX*/ } else p = sp->text; out2shstr(p); sep = ' '; } for (sp = arglist.list ; sp ; sp = sp->next) { if (sep != 0) outc(sep, &errout); out2shstr(sp->text); sep = ' '; } outc('\n', &errout); flushout(&errout); } /* Now locate the command. */ if (argc == 0) { cmdentry.cmdtype = CMDSPLBLTIN; cmdentry.u.bltin = bltincmd; } else { static const char PATH[] = "PATH="; int cmd_flags = DO_ERR; /* * Modify the command lookup path, if a PATH= assignment * is present */ for (sp = varlist.list; sp; sp = sp->next) if (strncmp(sp->text, PATH, sizeof(PATH) - 1) == 0) path = sp->text + sizeof(PATH) - 1; do { int argsused, use_syspath; find_command(argv[0], &cmdentry, cmd_flags, path); if (cmdentry.cmdtype == CMDUNKNOWN) { exitstatus = 127; flushout(&errout); goto out; } /* implement the 'command' builtin here */ if (cmdentry.cmdtype != CMDBUILTIN || cmdentry.u.bltin != bltincmd) break; cmd_flags |= DO_NOFUNC; argsused = parse_command_args(argc, argv, &use_syspath); if (argsused == 0) { /* use 'type' builting to display info */ cmdentry.u.bltin = typecmd; break; } argc -= argsused; argv += argsused; if (use_syspath) path = syspath() + 5; } while (argc != 0); if (cmdentry.cmdtype == CMDSPLBLTIN && cmd_flags & DO_NOFUNC) /* posix mandates that 'command <splbltin>' act as if <splbltin> was a normal builtin */ cmdentry.cmdtype = CMDBUILTIN; } /* Fork off a child process if necessary. */ if (cmd->ncmd.backgnd || (trap[0] && (flags & EV_EXIT) != 0) || (cmdentry.cmdtype == CMDNORMAL && (flags & EV_EXIT) == 0) || ((flags & EV_BACKCMD) != 0 && ((cmdentry.cmdtype != CMDBUILTIN && cmdentry.cmdtype != CMDSPLBLTIN) || cmdentry.u.bltin == dotcmd || cmdentry.u.bltin == evalcmd))) { INTOFF; jp = makejob(cmd, 1); mode = cmd->ncmd.backgnd; if (flags & EV_BACKCMD) { mode = FORK_NOJOB; if (sh_pipe(pip) < 0) error("Pipe call failed"); } #ifdef DO_SHAREDVFORK /* It is essential that if DO_SHAREDVFORK is defined that the * child's address space is actually shared with the parent as * we rely on this. */ if (usefork == 0 && cmdentry.cmdtype == CMDNORMAL) { pid_t pid; int serrno; savelocalvars = localvars; localvars = NULL; vforked = 1; switch (pid = vfork()) { case -1: serrno = errno; TRACE(("Vfork failed, errno=%d\n", serrno)); INTON; error("Cannot vfork (%s)", strerror(serrno)); break; case 0: /* Make sure that exceptions only unwind to * after the vfork(2) */ if (setjmp(jmploc.loc)) { if (exception == EXSHELLPROC) { /* We can't progress with the vfork, * so, set vforked = 2 so the parent * knows, and _exit(); */ vforked = 2; _exit(0); } else { _exit(exerrno); } } savehandler = handler; handler = &jmploc; listmklocal(varlist.list, VEXPORT | VNOFUNC); forkchild(jp, cmd, mode, vforked); break; default: handler = savehandler; /* restore from vfork(2) */ poplocalvars(); localvars = savelocalvars; if (vforked == 2) { vforked = 0; (void)waitpid(pid, NULL, 0); /* We need to progress in a normal fork fashion */ goto normal_fork; } vforked = 0; forkparent(jp, cmd, mode, pid); goto parent; } } else { normal_fork: #endif if (forkshell(jp, cmd, mode) != 0) goto parent; /* at end of routine */ FORCEINTON; #ifdef DO_SHAREDVFORK } #endif if (flags & EV_BACKCMD) { if (!vforked) { FORCEINTON; } close(pip[0]); if (pip[1] != 1) { close(1); copyfd(pip[1], 1, 1, 0); close(pip[1]); } } flags |= EV_EXIT; } /* This is the child process if a fork occurred. */ /* Execute the command. */ switch (cmdentry.cmdtype) { case CMDFUNCTION: #ifdef DEBUG trputs("Shell function: "); trargs(argv); #endif redirect(cmd->ncmd.redirect, REDIR_PUSH); saveparam = shellparam; shellparam.malloc = 0; shellparam.reset = 1; shellparam.nparam = argc - 1; shellparam.p = argv + 1; shellparam.optnext = NULL; INTOFF; savelocalvars = localvars; localvars = NULL; INTON; if (setjmp(jmploc.loc)) { if (exception == EXSHELLPROC) { freeparam((volatile struct shparam *) &saveparam); } else { freeparam(&shellparam); shellparam = saveparam; } poplocalvars(); localvars = savelocalvars; handler = savehandler; longjmp(handler->loc, 1); } savehandler = handler; handler = &jmploc; listmklocal(varlist.list, VEXPORT); /* stop shell blowing its stack */ if (++funcnest > 1000) error("too many nested function calls"); evaltree(cmdentry.u.func, flags & EV_TESTED); funcnest--; INTOFF; poplocalvars(); localvars = savelocalvars; freeparam(&shellparam); shellparam = saveparam; handler = savehandler; popredir(); INTON; if (evalskip == SKIPFUNC) { evalskip = SKIPNONE; skipcount = 0; } if (flags & EV_EXIT) exitshell(exitstatus); break; case CMDBUILTIN: case CMDSPLBLTIN: #ifdef DEBUG trputs("builtin command: "); trargs(argv); #endif mode = (cmdentry.u.bltin == execcmd) ? 0 : REDIR_PUSH; if (flags == EV_BACKCMD) { memout.nleft = 0; memout.nextc = memout.buf; memout.bufsize = 64; mode |= REDIR_BACKQ; } e = -1; savehandler = handler; savecmdname = commandname; handler = &jmploc; temp_path = 0; if (!setjmp(jmploc.loc)) { /* We need to ensure the command hash table isn't * corruped by temporary PATH assignments. * However we must ensure the 'local' command works! */ if (path != pathval() && (cmdentry.u.bltin == hashcmd || cmdentry.u.bltin == typecmd)) { savelocalvars = localvars; localvars = 0; temp_path = 1; mklocal(path - 5 /* PATH= */, 0); } redirect(cmd->ncmd.redirect, mode); /* exec is a special builtin, but needs this list... */ cmdenviron = varlist.list; /* we must check 'readonly' flag for all builtins */ listsetvar(varlist.list, cmdentry.cmdtype == CMDSPLBLTIN ? 0 : VNOSET); commandname = argv[0]; /* initialize nextopt */ argptr = argv + 1; optptr = NULL; /* and getopt */ optreset = 1; optind = 1; builtin_flags = flags; exitstatus = cmdentry.u.bltin(argc, argv); } else { e = exception; exitstatus = e == EXINT ? SIGINT + 128 : e == EXEXEC ? exerrno : 2; } handler = savehandler; flushall(); out1 = &output; out2 = &errout; freestdout(); if (temp_path) { poplocalvars(); localvars = savelocalvars; } cmdenviron = NULL; if (e != EXSHELLPROC) { commandname = savecmdname; if (flags & EV_EXIT) exitshell(exitstatus); } if (e != -1) { if ((e != EXERROR && e != EXEXEC) || cmdentry.cmdtype == CMDSPLBLTIN) exraise(e); FORCEINTON; } if (cmdentry.u.bltin != execcmd) popredir(); if (flags == EV_BACKCMD) { backcmd->buf = memout.buf; backcmd->nleft = memout.nextc - memout.buf; memout.buf = NULL; } break; default: #ifdef DEBUG trputs("normal command: "); trargs(argv); #endif redirect(cmd->ncmd.redirect, (vforked ? REDIR_VFORK : 0) | REDIR_KEEP); if (!vforked) for (sp = varlist.list ; sp ; sp = sp->next) setvareq(sp->text, VEXPORT|VSTACK); envp = environment(); shellexec(argv, envp, path, cmdentry.u.index, vforked); break; } goto out; parent: /* parent process gets here (if we forked) */ exitstatus = 0; /* if not altered just below */ if (mode == FORK_FG) { /* argument to fork */ exitstatus = waitforjob(jp); } else if (mode == FORK_NOJOB) { backcmd->fd = pip[0]; close(pip[1]); backcmd->jp = jp; } FORCEINTON; out: if (lastarg) /* dsl: I think this is intended to be used to support * '_' in 'vi' command mode during line editing... * However I implemented that within libedit itself. */ setvar("_", lastarg, 0); popstackmark(&smark); }
STATIC void openredirect(union node *redir, char memory[10], int flags) { int fd = redir->nfile.fd; char *fname; int f; int oflags = O_WRONLY|O_CREAT|O_TRUNC, eflags; /* * We suppress interrupts so that we won't leave open file * descriptors around. This may not be such a good idea because * an open of a device or a fifo can block indefinitely. */ INTOFF; memory[fd] = 0; switch (redir->nfile.type) { case NFROM: fname = redir->nfile.expfname; if (flags & REDIR_VFORK) eflags = O_NONBLOCK; else eflags = 0; if ((f = open(fname, O_RDONLY|eflags)) < 0) goto eopen; if (eflags) (void)fcntl(f, F_SETFL, fcntl(f, F_GETFL, 0) & ~eflags); break; case NFROMTO: fname = redir->nfile.expfname; if ((f = open(fname, O_RDWR|O_CREAT|O_TRUNC, 0666)) < 0) goto ecreate; break; case NTO: if (Cflag) oflags |= O_EXCL; /* FALLTHROUGH */ case NCLOBBER: fname = redir->nfile.expfname; if ((f = open(fname, oflags, 0666)) < 0) goto ecreate; break; case NAPPEND: fname = redir->nfile.expfname; if ((f = open(fname, O_WRONLY|O_CREAT|O_APPEND, 0666)) < 0) goto ecreate; break; case NTOFD: case NFROMFD: if (redir->ndup.dupfd >= 0) { /* if not ">&-" */ if (memory[redir->ndup.dupfd]) memory[fd] = 1; else copyfd(redir->ndup.dupfd, fd, 1); } INTON; return; case NHERE: case NXHERE: f = openhere(redir); break; default: abort(); } if (f != fd) { copyfd(f, fd, 1); close(f); } INTON; return; ecreate: exerrno = 1; error("cannot create %s: %s", fname, errmsg(errno, E_CREAT)); eopen: exerrno = 1; error("cannot open %s: %s", fname, errmsg(errno, E_OPEN)); }
static void sysrfork(void) { u32int flags; int rc, i; Process *p; Segment *s, *t; Fd *old; flags = arg(0); if(systrace) fprint(2, "rfork(%#o)\n", flags); if((flags & (RFFDG | RFCFDG)) == (RFFDG | RFCFDG) || (flags & (RFNAMEG | RFCNAMEG)) == (RFNAMEG | RFCNAMEG) || (flags & (RFENVG | RFCENVG)) == (RFENVG | RFCENVG)) { P->R[0] = -1; cherrstr("bad arg in syscall"); return; } if((flags & RFPROC) == 0) { if(flags & RFFDG) { old = P->fd; P->fd = copyfd(P->fd); fddecref(old); } if(flags & RFCFDG) { old = P->fd; P->fd = newfd(); fddecref(old); } P->R[0] = noteerr(rfork(flags), 0); return; } incref(&nproc); p = emallocz(sizeof(Process)); memcpy(p, P, sizeof(Process)); for(i = 0; i < SEGNUM; i++) { s = p->S[i]; if(s == nil) continue; if((flags & RFMEM) == 0 && i != SEGTEXT || i == SEGSTACK) { t = emallocz(sizeof(Segment)); incref(t); t->size = s->size; t->start = s->start; t->dref = emalloc(sizeof(Ref) + s->size); memset(t->dref, 0, sizeof(Ref)); incref(t->dref); t->data = t->dref + 1; memcpy(t->data, s->data, s->size); p->S[i] = t; } else { incref(s->dref); incref(s); } } if(flags & RFFDG) p->fd = copyfd(P->fd); else if(flags & RFCFDG) p->fd = newfd(); else incref(P->fd); incref(P->path); rc = rfork(RFMEM | flags); if(rc < 0) /* this should NEVER happen */ sysfatal("rfork failed wtf: %r"); if(rc == 0) { P = p; atexit(cleanup); P->pid = getpid(); inittos(); addproc(P); } P->R[0] = rc; }