Beispiel #1
0
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;
}
Beispiel #2
0
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;
    }
}
Beispiel #3
0
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));
}
Beispiel #4
0
/*
 * 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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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);
}
Beispiel #8
0
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));
}
Beispiel #9
0
/*
 * 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;
}
Beispiel #10
0
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);
}
Beispiel #11
0
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));
}
Beispiel #12
0
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;
}