Luna/kernel/src/fs/devices/MasterPTY.cpp

126 lines
3.8 KiB
C++

#include "fs/devices/MasterPTY.h"
#include "Pledge.h"
#include "fs/devices/DeviceRegistry.h"
#include "fs/devices/PTYMultiplexer.h"
#include "fs/devpts/FileSystem.h"
#include "memory/MemoryManager.h"
#include "thread/Scheduler.h"
Result<SharedPtr<VFS::Inode>> MasterPTY::create_pair(int index)
{
auto master = TRY(make_shared<MasterPTY>());
auto slave = TRY(make_shared<SlavePTY>());
auto name = TRY(String::format("%d"_sv, index));
for (auto& fs : g_devpts_instances) { fs->root_inode()->add_entry(slave, name.chars()); }
slave->m_name = move(name);
master->m_metadata.mode = 0666;
master->m_index = index;
master->m_slave = slave;
master->m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, 0);
master->m_settings.c_lflag = ECHO | ECHOE | ECHOCTL | ISIG | ICANON;
master->m_settings.c_cc[VEOF] = '\4';
master->m_settings.c_cc[VERASE] = '\b';
master->m_settings.c_cc[VINTR] = '\3';
master->m_settings.c_cc[VQUIT] = '\x1c';
master->m_window.ws_col = 80;
master->m_window.ws_row = 25;
slave->m_master = master.ptr();
slave->m_metadata.devid = luna_dev_makedev(DeviceRegistry::Terminal, index + 1);
slave->m_metadata.uid = Scheduler::current()->auth.euid;
slave->m_metadata.gid = Scheduler::current()->auth.egid;
slave->m_metadata.mode = 0620;
return (SharedPtr<VFS::Inode>)master;
}
Result<void> MasterPTY::handle_background_process_group(bool can_succeed, int signo) const
{
if (!m_foreground_process_group.has_value()) return {};
auto foreground_pgrp = m_foreground_process_group.value();
auto* current = Scheduler::current();
if (current->pgid == foreground_pgrp) return {};
if ((current->signal_mask.get(signo - 1)) || (current->signal_handlers[signo - 1].sa_handler == SIG_IGN))
{
if (can_succeed) return {};
return err(EIO);
}
current->send_signal(signo);
if (can_succeed) return err(EINTR);
return err(EIO);
}
Result<usize> MasterPTY::read(u8* buf, usize, usize length) const
{
length = m_buffer.dequeue_data(buf, length);
return length;
}
Result<usize> MasterPTY::write(const u8* buf, usize, usize length)
{
TRY(m_slave->m_buffer.append_data(buf, length));
return length;
}
Result<u64> MasterPTY::ioctl(int request, void* arg)
{
auto* current = Scheduler::current();
TRY(check_pledge(current, Promise::p_tty));
switch (request)
{
case TCGETS: {
return MemoryManager::copy_to_user_typed((struct termios*)arg, &m_settings) ? 0 : err(EFAULT);
}
case TCSETS: {
if (!MemoryManager::copy_from_user_typed((const struct termios*)arg, &m_settings)) return err(EFAULT);
return 0;
}
case TIOCSPGRP: {
pid_t pgid;
if (!MemoryManager::copy_from_user_typed((const pid_t*)arg, &pgid)) return err(EFAULT);
bool pgid_exists = false;
Scheduler::for_each_in_process_group(pgid, [&pgid_exists](Thread*) {
pgid_exists = true;
return false;
});
if (!pgid_exists) return err(EPERM);
m_foreground_process_group = pgid;
return 0;
}
case TIOCGPGRP: {
pid_t pgid = m_foreground_process_group.value_or((pid_t)next_thread_id());
if (!MemoryManager::copy_to_user_typed((pid_t*)arg, &pgid)) return err(EFAULT);
return 0;
}
case TIOCGWINSZ: {
if (!MemoryManager::copy_to_user_typed((struct winsize*)arg, &m_window)) return err(EFAULT);
return 0;
}
case TIOCGPTN: {
if (!MemoryManager::copy_to_user_typed((int*)arg, &m_index)) return err(EFAULT);
return 0;
}
default: return err(EINVAL);
}
}
MasterPTY::~MasterPTY()
{
m_slave->m_master = nullptr;
for (auto& fs : g_devpts_instances) { fs->root_inode()->remove_entry(m_slave->m_name.chars()); }
PTYMultiplexer::did_remove_pty(m_index);
}