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/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
|
||||||
|
|||||||
@@ -12,4 +12,4 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#define MONTAUK_BUILD_NUMBER 104
|
#define MONTAUK_BUILD_NUMBER 106
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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);
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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) {
|
||||||
|
|||||||
@@ -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();
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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
@@ -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.
@@ -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.
|
||||||
|
|||||||
@@ -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).
|
||||||
|
|||||||
@@ -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));
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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.
|
||||||
|
|||||||
@@ -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], '/');
|
||||||
|
|||||||
Reference in New Issue
Block a user