| 720 | |
| 721 | #ifdef _WIN32 |
| 722 | static bool bootstrap_production_spawn(void *context, |
| 723 | const cbm_daemon_bootstrap_launch_spec_t *spec) { |
| 724 | bootstrap_production_context_t *production = context; |
| 725 | if (production) { |
| 726 | production->spawn_error = ERROR_SUCCESS; |
| 727 | } |
| 728 | if (!spec || !spec->detached || spec->inherit_standard_handles || spec->use_shell) { |
| 729 | if (production) { |
| 730 | production->spawn_error = ERROR_INVALID_PARAMETER; |
| 731 | } |
| 732 | return false; |
| 733 | } |
| 734 | char command_line[BOOTSTRAP_PATH_CAP * 2]; |
| 735 | if (!cbm_build_win_cmdline(command_line, sizeof(command_line), spec->argv)) { |
| 736 | if (production) { |
| 737 | production->spawn_error = ERROR_INVALID_PARAMETER; |
| 738 | } |
| 739 | return false; |
| 740 | } |
| 741 | wchar_t *application = cbm_utf8_to_wide(spec->executable_path); |
| 742 | wchar_t *command = cbm_utf8_to_wide(command_line); |
| 743 | if (!application || !command) { |
| 744 | if (production) { |
| 745 | production->spawn_error = ERROR_NOT_ENOUGH_MEMORY; |
| 746 | } |
| 747 | free(application); |
| 748 | free(command); |
| 749 | return false; |
| 750 | } |
| 751 | STARTUPINFOW startup; |
| 752 | PROCESS_INFORMATION child; |
| 753 | ZeroMemory(&startup, sizeof(startup)); |
| 754 | ZeroMemory(&child, sizeof(child)); |
| 755 | startup.cb = sizeof(startup); |
| 756 | DWORD flags = DETACHED_PROCESS | CREATE_NEW_PROCESS_GROUP | CREATE_NO_WINDOW; |
| 757 | /* A managed frontend payload is intentionally contained in the permanent |
| 758 | * launcher's kill-on-close job. The account daemon outlives that one |
| 759 | * frontend and therefore uses breakaway when the containing job explicitly |
| 760 | * permits it. Do not request breakaway from an unrelated restrictive job: |
| 761 | * CreateProcess would fail and regress portable/package-manager payloads. */ |
| 762 | BOOL in_job = FALSE; |
| 763 | JOBOBJECT_EXTENDED_LIMIT_INFORMATION job_limits; |
| 764 | memset(&job_limits, 0, sizeof(job_limits)); |
| 765 | if (IsProcessInJob(GetCurrentProcess(), NULL, &in_job) && in_job && |
| 766 | QueryInformationJobObject(NULL, JobObjectExtendedLimitInformation, &job_limits, |
| 767 | sizeof(job_limits), NULL) && |
| 768 | (job_limits.BasicLimitInformation.LimitFlags & |
| 769 | (JOB_OBJECT_LIMIT_BREAKAWAY_OK | JOB_OBJECT_LIMIT_SILENT_BREAKAWAY_OK)) != 0) { |
| 770 | flags |= CREATE_BREAKAWAY_FROM_JOB; |
| 771 | } |
| 772 | BOOL created = CreateProcessW(application, command, NULL, NULL, FALSE, flags, NULL, NULL, |
| 773 | &startup, &child); |
| 774 | DWORD spawn_error = created ? ERROR_SUCCESS : GetLastError(); |
| 775 | free(application); |
| 776 | free(command); |
| 777 | if (production) { |
| 778 | production->spawn_error = spawn_error; |
| 779 | } |
nothing calls this directly
no test coverage detected