aboutsummaryrefslogtreecommitdiff
path: root/coreutils/timeout.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/timeout.c')
-rw-r--r--coreutils/timeout.c76
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
52static HANDLE child = INVALID_HANDLE_VALUE;
53
54static 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 */
62static 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
50static NOINLINE int timeout_wait(int timeout, pid_t pid) 78static 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
65int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 94int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
66int timeout_main(int argc UNUSED_PARAM, char **argv) 95int 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}