source: tools/watchdog.c @ 4b75ae9

Last change on this file since 4b75ae9 was 7bdcac1, checked in by Thierry Delisle <tdelisle@…>, 6 years ago

Added the option to make longrun tests run until failure

  • Property mode set to 100644
File size: 3.3 KB
RevLine 
[7bdcac1]1#include <errno.h>
2#include <fcntl.h>
3#include <getopt.h>
4#include <signal.h>
5#include <stdbool.h>
6#include <stdio.h>
7#include <stdlib.h>
8#include <string.h>
9#include <sys/select.h>
10#include <sys/stat.h>
11#include <sys/types.h>
12#include <sys/wait.h>
13#include <unistd.h>
14
15char * this_cmd = NULL;
16
17void parse_args(int argc, char * argv[]);
18int run();
19void printcmd();
20
21int main(int argc, char * argv[]) {
22        parse_args(argc, argv);
23
24        int retcode = run();
25        if( !WIFEXITED(retcode) ) {
26                printf("Child Error : %d ", retcode); printcmd();
27                return retcode;
28        }
29
30        printf("Child exited normally "); printcmd();
31        return 0;
32}
33
34void usage( FILE * out, int code ) {
35        fprintf(out, "%s [OPTION] [--] N CMD\n", this_cmd);
36        fprintf(out, "Run command, killing it if it doesn't print for more than 5 continuous seconds\n\n");
37        fprintf(out, "\t-h,--help\tprint this usage message\n");
38        exit(code);
39}
40
41char ** cmd_to_run = NULL;
42pid_t child_pid = 0;
43int pipe_fds[2];
44
45void arg_error(void) {
46        fprintf(stderr,"\n");
47        usage(stderr, 1);
48}
49
50void parse_args(int argc, char * argv[]) {
51        this_cmd = argv[0];
52
53        enum { Help, };
54        static struct option long_opts[] = {
55                { "help", no_argument, 0, Help },
56                { 0, 0, 0, 0 }
57        }; // long_opts
58        int long_index;
59
60        int c;
61        while ( (c = getopt_long( argc, argv, "h", long_opts, &long_index)) != -1 ) {
62                switch ( c ) {
63                        case Help:
64                        case 'h':
65                                usage(stdout, 0);
66                                break;
67                        default:
68                                arg_error();
69                                break;
70                } // switch
71        } // while
72
73        if( argc < optind + 1 ) {
74                fprintf(stderr, "Too few arguments\n");
75                arg_error();
76        }
77
78        cmd_to_run = argv + optind;
79}
80
81static void exit_handler (__attribute__((unused)) int a, __attribute__((unused)) void * b) {
82        close(pipe_fds[0]);
83        if(child_pid != 0) kill(child_pid, SIGKILL);
84}
85
86#define checked(call, ...) ({int ret = call(__VA_ARGS__); if (ret == -1) { perror(#call); exit(1); } ret;})
87
88void run_child();
89void make_noblock(int fd);
90void sink(int fd);
91int waitfd(int fd);
92
93int run() {
94        on_exit(exit_handler, NULL);
95        checked(pipe, pipe_fds);
96
97        printf("Watching command: "); printcmd();
98
99        child_pid = checked(fork);
100        if (child_pid == 0) { run_child(); }
101
102        close(pipe_fds[1]);
103        make_noblock(pipe_fds[0]);
104
105        int status;
106        while(waitpid(child_pid, &status, WNOHANG) == 0) {
107                if(waitfd(pipe_fds[0]) == 0) {
108                        printf("Child Deadlocked "); printcmd();
109                        exit(127);
110                }
111                sink(pipe_fds[0]);
112        }
113
114        child_pid = 0;
115        return status;
116
117        return 0;
118}
119
120void make_noblock(int fd) {
121        int flags = fcntl(fd, F_GETFL);
122        flags |= O_NONBLOCK;
123        fcntl(fd, F_SETFL, flags );
124}
125
126void sink(int fd) {
127        char buff[100];
128        int len = 100;
129        int rv;
130        do {
131                rv = read( fd, buff, len );
132        }
133        while(rv > 0);
134}
135
136int waitfd(int fd) {
137        fd_set set;
138        FD_ZERO(&set);
139        FD_SET(fd, &set);
140
141        struct timeval timeout;
142        timeout.tv_sec = 5;
143        timeout.tv_usec = 0;
144
145        int rv = select(fd + 1, &set, NULL, NULL, &timeout);
146        if(rv == -1) {
147                perror("select\n");
148                exit(1);
149        }
150        return rv;
151}
152
153void run_child() {
154        /* This is the child process. */
155        while ((dup2(pipe_fds[1], STDOUT_FILENO) == -1) && (errno == EINTR));
156
157        close(pipe_fds[1]);
158        close(pipe_fds[0]);
159
160        execvp ( *cmd_to_run, cmd_to_run);
161
162        /* The execvp  function returns only if an error occurs.  */
163        fprintf(stderr, "an error occurred in execvp\n");
164        abort ();
165}
166
167void printcmd() {
168        if(!cmd_to_run) return;
169        char ** cmd = cmd_to_run;
170        while (*cmd) {
171                printf("%s ", *cmd);
172                cmd++;
173        }
174        printf("\n");
175}
Note: See TracBrowser for help on using the repository browser.