144 lines
4.4 KiB
C
144 lines
4.4 KiB
C
// POSIX compatibility support for posix proc.
|
|
|
|
#include <stddef.h>
|
|
#include <string.h>
|
|
#include <ntlite/syscall.h>
|
|
#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];
|
|
PosixTranslatePath(path, native, sizeof(native));
|
|
|
|
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;
|
|
SYS_CREATE_PROCESS_REQUEST req = { SysSvFromCstr(native), SysSvFromCstr(cmdline), &procHandle };
|
|
uint32_t s = SysCreateProcess(&req);
|
|
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);
|
|
|
|
int 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);
|
|
}
|