redo boot around an explicit system volume and fixed kernel/HAL images, redo volumes and filesystem paths around capabilities instead of drive numbers and kernel CWD state, add a capability/security model with derived and revocable handles and security contexts, add port IPC and rssrv to manage the userspace resource namespace and publish the system volume, move process, dll and path loading to userspace and add process builder syscalls, init now supervises rssrv and the session process, redo the syscall ABI around request structs and four arguments, add a volume manager and proper partition arrival/removal handling so FAT and NTFS mount dynamically, clean up the HAL/DDK boundary so drivers don't depend on HAL internals, save fpu state properly now, the serial driver doesn't hang on a missing port, fix AHCI startup races, fix timeout accounting, fix shared mmap writeback, more smoke tests
This commit is contained in:
1 parent
4add6789ba
commit
f882d339fb
232 files changed
+20934
-8898
No files matched your search
+399
-81
@@ -1,103 +1,421 @@
|
||||
// Init support.
|
||||
// Init service manager. The kernel bootstraps only init; init starts and supervises user-mode system services.
|
||||
|
||||
#include <stdint.h>
|
||||
#include <stdbool.h>
|
||||
#include <stddef.h>
|
||||
#include <string.h>
|
||||
#include <ntlite/exception.h>
|
||||
#include <ntlite/process_loader.h>
|
||||
#include <ntlite/resource.h>
|
||||
#include <ntlite/security.h>
|
||||
#include <ntlite/service_control.h>
|
||||
#include <ntlite/syscall.h>
|
||||
|
||||
// Implements the itoa operation.
|
||||
void itoa(int num, char* str) {
|
||||
int i = 0;
|
||||
int is_negative = 0;
|
||||
#define INIT_SERVICE_READY_TIMEOUT_MS 5000u
|
||||
#define INIT_SERVICE_STOP_TIMEOUT_MS 5000u
|
||||
|
||||
// Handle 0 explicitly.
|
||||
if (num == 0) {
|
||||
str[i++] = '0';
|
||||
str[i] = '\0';
|
||||
return;
|
||||
}
|
||||
typedef struct INIT_RESOURCE_SERVICE {
|
||||
SYS_HANDLE Process;
|
||||
SYS_HANDLE ControlEndpoint;
|
||||
SYS_HANDLE AdminListener;
|
||||
} INIT_RESOURCE_SERVICE;
|
||||
|
||||
// Handle negative numbers.
|
||||
if (num < 0) {
|
||||
is_negative = 1;
|
||||
num = -num;
|
||||
}
|
||||
|
||||
// Process individual digits (result is in reverse).
|
||||
while (num != 0) {
|
||||
int rem = num % 10;
|
||||
str[i++] = rem + '0';
|
||||
num = num / 10;
|
||||
}
|
||||
|
||||
if (is_negative) {
|
||||
str[i++] = '-';
|
||||
}
|
||||
|
||||
str[i] = '\0'; // Null terminate
|
||||
|
||||
// Reverse the string.
|
||||
int start = 0;
|
||||
int end = i - 1;
|
||||
while (start < end) {
|
||||
char temp = str[start];
|
||||
str[start] = str[end];
|
||||
str[end] = temp;
|
||||
start++;
|
||||
end--;
|
||||
}
|
||||
// Writes one string through the privileged kernel debug channel.
|
||||
static void debug_print(const char* text) {
|
||||
SYS_PRINT_DEBUG_REQUEST request = { sizeof(request), SysSvFromCstr(text) };
|
||||
(void)SysPrintDebug(&request);
|
||||
}
|
||||
|
||||
// Implements the debug print operation.
|
||||
static void debug_print(const char* s) {
|
||||
SYS_PRINT_DEBUG_REQUEST req = { SysSvFromCstr(s) };
|
||||
(void)SysPrintDebug(&req);
|
||||
// Writes one status value in hexadecimal without pulling in a formatting runtime.
|
||||
static void debug_status(KSTATUS status) {
|
||||
static const char digits[] = "0123456789ABCDEF";
|
||||
char buffer[11] = "0x00000000";
|
||||
for (uint32_t i = 0; i < 8; ++i)
|
||||
buffer[2 + i] = digits[(status >> ((7u - i) * 4u)) & 0xFu];
|
||||
debug_print(buffer);
|
||||
}
|
||||
|
||||
// Initializes init process state and supervises the configured child process.
|
||||
void _start(void)
|
||||
{
|
||||
uint32_t runtimeStatus = NtlInitializeExceptionRuntime();
|
||||
if (runtimeStatus != NTLSTATUS_SUCCESS)
|
||||
SysExitProcess((int32_t)runtimeStatus);
|
||||
// Exits init without relying on a compiler runtime return path.
|
||||
static void exit_now(int code) {
|
||||
for (;;) SysExitProcess(code);
|
||||
}
|
||||
|
||||
SYS_STRING_VIEW args = SysGetPeb()->CommandLine;
|
||||
uint32_t h = 0;
|
||||
uint32_t s = 0;
|
||||
// Derives the least-privileged security context required by RSSRV.
|
||||
static KSTATUS derive_resource_service_context(SYS_HANDLE* contextOut) {
|
||||
if (!contextOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*contextOut = SYS_HANDLE_INVALID;
|
||||
SYS_DERIVE_SECURITY_CONTEXT_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.SourceContext = SYS_SECURITY_CONTEXT_CURRENT;
|
||||
request.EffectivePrivileges = SYS_PRIV_SYSTEM_SERVICE_REGISTER;
|
||||
request.DelegablePrivileges = 0;
|
||||
request.ServiceClaims = SYS_SERVICE_CLAIM_RESOURCE;
|
||||
request.DelegableServiceClaims = 0;
|
||||
request.Flags = SYS_SECURITY_CONTEXT_FLAG_NONE;
|
||||
request.ContextHandleOut = contextOut;
|
||||
return SysDeriveSecurityContext(&request);
|
||||
}
|
||||
|
||||
while (true) {
|
||||
debug_print("[init] starting\n");
|
||||
SYS_CREATE_PROCESS_REQUEST cp = { args, SysSvFromParts(0, 0), &h };
|
||||
s = SysCreateProcess(&cp);
|
||||
if (s != NTLSTATUS_SUCCESS) {
|
||||
debug_print("[init] FATAL: failed to start!\n");
|
||||
char buffer[12];
|
||||
itoa(s, buffer);
|
||||
debug_print(buffer);
|
||||
// Creates one private Port listener used only between init and a managed service.
|
||||
static KSTATUS create_control_listener(SYS_HANDLE* listenerOut) {
|
||||
SYS_CREATE_PORT_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.Flags = SYS_PORT_FLAG_NONE;
|
||||
request.Backlog = 1;
|
||||
request.HandleOut = listenerOut;
|
||||
return SysCreatePort(&request);
|
||||
}
|
||||
|
||||
// Connects init to the private control listener delegated to the child.
|
||||
static KSTATUS connect_control_listener(SYS_HANDLE listener, SYS_HANDLE* endpointOut) {
|
||||
SYS_CONNECT_PORT_REQUEST request;
|
||||
memset(&request, 0, sizeof(request));
|
||||
request.Size = sizeof(request);
|
||||
request.ListenerHandle = listener;
|
||||
request.Flags = SYS_PORT_CONNECT_FLAG_NONE;
|
||||
request.EndpointHandleOut = endpointOut;
|
||||
return SysConnectPort(&request);
|
||||
}
|
||||
|
||||
// Waits for RSSRV readiness and receives its private administrative namespace listener.
|
||||
static KSTATUS wait_resource_service_ready(SYS_HANDLE controlEndpoint, SYS_HANDLE* adminListenerOut) {
|
||||
if (!adminListenerOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
*adminListenerOut = SYS_HANDLE_INVALID;
|
||||
|
||||
NTL_SERVICE_CONTROL_MESSAGE message;
|
||||
SYS_PORT_MESSAGE_INFO info;
|
||||
SYS_HANDLE adminListener = SYS_HANDLE_INVALID;
|
||||
memset(&message, 0, sizeof(message));
|
||||
memset(&info, 0, sizeof(info));
|
||||
info.Size = sizeof(info);
|
||||
|
||||
SYS_RECEIVE_PORT_REQUEST receive;
|
||||
memset(&receive, 0, sizeof(receive));
|
||||
receive.Size = sizeof(receive);
|
||||
receive.EndpointHandle = controlEndpoint;
|
||||
receive.Flags = SYS_PORT_FLAG_NONE;
|
||||
receive.Payload = &message;
|
||||
receive.PayloadCapacity = sizeof(message);
|
||||
receive.HandlesOut = &adminListener;
|
||||
receive.HandleCapacity = 1;
|
||||
receive.InfoOut = &info;
|
||||
receive.TimeoutMilliseconds = INIT_SERVICE_READY_TIMEOUT_MS;
|
||||
KSTATUS status = SysReceivePort(&receive);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
if (info.Type != SYS_PORT_MESSAGE_NOTIFICATION || info.PayloadLength != sizeof(message) ||
|
||||
info.HandleCount != 1 || adminListener == SYS_HANDLE_INVALID ||
|
||||
message.Size != sizeof(message) || message.Version != NTL_SERVICE_CONTROL_VERSION ||
|
||||
message.Operation != NTL_SERVICE_CONTROL_READY ||
|
||||
message.Flags != NTL_SERVICE_READY_FLAG_RESOURCE_ADMIN_LISTENER ||
|
||||
!KSUCCESS(message.Status)) {
|
||||
if (adminListener != SYS_HANDLE_INVALID) (void)SysCloseHandle(adminListener);
|
||||
return NTLSTATUS_FAILURE;
|
||||
}
|
||||
|
||||
*adminListenerOut = adminListener;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Verifies private namespace administration and public /SystemRoot lookup before declaring RSSRV usable.
|
||||
static KSTATUS verify_resource_service(SYS_HANDLE adminListener, SYS_HANDLE namespaceVolume) {
|
||||
SYS_HANDLE admin = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = NtlResourceConnectListener(adminListener, &admin);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
uint32_t kind = NTL_RESOURCE_KIND_INVALID;
|
||||
status = NtlResourceQuery(admin, SYS_SV_LITERAL("/SystemRoot"), &kind);
|
||||
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_VOLUME) {
|
||||
(void)NtlResourceClose(admin);
|
||||
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
|
||||
}
|
||||
|
||||
// Exercise capability-based administration without leaving a bootstrap-only namespace entry behind.
|
||||
status = NtlResourceBind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"),
|
||||
NTL_RESOURCE_KIND_VOLUME, namespaceVolume,
|
||||
SYS_RIGHT_TRANSFER | SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN,
|
||||
SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)NtlResourceClose(admin);
|
||||
return status;
|
||||
}
|
||||
|
||||
SYS_HANDLE publicSession = SYS_HANDLE_INVALID;
|
||||
status = NtlResourceConnect(&publicSession);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
|
||||
(void)NtlResourceClose(admin);
|
||||
return status;
|
||||
}
|
||||
|
||||
SYS_HANDLE volume = SYS_HANDLE_INVALID;
|
||||
status = NtlResourceLookup(publicSession, SYS_SV_LITERAL("/SystemRoot"),
|
||||
SYS_RIGHT_QUERY | SYS_VOLUME_RIGHT_OPEN, &volume);
|
||||
if (KSUCCESS(status)) (void)SysCloseHandle(volume);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)NtlResourceClose(publicSession);
|
||||
(void)NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
|
||||
(void)NtlResourceClose(admin);
|
||||
return status;
|
||||
}
|
||||
|
||||
kind = NTL_RESOURCE_KIND_INVALID;
|
||||
status = NtlResourceQuery(publicSession, SYS_SV_LITERAL("/Init/BootstrapProbe"), &kind);
|
||||
if (!KSUCCESS(status) || kind != NTL_RESOURCE_KIND_VOLUME) {
|
||||
(void)NtlResourceClose(publicSession);
|
||||
(void)NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
|
||||
(void)NtlResourceClose(admin);
|
||||
return KSUCCESS(status) ? NTLSTATUS_FAILURE : status;
|
||||
}
|
||||
|
||||
status = NtlResourceUnbind(admin, SYS_SV_LITERAL("/Init/BootstrapProbe"));
|
||||
if (KSUCCESS(status)) {
|
||||
kind = NTL_RESOURCE_KIND_INVALID;
|
||||
KSTATUS queryStatus = NtlResourceQuery(publicSession, SYS_SV_LITERAL("/Init/BootstrapProbe"), &kind);
|
||||
if (queryStatus != NTLSTATUS_NOT_FOUND) status = NTLSTATUS_FAILURE;
|
||||
}
|
||||
|
||||
(void)NtlResourceClose(publicSession);
|
||||
(void)NtlResourceClose(admin);
|
||||
return status;
|
||||
}
|
||||
|
||||
// Tears down retained parent-side service handles without sending a stop message.
|
||||
static void close_resource_service(INIT_RESOURCE_SERVICE* service) {
|
||||
if (!service) return;
|
||||
if (service->ControlEndpoint != SYS_HANDLE_INVALID) {
|
||||
(void)SysDisconnectPort(service->ControlEndpoint);
|
||||
(void)SysCloseHandle(service->ControlEndpoint);
|
||||
}
|
||||
if (service->AdminListener != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(service->AdminListener);
|
||||
if (service->Process != SYS_HANDLE_INVALID)
|
||||
(void)SysCloseHandle(service->Process);
|
||||
service->Process = SYS_HANDLE_INVALID;
|
||||
service->ControlEndpoint = SYS_HANDLE_INVALID;
|
||||
service->AdminListener = SYS_HANDLE_INVALID;
|
||||
}
|
||||
|
||||
// Starts one restricted, import-free RSSRV instance through the userspace process loader.
|
||||
static KSTATUS start_resource_service(SYS_HANDLE systemVolume,
|
||||
SYS_HANDLE namespaceVolume,
|
||||
SYS_HANDLE volumeManager,
|
||||
SYS_HANDLE resourceContext,
|
||||
INIT_RESOURCE_SERVICE* serviceOut) {
|
||||
if (!serviceOut) return NTLSTATUS_INVALID_PARAMETER;
|
||||
memset(serviceOut, 0, sizeof(*serviceOut));
|
||||
|
||||
SYS_HANDLE controlListener = SYS_HANDLE_INVALID;
|
||||
KSTATUS status = create_control_listener(&controlListener);
|
||||
if (!KSUCCESS(status)) return status;
|
||||
|
||||
NTL_PROCESS_STARTUP_CAPABILITY startup[3];
|
||||
memset(startup, 0, sizeof(startup));
|
||||
startup[0].Tag = SYS_STARTUP_CAP_SYSTEM_VOLUME_NAMESPACE;
|
||||
startup[0].SourceHandle = namespaceVolume;
|
||||
startup[0].DesiredRights = SYS_RIGHT_QUERY | SYS_RIGHT_TRANSFER |
|
||||
SYS_VOLUME_RIGHT_OPEN | SYS_VOLUME_RIGHT_MODIFY;
|
||||
startup[0].DuplicateFlags = SYS_DUPLICATE_HANDLE_FLAG_NONE;
|
||||
startup[1].Tag = SYS_STARTUP_CAP_SERVICE_CONTROL;
|
||||
startup[1].SourceHandle = controlListener;
|
||||
startup[1].DesiredRights = SYS_RIGHT_QUERY | SYS_PORT_RIGHT_ACCEPT;
|
||||
startup[1].DuplicateFlags = SYS_DUPLICATE_HANDLE_FLAG_NONE;
|
||||
startup[2].Tag = SYS_STARTUP_CAP_VOLUME_MANAGER;
|
||||
startup[2].SourceHandle = volumeManager;
|
||||
startup[2].DesiredRights = SYS_RIGHT_QUERY |
|
||||
SYS_VOLUME_MANAGER_RIGHT_ENUMERATE | SYS_VOLUME_MANAGER_RIGHT_OPEN |
|
||||
SYS_VOLUME_MANAGER_RIGHT_WAIT;
|
||||
startup[2].DuplicateFlags = SYS_DUPLICATE_HANDLE_FLAG_NONE;
|
||||
|
||||
SYS_HANDLE process = SYS_HANDLE_INVALID;
|
||||
NTL_CREATE_PROCESS_AT_REQUEST create;
|
||||
memset(&create, 0, sizeof(create));
|
||||
create.Size = sizeof(create);
|
||||
create.Flags = NTL_PROCESS_LOAD_FLAG_NONE;
|
||||
create.RootHandle = systemVolume;
|
||||
create.Path = SYS_SV_LITERAL("system/rssrv.exe");
|
||||
create.CommandLine = SYS_SV_LITERAL("system/rssrv.exe");
|
||||
create.SecurityContext = resourceContext;
|
||||
create.ModuleRootHandle = systemVolume;
|
||||
create.ModuleDirectory = SYS_SV_LITERAL("system");
|
||||
create.ResolveModuleName = NtlResolveModuleNameIdentity;
|
||||
create.ResolveContext = (void*)0;
|
||||
create.StartupCapabilities = startup;
|
||||
create.StartupCapabilityCount = 3;
|
||||
create.ProcessHandleOut = &process;
|
||||
status = NtlCreateProcessAt(&create);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysCloseHandle(controlListener);
|
||||
return status;
|
||||
}
|
||||
|
||||
SYS_HANDLE controlEndpoint = SYS_HANDLE_INVALID;
|
||||
status = connect_control_listener(controlListener, &controlEndpoint);
|
||||
(void)SysCloseHandle(controlListener);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysKillProcess(process, 1);
|
||||
(void)SysCloseHandle(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
SYS_HANDLE adminListener = SYS_HANDLE_INVALID;
|
||||
status = wait_resource_service_ready(controlEndpoint, &adminListener);
|
||||
if (KSUCCESS(status))
|
||||
status = verify_resource_service(adminListener, namespaceVolume);
|
||||
if (!KSUCCESS(status)) {
|
||||
if (adminListener != SYS_HANDLE_INVALID) (void)SysCloseHandle(adminListener);
|
||||
(void)SysDisconnectPort(controlEndpoint);
|
||||
(void)SysCloseHandle(controlEndpoint);
|
||||
(void)SysKillProcess(process, 1);
|
||||
(void)SysCloseHandle(process);
|
||||
return status;
|
||||
}
|
||||
|
||||
serviceOut->Process = process;
|
||||
serviceOut->ControlEndpoint = controlEndpoint;
|
||||
serviceOut->AdminListener = adminListener;
|
||||
return NTLSTATUS_SUCCESS;
|
||||
}
|
||||
|
||||
// Requests graceful RSSRV shutdown, falling back to process termination if it stops responding.
|
||||
static void stop_resource_service(INIT_RESOURCE_SERVICE* service) {
|
||||
if (!service || service->Process == SYS_HANDLE_INVALID) return;
|
||||
|
||||
NTL_SERVICE_CONTROL_MESSAGE message;
|
||||
memset(&message, 0, sizeof(message));
|
||||
message.Size = sizeof(message);
|
||||
message.Version = NTL_SERVICE_CONTROL_VERSION;
|
||||
message.Operation = NTL_SERVICE_CONTROL_STOP;
|
||||
|
||||
SYS_SEND_PORT_REQUEST send;
|
||||
memset(&send, 0, sizeof(send));
|
||||
send.Size = sizeof(send);
|
||||
send.EndpointHandle = service->ControlEndpoint;
|
||||
send.Flags = SYS_PORT_FLAG_NONE;
|
||||
send.Payload = &message;
|
||||
send.PayloadLength = sizeof(message);
|
||||
send.TimeoutMilliseconds = INIT_SERVICE_STOP_TIMEOUT_MS;
|
||||
(void)SysSendPort(&send);
|
||||
|
||||
KSTATUS status = SysWaitSingle(service->Process, SYS_WAIT_FLAG_NONE, INIT_SERVICE_STOP_TIMEOUT_MS);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysKillProcess(service->Process, 1);
|
||||
(void)SysWait(service->Process, SYS_WAIT_FLAG_NONE);
|
||||
}
|
||||
close_resource_service(service);
|
||||
}
|
||||
|
||||
// Starts the configured native session child directly beneath the system-volume capability.
|
||||
static KSTATUS start_configured_child(SYS_HANDLE systemVolume, SYS_STRING_VIEW path, SYS_HANDLE* processOut) {
|
||||
NTL_CREATE_PROCESS_AT_REQUEST create;
|
||||
memset(&create, 0, sizeof(create));
|
||||
create.Size = sizeof(create);
|
||||
create.Flags = NTL_PROCESS_LOAD_FLAG_NONE;
|
||||
create.RootHandle = systemVolume;
|
||||
create.Path = path;
|
||||
create.CommandLine = path;
|
||||
create.SecurityContext = SYS_SECURITY_CONTEXT_CURRENT;
|
||||
create.ModuleRootHandle = systemVolume;
|
||||
create.ModuleDirectory = SYS_SV_LITERAL("system");
|
||||
create.ResolveModuleName = NtlResolveSystemModuleName;
|
||||
create.ProcessHandleOut = processOut;
|
||||
return NtlCreateProcessAt(&create);
|
||||
}
|
||||
|
||||
// Initializes init state and supervises RSSRV plus the configured session process.
|
||||
void _start(void) {
|
||||
KSTATUS status = NtlInitializeExceptionRuntime();
|
||||
if (!KSUCCESS(status)) exit_now((int)status);
|
||||
|
||||
SYS_HANDLE systemVolume = SysGetStartupCapability(SYS_STARTUP_CAP_SYSTEM_VOLUME);
|
||||
SYS_HANDLE namespaceVolume = SysGetStartupCapability(SYS_STARTUP_CAP_SYSTEM_VOLUME_NAMESPACE);
|
||||
SYS_HANDLE volumeManager = SysGetStartupCapability(SYS_STARTUP_CAP_VOLUME_MANAGER);
|
||||
if (systemVolume == SYS_HANDLE_INVALID || namespaceVolume == SYS_HANDLE_INVALID ||
|
||||
volumeManager == SYS_HANDLE_INVALID) {
|
||||
debug_print("[init] FATAL: bootstrap storage capability missing\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
SYS_HANDLE resourceContext = SYS_HANDLE_INVALID;
|
||||
status = derive_resource_service_context(&resourceContext);
|
||||
if (!KSUCCESS(status)) {
|
||||
debug_print("[init] FATAL: cannot derive RSSRV security context: ");
|
||||
debug_status(status);
|
||||
debug_print("\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
SYS_STRING_VIEW childPath = SysGetPeb()->CommandLine;
|
||||
if (!childPath.Data || childPath.Length == 0) {
|
||||
debug_print("[init] FATAL: no configured session process\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
for (;;) {
|
||||
INIT_RESOURCE_SERVICE resourceService;
|
||||
status = start_resource_service(systemVolume, namespaceVolume, volumeManager, resourceContext, &resourceService);
|
||||
if (!KSUCCESS(status)) {
|
||||
debug_print("[init] FATAL: RSSRV startup failed: ");
|
||||
debug_status(status);
|
||||
debug_print("\n");
|
||||
SysExitProcess(1);
|
||||
exit_now(1);
|
||||
}
|
||||
debug_print("[init] RSSRV ready\n");
|
||||
|
||||
debug_print("[init] waiting\n");
|
||||
s = SysWait(h, SYS_WAIT_FLAG_NONE);
|
||||
if (s != NTLSTATUS_SUCCESS)
|
||||
debug_print("[init] WARNING: SysWait returned error\n");
|
||||
for (;;) {
|
||||
SYS_HANDLE child = SYS_HANDLE_INVALID;
|
||||
status = start_configured_child(systemVolume, childPath, &child);
|
||||
if (!KSUCCESS(status)) {
|
||||
debug_print("[init] FATAL: failed to start configured child: ");
|
||||
debug_status(status);
|
||||
debug_print("\n");
|
||||
stop_resource_service(&resourceService);
|
||||
exit_now(1);
|
||||
}
|
||||
debug_print("[init] session process started\n");
|
||||
|
||||
int32_t exitCode = 0;
|
||||
if (SysGetProcessExitCode(h, &exitCode) != NTLSTATUS_SUCCESS) {
|
||||
debug_print("[init] WARNING: failed to read exit code\n");
|
||||
exitCode = 1;
|
||||
SYS_HANDLE waits[2] = { resourceService.Process, child };
|
||||
uint32_t signaled = 0;
|
||||
SYS_WAIT_MANY_REQUEST wait;
|
||||
memset(&wait, 0, sizeof(wait));
|
||||
wait.Size = sizeof(wait);
|
||||
wait.Flags = SYS_WAIT_FLAG_NONE;
|
||||
wait.Handles = waits;
|
||||
wait.Count = 2;
|
||||
wait.SignaledIndexOut = &signaled;
|
||||
wait.TimeoutMilliseconds = SYS_WAIT_TIMEOUT_INFINITE;
|
||||
status = SysWaitMany(&wait);
|
||||
if (!KSUCCESS(status)) {
|
||||
(void)SysKillProcess(child, 1);
|
||||
(void)SysCloseHandle(child);
|
||||
stop_resource_service(&resourceService);
|
||||
debug_print("[init] FATAL: service wait failed\n");
|
||||
exit_now(1);
|
||||
}
|
||||
|
||||
if (signaled == 0) {
|
||||
int32_t serviceExit = -1;
|
||||
(void)SysGetProcessExitCode(resourceService.Process, &serviceExit);
|
||||
debug_print("[init] RSSRV exited unexpectedly; restarting service plane\n");
|
||||
(void)SysKillProcess(child, 1);
|
||||
(void)SysWait(child, SYS_WAIT_FLAG_NONE);
|
||||
(void)SysCloseHandle(child);
|
||||
close_resource_service(&resourceService);
|
||||
break;
|
||||
}
|
||||
|
||||
int32_t exitCode = -1;
|
||||
status = SysGetProcessExitCode(child, &exitCode);
|
||||
(void)SysCloseHandle(child);
|
||||
if (!KSUCCESS(status)) exitCode = 1;
|
||||
if (exitCode == 0) {
|
||||
stop_resource_service(&resourceService);
|
||||
debug_print("[init] done\n");
|
||||
(void)SysCloseHandle(resourceContext);
|
||||
exit_now(0);
|
||||
}
|
||||
debug_print("[init] session process crashed; restarting\n");
|
||||
}
|
||||
|
||||
SysCloseHandle(h);
|
||||
|
||||
if (exitCode == 0)
|
||||
break;
|
||||
|
||||
debug_print("[init] child crashed, restarting\n");
|
||||
}
|
||||
|
||||
debug_print("[init] done\n");
|
||||
SysExitProcess(0);
|
||||
}
|
||||
Reference in new issue
Block a user