From 99402ca92c77b13bee5181c129db18ecd9bf8938 Mon Sep 17 00:00:00 2001 From: Ron Yorston Date: Fri, 7 Apr 2023 12:52:57 +0100 Subject: xargs: kill children when interrupted by Ctrl-C A user was running the following command in a clone of the busybox-w32 repo from a busybox-w32 shell using Git for Windows: git rev-list --all | xargs git grep main.c Using Ctrl-C to interrupt the command resulted in the familiar problem that two processes ended up competing for user input: in this case the busybox-w32 shell and the Git for Windows pager, less. Make the problem go away (in this particular case) by killing all the children of xargs when it's interrupted. This is probably a sensible thing to do for other circumstances too. Adds 64-100 bytes. (GitHub issue #306) --- findutils/xargs.c | 45 ++++++++++++++++++++++++++++++++++++++++++--- 1 file changed, 42 insertions(+), 3 deletions(-) diff --git a/findutils/xargs.c b/findutils/xargs.c index d6cdec22e..1023f80a3 100644 --- a/findutils/xargs.c +++ b/findutils/xargs.c @@ -121,9 +121,12 @@ struct globals { #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL int running_procs; int max_procs; -#if ENABLE_PLATFORM_MINGW32 +# if ENABLE_PLATFORM_MINGW32 HANDLE *procs; +# endif #endif +#if ENABLE_PLATFORM_MINGW32 + pid_t pid; #endif smalluint xargs_exitcode; #if ENABLE_FEATURE_XARGS_SUPPORT_QUOTES @@ -189,6 +192,35 @@ enum { IF_FEATURE_XARGS_SUPPORT_ARGS_FILE( "a:") +#if ENABLE_PLATFORM_MINGW32 +static BOOL WINAPI ctrl_handler(DWORD dwCtrlType) +{ + if (dwCtrlType == CTRL_C_EVENT || dwCtrlType == CTRL_BREAK_EVENT) { +# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL + if (G.max_procs == 1) +# endif + { + if (G.pid > 0) + kill(-G.pid, SIGTERM); + } +# if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL + else { + int i; + + for (i = 0; i < G.running_procs; ++i) { + pid_t pid = GetProcessId(G.procs[i]); + if (pid > 0) + kill(-pid, SIGTERM); + } + } +# endif + exit(128 + SIGINT); + return TRUE; + } + return FALSE; +} +#endif + #if ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL && ENABLE_PLATFORM_MINGW32 static int wait_for_slot(int *idx) { @@ -255,10 +287,11 @@ static int xargs_exec(void) #if !ENABLE_FEATURE_XARGS_SUPPORT_PARALLEL status = spawn_and_wait(G.args); #else +#if ENABLE_PLATFORM_MINGW32 if (G.max_procs == 1) { - status = spawn_and_wait(G.args); + G.pid = spawn(G.args); + status = G.pid < 0 ? -1 : wait4pid(G.pid); } else { -#if ENABLE_PLATFORM_MINGW32 int idx; status = !G.running_procs && !G.max_procs ? 0 : wait_for_slot(&idx); if (G.max_procs) { @@ -275,6 +308,9 @@ static int xargs_exec(void) } } #else + if (G.max_procs == 1) { + status = spawn_and_wait(G.args); + } else { pid_t pid; int wstat; again: @@ -723,6 +759,9 @@ int xargs_main(int argc UNUSED_PARAM, char **argv) INIT_G(); +#if ENABLE_PLATFORM_MINGW32 + SetConsoleCtrlHandler(ctrl_handler, TRUE); +#endif opt = getopt32long(argv, OPTION_STR, "no-run-if-empty\0" No_argument "r", &max_args, &max_chars, &G.eof_str, &G.eof_str -- cgit v1.2.3-55-g6feb