diff --git a/kernel/src/Api/BuildNo.hpp b/kernel/src/Api/BuildNo.hpp index 267149c..2cf2840 100644 --- a/kernel/src/Api/BuildNo.hpp +++ b/kernel/src/Api/BuildNo.hpp @@ -12,4 +12,4 @@ #pragma once -#define MONTAUK_BUILD_NUMBER 177 +#define MONTAUK_BUILD_NUMBER 178 diff --git a/kernel/src/Api/Process.hpp b/kernel/src/Api/Process.hpp index 215a0de..817506a 100644 --- a/kernel/src/Api/Process.hpp +++ b/kernel/src/Api/Process.hpp @@ -43,6 +43,43 @@ namespace montauk::abi { return Sched::LookupExitCode(pid); } + // Hand a freshly spawned child the parent's redirected console. Both spawn + // syscalls need this: a console tool launched from a GUI terminal must read + // its keys from the terminal's mailbox and write its output back up the + // stream, whether or not it also carries a capability grant. The child is + // created suspended (startReady == false) so its first instruction cannot + // run before the channels exist, and is started here once they do. + // Returns childPid, or kills the child and returns -1 on failure. + static int InheritRedirection(int childPid, Sched::Process* parent, int parentSlot) { + auto* child = Sched::GetProcessByPid(childPid); + int childSlot = Ipc::SlotForPid(childPid); + if (child == nullptr || childSlot < 0 || parentSlot < 0) { + Sched::KillProcess(childPid); + return -1; + } + + child->ioOutHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioOutHandle, childSlot); + child->ioInHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioInHandle, childSlot); + child->ioKeyHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioKeyHandle, childSlot); + + if (child->ioOutHandle < 0 || child->ioInHandle < 0 || child->ioKeyHandle < 0 || + !ConfigureRedirWaitsetForSlot(childSlot, child)) { + Sched::KillProcess(childPid); + return -1; + } + + child->redirected = true; + child->parentPid = parent->pid; + child->termCols = parent->termCols; + child->termRows = parent->termRows; + if (Sched::StartProcess(childPid) < 0) { + Sched::KillProcess(childPid); + return -1; + } + + return childPid; + } + static int Sys_Spawn(const char* path, const char* args, const char* environment = nullptr, uint32_t environmentLength = 0) { char resolved[256]; @@ -55,33 +92,8 @@ namespace montauk::abi { environment, environmentLength); if (childPid < 0) return childPid; - if (inheritRedirection) { - auto* child = Sched::GetProcessByPid(childPid); - int childSlot = Ipc::SlotForPid(childPid); - if (child == nullptr || childSlot < 0 || parentSlot < 0) { - Sched::KillProcess(childPid); - return -1; - } - - child->ioOutHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioOutHandle, childSlot); - child->ioInHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioInHandle, childSlot); - child->ioKeyHandle = DuplicateHandleBetweenSlots(parentSlot, parent->ioKeyHandle, childSlot); - - if (child->ioOutHandle < 0 || child->ioInHandle < 0 || child->ioKeyHandle < 0 || - !ConfigureRedirWaitsetForSlot(childSlot, child)) { - Sched::KillProcess(childPid); - return -1; - } - - child->redirected = true; - child->parentPid = parent->pid; - child->termCols = parent->termCols; - child->termRows = parent->termRows; - if (Sched::StartProcess(childPid) < 0) { - Sched::KillProcess(childPid); - return -1; - } - } + if (inheritRedirection) + return InheritRedirection(childPid, parent, parentSlot); return childPid; } @@ -115,8 +127,17 @@ namespace montauk::abi { char resolved[256]; if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1; - return Sched::Spawn(resolved, args, true, nullptr, 0, ©, - userOverride); + + int parentSlot = Ipc::CurrentSlot(); + bool inheritRedirection = parent->redirected; + int childPid = Sched::Spawn(resolved, args, !inheritRedirection, + nullptr, 0, ©, userOverride); + if (childPid < 0) return childPid; + + if (inheritRedirection) + return InheritRedirection(childPid, parent, parentSlot); + + return childPid; } // Copy the absolute path this process was spawned from (argv[0]).