#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> MasterPTY::create_pair(int index) { auto master = TRY(make_shared()); auto slave = TRY(make_shared()); 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)master; } Result 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 MasterPTY::read(u8* buf, usize, usize length) const { length = m_buffer.dequeue_data(buf, length); return length; } Result MasterPTY::write(const u8* buf, usize, usize length) { TRY(m_slave->m_buffer.append_data(buf, length)); return length; } Result 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); }