FILE *
popen(const char *cmd, const char *type)
{
	struct pid *cur;
	int pdes[2], serrno;
	pid_t pid;

	_DIAGASSERT(cmd != NULL);
	_DIAGASSERT(type != NULL);

	if ((cur = pdes_get(pdes, &type)) == NULL)
		return NULL;

#ifdef _REENTRANT
	(void)rwlock_rdlock(&pidlist_lock);
#endif
	(void)__readlockenv();
	switch (pid = vfork()) {
	case -1:			/* Error. */
		serrno = errno;
		(void)__unlockenv();
#ifdef _REENTRANT
		(void)rwlock_unlock(&pidlist_lock);
#endif
		pdes_error(pdes, cur);
		errno = serrno;
		return NULL;
		/* NOTREACHED */
	case 0:				/* Child. */
		pdes_child(pdes, type);
		execl(_PATH_BSHELL, "sh", "-c", cmd, NULL);
		_exit(127);
		/* NOTREACHED */
	}
	(void)__unlockenv();

	pdes_parent(pdes, cur, pid, type);

#ifdef _REENTRANT
	(void)rwlock_unlock(&pidlist_lock);
#endif

	return cur->fp;
}
Esempio n. 2
0
FILE *
popen(const char *command, const char *type)
{
	struct pid *cur, *old;
	FILE *iop;
	const char * volatile xtype = type;
	int pdes[2], pid, serrno;
	volatile int twoway;
	int flags;

	_DIAGASSERT(command != NULL);
	_DIAGASSERT(xtype != NULL);

	flags = strchr(xtype, 'e') ? O_CLOEXEC : 0;
	if (strchr(xtype, '+')) {
		int stype = flags ? (SOCK_STREAM | SOCK_CLOEXEC) : SOCK_STREAM;
		twoway = 1;
		xtype = "r+";
		if (socketpair(AF_LOCAL, stype, 0, pdes) < 0)
			return NULL;
	} else  {
		twoway = 0;
		xtype = strrchr(xtype, 'r') ? "r" : "w";
		if (pipe2(pdes, flags) == -1)
			return NULL;
	}

	if ((cur = malloc(sizeof(struct pid))) == NULL) {
		(void)close(pdes[0]);
		(void)close(pdes[1]);
		errno = ENOMEM;
		return (NULL);
	}

#if defined(__minix)
	rwlock_rdlock(&pidlist_lock);
#else
	(void)rwlock_rdlock(&pidlist_lock);
#endif /* defined(__minix) */
	(void)__readlockenv();
	switch (pid = vfork()) {
	case -1:			/* Error. */
		serrno = errno;
		(void)__unlockenv();
#if defined(__minix)
		rwlock_unlock(&pidlist_lock);
#else
		(void)rwlock_unlock(&pidlist_lock);
#endif /* defined(__minix) */
		free(cur);
		(void)close(pdes[0]);
		(void)close(pdes[1]);
		errno = serrno;
		return (NULL);
		/* NOTREACHED */
	case 0:				/* Child. */
		/* POSIX.2 B.3.2.2 "popen() shall ensure that any streams
		   from previous popen() calls that remain open in the 
		   parent process are closed in the new child process. */
		for (old = pidlist; old; old = old->next)
#ifdef _REENTRANT
			close(old->fd); /* don't allow a flush */
#else
			close(fileno(old->fp)); /* don't allow a flush */
#endif

		if (*xtype == 'r') {
			(void)close(pdes[0]);
			if (pdes[1] != STDOUT_FILENO) {
				(void)dup2(pdes[1], STDOUT_FILENO);
				(void)close(pdes[1]);
			}
			if (twoway)
				(void)dup2(STDOUT_FILENO, STDIN_FILENO);
		} else {
			(void)close(pdes[1]);
			if (pdes[0] != STDIN_FILENO) {
				(void)dup2(pdes[0], STDIN_FILENO);
				(void)close(pdes[0]);
			}
		}

		execl(_PATH_BSHELL, "sh", "-c", command, NULL);
		_exit(127);
		/* NOTREACHED */
	}
	(void)__unlockenv();

	/* Parent; assume fdopen can't fail. */
	if (*xtype == 'r') {
		iop = fdopen(pdes[0], xtype);
#ifdef _REENTRANT
		cur->fd = pdes[0];
#endif
		(void)close(pdes[1]);
	} else {
		iop = fdopen(pdes[1], xtype);
#ifdef _REENTRANT
		cur->fd = pdes[1];
#endif
		(void)close(pdes[0]);
	}

	/* Link into list of file descriptors. */
	cur->fp = iop;
	cur->pid =  pid;
	cur->next = pidlist;
	pidlist = cur;
#if defined(__minix)
	rwlock_unlock(&pidlist_lock);
#else
	(void)rwlock_unlock(&pidlist_lock);
#endif /* defined(__minix) */

	return (iop);
}
Esempio n. 3
0
int
system(const char *command)
{
	pid_t pid;
	struct sigaction intsa, quitsa, sa;
	sigset_t nmask, omask;
	int pstat;
	const char *argp[] = {"sh", "-c", NULL, NULL};
	argp[2] = command;

	/*
	 * ISO/IEC 9899:1999 in 7.20.4.6 describes this special case.
	 * We need to check availability of a command interpreter.
	 */
	if (command == NULL) {
		if (access(_PATH_BSHELL, X_OK) == 0)
			return 1;
		return 0;
	}

	sa.sa_handler = SIG_IGN;
	sigemptyset(&sa.sa_mask);
	sa.sa_flags = 0;

	if (sigaction(SIGINT, &sa, &intsa) == -1)
		return -1;
	if (sigaction(SIGQUIT, &sa, &quitsa) == -1) {
		sigaction(SIGINT, &intsa, NULL);
		return -1;
	}

	sigemptyset(&nmask);
	sigaddset(&nmask, SIGCHLD);
	if (sigprocmask(SIG_BLOCK, &nmask, &omask) == -1) {
		sigaction(SIGINT, &intsa, NULL);
		sigaction(SIGQUIT, &quitsa, NULL);
		return -1;
	}

	(void)__readlockenv();
	switch(pid = vfork()) {
	case -1:			/* error */
		(void)__unlockenv();
		sigaction(SIGINT, &intsa, NULL);
		sigaction(SIGQUIT, &quitsa, NULL);
		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
		return -1;
	case 0:				/* child */
		sigaction(SIGINT, &intsa, NULL);
		sigaction(SIGQUIT, &quitsa, NULL);
		(void)sigprocmask(SIG_SETMASK, &omask, NULL);
		execve(_PATH_BSHELL, __UNCONST(argp), environ);
		_exit(127);
	}
	(void)__unlockenv();

	while (waitpid(pid, &pstat, 0) == -1) {
		if (errno != EINTR) {
			pstat = -1;
			break;
		}
	}

	sigaction(SIGINT, &intsa, NULL);
	sigaction(SIGQUIT, &quitsa, NULL);
	(void)sigprocmask(SIG_SETMASK, &omask, NULL);

	return (pstat);
}