fix: inherit process environment and untrack libc objects

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