diff options
author | Marius Halden <marius.h@lden.org> | 2015-10-29 00:00:48 +0100 |
---|---|---|
committer | Marius Halden <marius.h@lden.org> | 2015-10-29 00:00:48 +0100 |
commit | a844411b86140c334f1ab5ec06116f70da9ec354 (patch) | |
tree | 7a1e86c8098cca8d7302f3d4e9028764024c19d4 /piper.c | |
download | piper-a844411b86140c334f1ab5ec06116f70da9ec354.tar.gz piper-a844411b86140c334f1ab5ec06116f70da9ec354.tar.bz2 piper-a844411b86140c334f1ab5ec06116f70da9ec354.tar.xz |
Initial
Diffstat (limited to 'piper.c')
-rw-r--r-- | piper.c | 197 |
1 files changed, 197 insertions, 0 deletions
@@ -0,0 +1,197 @@ +#include <errno.h> +#include <signal.h> +#include <stdio.h> +#include <stdlib.h> +#include <string.h> +#include <sys/types.h> +#include <sys/wait.h> +#include <unistd.h> + +#define NUM_PROCS 2 + +struct proc { + pid_t pid; + char *cmd; + char **argv; + int _stdin; + int _stdout; + int _stderr; +} procs[NUM_PROCS]; + +int fds[2]; + +volatile sig_atomic_t terminate = 0; +volatile sig_atomic_t sendsignal = 0; + +void +gen_argv(struct proc *proc) +{ + int i; + char *saveptr, *tmp; + char **argv = malloc(sizeof(char*) * 1024); + char **head = argv; + char *cmd2 = strdup(proc->cmd); + // XXX: Check malloc/strdup return + // XXX: Check for overflow in tmp + + for (i = 0; i < 1024; i++) + argv[i] = NULL; + + tmp = strtok_r(cmd2, " \t", &saveptr); + while (tmp != NULL) { + *(head++) = strdup(tmp); + tmp = strtok_r(NULL, " \t", &saveptr); + } + *head = NULL; + + free(cmd2); + + proc->argv = argv; +} + +int +run_cmd(struct proc *proc) +{ + pid_t cpid; + + cpid = fork(); + if (cpid == 0) { + if (proc->_stdin != -1) { + close(0); + dup2(proc->_stdin, 0); + } + if (proc->_stdout != -1) { + close(1); + dup2(proc->_stdout, 1); + } + if (proc->_stderr != -1) { + close(2); + dup2(proc->_stderr, 2); + } + close(fds[0]); + close(fds[1]); + + execvp(proc->argv[0], proc->argv); + perror("execvp"); + } else if (cpid == -1) { + // error D: + return -1; + } else { + proc->pid = cpid; + } + + return 0; +} + +int +have_child() +{ + int i; + for (i = 0; i < NUM_PROCS; i++) { + if (procs[i].pid != -1) + return 1; + } + + return 0; +} + +struct proc * +proc_by_pid(pid_t pid) +{ + int i; + for (i = 0; i < NUM_PROCS; i++) { + if (procs[i].pid == pid) + return &procs[i]; + } + + return NULL; +} + +void +signal_procs() +{ + int i; + for (i = 0; i < NUM_PROCS; i++) { + if (procs[i].pid != -1) + kill(procs[i].pid, sendsignal); //XXX: Check return? + } + + sendsignal = 0; +} + +void +handle_nonfatal(int sig, siginfo_t *siginfo, void *ucontext) +{ + sendsignal = sig; +} + +void +handle_fatal(int sig, siginfo_t *siginfo, void *ucontext) +{ + terminate = 1; + sendsignal = sig; +} + +int +main(int argc, char **argv) +{ + if (argc < 2) { + fprintf(stderr, "Usage: piper <cmd1> <cmd2>\n"); + return 1; + } + + struct sigaction act; + memset(&act, 0, sizeof(act)); + + act.sa_sigaction = &handle_fatal; + act.sa_flags = SA_SIGINFO; + + sigaction(SIGINT, &act, NULL); + sigaction(SIGHUP, &act, NULL); + sigaction(SIGTERM, &act, NULL); + + act.sa_sigaction = &handle_nonfatal; + sigaction(SIGUSR1, &act, NULL); + sigaction(SIGUSR2, &act, NULL); + + procs[0].cmd = strdup(argv[1]); + procs[1].cmd = strdup(argv[2]); + + int i; + for (i = 0; i < NUM_PROCS; i++) { + procs[i].pid = -1; + procs[i]._stdin = -1; + procs[i]._stdout = -1; + procs[i]._stderr = -1; + gen_argv(&procs[i]); + } + + pipe(fds); // XXX: Check return code + + procs[0]._stdout = fds[1]; + procs[0]._stderr = fds[1]; + procs[1]._stdin = fds[0]; + + run_cmd(&procs[0]); + run_cmd(&procs[1]); // XXX: Check return codes + + while (have_child()) { + int status; + pid_t pid; + + if (sendsignal != 0) + signal_procs(); + + pid = wait(&status); + if (pid == -1 && errno == EINTR) + continue; + + struct proc *p = proc_by_pid(pid); // XXX: Check return code + p->pid = -1; + + if (!terminate) + run_cmd(p); // XXX: Check return code + } + + return 0; +} |