aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRon Yorston <rmy@pobox.com>2024-06-22 10:40:16 +0100
committerRon Yorston <rmy@pobox.com>2024-06-22 12:26:19 +0100
commit790e37727319c3dd9c2d4e45dac9b6cc38a5d25f (patch)
treeb375a322562dd6691b7eaf139d2b7b844b31ccb9
parent91226ced0a04302dfe04227aff062cade476a930 (diff)
downloadbusybox-w32-790e37727319c3dd9c2d4e45dac9b6cc38a5d25f.tar.gz
busybox-w32-790e37727319c3dd9c2d4e45dac9b6cc38a5d25f.tar.bz2
busybox-w32-790e37727319c3dd9c2d4e45dac9b6cc38a5d25f.zip
win32: revert 'don't set error mode'
Commit eb376b5d1 (win32: don't set error mode) removed a call to SetErrorMode(SEM_FAILCRITICALERRORS). But the documentation says: Best practice is that all applications call the process-wide SetErrorMode function with a parameter of SEM_FAILCRITICALERRORS at startup. This is to prevent error mode dialogs from hanging the application. Doing this prevents the system from displaying useful information, though. The application should attempt to tell the user what went wrong. Reinstate the call to SetErrorMode() and try to provide an error message, at least for the situation mentioned in issue #423 and other similar cases. Adds 360-368 bytes. (GitHub issue #423)
-rw-r--r--libbb/appletlib.c4
-rw-r--r--win32/process.c93
2 files changed, 68 insertions, 29 deletions
diff --git a/libbb/appletlib.c b/libbb/appletlib.c
index 51824f1b3..c90285ae9 100644
--- a/libbb/appletlib.c
+++ b/libbb/appletlib.c
@@ -1349,6 +1349,10 @@ int main(int argc UNUSED_PARAM, char **argv)
1349 break; 1349 break;
1350 } 1350 }
1351 } 1351 }
1352
1353 /* Have this process handle critical errors itself: the default
1354 * system-generated error dialogs may be inconvenient. */
1355 SetErrorMode(SEM_FAILCRITICALERRORS);
1352#endif 1356#endif
1353 1357
1354#if defined(__MINGW64_VERSION_MAJOR) 1358#if defined(__MINGW64_VERSION_MAJOR)
diff --git a/win32/process.c b/win32/process.c
index caea87492..94a1e23a9 100644
--- a/win32/process.c
+++ b/win32/process.c
@@ -443,7 +443,65 @@ BOOL WINAPI kill_child_ctrl_handler(DWORD dwCtrlType)
443 return FALSE; 443 return FALSE;
444} 444}
445 445
446static NORETURN void wait_for_child(HANDLE child) 446static int exit_code_to_wait_status_cmd(DWORD exit_code, const char *cmd)
447{
448 int sig, status;
449 DECLARE_PROC_ADDR(ULONG, RtlNtStatusToDosError, NTSTATUS);
450 DWORD flags, code;
451 char *msg = NULL;
452
453 if (exit_code == 0xc0000005)
454 return SIGSEGV;
455 else if (exit_code == 0xc000013a)
456 return SIGINT;
457
458 // When a process is terminated as if by a signal the Windows
459 // exit code is zero apart from the signal in its topmost byte.
460 // This is a busybox-w32 convention.
461 sig = exit_code >> 24;
462 if (sig != 0 && exit_code == sig << 24 && is_valid_signal(sig))
463 return sig;
464
465 // The exit code may be an NTSTATUS code. Try to obtain a
466 // descriptive message for it.
467 if (exit_code > 0xff) {
468 flags = FORMAT_MESSAGE_ALLOCATE_BUFFER | FORMAT_MESSAGE_FROM_SYSTEM;
469 if (INIT_PROC_ADDR(ntdll.dll, RtlNtStatusToDosError)) {
470 code = RtlNtStatusToDosError(exit_code);
471 if (FormatMessage(flags, NULL, code, 0, (char *)&msg, 0, NULL)) {
472 char *cr = strrchr(msg, '\r');
473 if (cr) { // Replace CRLF with a space
474 cr[0] = ' ';
475 cr[1] = '\0';
476 }
477 }
478 }
479
480 if (cmd)
481 bb_error_msg("%s: %sError 0x%lx", cmd, msg ?: "", exit_code);
482 else
483 bb_error_msg("%s: %sError 0x%lx" + 4, msg ?: "", exit_code);
484 LocalFree(msg);
485 }
486
487 // Use least significant byte as exit code, but not if it's zero
488 // and the Windows exit code as a whole is non-zero.
489 status = exit_code & 0xff;
490 if (exit_code != 0 && status == 0)
491 status = 255;
492 return status << 8;
493}
494
495static int exit_code_to_posix_cmd(DWORD exit_code, const char *cmd)
496{
497 int status = exit_code_to_wait_status_cmd(exit_code, cmd);
498
499 if (WIFSIGNALED(status))
500 return 128 + WTERMSIG(status);
501 return WEXITSTATUS(status);
502}
503
504static NORETURN void wait_for_child(HANDLE child, const char *cmd)
447{ 505{
448 DWORD code; 506 DWORD code;
449 507
@@ -451,7 +509,7 @@ static NORETURN void wait_for_child(HANDLE child)
451 SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE); 509 SetConsoleCtrlHandler(kill_child_ctrl_handler, TRUE);
452 WaitForSingleObject(child, INFINITE); 510 WaitForSingleObject(child, INFINITE);
453 GetExitCodeProcess(child, &code); 511 GetExitCodeProcess(child, &code);
454 exit(exit_code_to_posix(code)); 512 exit(exit_code_to_posix_cmd(code, cmd));
455} 513}
456 514
457int 515int
@@ -459,7 +517,7 @@ mingw_execvp(const char *cmd, char *const *argv)
459{ 517{
460 intptr_t ret = mingw_spawnvp(P_NOWAIT, cmd, argv); 518 intptr_t ret = mingw_spawnvp(P_NOWAIT, cmd, argv);
461 if (ret != -1) 519 if (ret != -1)
462 wait_for_child((HANDLE)ret); 520 wait_for_child((HANDLE)ret, cmd);
463 return ret; 521 return ret;
464} 522}
465 523
@@ -468,7 +526,7 @@ mingw_execve(const char *cmd, char *const *argv, char *const *envp)
468{ 526{
469 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0); 527 intptr_t ret = mingw_spawn_interpreter(P_NOWAIT, cmd, argv, envp, 0);
470 if (ret != -1) 528 if (ret != -1)
471 wait_for_child((HANDLE)ret); 529 wait_for_child((HANDLE)ret, cmd);
472 return ret; 530 return ret;
473} 531}
474 532
@@ -896,33 +954,10 @@ int FAST_FUNC is_valid_signal(int number)
896 954
897int exit_code_to_wait_status(DWORD exit_code) 955int exit_code_to_wait_status(DWORD exit_code)
898{ 956{
899 int sig, status; 957 return exit_code_to_wait_status_cmd(exit_code, NULL);
900
901 if (exit_code == 0xc0000005)
902 return SIGSEGV;
903 else if (exit_code == 0xc000013a)
904 return SIGINT;
905
906 // When a process is terminated as if by a signal the Windows
907 // exit code is zero apart from the signal in its topmost byte.
908 // This is a busybox-w32 convention.
909 sig = exit_code >> 24;
910 if (sig != 0 && exit_code == sig << 24 && is_valid_signal(sig))
911 return sig;
912
913 // Use least significant byte as exit code, but not if it's zero
914 // and the Windows exit code as a whole is non-zero.
915 status = exit_code & 0xff;
916 if (exit_code != 0 && status == 0)
917 status = 255;
918 return status << 8;
919} 958}
920 959
921int exit_code_to_posix(DWORD exit_code) 960int exit_code_to_posix(DWORD exit_code)
922{ 961{
923 int status = exit_code_to_wait_status(exit_code); 962 return exit_code_to_posix_cmd(exit_code, NULL);
924
925 if (WIFSIGNALED(status))
926 return 128 + WTERMSIG(status);
927 return WEXITSTATUS(status);
928} 963}