1f08c3bdfSopenharmony_ci/*
2f08c3bdfSopenharmony_ci * Copyright (c) 2004, Bull S.A..  All rights reserved.
3f08c3bdfSopenharmony_ci * Created by: Sebastien Decugis
4f08c3bdfSopenharmony_ci
5f08c3bdfSopenharmony_ci * This program is free software; you can redistribute it and/or modify it
6f08c3bdfSopenharmony_ci * under the terms of version 2 of the GNU General Public License as
7f08c3bdfSopenharmony_ci * published by the Free Software Foundation.
8f08c3bdfSopenharmony_ci *
9f08c3bdfSopenharmony_ci * This program is distributed in the hope that it would be useful, but
10f08c3bdfSopenharmony_ci * WITHOUT ANY WARRANTY; without even the implied warranty of
11f08c3bdfSopenharmony_ci * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
12f08c3bdfSopenharmony_ci *
13f08c3bdfSopenharmony_ci * You should have received a copy of the GNU General Public License along
14f08c3bdfSopenharmony_ci * with this program; if not, write the Free Software Foundation, Inc.,
15f08c3bdfSopenharmony_ci * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16f08c3bdfSopenharmony_ci
17f08c3bdfSopenharmony_ci * This utility software allows to run any executable file with a timeout limit.
18f08c3bdfSopenharmony_ci * The syntax is:
19f08c3bdfSopenharmony_ci * $ ./t0 n exe arglist
20f08c3bdfSopenharmony_ci *  where n is the timeout duration in seconds,
21f08c3bdfSopenharmony_ci *        exe is the executable filename to run,
22f08c3bdfSopenharmony_ci *        arglist is the arguments to be passed to executable.
23f08c3bdfSopenharmony_ci *
24f08c3bdfSopenharmony_ci * The use of this utility is intended to be "transparent", which means
25f08c3bdfSopenharmony_ci * everything is as if
26f08c3bdfSopenharmony_ci * $ exe arglist
27f08c3bdfSopenharmony_ci *   had been called, and a call to "alarm(n)" had been added inside exe's main.
28f08c3bdfSopenharmony_ci *
29f08c3bdfSopenharmony_ci * SPECIAL CASE:
30f08c3bdfSopenharmony_ci * $ ./t0 0
31f08c3bdfSopenharmony_ci *  Here another arg is not required. This special case will return immediatly
32f08c3bdfSopenharmony_ci *  as if it has been timedout. This is useful to check a timeout return code value.
33f08c3bdfSopenharmony_ci *
34f08c3bdfSopenharmony_ci */
35f08c3bdfSopenharmony_ci
36f08c3bdfSopenharmony_ci#include <sys/types.h>
37f08c3bdfSopenharmony_ci#include <sys/wait.h>
38f08c3bdfSopenharmony_ci#include <errno.h>
39f08c3bdfSopenharmony_ci#include <pthread.h>
40f08c3bdfSopenharmony_ci#include <signal.h>
41f08c3bdfSopenharmony_ci#include <stdio.h>
42f08c3bdfSopenharmony_ci#include <stdlib.h>
43f08c3bdfSopenharmony_ci#include <string.h>
44f08c3bdfSopenharmony_ci#include <unistd.h>
45f08c3bdfSopenharmony_ci
46f08c3bdfSopenharmony_cistatic pid_t pid_to_monitor;
47f08c3bdfSopenharmony_ci
48f08c3bdfSopenharmony_cistatic void sighandler(int sig)
49f08c3bdfSopenharmony_ci{
50f08c3bdfSopenharmony_ci	if (0 < pid_to_monitor) {
51f08c3bdfSopenharmony_ci		if (kill(pid_to_monitor, SIGKILL) == -1) {
52f08c3bdfSopenharmony_ci			perror("kill(.., SIGKILL) failed");
53f08c3bdfSopenharmony_ci			abort();	/* Something's really screwed up if we get here. */
54f08c3bdfSopenharmony_ci		}
55f08c3bdfSopenharmony_ci		waitpid(pid_to_monitor, NULL, WNOHANG);
56f08c3bdfSopenharmony_ci	}
57f08c3bdfSopenharmony_ci	exit(SIGALRM + 128);
58f08c3bdfSopenharmony_ci}
59f08c3bdfSopenharmony_ci
60f08c3bdfSopenharmony_ciint main(int argc, char *argv[])
61f08c3bdfSopenharmony_ci{
62f08c3bdfSopenharmony_ci	int status, timeout;
63f08c3bdfSopenharmony_ci
64f08c3bdfSopenharmony_ci	/* Special case: t0 0 */
65f08c3bdfSopenharmony_ci	if (argc == 2 && (strncmp(argv[1], "0", 1) == 0)) {
66f08c3bdfSopenharmony_ci		kill(getpid(), SIGALRM);
67f08c3bdfSopenharmony_ci		exit(1);
68f08c3bdfSopenharmony_ci	}
69f08c3bdfSopenharmony_ci
70f08c3bdfSopenharmony_ci	/* General case */
71f08c3bdfSopenharmony_ci	if (argc < 3) {
72f08c3bdfSopenharmony_ci		printf("\nUsage: \n");
73f08c3bdfSopenharmony_ci		printf("  $ %s n exe arglist\n", argv[0]);
74f08c3bdfSopenharmony_ci		printf("  $ %s 0\n", argv[0]);
75f08c3bdfSopenharmony_ci		printf("\nWhere:\n");
76f08c3bdfSopenharmony_ci		printf("  n       is the timeout duration in seconds,\n");
77f08c3bdfSopenharmony_ci		printf("  exe     is the executable filename to run,\n");
78f08c3bdfSopenharmony_ci		printf
79f08c3bdfSopenharmony_ci		    ("  arglist is the arguments to be passed to executable.\n\n");
80f08c3bdfSopenharmony_ci		printf
81f08c3bdfSopenharmony_ci		    ("  The second use case will emulate an immediate timeout.\n\n");
82f08c3bdfSopenharmony_ci		exit(1);
83f08c3bdfSopenharmony_ci	}
84f08c3bdfSopenharmony_ci
85f08c3bdfSopenharmony_ci	timeout = atoi(argv[1]);
86f08c3bdfSopenharmony_ci	if (timeout < 1) {
87f08c3bdfSopenharmony_ci		fprintf(stderr,
88f08c3bdfSopenharmony_ci			"Invalid timeout value \"%s\". Timeout must be a positive integer.\n",
89f08c3bdfSopenharmony_ci			argv[1]);
90f08c3bdfSopenharmony_ci		exit(1);
91f08c3bdfSopenharmony_ci	}
92f08c3bdfSopenharmony_ci
93f08c3bdfSopenharmony_ci	if (signal(SIGALRM, sighandler) == SIG_ERR) {
94f08c3bdfSopenharmony_ci		perror("signal failed");
95f08c3bdfSopenharmony_ci		exit(1);
96f08c3bdfSopenharmony_ci	}
97f08c3bdfSopenharmony_ci
98f08c3bdfSopenharmony_ci	alarm(timeout);
99f08c3bdfSopenharmony_ci
100f08c3bdfSopenharmony_ci	switch (pid_to_monitor = fork()) {
101f08c3bdfSopenharmony_ci	case -1:
102f08c3bdfSopenharmony_ci		perror("fork failed");
103f08c3bdfSopenharmony_ci		exit(1);
104f08c3bdfSopenharmony_ci	case 0:
105f08c3bdfSopenharmony_ci		setpgid(0, 0);
106f08c3bdfSopenharmony_ci		execvp(argv[2], &argv[2]);
107f08c3bdfSopenharmony_ci		perror("execvp failed");
108f08c3bdfSopenharmony_ci		exit(1);
109f08c3bdfSopenharmony_ci	default:
110f08c3bdfSopenharmony_ci
111f08c3bdfSopenharmony_ci		for (;;) {
112f08c3bdfSopenharmony_ci			if (waitpid(pid_to_monitor, &status, 0) ==
113f08c3bdfSopenharmony_ci			    pid_to_monitor)
114f08c3bdfSopenharmony_ci				break;
115f08c3bdfSopenharmony_ci			else if (errno == EINTR) {
116f08c3bdfSopenharmony_ci				perror("waitpid failed");
117f08c3bdfSopenharmony_ci				exit(1);
118f08c3bdfSopenharmony_ci			}
119f08c3bdfSopenharmony_ci		}
120f08c3bdfSopenharmony_ci		/* Relay the child's status back to run-tests.sh */
121f08c3bdfSopenharmony_ci		if (WIFEXITED(status))
122f08c3bdfSopenharmony_ci			exit(WEXITSTATUS(status));
123f08c3bdfSopenharmony_ci		else if (WIFSIGNALED(status))
124f08c3bdfSopenharmony_ci			exit(WTERMSIG(status) + 128);
125f08c3bdfSopenharmony_ci
126f08c3bdfSopenharmony_ci	}
127f08c3bdfSopenharmony_ci
128f08c3bdfSopenharmony_ci	exit(1);
129f08c3bdfSopenharmony_ci}
130