Skip to content

Instantly share code, notes, and snippets.

@mikdusan

mikdusan/main.c Secret

Last active May 9, 2021 14:24
Show Gist options
  • Star 0 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save mikdusan/e52dbd69c94f01c9650f9dcd1e8d1bf2 to your computer and use it in GitHub Desktop.
Save mikdusan/e52dbd69c94f01c9650f9dcd1e8d1bf2 to your computer and use it in GitHub Desktop.
poll child process stdout/stderr
#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 /`
// cc -E -Wp,-v -xc /dev/null
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;
}
@mikdusan
Copy link
Author

mikdusan commented May 9, 2021

sample output from dragonfly:

[0] ./main
[1] /bin/ls
[2] -al
[3] /
pipes: 3,4,5,6
poll rv=1
fd[0].revents=0x0001 [1].revents=0x0000
fd[0] read=1175 bytes
poll rv=2
fd[0].revents=0x0001 [1].revents=0x0001
fd[0] read=0 bytes
fd[1] read=0 bytes
poll rv=2
fd[0].revents=0x0001 [1].revents=0x0001
fd[0] read=0 bytes
fd[1] read=0 bytes
poll rv=2
fd[0].revents=0x0001 [1].revents=0x0001
fd[0] read=0 bytes
fd[1] read=0 bytes
poll rv=2
...

@mikdusan
Copy link
Author

mikdusan commented May 9, 2021

sample output from freebsd:

[0] ./main
[1] /bin/ls
[2] -al
[3] /
pipes: 3,4,5,6
poll rv=2
fd[0].revents=0x0011 [1].revents=0x0011
fd[0] read=1616 bytes
fd[1] read=0 bytes
child 1855 exited with status 0

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment