// POSIX compatibility support for posix proc. #include #include #include #include #include #include "posix.h" #include "posix_path.h" static SYS_PEB* gProcessPeb = NULL; // Implements the peb operation. static SYS_PEB* PosixPeb(void) { if (!gProcessPeb) gProcessPeb = SysGetPeb(); return gProcessPeb; } // Implements the posix get command line operation. __declspec(dllexport) const char* posix_get_command_line(void) { SYS_PEB* peb = PosixPeb(); if (!peb || peb->Magic != SYS_PEB_MAGIC || !peb->CommandLine.Data) return ""; return peb->CommandLine.Data; } // pid -> proc handle table (user-mode side, for waitpid). #define PROC_TABLE_SIZE 32 typedef struct { pid_t pid; uint32_t handle; bool used; } ProcEntry; static ProcEntry gProcTable[PROC_TABLE_SIZE]; // Implements the proc Table Insert operation. static void ProcTableInsert(pid_t pid, uint32_t handle) { for (int i = 0; i < PROC_TABLE_SIZE; i++) { if (!gProcTable[i].used) { gProcTable[i] = (ProcEntry){ pid, handle, true }; return; } } SysCloseHandle(handle); } // Implements the proc Table Find operation. static uint32_t ProcTableFind(pid_t pid) { for (int i = 0; i < PROC_TABLE_SIZE; i++) if (gProcTable[i].used && gProcTable[i].pid == pid) return gProcTable[i].handle; return 0; } // Implements the proc Table Remove operation. static void ProcTableRemove(pid_t pid) { for (int i = 0; i < PROC_TABLE_SIZE; i++) if (gProcTable[i].used && gProcTable[i].pid == pid) gProcTable[i].used = false; } // Build a flat Windows-style cmdline from a NULL-terminated argv array. // Each token that contains a space is wrapped in double-quotes. // argv[0] is included (it becomes the executable token visible to _start). static void BuildCmdline(char* const argv[], char* out, size_t outSize) { size_t pos = 0; for (int i = 0; argv && argv[i]; i++) { if (i > 0 && pos < outSize - 1) out[pos++] = ' '; const char* tok = argv[i]; bool needQuote = false; for (const char* c = tok; *c; c++) if (*c == ' ' || *c == '\t') { needQuote = true; break; } if (needQuote && pos < outSize - 1) out[pos++] = '"'; for (; *tok && pos < outSize - 2; tok++) { if (*tok == '"') { out[pos++] = '\\'; } out[pos++] = *tok; } if (needQuote && pos < outSize - 1) out[pos++] = '"'; } if (pos < outSize) out[pos] = '\0'; } // POSIX API. __declspec(dllexport) pid_t getpid(void) { return (pid_t)SysGetCurrentPid(); } __declspec(dllexport) int posix_spawn(pid_t* pidOut, const char* path, const posix_spawn_file_actions_t* file_actions, // ignored v1 const posix_spawnattr_t* attrp, // ignored v1 char* const argv[], char* const envp[]) // ignored v1 { (void)file_actions; (void)attrp; (void)envp; char native[512]; uint32_t pathStatus = PosixProcessPath(path, native, sizeof(native)); if (pathStatus != NTLSTATUS_SUCCESS) { errno = ENOENT; return -1; } SYS_HANDLE imageFile = SYS_HANDLE_INVALID; pathStatus = NtlOpenFile(SysSvFromCstr(native), SYS_FILE_ACCESS_READ | SYS_FILE_ACCESS_QUERY, SYS_FILE_OPEN_EXISTING, SYS_FILE_FLAG_NONE, &imageFile); if (pathStatus != NTLSTATUS_SUCCESS) { errno = ENOENT; return -1; } char cmdline[512]; BuildCmdline(argv, cmdline, sizeof(cmdline)); // If argv was NULL or empty, fall back to just the path so _start still // gets a meaningful argv[0]. if (cmdline[0] == '\0') { size_t len = strlen(path); if (len >= sizeof(cmdline)) len = sizeof(cmdline) - 1; memcpy(cmdline, path, len); cmdline[len] = '\0'; } uint32_t procHandle = 0; NTL_CREATE_SYSTEM_PROCESS_REQUEST req; memset(&req, 0, sizeof(req)); req.Size = sizeof(req); req.Flags = NTL_PROCESS_LOAD_FLAG_NONE; req.ImageFile = imageFile; req.Path = SysSvFromCstr(native); req.CommandLine = SysSvFromCstr(cmdline); req.SecurityContext = SYS_SECURITY_CONTEXT_CURRENT; req.ResolveModuleName = PosixResolveModuleName; req.ProcessHandleOut = &procHandle; uint32_t s = NtlCreateSystemProcess(&req); if (imageFile != SYS_HANDLE_INVALID) (void)SysCloseHandle(imageFile); if (s != 0) { errno = ENOENT; return -1; } uint32_t kpid = 0; SysGetProcessPid(procHandle, &kpid); ProcTableInsert((pid_t)kpid, procHandle); if (pidOut) *pidOut = (pid_t)kpid; return 0; } // options: WNOHANG not supported in v1 (always blocks). __declspec(dllexport) pid_t waitpid(pid_t pid, int* status, int options) { (void)options; uint32_t handle = ProcTableFind(pid); if (!handle) { errno = ESRCH; return -1; } SysWait(handle, SYS_WAIT_FLAG_NONE); int32_t exitCode = 0; SysGetProcessExitCode(handle, &exitCode); if (status) *status = exitCode << 8; // WEXITSTATUS convention SysCloseHandle(handle); ProcTableRemove(pid); return pid; } // Implements the exit operation. __declspec(dllexport) void exit(int status) { SysExitProcess(status); }