Serenity Operating System
1/*
2 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
3 *
4 * SPDX-License-Identifier: BSD-2-Clause
5 */
6
7#include <AK/Singleton.h>
8#include <Kernel/Debug.h>
9#include <Kernel/Process.h>
10#include <Kernel/TTY/MasterPTY.h>
11#include <Kernel/TTY/SlavePTY.h>
12
13namespace Kernel {
14
15static Singleton<SpinlockProtected<SlavePTY::List, LockRank::None>> s_all_instances;
16
17SpinlockProtected<SlavePTY::List, LockRank::None>& SlavePTY::all_instances()
18{
19 return s_all_instances;
20}
21
22bool SlavePTY::unref() const
23{
24 bool did_hit_zero = SlavePTY::all_instances().with([&](auto&) {
25 if (deref_base())
26 return false;
27 m_list_node.remove();
28 const_cast<SlavePTY&>(*this).revoke_weak_ptrs();
29 return true;
30 });
31 if (did_hit_zero) {
32 const_cast<SlavePTY&>(*this).will_be_destroyed();
33 delete this;
34 }
35 return did_hit_zero;
36}
37
38SlavePTY::SlavePTY(MasterPTY& master, unsigned index)
39 : TTY(201, index)
40 , m_master(master)
41 , m_index(index)
42{
43 auto& process = Process::current();
44 auto credentials = process.credentials();
45 set_uid(credentials->uid());
46 set_gid(credentials->gid());
47 set_size(80, 25);
48
49 SlavePTY::all_instances().with([&](auto& list) { list.append(*this); });
50}
51
52SlavePTY::~SlavePTY()
53{
54 dbgln_if(SLAVEPTY_DEBUG, "~SlavePTY({})", m_index);
55}
56
57ErrorOr<NonnullOwnPtr<KString>> SlavePTY::pseudo_name() const
58{
59 return KString::formatted("pts:{}", m_index);
60}
61
62void SlavePTY::echo(u8 ch)
63{
64 if (should_echo_input()) {
65 auto buffer = UserOrKernelBuffer::for_kernel_buffer(&ch);
66 [[maybe_unused]] auto result = m_master->on_slave_write(buffer, 1);
67 }
68}
69
70void SlavePTY::on_master_write(UserOrKernelBuffer const& buffer, size_t size)
71{
72 auto result = buffer.read_buffered<128>(size, [&](ReadonlyBytes data) {
73 for (const auto& byte : data)
74 emit(byte, false);
75 return data.size();
76 });
77 if (!result.is_error())
78 evaluate_block_conditions();
79}
80
81ErrorOr<size_t> SlavePTY::on_tty_write(UserOrKernelBuffer const& data, size_t size)
82{
83 m_time_of_last_write = kgettimeofday().to_truncated_seconds();
84 return m_master->on_slave_write(data, size);
85}
86
87bool SlavePTY::can_write(OpenFileDescription const&, u64) const
88{
89 return m_master->can_write_from_slave();
90}
91
92bool SlavePTY::can_read(OpenFileDescription const& description, u64 offset) const
93{
94 if (m_master->is_closed())
95 return true;
96 return TTY::can_read(description, offset);
97}
98
99ErrorOr<size_t> SlavePTY::read(OpenFileDescription& description, u64 offset, UserOrKernelBuffer& buffer, size_t size)
100{
101 if (m_master->is_closed())
102 return 0;
103 return TTY::read(description, offset, buffer, size);
104}
105
106ErrorOr<void> SlavePTY::close()
107{
108 m_master->notify_slave_closed({});
109 return {};
110}
111
112FileBlockerSet& SlavePTY::blocker_set()
113{
114 return m_master->blocker_set();
115}
116
117}