Index: tools/Makefile.am
===================================================================
--- tools/Makefile.am	(revision bd946e4dec0434c16bceed37f87da51933bdea63)
+++ tools/Makefile.am	(revision 3fc59bdb3dcc1b79be061440b40a2cebb66b85f3)
@@ -18,5 +18,5 @@
 CFLAGS = -Wall -Wextra -O2 -g
 
-noinst_PROGRAMS = busy catchsig repeat
+noinst_PROGRAMS = busy catchsig repeat watchdog
 
 busy_SOURCES     = busy.c
@@ -24,2 +24,3 @@
 catchsig_SOURCES = catchsig.c
 repeat_SOURCES   = repeat.c
+watchdog_SOURCES = watchdog.c
Index: tools/Makefile.in
===================================================================
--- tools/Makefile.in	(revision bd946e4dec0434c16bceed37f87da51933bdea63)
+++ tools/Makefile.in	(revision 3fc59bdb3dcc1b79be061440b40a2cebb66b85f3)
@@ -92,5 +92,6 @@
 build_triplet = @build@
 host_triplet = @host@
-noinst_PROGRAMS = busy$(EXEEXT) catchsig$(EXEEXT) repeat$(EXEEXT)
+noinst_PROGRAMS = busy$(EXEEXT) catchsig$(EXEEXT) repeat$(EXEEXT) \
+	watchdog$(EXEEXT)
 subdir = tools
 ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
@@ -115,4 +116,7 @@
 repeat_OBJECTS = $(am_repeat_OBJECTS)
 repeat_LDADD = $(LDADD)
+am_watchdog_OBJECTS = watchdog.$(OBJEXT)
+watchdog_OBJECTS = $(am_watchdog_OBJECTS)
+watchdog_LDADD = $(LDADD)
 AM_V_P = $(am__v_P_@AM_V@)
 am__v_P_ = $(am__v_P_@AM_DEFAULT_V@)
@@ -143,6 +147,8 @@
 am__v_CCLD_0 = @echo "  CCLD    " $@;
 am__v_CCLD_1 = 
-SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES)
-DIST_SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES)
+SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) \
+	$(watchdog_SOURCES)
+DIST_SOURCES = $(busy_SOURCES) $(catchsig_SOURCES) $(repeat_SOURCES) \
+	$(watchdog_SOURCES)
 am__can_run_installinfo = \
   case $$AM_UPDATE_INFO_DIR in \
@@ -295,4 +301,5 @@
 catchsig_SOURCES = catchsig.c
 repeat_SOURCES = repeat.c
+watchdog_SOURCES = watchdog.c
 all: all-am
 
@@ -344,4 +351,8 @@
 	$(AM_V_CCLD)$(LINK) $(repeat_OBJECTS) $(repeat_LDADD) $(LIBS)
 
+watchdog$(EXEEXT): $(watchdog_OBJECTS) $(watchdog_DEPENDENCIES) $(EXTRA_watchdog_DEPENDENCIES) 
+	@rm -f watchdog$(EXEEXT)
+	$(AM_V_CCLD)$(LINK) $(watchdog_OBJECTS) $(watchdog_LDADD) $(LIBS)
+
 mostlyclean-compile:
 	-rm -f *.$(OBJEXT)
@@ -353,4 +364,5 @@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/catchsig.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/repeat.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/watchdog.Po@am__quote@
 
 .c.o:
