summaryrefslogtreecommitdiff
path: root/Kernel/TTY/SlavePTY.cpp
blob: f916a330f354e890c3bb689406d51c120013ed64 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
/*
 * Copyright (c) 2018-2021, Andreas Kling <kling@serenityos.org>
 *
 * SPDX-License-Identifier: BSD-2-Clause
 */

#include <AK/Singleton.h>
#include <Kernel/Debug.h>
#include <Kernel/FileSystem/DevPtsFS.h>
#include <Kernel/Process.h>
#include <Kernel/TTY/MasterPTY.h>
#include <Kernel/TTY/SlavePTY.h>

namespace Kernel {

static Singleton<SpinlockProtected<SlavePTY::List>> s_all_instances;

SpinlockProtected<SlavePTY::List>& SlavePTY::all_instances()
{
    return s_all_instances;
}

bool SlavePTY::unref() const
{
    bool did_hit_zero = SlavePTY::all_instances().with([&](auto&) {
        if (deref_base())
            return false;
        m_list_node.remove();
        const_cast<SlavePTY&>(*this).revoke_weak_ptrs();
        return true;
    });
    if (did_hit_zero) {
        const_cast<SlavePTY&>(*this).will_be_destroyed();
        delete this;
    }
    return did_hit_zero;
}

SlavePTY::SlavePTY(MasterPTY& master, unsigned index)
    : TTY(201, index)
    , m_master(master)
    , m_index(index)
{
    auto& process = Process::current();
    set_uid(process.uid());
    set_gid(process.gid());
    set_size(80, 25);

    SlavePTY::all_instances().with([&](auto& list) { list.append(*this); });
}

SlavePTY::~SlavePTY()
{
    dbgln_if(SLAVEPTY_DEBUG, "~SlavePTY({})", m_index);
}

ErrorOr<NonnullOwnPtr<KString>> SlavePTY::pseudo_name() const
{
    return KString::formatted("pts:{}", m_index);
}

void SlavePTY::echo(u8 ch)
{
    if (should_echo_input()) {
        auto buffer = UserOrKernelBuffer::for_kernel_buffer(&ch);
        [[maybe_unused]] auto result = m_master->on_slave_write(buffer, 1);
    }
}

void SlavePTY::on_master_write(const UserOrKernelBuffer& buffer, size_t size)
{
    auto result = buffer.read_buffered<128>(size, [&](ReadonlyBytes data) {
        for (const auto& byte : data)
            emit(byte, false);
        return data.size();
    });
    if (!result.is_error())
        evaluate_block_conditions();
}

ErrorOr<size_t> SlavePTY::on_tty_write(const UserOrKernelBuffer& data, size_t size)
{
    m_time_of_last_write = kgettimeofday().to_truncated_seconds();
    return m_master->on_slave_write(data, size);
}

bool SlavePTY::can_write(const OpenFileDescription&, u64) const
{
    return m_master->can_write_from_slave();
}

bool SlavePTY::can_read(const OpenFileDescription& description, u64 offset) const
{
    if (m_master->is_closed())
        return true;
    return TTY::can_read(description, offset);
}

ErrorOr<size_t> SlavePTY::read(OpenFileDescription& description, u64 offset, UserOrKernelBuffer& buffer, size_t size)
{
    if (m_master->is_closed())
        return 0;
    return TTY::read(description, offset, buffer, size);
}

ErrorOr<void> SlavePTY::close()
{
    m_master->notify_slave_closed({});
    return {};
}

FileBlockerSet& SlavePTY::blocker_set()
{
    return m_master->blocker_set();
}

}