~emersion/blackbox

4f8e51ebbd48739f5ff782a8e6e624ae8fcb5014 — Simon Ser 3 months ago 5b298bf master
Accept command to run as arg
2 files changed, 67 insertions(+), 3 deletions(-)

M README.md
M main.c
M README.md => README.md +5 -1
@@ 11,11 11,15 @@ after-the-fact via a Unix socket. Useful when trying to obtain data about a

## Usage

    <program> 2>&1 | blackbox
    blackbox -- <program>

`<program>` can be used normally for extended periods of time. blackbox will
print instructions that can be used to grab logs when the bug is reproduced.

blackbox can also read from the standard input:

    <program> 2>&1 | blackbox

## License

AGPLv3, see LICENSE.

M main.c => main.c +62 -2
@@ 6,6 6,7 @@
#include <stdlib.h>
#include <sys/socket.h>
#include <sys/un.h>
#include <sys/wait.h>
#include <unistd.h>

struct ring_buffer {


@@ 76,12 77,71 @@ int main(int argc, char *argv[]) {
		// TODO: add more useful options
		switch (opt) {
		default:
			fprintf(stderr, "usage: blackbox\n");
			fprintf(stderr, "usage: blackbox [command...]\n");
			return 1;
		}
	}

	int in_fd = STDIN_FILENO;
	int in_fd;
	if (optind < argc) {
		char **cmd = &argv[optind];

		int child_pipe[2];
		if (pipe(child_pipe) != 0) {
			perror("pipe failed");
			return 1;
		}

		pid_t pid = fork();
		if (pid < 0) {
			perror("fork failed");
			return 1;
		} else if (pid == 0) {
			close(child_pipe[0]);

			// Redirect stdout to the pipe
			if (dup2(child_pipe[1], STDOUT_FILENO) < 0) {
				perror("dup2 failed");
				_exit(1);
			}
			close(child_pipe[1]);

			// Then redirect stderr to stdout
			if (dup2(STDOUT_FILENO, STDERR_FILENO) < 0) {
				perror("dup2 failed");
				_exit(1);
			}

			// Fork again to avoid SIGCHLD
			pid = fork();
			if (pid < 0) {
				perror("fork failed");
				_exit(1);
			} else if (pid == 0) {
				execvp(cmd[0], cmd);
				perror("execvp failed");
				_exit(1);
			}

			_exit(0);
		}

		close(child_pipe[1]);
		in_fd = child_pipe[0];

		int stat;
		if (waitpid(pid, &stat, 0) < 0) {
			perror("waitpid failed");
			return 1;
		}
		if (stat != 0) {
			fprintf(stderr, "failed to spawn child process\n");
			return 1;
		}
	} else {
		in_fd = STDIN_FILENO;
	}

	if (set_nonblock(in_fd) != 0) {
		return 1;
	}