|
#include <errno.h>
|
|
#include <poll.h>
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
#include <sys/types.h>
|
|
#include <sys/wait.h>
|
|
#include <unistd.h>
|
|
|
|
// invoke with something like: `main /bin/ls -al /`
|
|
|
|
int main(int argc, char *argv[], char *envp[]) {
|
|
int i = 0;
|
|
for (int i = 0; i < argc; i += 1) {
|
|
printf("[%d] %s\n", i, argv[i]);
|
|
}
|
|
|
|
if (argc < 2) {
|
|
fprintf(stderr, "usage: %s exe [arg]...\n", argv[0]);
|
|
exit(1);
|
|
}
|
|
|
|
int stdout_pipe[2];
|
|
if (pipe(stdout_pipe) == -1) {
|
|
fprintf(stderr, "pipe(stdout_pipe) failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
int stderr_pipe[2];
|
|
if (pipe(stderr_pipe) == -1) {
|
|
fprintf(stderr, "pipe(stderr_pipe) failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
printf("pipes: %d,%d,%d,%d\n", stdout_pipe[0], stdout_pipe[1], stderr_pipe[0], stderr_pipe[1]);
|
|
|
|
pid_t child_pid = fork();
|
|
if (child_pid == -1) {
|
|
fprintf(stderr, "fork failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
// child
|
|
if (child_pid == 0) {
|
|
if (dup2(stdout_pipe[1], STDOUT_FILENO) == -1) {
|
|
fprintf(stderr, "dup2(STDOUT_FILENO) failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
if (dup2(stderr_pipe[1], STDERR_FILENO) == -1) {
|
|
fprintf(stderr, "dup2(STDOUT_FILENO) failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
close(stdout_pipe[0]);
|
|
close(stdout_pipe[1]);
|
|
close(stderr_pipe[0]);
|
|
close(stderr_pipe[1]);
|
|
|
|
int rv = execve(argv[1], &argv[1], envp);
|
|
if (rv == -1) {
|
|
fprintf(stderr, "execve failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
}
|
|
|
|
// parent
|
|
|
|
close(stdout_pipe[1]);
|
|
close(stderr_pipe[1]);
|
|
|
|
struct pollfd fds[2];
|
|
fds[0].fd = stdout_pipe[0];
|
|
fds[0].events = POLLIN;
|
|
fds[1].fd = stderr_pipe[0];
|
|
fds[1].events = POLLIN;
|
|
|
|
int nactive = 2;
|
|
while (nactive > 0) {
|
|
int rv = poll(fds, 2, -1);
|
|
if (rv == -1) {
|
|
fprintf(stderr, "poll failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
printf("poll rv=%d\n", rv);
|
|
if (rv == 0) continue;
|
|
|
|
printf("fd[0].revents=0x%04x [1].revents=0x%04x\n", fds[0].revents, fds[1].revents);
|
|
char buf[8192];
|
|
|
|
if (fds[0].revents & POLLIN) {
|
|
memset(buf, 0, sizeof(buf));
|
|
ssize_t nbytes = read(fds[0].fd, buf, sizeof(buf) - 1);
|
|
printf("fd[0] read=%ld bytes\n", nbytes);
|
|
}
|
|
|
|
if (fds[1].revents & POLLIN) {
|
|
memset(buf, 0, sizeof(buf));
|
|
ssize_t nbytes = read(fds[1].fd, buf, sizeof(buf) - 1);
|
|
printf("fd[1] read=%ld bytes\n", nbytes);
|
|
}
|
|
|
|
if (fds[0].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
|
fds[0].fd = -1;
|
|
nactive -= 1;
|
|
}
|
|
if (fds[1].revents & (POLLERR | POLLHUP | POLLNVAL)) {
|
|
fds[1].fd = -1;
|
|
nactive -= 1;
|
|
}
|
|
}
|
|
|
|
int status;
|
|
int rv = waitpid(child_pid, &status, 0);
|
|
if (rv == -1) {
|
|
fprintf(stderr, "waitpid failed: %s\n", strerror(errno));
|
|
exit(1);
|
|
}
|
|
|
|
printf("child %d exited with status %d\n", child_pid, status);
|
|
|
|
return 0;
|
|
}
|