diff options
-rw-r--r-- | libbb/appletlib.c | 4 | ||||
-rw-r--r-- | win32/process.c | 93 |
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 | ||
446 | static NORETURN void wait_for_child(HANDLE child) | 446 | static 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 | |||
495 | static 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 | |||
504 | static 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 | ||
457 | int | 515 | int |
@@ -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 | ||
897 | int exit_code_to_wait_status(DWORD exit_code) | 955 | int 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 | ||
921 | int exit_code_to_posix(DWORD exit_code) | 960 | int 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 | } |