diff options
Diffstat (limited to 'coreutils/timeout.c')
-rw-r--r-- | coreutils/timeout.c | 71 |
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 | ||
51 | static HANDLE child = INVALID_HANDLE_VALUE; | ||
52 | |||
53 | static 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 */ | ||
61 | static 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 | ||
50 | static NOINLINE int timeout_wait(int timeout, pid_t pid) | 77 | static 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 | ||
65 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 93 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
66 | int timeout_main(int argc UNUSED_PARAM, char **argv) | 94 | int 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 | } |