summaryrefslogtreecommitdiffstats
path: root/mcwrapper.c
diff options
context:
space:
mode:
Diffstat (limited to 'mcwrapper.c')
-rw-r--r--mcwrapper.c319
1 files changed, 319 insertions, 0 deletions
diff --git a/mcwrapper.c b/mcwrapper.c
new file mode 100644
index 0000000..6aedd14
--- /dev/null
+++ b/mcwrapper.c
@@ -0,0 +1,319 @@
+#include <err.h>
+#include <errno.h>
+#include <signal.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <time.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
+reap_all()
+{
+ int i;
+ for (i = 0; i < NUM_PROCS; i++) {
+ if (procs[i].pid != -1)
+ kill(procs[i].pid, SIGTERM);
+ }
+
+ sleep(5);
+
+ for (i = 0; i < NUM_PROCS; i++) {
+ if (procs[i].pid != -1)
+ kill(procs[i].pid, SIGKILL);
+ }
+
+ while (wait(NULL) != -1 || errno == EINTR)
+ ;
+}
+
+void
+fail(int exit, const char *msg, ...)
+{
+ reap_all();
+
+ va_list args;
+ va_start(args, msg);
+ verr(exit, msg, args);
+ va_end(args); // Not reached?
+}
+
+void
+failx(int exit, const char *msg, ...)
+{
+ reap_all();
+
+ va_list args;
+ va_start(args, msg);
+ verrx(exit, msg, args);
+ va_end(args); // Not reached?
+}
+
+void
+grow_argv(char ***argv, size_t *len)
+{
+#define GROW_SIZE 32
+
+ char **ret = realloc(*argv, sizeof(char *) * (*len + GROW_SIZE));
+ if (ret == NULL)
+ err(1, "realloc");
+
+ *argv = ret;
+ *len += GROW_SIZE;
+
+#undef GROW_SIZE
+}
+
+void
+gen_argv(struct proc *proc)
+{
+ char *saveptr, *tmp, *cmd;
+ char **argv = NULL, **head;
+
+ size_t len = 0, used = 0;
+
+
+ cmd = strdup(proc->cmd);
+ if (cmd == NULL)
+ err(1, "strdup");
+
+ grow_argv(&argv, &len);
+ head = argv;
+
+ tmp = strtok_r(cmd, " \t", &saveptr);
+ while (tmp != NULL) {
+ *(head++) = strdup(tmp);
+ used++;
+
+ if (used >= len) {
+ grow_argv(&argv, &len);
+ head = argv + used;
+ }
+
+ tmp = strtok_r(NULL, " \t", &saveptr);
+ }
+ *head = NULL;
+
+ free(cmd);
+
+ proc->argv = argv;
+}
+
+void
+run_cmd(struct proc *proc)
+{
+ pid_t cpid;
+
+ cpid = fork();
+ if (cpid == 0) {
+ if (proc->_stdin != -1) {
+ if (close(0) == -1)
+ fail(1, "close");
+ if (dup2(proc->_stdin, 0) == -1)
+ fail(1, "dup2");
+ }
+ if (proc->_stdout != -1) {
+ if (close(1) == -1)
+ fail(1, "close");
+ if (dup2(proc->_stdout, 1) == -1)
+ fail(1, "dup2");
+ }
+ if (proc->_stderr != -1) {
+ if (close(2) == -1)
+ fail(1, "close");
+ if (dup2(proc->_stderr, 2) == -1)
+ fail(1, "dup2");
+ }
+
+ close(fds[0]); // These aren't very important if they fail
+ close(fds[1]);
+
+ execvp(proc->argv[0], proc->argv);
+
+ perror("execvp");
+ _exit(128);
+ } else if (cpid == -1) {
+ fail(1, "fork");
+ } else {
+ proc->pid = cpid;
+ }
+}
+
+int
+have_children()
+{
+ int i;
+ for (i = 0; i < NUM_PROCS; i++) {
+ if (procs[i].pid != -1)
+ return 1;
+ }
+
+ return 0;
+}
+
+void
+signal_procs()
+{
+ if (terminate == 1) {
+ if (procs[0].pid != -1)
+ kill(procs[0].pid, sendsignal);
+ else
+ kill(procs[1].pid, sendsignal);
+ } else {
+ int i;
+ for (i = 0; i < NUM_PROCS; i++)
+ kill(procs[i].pid, sendsignal);
+ }
+
+ 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;
+}
+
+void
+setup_signals()
+{
+ struct sigaction act;
+ memset(&act, 0, sizeof(act));
+
+ act.sa_sigaction = &handle_fatal;
+ act.sa_flags = SA_SIGINFO;
+
+ if (sigaction(SIGINT, &act, NULL) == -1)
+ err(1, "sigaction");
+ if (sigaction(SIGHUP, &act, NULL) == -1)
+ err(1, "sigaction");
+ if (sigaction(SIGTERM, &act, NULL) == -1)
+ err(1, "sigaction");
+
+ act.sa_sigaction = &handle_nonfatal;
+ if (sigaction(SIGUSR1, &act, NULL) == -1)
+ err(1, "sigaction");
+ if (sigaction(SIGUSR2, &act, NULL) == -1)
+ err(1, "sigaction");
+}
+
+void
+start_missing_procs()
+{
+ int i;
+ for (i = NUM_PROCS - 1; i >= 0; i--) {
+ if (procs[i].pid == -1)
+ run_cmd(&procs[i]);
+ }
+}
+
+void
+print_argv()
+{
+ int i;
+ for (i = 0; i < NUM_PROCS; i++) {
+ char **tmp = procs[i].argv;
+
+ while (*tmp)
+ printf("%s ", *tmp++);
+
+ printf("\n");
+ }
+}
+
+int
+have_nonstarted()
+{
+ return 0;
+}
+
+int
+main(int argc, char **argv)
+{
+ int i;
+
+ if (argc < 3) {
+ fprintf(stderr, "Usage: piper <cmd1> <cmd2>\n");
+ return 1;
+ }
+
+ setup_signals();
+
+ for (i = 0; i < NUM_PROCS; i++) {
+ procs[i].cmd = strdup(argv[i + 1]);
+ if (procs[i].cmd == NULL)
+ err(1, "strdup");
+
+ procs[i].pid = -1;
+ procs[i]._stdin = -1;
+ procs[i]._stdout = -1;
+ procs[i]._stderr = -1;
+ gen_argv(&procs[i]);
+ }
+
+ if (pipe(fds) == -1)
+ err(1, "pipe");
+
+ procs[0]._stdout = fds[1];
+ procs[0]._stderr = fds[1];
+ procs[1]._stdin = fds[0];
+
+ while (!terminate || have_children()) {
+ pid_t pid;
+
+ if (!terminate)
+ start_missing_procs();
+
+ if (sendsignal != 0)
+ signal_procs();
+
+ pid = waitpid(0, NULL, 0);
+ if (pid == -1) {
+ if (errno == EINTR) {
+ continue;
+ } else
+ fail(1, "wait");
+ } else if (pid == procs[0].pid) {
+ terminate = 1;
+
+ //if (sendsignal == 0)
+ // sendsignal = SIGTERM;
+
+ close(fds[0]);
+ close(fds[1]);
+
+ procs[0].pid = -1;
+ } else if (pid == procs[1].pid) {
+ procs[1].pid = -1;
+ }
+ }
+
+ return 0;
+}