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; }
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); }
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); }