Serenity Operating System
at master 138 lines 3.8 kB view raw
1/* 2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org> 3 * 4 * SPDX-License-Identifier: BSD-2-Clause 5 */ 6 7#include <Kernel/API/Ioctl.h> 8#include <Kernel/API/POSIX/errno.h> 9#include <Kernel/API/POSIX/signal_numbers.h> 10#include <Kernel/Debug.h> 11#include <Kernel/InterruptDisabler.h> 12#include <Kernel/Process.h> 13#include <Kernel/TTY/MasterPTY.h> 14#include <Kernel/TTY/PTYMultiplexer.h> 15#include <Kernel/TTY/SlavePTY.h> 16 17namespace Kernel { 18 19ErrorOr<NonnullLockRefPtr<MasterPTY>> MasterPTY::try_create(unsigned int index) 20{ 21 auto buffer = TRY(DoubleBuffer::try_create("MasterPTY: Buffer"sv)); 22 auto master_pty = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) MasterPTY(index, move(buffer)))); 23 auto slave_pty = TRY(adopt_nonnull_lock_ref_or_enomem(new (nothrow) SlavePTY(*master_pty, index))); 24 master_pty->m_slave = slave_pty; 25 TRY(master_pty->after_inserting()); 26 TRY(slave_pty->after_inserting()); 27 return master_pty; 28} 29 30MasterPTY::MasterPTY(unsigned index, NonnullOwnPtr<DoubleBuffer> buffer) 31 : CharacterDevice(200, index) 32 , m_index(index) 33 , m_buffer(move(buffer)) 34{ 35 auto& process = Process::current(); 36 auto credentials = process.credentials(); 37 set_uid(credentials->uid()); 38 set_gid(credentials->gid()); 39 40 m_buffer->set_unblock_callback([this]() { 41 if (m_slave) 42 evaluate_block_conditions(); 43 }); 44} 45 46MasterPTY::~MasterPTY() 47{ 48 dbgln_if(MASTERPTY_DEBUG, "~MasterPTY({})", m_index); 49 PTYMultiplexer::the().notify_master_destroyed({}, m_index); 50} 51 52ErrorOr<size_t> MasterPTY::read(OpenFileDescription&, u64, UserOrKernelBuffer& buffer, size_t size) 53{ 54 if (!m_slave && m_buffer->is_empty()) 55 return 0; 56 return m_buffer->read(buffer, size); 57} 58 59ErrorOr<size_t> MasterPTY::write(OpenFileDescription&, u64, UserOrKernelBuffer const& buffer, size_t size) 60{ 61 if (!m_slave) 62 return EIO; 63 m_slave->on_master_write(buffer, size); 64 return size; 65} 66 67bool MasterPTY::can_read(OpenFileDescription const&, u64) const 68{ 69 if (!m_slave) 70 return true; 71 return !m_buffer->is_empty(); 72} 73 74bool MasterPTY::can_write(OpenFileDescription const&, u64) const 75{ 76 return true; 77} 78 79void MasterPTY::notify_slave_closed(Badge<SlavePTY>) 80{ 81 dbgln_if(MASTERPTY_DEBUG, "MasterPTY({}): slave closed, my retains: {}, slave retains: {}", m_index, ref_count(), m_slave->ref_count()); 82 // +1 ref for my MasterPTY::m_slave 83 // +1 ref for OpenFileDescription::m_device 84 if (m_slave->ref_count() == 2) 85 m_slave = nullptr; 86} 87 88ErrorOr<size_t> MasterPTY::on_slave_write(UserOrKernelBuffer const& data, size_t size) 89{ 90 if (m_closed) 91 return EIO; 92 return m_buffer->write(data, size); 93} 94 95bool MasterPTY::can_write_from_slave() const 96{ 97 if (m_closed) 98 return true; 99 return m_buffer->space_for_writing(); 100} 101 102ErrorOr<void> MasterPTY::close() 103{ 104 InterruptDisabler disabler; 105 // After the closing OpenFileDescription dies, slave is the only thing keeping me alive. 106 // From this point, let's consider ourselves closed. 107 m_closed = true; 108 109 if (m_slave) 110 m_slave->hang_up(); 111 112 return {}; 113} 114 115ErrorOr<void> MasterPTY::ioctl(OpenFileDescription& description, unsigned request, Userspace<void*> arg) 116{ 117 TRY(Process::current().require_promise(Pledge::tty)); 118 if (!m_slave) 119 return EIO; 120 switch (request) { 121 case TIOCGPTN: { 122 int master_pty_index = index(); 123 return copy_to_user(static_ptr_cast<int*>(arg), &master_pty_index); 124 } 125 case TIOCSWINSZ: 126 case TIOCGPGRP: 127 return m_slave->ioctl(description, request, arg); 128 default: 129 return EINVAL; 130 } 131} 132 133ErrorOr<NonnullOwnPtr<KString>> MasterPTY::pseudo_path(OpenFileDescription const&) const 134{ 135 return KString::formatted("ptm:{}", m_index); 136} 137 138}