aboutsummaryrefslogtreecommitdiff
path: root/coreutils
diff options
context:
space:
mode:
Diffstat (limited to 'coreutils')
-rw-r--r--coreutils/printf.c2
-rw-r--r--coreutils/timeout.c84
-rw-r--r--coreutils/uudecode.c11
3 files changed, 71 insertions, 26 deletions
diff --git a/coreutils/printf.c b/coreutils/printf.c
index cc26ecd03..da129f909 100644
--- a/coreutils/printf.c
+++ b/coreutils/printf.c
@@ -378,7 +378,7 @@ static char **print_formatted(char *f, char **argv, int *conv_err)
378 } 378 }
379 break; 379 break;
380 } 380 }
381 if (*f && strchr("-+ #", *f)) { 381 while (*f && strchr("-+ #0", *f)) {
382 ++f; 382 ++f;
383 ++direc_length; 383 ++direc_length;
384 } 384 }
diff --git a/coreutils/timeout.c b/coreutils/timeout.c
index b161f4e91..74df31d10 100644
--- a/coreutils/timeout.c
+++ b/coreutils/timeout.c
@@ -39,10 +39,11 @@
39//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o 39//kbuild:lib-$(CONFIG_TIMEOUT) += timeout.o
40 40
41//usage:#define timeout_trivial_usage 41//usage:#define timeout_trivial_usage
42//usage: "[-s SIG] 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 47
47#include "libbb.h" 48#include "libbb.h"
48 49
@@ -55,6 +56,38 @@ static void kill_child(void)
55 kill_SIGTERM_by_handle(child); 56 kill_SIGTERM_by_handle(child);
56 } 57 }
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
77static NOINLINE int timeout_wait(int timeout, pid_t pid)
78{
79 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */
80 while (1) {
81 sleep1();
82 if (--timeout <= 0)
83 break;
84 if (kill(pid, 0)) {
85 /* process is gone */
86 return EXIT_SUCCESS;
87 }
88 }
89 return EXIT_FAILURE;
90}
58#endif 91#endif
59 92
60int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; 93int timeout_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
@@ -69,11 +102,13 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
69#endif 102#endif
70 int parent = 0; 103 int parent = 0;
71 int timeout; 104 int timeout;
105 int kill_timeout;
72 pid_t pid; 106 pid_t pid;
73#if !BB_MMU 107#if !BB_MMU
74 char *sv1, *sv2; 108 char *sv1, *sv2;
75#endif 109#endif
76 const char *opt_s = "TERM"; 110 const char *opt_s = "TERM";
111 char *opt_k = NULL;
77 112
78#if ENABLE_PLATFORM_MINGW32 113#if ENABLE_PLATFORM_MINGW32
79 xfunc_error_retval = 125; 114 xfunc_error_retval = 125;
@@ -83,7 +118,7 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
83 118
84 /* -t SECONDS; -p PARENT_PID */ 119 /* -t SECONDS; -p PARENT_PID */
85 /* '+': stop at first non-option */ 120 /* '+': stop at first non-option */
86 getopt32(argv, "+s:" USE_FOR_NOMMU("p:+"), &opt_s, &parent); 121 getopt32(argv, "+s:k:" USE_FOR_NOMMU("p:+"), &opt_s, &opt_k, &parent);
87 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */ 122 /*argv += optind; - no, wait for bb_daemonize_or_rexec! */
88 123
89 signo = get_signum(opt_s); 124 signo = get_signum(opt_s);
@@ -94,6 +129,10 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
94#endif 129#endif
95 bb_error_msg_and_die("unknown signal '%s'", opt_s); 130 bb_error_msg_and_die("unknown signal '%s'", opt_s);
96 131
132 kill_timeout = 0;
133 if (opt_k)
134 kill_timeout = parse_duration_str(opt_k);
135
97 if (!argv[optind]) 136 if (!argv[optind])
98 bb_show_usage(); 137 bb_show_usage();
99 timeout = parse_duration_str(argv[optind++]); 138 timeout = parse_duration_str(argv[optind++]);
@@ -128,17 +167,16 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
128 bb_daemonize_or_rexec(0, argv); 167 bb_daemonize_or_rexec(0, argv);
129 /* Here we are grandchild. Sleep, then kill grandparent */ 168 /* Here we are grandchild. Sleep, then kill grandparent */
130 grandchild: 169 grandchild:
131 /* Just sleep(HUGE_NUM); kill(parent) may kill wrong process! */ 170 if (timeout_wait(timeout, parent) == EXIT_SUCCESS)
132 while (1) { 171 return EXIT_SUCCESS;
133 sleep1(); 172 kill(parent, signo);
134 if (--timeout <= 0) 173
135 break; 174 if (kill_timeout > 0) {
136 if (kill(parent, 0)) { 175 if (timeout_wait(kill_timeout, parent) == EXIT_SUCCESS)
137 /* process is gone */
138 return EXIT_SUCCESS; 176 return EXIT_SUCCESS;
139 } 177 kill(parent, SIGKILL);
140 } 178 }
141 kill(parent, signo); 179
142 return EXIT_SUCCESS; 180 return EXIT_SUCCESS;
143 } 181 }
144 182
@@ -163,21 +201,19 @@ int timeout_main(int argc UNUSED_PARAM, char **argv)
163 201
164 child = (HANDLE)ret; 202 child = (HANDLE)ret;
165 atexit(kill_child); 203 atexit(kill_child);
166 while (1) { 204 if (timeout_wait(timeout, child, &status))
167 sleep(1); 205 goto finish;
168 if (signo && --timeout <= 0) { 206 status = signo == SIGKILL ? 137 : 124;
169 status = signo == SIGKILL ? 137 : 124;
170 break;
171 }
172 if (WaitForSingleObject(child, 0) == WAIT_OBJECT_0) {
173 /* process is gone */
174 GetExitCodeProcess(child, &status);
175 goto finish;
176 }
177 }
178 207
179 pid = (pid_t)GetProcessId(child); 208 pid = (pid_t)GetProcessId(child);
180 kill(pid, signo); 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 }
181 finish: 217 finish:
182 CloseHandle(child); 218 CloseHandle(child);
183 child = INVALID_HANDLE_VALUE; 219 child = INVALID_HANDLE_VALUE;
diff --git a/coreutils/uudecode.c b/coreutils/uudecode.c
index a607977e9..e90902f52 100644
--- a/coreutils/uudecode.c
+++ b/coreutils/uudecode.c
@@ -155,7 +155,16 @@ int uudecode_main(int argc UNUSED_PARAM, char **argv)
155 break; 155 break;
156 } 156 }
157 dst_stream = stdout; 157 dst_stream = stdout;
158 if (NOT_LONE_DASH(outname)) { 158 if (NOT_LONE_DASH(outname)
159/* https://pubs.opengroup.org/onlinepubs/9699919799/utilities/uudecode.html
160 * https://pubs.opengroup.org/onlinepubs/9699919799/utilities/uuencode.html
161 * The above says that output file name specified in input file
162 * or overridden by -o OUTFILE can be special "/dev/stdout" string.
163 * This usually works "implicitly": many systems have /dev/stdout.
164 * If ENABLE_DESKTOP, support that explicitly:
165 */
166 && (!ENABLE_DESKTOP || strcmp(outname, "/dev/stdout") != 0)
167 ) {
159 dst_stream = xfopen_for_write(outname); 168 dst_stream = xfopen_for_write(outname);
160 fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO)); 169 fchmod(fileno(dst_stream), mode & (S_IRWXU | S_IRWXG | S_IRWXO));
161 } 170 }