fix: inherit process environment and untrack libc objects
This commit is contained in:
+2
-1
@@ -17,7 +17,8 @@ programs/src/*/obj/
|
||||
programs/libs/*/obj/
|
||||
programs/lib/libc/liblibc.a
|
||||
programs/lib/libc/liblibc-full.a
|
||||
programs/lib/libc/obj/libc-merged.o
|
||||
programs/lib/libc/*.o
|
||||
programs/lib/libc/obj/
|
||||
programs/lib/libloader/liblibloader.a
|
||||
programs/gui/icons/
|
||||
CLAUDE.md
|
||||
|
||||
@@ -12,4 +12,4 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#define MONTAUK_BUILD_NUMBER 104
|
||||
#define MONTAUK_BUILD_NUMBER 106
|
||||
|
||||
@@ -43,14 +43,16 @@ namespace montauk::abi {
|
||||
return Sched::LookupExitCode(pid);
|
||||
}
|
||||
|
||||
static int Sys_Spawn(const char* path, const char* args) {
|
||||
static int Sys_Spawn(const char* path, const char* args,
|
||||
const char* environment = nullptr, uint32_t environmentLength = 0) {
|
||||
char resolved[256];
|
||||
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
|
||||
|
||||
auto* parent = Sched::GetCurrentProcessPtr();
|
||||
int parentSlot = Ipc::CurrentSlot();
|
||||
bool inheritRedirection = parent && parent->redirected;
|
||||
int childPid = Sched::Spawn(resolved, args, !inheritRedirection);
|
||||
int childPid = Sched::Spawn(resolved, args, !inheritRedirection,
|
||||
environment, environmentLength);
|
||||
if (childPid < 0) return childPid;
|
||||
|
||||
if (inheritRedirection) {
|
||||
@@ -107,6 +109,24 @@ namespace montauk::abi {
|
||||
return i;
|
||||
}
|
||||
|
||||
static int Sys_GetEnviron(char* buf, uint64_t maxLen) {
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (proc == nullptr || buf == nullptr || maxLen == 0) return -1;
|
||||
if (maxLen < proc->environmentLength) return -2;
|
||||
for (uint32_t i = 0; i < proc->environmentLength; i++)
|
||||
buf[i] = proc->environment[i];
|
||||
return (int)proc->environmentLength;
|
||||
}
|
||||
|
||||
static int Sys_SetEnviron(const char* buf, uint64_t len) {
|
||||
auto* proc = Sched::GetCurrentProcessPtr();
|
||||
if (proc == nullptr || buf == nullptr || len == 0 ||
|
||||
len > Sched::Process::EnvironmentBytes || buf[len - 1] != '\0') return -1;
|
||||
for (uint64_t i = 0; i < len; i++) proc->environment[i] = buf[i];
|
||||
proc->environmentLength = (uint32_t)len;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int Sys_ProcList(ProcInfo* buf, int maxCount) {
|
||||
if (buf == nullptr || maxCount <= 0) return 0;
|
||||
int count = 0;
|
||||
|
||||
@@ -149,8 +149,25 @@ namespace montauk::abi {
|
||||
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
|
||||
return (int64_t)Sys_Spawn((const char*)frame->arg1,
|
||||
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr);
|
||||
case SYS_SPAWN_ENV:
|
||||
if (!UserMemory::String(frame->arg1, kMaxPathBytes)) return -1;
|
||||
if (frame->arg2 != 0 && !UserMemory::String(frame->arg2, kMaxArgsBytes)) return -1;
|
||||
if (frame->arg3 == 0 || frame->arg4 == 0 ||
|
||||
frame->arg4 > Sched::Process::EnvironmentBytes ||
|
||||
!UserMemory::Range(frame->arg3, frame->arg4, false) ||
|
||||
((const char*)frame->arg3)[frame->arg4 - 1] != '\0') return -1;
|
||||
return (int64_t)Sys_Spawn((const char*)frame->arg1,
|
||||
UserMemory::IsUserPtr(frame->arg2) ? (const char*)frame->arg2 : nullptr,
|
||||
(const char*)frame->arg3, (uint32_t)frame->arg4);
|
||||
case SYS_WAITPID:
|
||||
return Sys_WaitPid((int)frame->arg1);
|
||||
case SYS_GETENVIRON:
|
||||
if (!UserMemory::Range(frame->arg1, frame->arg2, true)) return -1;
|
||||
return Sys_GetEnviron((char*)frame->arg1, frame->arg2);
|
||||
case SYS_SETENVIRON:
|
||||
if (frame->arg2 == 0 || frame->arg2 > Sched::Process::EnvironmentBytes ||
|
||||
!UserMemory::Range(frame->arg1, frame->arg2, false)) return -1;
|
||||
return Sys_SetEnviron((const char*)frame->arg1, frame->arg2);
|
||||
case SYS_FBINFO:
|
||||
if (!UserMemory::Writable<FbInfo>(frame->arg1)) return -1;
|
||||
Sys_FbInfo((FbInfo*)frame->arg1);
|
||||
|
||||
@@ -315,6 +315,9 @@ namespace montauk::abi {
|
||||
static constexpr uint64_t SYS_MMAP_ANON = 168;
|
||||
static constexpr uint64_t SYS_MUNMAP = 169;
|
||||
static constexpr uint64_t SYS_MPROTECT = 170;
|
||||
static constexpr uint64_t SYS_GETENVIRON = 171;
|
||||
static constexpr uint64_t SYS_SETENVIRON = 172;
|
||||
static constexpr uint64_t SYS_SPAWN_ENV = 173;
|
||||
|
||||
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
|
||||
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
|
||||
|
||||
@@ -294,6 +294,8 @@ namespace Sched {
|
||||
processTable[i].heapNext = 0;
|
||||
processTable[i].readdirCursor = 0;
|
||||
processTable[i].args[0] = '\0';
|
||||
processTable[i].environment[0] = '\0';
|
||||
processTable[i].environmentLength = 1;
|
||||
processTable[i].user[0] = '\0';
|
||||
processTable[i].cwd[0] = '\0';
|
||||
processTable[i].runningOnCpu = -1;
|
||||
@@ -337,7 +339,8 @@ namespace Sched {
|
||||
<< " process slots, " << (uint64_t)TimeSliceMs << " ms time slice)";
|
||||
}
|
||||
|
||||
int Spawn(const char* vfsPath, const char* args, bool startReady) {
|
||||
int Spawn(const char* vfsPath, const char* args, bool startReady,
|
||||
const char* environment, uint32_t environmentLength) {
|
||||
schedLock.Acquire();
|
||||
|
||||
int slot = -1;
|
||||
@@ -511,6 +514,9 @@ namespace Sched {
|
||||
|
||||
auto* currentCpu = Smp::GetCurrentCpuData();
|
||||
int parentSlot = currentCpu ? currentCpu->currentSlot : -1;
|
||||
int parentPrimarySlot = parentSlot;
|
||||
if (parentPrimarySlot >= 0 && processTable[parentPrimarySlot].primarySlot >= 0)
|
||||
parentPrimarySlot = processTable[parentPrimarySlot].primarySlot;
|
||||
|
||||
// Copy arguments string into process
|
||||
proc.args[0] = '\0';
|
||||
@@ -522,6 +528,23 @@ namespace Sched {
|
||||
proc.args[i] = '\0';
|
||||
}
|
||||
|
||||
// posix_spawn(envp) supplies an explicit snapshot. Plain spawn calls
|
||||
// omit it and inherit the environment stored on the parent process.
|
||||
if (environment != nullptr && environmentLength > 0 &&
|
||||
environmentLength <= Process::EnvironmentBytes) {
|
||||
for (uint32_t i = 0; i < environmentLength; i++)
|
||||
proc.environment[i] = environment[i];
|
||||
proc.environmentLength = environmentLength;
|
||||
} else if (parentPrimarySlot >= 0) {
|
||||
auto& parent = processTable[parentPrimarySlot];
|
||||
for (uint32_t i = 0; i < parent.environmentLength; i++)
|
||||
proc.environment[i] = parent.environment[i];
|
||||
proc.environmentLength = parent.environmentLength;
|
||||
} else {
|
||||
proc.environment[0] = '\0';
|
||||
proc.environmentLength = 1;
|
||||
}
|
||||
|
||||
// Inherit user string from parent, or default to "system" if no parent
|
||||
{
|
||||
if (parentSlot >= 0) {
|
||||
|
||||
@@ -65,6 +65,7 @@ namespace Sched {
|
||||
};
|
||||
|
||||
struct Process {
|
||||
static constexpr uint32_t EnvironmentBytes = 4096;
|
||||
int pid;
|
||||
ProcessState state;
|
||||
int waitingForPid; // PID this process is blocked on (-1 if none)
|
||||
@@ -82,6 +83,8 @@ namespace Sched {
|
||||
uint64_t heapNext; // Simple bump allocator for user heap
|
||||
uint32_t readdirCursor; // Next SYS_READDIR scratch slot
|
||||
char args[4096]; // Command-line arguments (set by parent via Spawn)
|
||||
char environment[EnvironmentBytes]; // NUL-separated NAME=VALUE entries
|
||||
uint32_t environmentLength;
|
||||
char user[32]; // Owner user name (inherited from parent on spawn)
|
||||
char cwd[256]; // Absolute current working directory
|
||||
|
||||
@@ -139,7 +142,8 @@ namespace Sched {
|
||||
};
|
||||
|
||||
void Initialize();
|
||||
int Spawn(const char* vfsPath, const char* args = nullptr, bool startReady = true);
|
||||
int Spawn(const char* vfsPath, const char* args = nullptr, bool startReady = true,
|
||||
const char* environment = nullptr, uint32_t environmentLength = 0);
|
||||
int StartProcess(int pid);
|
||||
void Schedule();
|
||||
|
||||
|
||||
@@ -233,6 +233,9 @@ namespace montauk::abi {
|
||||
static constexpr uint64_t SYS_MMAP_ANON = 168;
|
||||
static constexpr uint64_t SYS_MUNMAP = 169;
|
||||
static constexpr uint64_t SYS_MPROTECT = 170;
|
||||
static constexpr uint64_t SYS_GETENVIRON = 171;
|
||||
static constexpr uint64_t SYS_SETENVIRON = 172;
|
||||
static constexpr uint64_t SYS_SPAWN_ENV = 173;
|
||||
|
||||
// Tunable parameters (for SYS_SDR_SETPARAM / SYS_SDR_GETPARAM).
|
||||
static constexpr int SDR_PARAM_FREQ = 0; // center frequency, Hz
|
||||
|
||||
@@ -73,6 +73,9 @@ extern "C" {
|
||||
#define MTK_SYS_MOUSESTATE 47
|
||||
#define MTK_SYS_SETMOUSEBOUNDS 48
|
||||
#define MTK_SYS_SPAWN_REDIR 49
|
||||
#define MTK_SYS_GETENVIRON 171
|
||||
#define MTK_SYS_SETENVIRON 172
|
||||
#define MTK_SYS_SPAWN_ENV 173
|
||||
#define MTK_SYS_CHILDIO_READ 50
|
||||
#define MTK_SYS_CHILDIO_WRITE 51
|
||||
#define MTK_SYS_CHILDIO_WRITEKEY 52
|
||||
|
||||
@@ -15,7 +15,7 @@ extern "C" {
|
||||
* Limitations (kernel spawn model):
|
||||
* - argv is joined into a single args string; arguments containing
|
||||
* spaces are rejected with EINVAL (no quoting in the kernel).
|
||||
* - envp is ignored (no environment transfer on spawn).
|
||||
* - envp is copied into the child; NULL inherits the current environment.
|
||||
* - file actions must be empty: stdio redirection needs kernel
|
||||
* support that does not exist yet, so any recorded action makes
|
||||
* posix_spawn fail with ENOTSUP rather than misbehave silently.
|
||||
|
||||
@@ -34,8 +34,10 @@ static inline long _sys2(long nr, long a1, long a2) {
|
||||
#define SYS_EXIT 0
|
||||
#define SYS_GETARGS 25
|
||||
#define SYS_GETEXECPATH 151
|
||||
#define SYS_GETENVIRON 171
|
||||
|
||||
extern int main(int argc, char** argv);
|
||||
extern void __libc_init_environ(const char *blob, unsigned long len);
|
||||
|
||||
/* Global constructor/destructor tables. The linker provides these
|
||||
boundary symbols whenever .preinit_array/.init_array/.fini_array
|
||||
@@ -72,9 +74,13 @@ static void _run_fini_array(void) {
|
||||
void _start(void) {
|
||||
/* Static: 4 KiB args + 256 argv slots would crowd a 32 KiB stack. */
|
||||
static char argbuf[4096];
|
||||
static char envbuf[4096];
|
||||
static char pathbuf[256];
|
||||
static char* argv[256];
|
||||
int len = (int)_sys2(SYS_GETARGS, (long)argbuf, (long)sizeof(argbuf));
|
||||
int envlen = (int)_sys2(SYS_GETENVIRON, (long)envbuf, (long)sizeof(envbuf));
|
||||
if (envlen > 0)
|
||||
__libc_init_environ(envbuf, (unsigned long)envlen);
|
||||
|
||||
int argc = 0;
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
+133
-19
@@ -123,6 +123,9 @@ static inline long _zos_syscall4(long nr, long a1, long a2, long a3, long a4) {
|
||||
#define SYS_MMAP_ANON 168
|
||||
#define SYS_MUNMAP 169
|
||||
#define SYS_MPROTECT 170
|
||||
#define SYS_GETENVIRON 171
|
||||
#define SYS_SETENVIRON 172
|
||||
#define SYS_SPAWN_ENV 173
|
||||
|
||||
/* ========================================================================
|
||||
errno
|
||||
@@ -164,9 +167,15 @@ struct _DIR {
|
||||
struct _env_entry {
|
||||
char *name;
|
||||
char *value;
|
||||
char *string;
|
||||
};
|
||||
|
||||
static struct _env_entry _env_entries[64];
|
||||
static char *_environ_vector[65];
|
||||
char **environ = _environ_vector;
|
||||
static int _environ_initialized;
|
||||
static int _environ_loading;
|
||||
void __libc_init_environ(const char *blob, size_t len);
|
||||
static sighandler_t _signal_handlers[32];
|
||||
|
||||
static const char *_weekday_short[] = {
|
||||
@@ -354,6 +363,39 @@ static int _alloc_env_slot(void) {
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void _rebuild_environ(void) {
|
||||
int out = 0;
|
||||
for (int i = 0; i < (int)(sizeof(_env_entries) / sizeof(_env_entries[0])); i++) {
|
||||
if (_env_entries[i].string != NULL)
|
||||
_environ_vector[out++] = _env_entries[i].string;
|
||||
}
|
||||
_environ_vector[out] = NULL;
|
||||
}
|
||||
|
||||
static int _sync_environ_to_kernel(void) {
|
||||
static char blob[4096];
|
||||
size_t out = 0;
|
||||
for (int i = 0; i < (int)(sizeof(_env_entries) / sizeof(_env_entries[0])); i++) {
|
||||
if (_env_entries[i].string == NULL) continue;
|
||||
size_t len = strlen(_env_entries[i].string) + 1;
|
||||
if (out + len >= sizeof(blob)) return -1;
|
||||
memcpy(blob + out, _env_entries[i].string, len);
|
||||
out += len;
|
||||
}
|
||||
blob[out++] = '\0';
|
||||
return _zos_syscall2(SYS_SETENVIRON, (long)blob, (long)out) < 0 ? -1 : 0;
|
||||
}
|
||||
|
||||
static void _ensure_environ_initialized(void) {
|
||||
if (_environ_initialized) return;
|
||||
static char blob[4096];
|
||||
int len = (int)_zos_syscall2(SYS_GETENVIRON, (long)blob, (long)sizeof(blob));
|
||||
if (len > 0)
|
||||
__libc_init_environ(blob, (size_t)len);
|
||||
else
|
||||
_environ_initialized = 1;
|
||||
}
|
||||
|
||||
/* ========================================================================
|
||||
string.h functions
|
||||
======================================================================== */
|
||||
@@ -1053,6 +1095,7 @@ unsigned long strtoul(const char *nptr, char **endptr, int base) {
|
||||
|
||||
char *getenv(const char *name) {
|
||||
if (name == NULL || name[0] == '\0') return NULL;
|
||||
_ensure_environ_initialized();
|
||||
|
||||
int slot = _find_env_slot(name);
|
||||
if (slot < 0) return NULL;
|
||||
@@ -1064,33 +1107,55 @@ int setenv(const char *name, const char *value, int overwrite) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
_ensure_environ_initialized();
|
||||
|
||||
int slot = _find_env_slot(name);
|
||||
if (slot >= 0 && !overwrite) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
size_t required = 1 + strlen(name) + strlen(value) + 2; /* final NUL, '=', entry NUL */
|
||||
for (int i = 0; i < (int)(sizeof(_env_entries) / sizeof(_env_entries[0])); i++) {
|
||||
if (i != slot && _env_entries[i].string != NULL)
|
||||
required += strlen(_env_entries[i].string) + 1;
|
||||
}
|
||||
if (required >= 4096) {
|
||||
errno = E2BIG;
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (slot < 0) {
|
||||
slot = _alloc_env_slot();
|
||||
if (slot < 0) {
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
free(_env_entries[slot].name);
|
||||
free(_env_entries[slot].value);
|
||||
_env_entries[slot].name = NULL;
|
||||
_env_entries[slot].value = NULL;
|
||||
}
|
||||
|
||||
_env_entries[slot].name = strdup(name);
|
||||
_env_entries[slot].value = strdup(value);
|
||||
if (_env_entries[slot].name == NULL || _env_entries[slot].value == NULL) {
|
||||
char *new_name = strdup(name);
|
||||
char *new_value = strdup(value);
|
||||
char *new_string = (char *)malloc(strlen(name) + strlen(value) + 2);
|
||||
if (new_name == NULL || new_value == NULL || new_string == NULL) {
|
||||
free(new_name);
|
||||
free(new_value);
|
||||
free(new_string);
|
||||
errno = ENOMEM;
|
||||
return -1;
|
||||
}
|
||||
|
||||
strcpy(new_string, name);
|
||||
strcat(new_string, "=");
|
||||
strcat(new_string, value);
|
||||
free(_env_entries[slot].name);
|
||||
free(_env_entries[slot].value);
|
||||
_env_entries[slot].name = NULL;
|
||||
_env_entries[slot].value = NULL;
|
||||
errno = ENOMEM;
|
||||
free(_env_entries[slot].string);
|
||||
_env_entries[slot].name = new_name;
|
||||
_env_entries[slot].value = new_value;
|
||||
_env_entries[slot].string = new_string;
|
||||
_rebuild_environ();
|
||||
|
||||
if (!_environ_loading && _sync_environ_to_kernel() < 0) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
|
||||
@@ -1102,14 +1167,22 @@ int unsetenv(const char *name) {
|
||||
errno = EINVAL;
|
||||
return -1;
|
||||
}
|
||||
_ensure_environ_initialized();
|
||||
|
||||
int slot = _find_env_slot(name);
|
||||
if (slot < 0) return 0;
|
||||
|
||||
free(_env_entries[slot].name);
|
||||
free(_env_entries[slot].value);
|
||||
free(_env_entries[slot].string);
|
||||
_env_entries[slot].name = NULL;
|
||||
_env_entries[slot].value = NULL;
|
||||
_env_entries[slot].string = NULL;
|
||||
_rebuild_environ();
|
||||
if (_sync_environ_to_kernel() < 0) {
|
||||
errno = EIO;
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
@@ -4114,7 +4187,6 @@ int posix_spawn(pid_t *pid, const char *path,
|
||||
const posix_spawnattr_t *attr,
|
||||
char *const argv[], char *const envp[]) {
|
||||
(void)attr;
|
||||
(void)envp; /* no environment transfer on Montauk spawn */
|
||||
|
||||
if (path == NULL) {
|
||||
return EINVAL;
|
||||
@@ -4148,7 +4220,24 @@ int posix_spawn(pid_t *pid, const char *path,
|
||||
}
|
||||
argsbuf[o] = '\0';
|
||||
|
||||
long child = _zos_syscall2(SYS_SPAWN, (long)path, (long)argsbuf);
|
||||
long child;
|
||||
if (envp == NULL) {
|
||||
child = _zos_syscall2(SYS_SPAWN, (long)path, (long)argsbuf);
|
||||
} else {
|
||||
static char envbuf[4096];
|
||||
size_t envlen = 0;
|
||||
for (int i = 0; envp[i] != NULL; i++) {
|
||||
const char *eq = strchr(envp[i], '=');
|
||||
if (eq == NULL || eq == envp[i]) return EINVAL;
|
||||
size_t len = strlen(envp[i]) + 1;
|
||||
if (envlen + len >= sizeof(envbuf)) return E2BIG;
|
||||
memcpy(envbuf + envlen, envp[i], len);
|
||||
envlen += len;
|
||||
}
|
||||
envbuf[envlen++] = '\0';
|
||||
child = _zos_syscall4(SYS_SPAWN_ENV, (long)path, (long)argsbuf,
|
||||
(long)envbuf, (long)envlen);
|
||||
}
|
||||
if (child < 0) {
|
||||
return ENOENT;
|
||||
}
|
||||
@@ -4192,12 +4281,37 @@ int posix_spawnp(pid_t *pid, const char *file,
|
||||
return ENOENT;
|
||||
}
|
||||
|
||||
/* The libc environment lives in name/value slots (getenv/setenv), not
|
||||
NAME=VALUE strings, and exec* is unimplemented, so nothing can
|
||||
consume a populated environ yet. An empty, valid vector satisfies
|
||||
POSIX-shaped code until the posix_spawn work builds the real one. */
|
||||
static char *_environ_empty[] = { NULL };
|
||||
char **environ = _environ_empty;
|
||||
/* Called by crt1 before constructors. The kernel stores the inherited
|
||||
environment as consecutive NAME=VALUE strings followed by an extra NUL. */
|
||||
void __libc_init_environ(const char *blob, size_t len) {
|
||||
if (_environ_initialized || blob == NULL || len == 0) return;
|
||||
_environ_initialized = 1;
|
||||
_environ_loading = 1;
|
||||
|
||||
size_t off = 0;
|
||||
while (off < len && blob[off] != '\0') {
|
||||
size_t end = off;
|
||||
while (end < len && blob[end] != '\0') end++;
|
||||
if (end == len) break;
|
||||
|
||||
size_t eq = off;
|
||||
while (eq < end && blob[eq] != '=') eq++;
|
||||
if (eq > off && eq < end) {
|
||||
size_t name_len = eq - off;
|
||||
char *name = (char *)malloc(name_len + 1);
|
||||
if (name == NULL) break;
|
||||
memcpy(name, blob + off, name_len);
|
||||
name[name_len] = '\0';
|
||||
if (setenv(name, blob + eq + 1, 1) < 0) {
|
||||
free(name);
|
||||
break;
|
||||
}
|
||||
free(name);
|
||||
}
|
||||
off = end + 1;
|
||||
}
|
||||
_environ_loading = 0;
|
||||
}
|
||||
|
||||
/* No fork/exec process model on Montauk (spawn-style only, see
|
||||
SYS_SPAWN). These exist so POSIX code links; they fail cleanly at
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -59,6 +59,10 @@
|
||||
The argument string is set by the parent when calling spawn().
|
||||
If no arguments were provided, the buffer will be empty.
|
||||
|
||||
A spawned child inherits a snapshot of its parent's environment. Libc
|
||||
exposes it through getenv(), setenv(), and environ. posix_spawn() can
|
||||
instead provide an explicit envp for the child.
|
||||
|
||||
.SH NOTES
|
||||
The _start() entry point receives no argc/argv. Use getargs()
|
||||
to retrieve the argument string passed by the parent process.
|
||||
|
||||
@@ -39,7 +39,8 @@
|
||||
int montauk::getpid();
|
||||
|
||||
.B SYS_SPAWN (20)
|
||||
Spawn a new process from an ELF binary on the VFS.
|
||||
Spawn a new process from an ELF binary on the VFS. The child inherits
|
||||
a snapshot of the caller's environment.
|
||||
int montauk::spawn(const char* path, const char* args = nullptr);
|
||||
|
||||
.B SYS_WAITPID (23)
|
||||
@@ -50,6 +51,11 @@
|
||||
Get the argument string passed to this process at spawn time.
|
||||
int montauk::getargs(char* buf, uint64_t maxLen);
|
||||
|
||||
.B SYS_GETENVIRON (171), SYS_SETENVIRON (172), SYS_SPAWN_ENV (173)
|
||||
Libc process-environment transport. Environment data is encoded as
|
||||
consecutive NAME=VALUE strings with a final empty string. Applications
|
||||
normally use getenv(3), setenv(3), environ, and posix_spawn(3).
|
||||
|
||||
.B SYS_PROCLIST (61)
|
||||
List running processes (pid, parent, state, name, heap usage,
|
||||
accumulated CPU time).
|
||||
|
||||
@@ -39,6 +39,9 @@ static inline long _sys2(long nr, long a1, long a2) {
|
||||
|
||||
#define SYS_GETSIZE 8
|
||||
#define SYS_GETARGS 25
|
||||
#define SYS_GETENVIRON 171
|
||||
|
||||
void __libc_init_environ(const char *blob, unsigned long len);
|
||||
|
||||
/* fdopen, strtoll and strtoull used to be defined here; they moved
|
||||
into the Montauk libc with the native binutils port. */
|
||||
@@ -50,6 +53,11 @@ static inline long _sys2(long nr, long a1, long a2) {
|
||||
int main(int argc, char **argv);
|
||||
|
||||
void _start(void) {
|
||||
static char envbuf[4096];
|
||||
int envlen = (int)_sys2(SYS_GETENVIRON, (long)envbuf, sizeof(envbuf));
|
||||
if (envlen > 0)
|
||||
__libc_init_environ(envbuf, (unsigned long)envlen);
|
||||
|
||||
/* Get command-line arguments from kernel */
|
||||
char argbuf[256];
|
||||
int len = (int)_sys2(SYS_GETARGS, (long)argbuf, sizeof(argbuf));
|
||||
|
||||
@@ -32,7 +32,7 @@ void exit(int code); // Terminate process (nore
|
||||
void yield(); // Yield CPU to scheduler
|
||||
void sleep_ms(uint64_t ms); // Sleep for milliseconds
|
||||
int getpid(); // Get current process ID
|
||||
int spawn(const char* path, const char* args); // Spawn child process (-1 on error)
|
||||
int spawn(const char* path, const char* args); // Spawn child, inheriting environment
|
||||
int waitpid(int pid); // Wait for process to exit
|
||||
int kill(int pid); // Kill a process
|
||||
int proclist(ProcInfo* buf, int max); // List all processes (returns count)
|
||||
|
||||
@@ -208,6 +208,9 @@ namespace montauk::abi {
|
||||
|
||||
// Absolute path of the running executable (for argv[0]).
|
||||
static constexpr uint64_t SYS_GETEXECPATH = 151; // (index, flags) -> new front index; index=-1 queries support (1/0); flags bit0 = wait vsync
|
||||
static constexpr uint64_t SYS_GETENVIRON = 171;
|
||||
static constexpr uint64_t SYS_SETENVIRON = 172;
|
||||
static constexpr uint64_t SYS_SPAWN_ENV = 173;
|
||||
|
||||
// Path metadata (size, timestamps, mode). (const char* path, FileStat* out) -> 0, -1 on error/unsupported.
|
||||
static constexpr uint64_t SYS_STAT = 152;
|
||||
|
||||
@@ -73,6 +73,9 @@ extern "C" {
|
||||
#define MTK_SYS_MOUSESTATE 47
|
||||
#define MTK_SYS_SETMOUSEBOUNDS 48
|
||||
#define MTK_SYS_SPAWN_REDIR 49
|
||||
#define MTK_SYS_GETENVIRON 171
|
||||
#define MTK_SYS_SETENVIRON 172
|
||||
#define MTK_SYS_SPAWN_ENV 173
|
||||
#define MTK_SYS_CHILDIO_READ 50
|
||||
#define MTK_SYS_CHILDIO_WRITE 51
|
||||
#define MTK_SYS_CHILDIO_WRITEKEY 52
|
||||
|
||||
@@ -15,7 +15,7 @@ extern "C" {
|
||||
* Limitations (kernel spawn model):
|
||||
* - argv is joined into a single args string; arguments containing
|
||||
* spaces are rejected with EINVAL (no quoting in the kernel).
|
||||
* - envp is ignored (no environment transfer on spawn).
|
||||
* - envp is copied into the child; NULL inherits the current environment.
|
||||
* - file actions must be empty: stdio redirection needs kernel
|
||||
* support that does not exist yet, so any recorded action makes
|
||||
* posix_spawn fail with ENOTSUP rather than misbehave silently.
|
||||
|
||||
@@ -66,12 +66,12 @@
|
||||
prefix_from_env ("PATH", &path);
|
||||
|
||||
+#ifdef __montauk__
|
||||
+ /* MontaukOS does not pass environment variables across spawn yet, so
|
||||
+ COMPILER_PATH and PATH above are always empty. Derive the compiler
|
||||
+ search path from argv[0] instead: the driver invokes collect2 by its
|
||||
+ full path (the kernel provides the real exec path in argv[0]), and
|
||||
+ `ld` lives in the same libexec directory. Also seed PATH with the
|
||||
+ SDK bin directories so the nm/strip/tooldir fallbacks work. */
|
||||
+ /* Keep a fallback for early boot and deliberately minimal environments.
|
||||
+ Derive the compiler search path from argv[0]: the driver invokes
|
||||
+ collect2 by its full path (the kernel provides the real exec path in
|
||||
+ argv[0]), and `ld` lives in the same libexec directory. Also seed PATH
|
||||
+ with the SDK bin directories when the caller did not provide one. */
|
||||
+
|
||||
+ if (cpath.plist == NULL && argv[0] != NULL)
|
||||
+ {
|
||||
+ const char *slash = strrchr (argv[0], '/');
|
||||
|
||||
Reference in New Issue
Block a user