Index: tools/error.c
===================================================================
--- tools/error.c	(revision 3fc59bdb3dcc1b79be061440b40a2cebb66b85f3)
+++ tools/error.c	(revision 3fc59bdb3dcc1b79be061440b40a2cebb66b85f3)
@@ -0,0 +1,10 @@
+#include <signal.h>
+#include <unistd.h>
+
+int main() {
+	// while(1);
+	sleep(2);
+	// raise(SIGABRT);
+	raise(SIGSEGV);
+	return 0;
+}
Index: tools/watchdog.c
===================================================================
--- tools/watchdog.c	(revision 3fc59bdb3dcc1b79be061440b40a2cebb66b85f3)
+++ tools/watchdog.c	(revision 3fc59bdb3dcc1b79be061440b40a2cebb66b85f3)
@@ -0,0 +1,175 @@
+#include <errno.h>
+#include <fcntl.h>
+#include <getopt.h>
+#include <signal.h>
+#include <stdbool.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/select.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <sys/wait.h>
+#include <unistd.h>
+
+char * this_cmd = NULL;
+
+void parse_args(int argc, char * argv[]);
+int run();
+void printcmd();
+
+int main(int argc, char * argv[]) {
+	parse_args(argc, argv);
+
+	int retcode = run();
+	if( !WIFEXITED(retcode) ) {
+		printf("Child Error : %d ", retcode); printcmd();
+		return retcode;
+	}
+
+	printf("Child exited normally "); printcmd();
+	return 0;
+}
+
+void usage( FILE * out, int code ) {
+	fprintf(out, "%s [OPTION] [--] N CMD\n", this_cmd);
+	fprintf(out, "Run command, killing it if it doesn't print for more than 5 continuous seconds\n\n");
+	fprintf(out, "\t-h,--help\tprint this usage message\n");
+	exit(code);
+}
+
+char ** cmd_to_run = NULL;
+pid_t child_pid = 0;
+int pipe_fds[2];
+
+void arg_error(void) {
+	fprintf(stderr,"\n");
+	usage(stderr, 1);
+}
+
+void parse_args(int argc, char * argv[]) {
+	this_cmd = argv[0];
+
+	enum { Help, };
+	static struct option long_opts[] = {
+		{ "help", no_argument, 0, Help },
+		{ 0, 0, 0, 0 }
+	}; // long_opts
+	int long_index;
+
+	int c;
+	while ( (c = getopt_long( argc, argv, "h", long_opts, &long_index)) != -1 ) {
+		switch ( c ) {
+			case Help:
+			case 'h':
+				usage(stdout, 0);
+				break;
+			default:
+				arg_error();
+				break;
+		} // switch
+	} // while
+
+	if( argc < optind + 1 ) {
+		fprintf(stderr, "Too few arguments\n");
+		arg_error();
+	}
+
+	cmd_to_run = argv + optind;
+}
+
+static void exit_handler (__attribute__((unused)) int a, __attribute__((unused)) void * b) {
+	close(pipe_fds[0]);
+	if(child_pid != 0) kill(child_pid, SIGKILL);
+}
+
+#define checked(call, ...) ({int ret = call(__VA_ARGS__); if (ret == -1) { perror(#call); exit(1); } ret;})
+
+void run_child();
+void make_noblock(int fd);
+void sink(int fd);
+int waitfd(int fd);
+
+int run() {
+	on_exit(exit_handler, NULL);
+	checked(pipe, pipe_fds);
+
+	printf("Watching command: "); printcmd();
+
+	child_pid = checked(fork);
+	if (child_pid == 0) { run_child(); }
+
+	close(pipe_fds[1]);
+	make_noblock(pipe_fds[0]);
+
+	int status;
+	while(waitpid(child_pid, &status, WNOHANG) == 0) {
+		if(waitfd(pipe_fds[0]) == 0) {
+			printf("Child Deadlocked "); printcmd();
+			exit(127);
+		}
+		sink(pipe_fds[0]);
+	}
+
+	child_pid = 0;
+	return status;
+
+	return 0;
+}
+
+void make_noblock(int fd) {
+	int flags = fcntl(fd, F_GETFL);
+	flags |= O_NONBLOCK;
+	fcntl(fd, F_SETFL, flags );
+}
+
+void sink(int fd) {
+	char buff[100];
+	int len = 100;
+	int rv;
+	do {
+		rv = read( fd, buff, len );
+	}
+	while(rv > 0);
+}
+
+int waitfd(int fd) {
+	fd_set set;
+	FD_ZERO(&set);
+	FD_SET(fd, &set);
+
+	struct timeval timeout;
+	timeout.tv_sec = 5;
+	timeout.tv_usec = 0;
+
+	int rv = select(fd + 1, &set, NULL, NULL, &timeout);
+	if(rv == -1) {
+		perror("select\n");
+		exit(1);
+	}
+	return rv;
+}
+
+void run_child() {
+	/* This is the child process. */
+	while ((dup2(pipe_fds[1], STDOUT_FILENO) == -1) && (errno == EINTR));
+
+	close(pipe_fds[1]);
+	close(pipe_fds[0]);
+
+	execvp ( *cmd_to_run, cmd_to_run);
+
+	/* The execvp  function returns only if an error occurs.  */
+	fprintf(stderr, "an error occurred in execvp\n");
+	abort ();
+}
+
+void printcmd() {
+	if(!cmd_to_run) return;
+	char ** cmd = cmd_to_run;
+	while (*cmd) {
+		printf("%s ", *cmd);
+		cmd++;
+	}
+	printf("\n");
+}
