aboutsummaryrefslogtreecommitdiff
path: root/coreutils/timeout.c
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils/timeout.c')
-rw-r--r--coreutils/timeout.c73
1 files changed, 73 insertions, 0 deletions
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index 84299a0a5..58f96192b 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -43,10 +43,35 @@
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."
46//usage: IF_PLATFORM_MINGW32("\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 pid_t pid = (pid_t)GetProcessId(child);
58 if (pid)
59 kill(pid, SIGTERM);
60 }
61}
62
63/* Return TRUE if child exits before timeout expires */
64static NOINLINE int timeout_wait(duration_t timeout, HANDLE proc, DWORD *status)
65{
66 DWORD t = (DWORD)(timeout * 1000);
67 if (WaitForSingleObject(proc, t) == WAIT_OBJECT_0) {
68 /* process is gone */
69 GetExitCodeProcess(proc, status);
70 return TRUE;
71 }
72 return FALSE;
73}
74#else
50static NOINLINE int timeout_wait(duration_t timeout, pid_t pid) 75static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
51{ 76{
52 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ 77 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
@@ -66,13 +91,19 @@ static NOINLINE int timeout_wait(duration_t timeout, pid_t pid)
66 } 91 }
67 return EXIT_FAILURE; 92 return EXIT_FAILURE;
68} 93}
94#endif
69 95
70int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 96int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
71int timeout_main(int argc UNUSED_PARAM, char **argv) 97int timeout_main(int argc UNUSED_PARAM, char **argv)
72{ 98{
73 int signo; 99 int signo;
100#if !ENABLE_PLATFORM_MINGW32
74 int status; 101 int status;
75 int parent = 0; 102 int parent = 0;
103#else
104 intptr_t ret;
105 DWORD status = EXIT_SUCCESS;
106#endif
76 duration_t timeout; 107 duration_t timeout;
77 duration_t kill_timeout; 108 duration_t kill_timeout;
78 pid_t pid; 109 pid_t pid;
@@ -82,15 +113,27 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
82 const char *opt_s = "TERM"; 113 const char *opt_s = "TERM";
83 char *opt_k = NULL; 114 char *opt_k = NULL;
84 115
116#if ENABLE_PLATFORM_MINGW32
117 xfunc_error_retval = 125;
118#endif
119
85 /* -p option is not documented, it is needed to support NOMMU. */ 120 /* -p option is not documented, it is needed to support NOMMU. */
86 121
87 /* -t SECONDS; -p PARENT_PID */ 122 /* -t SECONDS; -p PARENT_PID */
88 /* '+': stop at first non-option */ 123 /* '+': stop at first non-option */
124#if !ENABLE_PLATFORM_MINGW32
89 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent); 125 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent);
126#else
127 getopt32(argv, "+s:k:", &opt_s, &opt_k);
128#endif
90 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ 129 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
91 130
92 signo = get_signum(opt_s); 131 signo = get_signum(opt_s);
132#if !ENABLE_PLATFORM_MINGW32
93 if (signo < 0) 133 if (signo < 0)
134#else
135 if (!is_valid_signal(signo))
136#endif
94 bb_error_msg_and_die("unknown signal '%s'", opt_s); 137 bb_error_msg_and_die("unknown signal '%s'", opt_s);
95 138
96 kill_timeout = 0; 139 kill_timeout = 0;
@@ -103,6 +146,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
103 if (!argv[optind]) /* no PROG? */ 146 if (!argv[optind]) /* no PROG? */
104 bb_show_usage(); 147 bb_show_usage();
105 148
149#if !ENABLE_PLATFORM_MINGW32
106 /* We want to create a grandchild which will watch 150 /* We want to create a grandchild which will watch
107 * and kill the grandparent. Other methods: 151 * and kill the grandparent. Other methods:
108 * making parent watch child disrupts parent<->child link 152 * making parent watch child disrupts parent<->child link
@@ -155,4 +199,33 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
155 argv[1] = sv2; 199 argv[1] = sv2;
156#endif 200#endif
157 BB_EXECVP_or_die(argv); 201 BB_EXECVP_or_die(argv);
202#else /* ENABLE_PLATFORM_MINGW32 */
203 argv += optind;
204 if ((ret=mingw_spawn_proc((const char **)argv)) == -1) {
205 xfunc_error_retval = errno == EACCES ? 126 : 127;
206 bb_perror_msg_and_die("can't execute '%s'", argv[0]);
207 }
208
209 child = (HANDLE)ret;
210 atexit(kill_child);
211 if (timeout_wait(timeout, child, &status))
212 goto finish;
213 status = signo == SIGKILL ? 137 : 124;
214
215 pid = (pid_t)GetProcessId(child);
216 if (pid) {
217 kill(pid, signo);
218
219 if (kill_timeout > 0) {
220 if (timeout_wait(kill_timeout, child, &status))
221 goto finish;
222 kill(pid, SIGKILL);
223 status = 137;
224 }
225 }
226 finish:
227 CloseHandle(child);
228 child = INVALID_HANDLE_VALUE;
229 return status;
230#endif
158} 231}