aboutsummaryrefslogtreecommitdiffstats
path: root/Tools/portbuild/scripts/pnohang.c
blob: 8a3f01797707af65ae9099fbe1263726c5965929 (plain) (blame)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/* pnohang: executes command ($4-) with output in file ($3)
 * kills command if no output with $1 seconds with message in $2
 * usage: pnohang timeout file command args ...
 */

#include <sys/param.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
#include <signal.h>
#include <unistd.h>
#include <time.h>
#include <errno.h>
#include <fcntl.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>

int
main(int argc, char *argv[])
{
        int timeout, status, i, result, ofd;
    char *command, *outfile, *message, args[MAXPATHLEN + 1];
    char logstr[BUFSIZ + 1];
    pid_t pid, pid1, pid2, child;
    time_t now;
    struct stat st;
    struct sigaction sv;

    if (argc < 3) {
            printf("usage: %s timeout outfile message command [args...]\n",
            argv[0]);
        exit(1);
    }

    timeout = atoi(argv[1]);
    outfile = argv[2];
    message = argv[3];
    command = argv[4];

    bzero(args, MAXPATHLEN + 1);
    for (i = 4; i < argc; i++) {
            strlcat(args, argv[i], MAXPATHLEN - strlen(args));
        strlcat(args, " ", MAXPATHLEN - strlen(args));
    }

    pid = getpid();

    /*printf("timeout is %d\n", timeout);
    printf("outfile is %s\n", outfile);
    printf("message is %s\n", message);
    printf("arguments are %s", args);*/

    if ((ofd = open(outfile, O_CREAT|O_TRUNC|O_WRONLY, 0600)) == -1)
        err(1, "open");

    if (dup2(ofd, STDOUT_FILENO) == -1)
        err(1, "dup2 stdout");
    if (dup2(ofd, STDERR_FILENO) == -1)
        err(1, "dup2 stderr");

    if ((pid1 = fork()) > 0) {
            if ((pid2 = fork()) > 0) {
            sv.sa_handler = SIG_IGN;
            sigemptyset(&sv.sa_mask);
            sv.sa_flags = 0;
            sigaction(SIGTERM, &sv, 0);

            /* parent */
            child = wait(&status);
            /*printf("exited child is %d, status is %d\n", child, status);*/

            if (pid1 = child) {
            /*printf("killing process %d (second child)\n", pid2);*/
            kill(pid2, SIGTERM);
            } else {
            /*printf("killing process %d (first child)\n", pid1);*/
            kill(pid1, SIGTERM);
            }
            /* exit status in upper 8 bits, killed signal (if any) in
             * lower 8 bits
             */
            exit((status >> 8) | (status & 0xff));
        } else {
            /* second child */
            for (;;) {
            sleep(timeout/10);
            now = time(NULL);
            stat(outfile, &st);
            if ((now - st.st_mtime) > timeout) {
                /*snprintf(logstr, BUFSIZ, "logger -t %s killing %s %s, pid %d since no output in %d seconds", argv[0], args, message, pid, timeout);
                system(logstr);*/
                printf("%s: killing %s (%s, pid %d and %d) since no output in %d seconds since %s", argv[0], args, message, pid1, pid, timeout, ctime(&now));
                printf("ps jgx before the signal\n");
                system("ps jgxww");
                sleep(1); /* give it a chance to output the message */
                kill(pid1, SIGTERM);
                sleep(1);
                kill(pid, SIGTERM);
                sleep(1);
                system("ps jgxww");
                exit(1);
            }
            }
        }
    } else {
            /* first child */
        /*printf("executing %s\n", args);*/
        result = execvp(command, argv + 4);
        if (result < 0) {
            printf("Failed to exec %s: %s\n", args, strerror(errno));
            exit(1);
        }
    }

    return 0;
}