diff options
Diffstat (limited to 'coreutils/timeout.c')
-rw-r--r-- | coreutils/timeout.c | 76 |
1 files changed, 75 insertions, 1 deletions
diff --git a/coreutils/timeout.c b/coreutils/timeout.c index 18aa9ebeb..0d6a2c612 100644 --- a/coreutils/timeout.c +++ b/coreutils/timeout.c | |||
@@ -42,11 +42,39 @@ | |||
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: IF_NOT_PLATFORM_MINGW32("Default SIG: TERM.") |
46 | //usage: IF_PLATFORM_MINGW32("Default SIG: TERM.\n") | ||
46 | //usage: "If it still exists in KILL_SECS seconds, send KILL.\n" | 47 | //usage: "If it still exists in KILL_SECS seconds, send KILL.\n" |
47 | 48 | ||
48 | #include "libbb.h" | 49 | #include "libbb.h" |
49 | 50 | ||
51 | #if ENABLE_PLATFORM_MINGW32 | ||
52 | static HANDLE child = INVALID_HANDLE_VALUE; | ||
53 | |||
54 | static void kill_child(void) | ||
55 | { | ||
56 | if (child != INVALID_HANDLE_VALUE) { | ||
57 | kill_signal_by_handle(child, SIGTERM); | ||
58 | } | ||
59 | } | ||
60 | |||
61 | /* Return TRUE if child exits before timeout expires */ | ||
62 | static NOINLINE int timeout_wait(int timeout, HANDLE proc, DWORD *status) | ||
63 | { | ||
64 | /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ | ||
65 | while (1) { | ||
66 | sleep1(); | ||
67 | if (--timeout <= 0) | ||
68 | break; | ||
69 | if (WaitForSingleObject(proc, 0) == WAIT_OBJECT_0) { | ||
70 | /* process is gone */ | ||
71 | GetExitCodeProcess(proc, status); | ||
72 | return TRUE; | ||
73 | } | ||
74 | } | ||
75 | return FALSE; | ||
76 | } | ||
77 | #else | ||
50 | static NOINLINE int timeout_wait(int timeout, pid_t pid) | 78 | static NOINLINE int timeout_wait(int timeout, pid_t pid) |
51 | { | 79 | { |
52 | /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ | 80 | /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ |
@@ -61,13 +89,19 @@ static NOINLINE int timeout_wait(int timeout, pid_t pid) | |||
61 | } | 89 | } |
62 | return EXIT_FAILURE; | 90 | return EXIT_FAILURE; |
63 | } | 91 | } |
92 | #endif | ||
64 | 93 | ||
65 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; | 94 | int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; |
66 | int timeout_main(int argc UNUSED_PARAM, char **argv) | 95 | int timeout_main(int argc UNUSED_PARAM, char **argv) |
67 | { | 96 | { |
68 | int signo; | 97 | int signo; |
98 | #if !ENABLE_PLATFORM_MINGW32 | ||
69 | int status; | 99 | int status; |
70 | int parent = 0; | 100 | int parent = 0; |
101 | #else | ||
102 | intptr_t ret; | ||
103 | DWORD status = EXIT_SUCCESS; | ||
104 | #endif | ||
71 | int timeout; | 105 | int timeout; |
72 | int kill_timeout; | 106 | int kill_timeout; |
73 | pid_t pid; | 107 | pid_t pid; |
@@ -77,15 +111,27 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
77 | const char *opt_s = "TERM"; | 111 | const char *opt_s = "TERM"; |
78 | char *opt_k = NULL; | 112 | char *opt_k = NULL; |
79 | 113 | ||
114 | #if ENABLE_PLATFORM_MINGW32 | ||
115 | xfunc_error_retval = 125; | ||
116 | #endif | ||
117 | |||
80 | /* -p option is not documented, it is needed to support NOMMU. */ | 118 | /* -p option is not documented, it is needed to support NOMMU. */ |
81 | 119 | ||
82 | /* -t SECONDS; -p PARENT_PID */ | 120 | /* -t SECONDS; -p PARENT_PID */ |
83 | /* '+': stop at first non-option */ | 121 | /* '+': stop at first non-option */ |
122 | #if !ENABLE_PLATFORM_MINGW32 | ||
84 | getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent); | 123 | getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent); |
124 | #else | ||
125 | getopt32(argv, "+s:k:", &opt_s, &opt_k); | ||
126 | #endif | ||
85 | /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ | 127 | /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ |
86 | 128 | ||
87 | signo = get_signum(opt_s); | 129 | signo = get_signum(opt_s); |
130 | #if !ENABLE_PLATFORM_MINGW32 | ||
88 | if (signo < 0) | 131 | if (signo < 0) |
132 | #else | ||
133 | if (!is_valid_signal(signo)) | ||
134 | #endif | ||
89 | bb_error_msg_and_die("unknown signal '%s'", opt_s); | 135 | bb_error_msg_and_die("unknown signal '%s'", opt_s); |
90 | 136 | ||
91 | kill_timeout = 0; | 137 | kill_timeout = 0; |
@@ -98,6 +144,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
98 | if (!argv[optind]) /* no PROG? */ | 144 | if (!argv[optind]) /* no PROG? */ |
99 | bb_show_usage(); | 145 | bb_show_usage(); |
100 | 146 | ||
147 | #if !ENABLE_PLATFORM_MINGW32 | ||
101 | /* We want to create a grandchild which will watch | 148 | /* We want to create a grandchild which will watch |
102 | * and kill the grandparent. Other methods: | 149 | * and kill the grandparent. Other methods: |
103 | * making parent watch child disrupts parent<->child link | 150 | * making parent watch child disrupts parent<->child link |
@@ -150,4 +197,31 @@ int timeout_main(int argc UNUSED_PARAM, char **argv) | |||
150 | argv[1] = sv2; | 197 | argv[1] = sv2; |
151 | #endif | 198 | #endif |
152 | BB_EXECVP_or_die(argv); | 199 | BB_EXECVP_or_die(argv); |
200 | #else /* ENABLE_PLATFORM_MINGW32 */ | ||
201 | argv += optind; | ||
202 | if ((ret=mingw_spawn_proc((const char **)argv)) == -1) { | ||
203 | xfunc_error_retval = errno == EACCES ? 126 : 127; | ||
204 | bb_perror_msg_and_die("can't execute '%s'", argv[0]); | ||
205 | } | ||
206 | |||
207 | child = (HANDLE)ret; | ||
208 | atexit(kill_child); | ||
209 | if (timeout_wait(timeout, child, &status)) | ||
210 | goto finish; | ||
211 | status = signo == SIGKILL ? 137 : 124; | ||
212 | |||
213 | pid = (pid_t)GetProcessId(child); | ||
214 | kill(pid, signo); | ||
215 | |||
216 | if (kill_timeout > 0) { | ||
217 | if (timeout_wait(kill_timeout, child, &status)) | ||
218 | goto finish; | ||
219 | kill(pid, SIGKILL); | ||
220 | status = 137; | ||
221 | } | ||
222 | finish: | ||
223 | CloseHandle(child); | ||
224 | child = INVALID_HANDLE_VALUE; | ||
225 | return status; | ||
226 | #endif | ||
153 | } | 227 | } |