summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile9
-rw-r--r--piper.c197
2 files changed, 206 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..a586703
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,9 @@
+
+
+piper: piper.c
+ ${CC} -o piper -Wall -Werror piper.c
+
+.PHONY: clean
+
+clean:
+ rm -f piper
diff --git a/piper.c b/piper.c
new file mode 100644
index 0000000..af35e6e
--- /dev/null
+++ b/piper.c
@@ -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;
+}