aboutsummaryrefslogtreecommitdiff
path: root/coreutils/timeout.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/timeout.c')
-rw-r--r--coreutils/timeout.c71
1 files changed, 70 insertions, 1 deletions
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index 06108f315..74df31d10 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -42,11 +42,38 @@
42//usage: "[-s SIG] [-k KILL_SECS] SECS PROG ARGS" 42//usage: "[-s SIG] [-k KILL_SECS] SECS PROG ARGS"
43//usage:#define timeout_full_usage "\n\n" 43//usage:#define timeout_full_usage "\n\n"
44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n" 44//usage: "Run PROG. Send SIG to it if it is not gone in SECS seconds.\n"
45//usage: "Default SIG: TERM." 45//usage: "Default SIG: TERM.\n"
46//usage: "If it still exists in KILL_SECS seconds, send KILL.\n" 46//usage: "If it still exists in KILL_SECS seconds, send KILL.\n"
47 47
48#include "libbb.h" 48#include "libbb.h"
49 49
50#if ENABLE_PLATFORM_MINGW32
51static HANDLE child = INVALID_HANDLE_VALUE;
52
53static void kill_child(void)
54{
55 if (child != INVALID_HANDLE_VALUE) {
56 kill_SIGTERM_by_handle(child);
57 }
58}
59
60/* Return TRUE if child exits before timeout expires */
61static NOINLINE int timeout_wait(int timeout, HANDLE proc, DWORD *status)
62{
63 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
64 while (1) {
65 sleep1();
66 if (--timeout <= 0)
67 break;
68 if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0) {
69 /* process is gone */
70 GetExitCodeProcess(proc, status);
71 return TRUE;
72 }
73 }
74 return FALSE;
75}
76#else
50static NOINLINE int timeout_wait(int timeout, pid_t pid) 77static NOINLINE int timeout_wait(int timeout, pid_t pid)
51{ 78{
52 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ 79 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
@@ -61,12 +88,18 @@ static NOINLINE int timeout_wait(int timeout, pid_t pid)
61 } 88 }
62 return EXIT_FAILURE; 89 return EXIT_FAILURE;
63} 90}
91#endif
64 92
65int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 93int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
66int timeout_main(int argc UNUSED_PARAM, char **argv) 94int timeout_main(int argc UNUSED_PARAM, char **argv)
67{ 95{
68 int signo; 96 int signo;
97#if !ENABLE_PLATFORM_MINGW32
69 int status; 98 int status;
99#else
100 intptr_t ret;
101 DWORD status = EXIT_SUCCESS;
102#endif
70 int parent = 0; 103 int parent = 0;
71 int timeout; 104 int timeout;
72 int kill_timeout; 105 int kill_timeout;
@@ -77,6 +110,10 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
77 const char *opt_s = "TERM"; 110 const char *opt_s = "TERM";
78 char *opt_k = NULL; 111 char *opt_k = NULL;
79 112
113#if ENABLE_PLATFORM_MINGW32
114 xfunc_error_retval = 125;
115#endif
116
80 /* -p option is not documented, it is needed to support NOMMU. */ 117 /* -p option is not documented, it is needed to support NOMMU. */
81 118
82 /* -t SECONDS; -p PARENT_PID */ 119 /* -t SECONDS; -p PARENT_PID */
@@ -85,7 +122,11 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
85 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ 122 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
86 123
87 signo = get_signum(opt_s); 124 signo = get_signum(opt_s);
125#if !ENABLE_PLATFORM_MINGW32
88 if (signo < 0) 126 if (signo < 0)
127#else
128 if (signo != SIGTERM && signo != SIGKILL && signo != 0)
129#endif
89 bb_error_msg_and_die("unknown signal '%s'", opt_s); 130 bb_error_msg_and_die("unknown signal '%s'", opt_s);
90 131
91 kill_timeout = 0; 132 kill_timeout = 0;
@@ -98,6 +139,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
98 if (!argv[optind]) /* no PROG? */ 139 if (!argv[optind]) /* no PROG? */
99 bb_show_usage(); 140 bb_show_usage();
100 141
142#if !ENABLE_PLATFORM_MINGW32
101 /* We want to create a grandchild which will watch 143 /* We want to create a grandchild which will watch
102 * and kill the grandparent. Other methods: 144 * and kill the grandparent. Other methods:
103 * making parent watch child disrupts parent<->child link 145 * making parent watch child disrupts parent<->child link
@@ -150,4 +192,31 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
150 argv[1] = sv2; 192 argv[1] = sv2;
151#endif 193#endif
152 BB_EXECVP_or_die(argv); 194 BB_EXECVP_or_die(argv);
195#else /* ENABLE_PLATFORM_MINGW32 */
196 argv += optind;
197 if ((ret=mingw_spawn_proc((const char **)argv)) == -1) {
198 xfunc_error_retval = errno == EACCES ? 126 : 127;
199 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
200 }
201
202 child = (HANDLE)ret;
203 atexit(kill_child);
204 if (timeout_wait(timeout, child, &status))
205 goto finish;
206 status = signo == SIGKILL ? 137 : 124;
207
208 pid = (pid_t)GetProcessId(child);
209 kill(pid, signo);
210
211 if (kill_timeout > 0) {
212 if (timeout_wait(kill_timeout, child, &status))
213 goto finish;
214 kill(parent, SIGKILL);
215 status = 137;
216 }
217 finish:
218 CloseHandle(child);
219 child = INVALID_HANDLE_VALUE;
220 return status;
221#endif
153} 222}