1#include <sys/time.h> 2#include <sys/types.h> 3#include <sys/stat.h> 4#include <sys/wait.h> 5#include <fcntl.h> 6#include <unistd.h> 7#include <errno.h> 8#include <signal.h> 9 10#include <stdlib.h> 11#include <stdio.h> 12 13pid_t childpid; 14 15void kill_child_exit(int ignored) 16{ 17 kill(childpid, SIGKILL); 18 exit(1); 19} 20 21 22int main(int argc, char *argv[]) 23{ 24 char *logfile; 25 int timeout = argc > 3 ? atoi(argv[3]) : 5; 26 int pipe_fds[2]; 27 if (argc < 3) { 28 fprintf(stderr, "Usage: %s dp-program logfile [timeout]\n", argv[0]); 29 exit(1); 30 } 31 logfile = argv[2]; 32 if (timeout <= 0) { 33 fprintf(stderr, "Timeout must be positive non-zero\n"); 34 exit(1); 35 } 36 37 if (pipe(pipe_fds) != 0) { 38 perror("Creating pipe in main"); 39 exit(1); 40 } 41 childpid = fork(); 42 if (childpid < 0) { 43 perror("forking in main"); 44 exit(1); 45 } 46 if (childpid == 0) { 47 /* in child */ 48 /* want to write stdout to pipe, stderr to log file */ 49 /* stdin must be the file test_coopers.sml */ 50 int logfile_fd; 51 char *child_args[2] = {argv[1], 0}; 52 if (dup2(pipe_fds[1], STDOUT_FILENO) == -1) { 53 perror("dup2 for stdout in child"); 54 exit(1); 55 } 56 close(STDIN_FILENO); 57 logfile_fd = open(logfile, O_WRONLY | O_CREAT | O_TRUNC, 0644); 58 if (logfile_fd == -1) { 59 perror("child opening logfile"); 60 exit(1); 61 } 62 if (dup2(logfile_fd, STDERR_FILENO) == -1) { 63 perror("dup2 for stderr in child"); 64 exit(1); 65 } 66 /* can now exec hol */ 67 execv(child_args[0], child_args); 68 perror("exec in child"); 69 exit(1); 70 } else { 71 /* in parent */ 72 fd_set to_watch; 73 struct timeval tv; 74 char buffer[80]; 75 int numread, read_anything = 0; 76 signal(SIGINT, kill_child_exit); 77 FD_ZERO(&to_watch); 78 FD_SET(pipe_fds[0], &to_watch); 79 select(pipe_fds[0] + 1, &to_watch, 0, 0, &tv); 80 while (1) { 81 int retval; 82 FD_SET(pipe_fds[0], &to_watch); 83 /* need to do this potentially redundant assignment to tv because 84 select leaves the value of tv undefined */ 85 tv.tv_sec = timeout; 86 tv.tv_usec = 0; 87 retval = select(pipe_fds[0] + 1, &to_watch, 0, 0, &tv); 88 if (retval == -1) { 89 perror("select in parent"); 90 exit(1); 91 } 92 if (retval == 0) { 93 /* nothing new to read - maybe the child has exited, 94 otherwise interrupt the child */ 95 int status, wait_retval; 96 wait_retval = waitpid(childpid, &status, WNOHANG); 97 if (wait_retval == 0) { 98 if (read_anything) { 99 /* child still fine, interrupt it to wake it up */ 100 if (kill(childpid, SIGINT) == -1) { 101 perror("kill in parent"); 102 exit(1); 103 } 104 } 105 continue; 106 } else if (wait_retval < 0) { 107 perror("parent waiting"); 108 exit(1); 109 } 110 if (WIFEXITED(status)) { 111 fprintf(stderr, "Child exited with code %d\n", WEXITSTATUS(status)); 112 exit(1); 113 } else /* (WIFSIGNALLED(status)) is true */ { 114 fprintf(stderr, "Child was stopped by signal %d\n", 115 WTERMSIG(status)); 116 exit(1); 117 } 118 } 119 /* retval was one */ 120 numread = read(pipe_fds[0], buffer, 80); 121 if (numread < 0) { 122 if (errno == EINTR) continue; 123 perror("read in parent"); 124 exit(1); 125 } 126 if (numread == 0) { exit(0); } 127 read_anything = 1; 128 write(STDOUT_FILENO, buffer, numread); 129 } 130 } 131} 132 133 134 135 136 137