123 lines
5.1 KiB
C++
123 lines
5.1 KiB
C++
/*
|
|
* IoRedir.hpp
|
|
* SYS_SPAWN_REDIR, SYS_CHILDIO_READ, SYS_CHILDIO_WRITE,
|
|
* SYS_CHILDIO_WRITEKEY, SYS_CHILDIO_SETTERMSZ syscalls
|
|
* Copyright (c) 2026 Daniel Hammer
|
|
*/
|
|
|
|
#pragma once
|
|
#include <Sched/Scheduler.hpp>
|
|
#include "Syscall.hpp"
|
|
#include "Common.hpp"
|
|
#include "Path.hpp"
|
|
|
|
namespace Montauk {
|
|
|
|
static int Sys_SpawnRedir(const char* path, const char* args) {
|
|
char resolved[256];
|
|
if (!ResolveProcessPath(path, resolved, sizeof(resolved))) return -1;
|
|
|
|
int parentSlot = Ipc::CurrentSlot();
|
|
int childPid = Sched::Spawn(resolved, args, false);
|
|
if (childPid < 0) return -1;
|
|
|
|
auto* child = Sched::GetProcessByPid(childPid);
|
|
int childSlot = Ipc::SlotForPid(childPid);
|
|
if (child == nullptr || childSlot < 0 || parentSlot < 0) {
|
|
Sched::KillProcess(childPid);
|
|
return -1;
|
|
}
|
|
|
|
Ipc::Stream* outStream = Ipc::CreateStream();
|
|
Ipc::Stream* inStream = Ipc::CreateStream();
|
|
Ipc::Mailbox* keyMailbox = Ipc::CreateMailbox();
|
|
if (outStream == nullptr || inStream == nullptr || keyMailbox == nullptr) {
|
|
if (outStream != nullptr) Ipc::ReleaseStream(outStream, false, false);
|
|
if (inStream != nullptr) Ipc::ReleaseStream(inStream, false, false);
|
|
if (keyMailbox != nullptr) Ipc::ReleaseMailbox(keyMailbox, false, false);
|
|
Sched::KillProcess(childPid);
|
|
return -1;
|
|
}
|
|
|
|
int parentOutHandle = Ipc::InstallHandleForSlot(
|
|
parentSlot, (Ipc::Object*)outStream, Ipc::HandleType::Stream, Ipc::RightRead);
|
|
int parentInHandle = Ipc::InstallHandleForSlot(
|
|
parentSlot, (Ipc::Object*)inStream, Ipc::HandleType::Stream, Ipc::RightWrite);
|
|
int parentKeyHandle = Ipc::InstallHandleForSlot(
|
|
parentSlot, (Ipc::Object*)keyMailbox, Ipc::HandleType::Mailbox, Ipc::RightSend);
|
|
|
|
child->ioOutHandle = Ipc::InstallHandleForSlot(
|
|
childSlot, (Ipc::Object*)outStream, Ipc::HandleType::Stream,
|
|
Ipc::RightWrite | Ipc::RightWait | Ipc::RightDup);
|
|
child->ioInHandle = Ipc::InstallHandleForSlot(
|
|
childSlot, (Ipc::Object*)inStream, Ipc::HandleType::Stream,
|
|
Ipc::RightRead | Ipc::RightWait | Ipc::RightDup);
|
|
child->ioKeyHandle = Ipc::InstallHandleForSlot(
|
|
childSlot, (Ipc::Object*)keyMailbox, Ipc::HandleType::Mailbox,
|
|
Ipc::RightRecv | Ipc::RightWait | Ipc::RightDup);
|
|
|
|
if (parentOutHandle < 0 || parentInHandle < 0 || parentKeyHandle < 0 ||
|
|
child->ioOutHandle < 0 || child->ioInHandle < 0 || child->ioKeyHandle < 0 ||
|
|
!ConfigureRedirWaitsetForSlot(childSlot, child)) {
|
|
if (parentOutHandle >= 0) Ipc::CloseHandleForSlot(parentSlot, parentOutHandle);
|
|
if (parentInHandle >= 0) Ipc::CloseHandleForSlot(parentSlot, parentInHandle);
|
|
if (parentKeyHandle >= 0) Ipc::CloseHandleForSlot(parentSlot, parentKeyHandle);
|
|
if (child->ioOutHandle < 0) Ipc::ReleaseStream(outStream, false, false);
|
|
if (child->ioInHandle < 0) Ipc::ReleaseStream(inStream, false, false);
|
|
if (child->ioKeyHandle < 0) Ipc::ReleaseMailbox(keyMailbox, false, false);
|
|
Sched::KillProcess(childPid);
|
|
return -1;
|
|
}
|
|
|
|
child->redirected = true;
|
|
child->parentPid = Sched::GetCurrentPid();
|
|
child->termCols = 80;
|
|
child->termRows = 25;
|
|
if (Sched::StartProcess(childPid) < 0) {
|
|
Sched::KillProcess(childPid);
|
|
return -1;
|
|
}
|
|
|
|
return childPid;
|
|
}
|
|
|
|
static int Sys_ChildIoRead(int childPid, char* buf, int maxLen) {
|
|
auto* child = Sched::GetProcessByPid(childPid);
|
|
Ipc::Stream* stream = GetRedirOutStream(child);
|
|
if (child == nullptr || !child->redirected || stream == nullptr) return -1;
|
|
return Ipc::StreamRead(stream, (uint8_t*)buf, maxLen, true);
|
|
}
|
|
|
|
static int Sys_ChildIoWrite(int childPid, const char* data, int len) {
|
|
auto* child = Sched::GetProcessByPid(childPid);
|
|
Ipc::Stream* stream = GetRedirInStream(child);
|
|
if (child == nullptr || !child->redirected || stream == nullptr) return -1;
|
|
return WriteAllToStream(stream, (const uint8_t*)data, len);
|
|
}
|
|
|
|
static int Sys_ChildIoWriteKey(int childPid, const KeyEvent* key) {
|
|
if (key == nullptr) return -1;
|
|
auto* child = Sched::GetProcessByPid(childPid);
|
|
Ipc::Mailbox* mailbox = GetRedirKeyMailbox(child);
|
|
if (child == nullptr || !child->redirected || mailbox == nullptr) return -1;
|
|
|
|
for (;;) {
|
|
int rc = Ipc::MailboxSend(mailbox, 0, key, sizeof(KeyEvent));
|
|
if (rc < 0) return -1;
|
|
if (rc == 0) {
|
|
Sched::BlockOnObject(mailbox, 0);
|
|
continue;
|
|
}
|
|
return 0;
|
|
}
|
|
}
|
|
|
|
static int Sys_ChildIoSetTermsz(int childPid, int cols, int rows) {
|
|
auto* child = Sched::GetProcessByPid(childPid);
|
|
if (child == nullptr || !child->redirected) return -1;
|
|
child->termCols = cols;
|
|
child->termRows = rows;
|
|
return 0;
|
|
}
|
|
};
|