Serenity Operating System
1/*
2 * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions are met:
7 *
8 * 1. Redistributions of source code must retain the above copyright notice, this
9 * list of conditions and the following disclaimer.
10 *
11 * 2. Redistributions in binary form must reproduce the above copyright notice,
12 * this list of conditions and the following disclaimer in the documentation
13 * and/or other materials provided with the distribution.
14 *
15 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
16 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
18 * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
21 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
22 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
23 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
24 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25 */
26
27#pragma once
28
29#include <AK/HashMap.h>
30#include <AK/Types.h>
31#include <Kernel/FileSystem/FileSystem.h>
32#include <Kernel/FileSystem/Inode.h>
33#include <Kernel/KBuffer.h>
34#include <Kernel/Lock.h>
35
36namespace Kernel {
37
38class Process;
39
40class ProcFSInode;
41
42class ProcFS final : public FS {
43 friend class ProcFSInode;
44
45public:
46 virtual ~ProcFS() override;
47 static NonnullRefPtr<ProcFS> create();
48
49 virtual bool initialize() override;
50 virtual const char* class_name() const override;
51
52 virtual InodeIdentifier root_inode() const override;
53 virtual RefPtr<Inode> get_inode(InodeIdentifier) const override;
54
55 virtual KResultOr<NonnullRefPtr<Inode>> create_inode(InodeIdentifier parent_id, const String& name, mode_t, off_t size, dev_t, uid_t, gid_t) override;
56 virtual KResult create_directory(InodeIdentifier parent_id, const String& name, mode_t, uid_t, gid_t) override;
57
58 static void add_sys_bool(String&&, Lockable<bool>&, Function<void()>&& notify_callback = nullptr);
59 static void add_sys_string(String&&, Lockable<String>&, Function<void()>&& notify_callback = nullptr);
60
61private:
62 ProcFS();
63
64 struct ProcFSDirectoryEntry {
65 ProcFSDirectoryEntry() {}
66 ProcFSDirectoryEntry(const char* a_name, unsigned a_proc_file_type, bool a_supervisor_only, Function<Optional<KBuffer>(InodeIdentifier)>&& a_read_callback = nullptr, Function<ssize_t(InodeIdentifier, const ByteBuffer&)>&& a_write_callback = nullptr, RefPtr<ProcFSInode>&& a_inode = nullptr)
67 : name(a_name)
68 , proc_file_type(a_proc_file_type)
69 , supervisor_only(a_supervisor_only)
70 , read_callback(move(a_read_callback))
71 , write_callback(move(a_write_callback))
72 , inode(move(a_inode))
73 {
74 }
75
76 const char* name { nullptr };
77 unsigned proc_file_type { 0 };
78 bool supervisor_only { false };
79 Function<Optional<KBuffer>(InodeIdentifier)> read_callback;
80 Function<ssize_t(InodeIdentifier, const ByteBuffer&)> write_callback;
81 RefPtr<ProcFSInode> inode;
82 InodeIdentifier identifier(unsigned fsid) const;
83 };
84
85 ProcFSDirectoryEntry* get_directory_entry(InodeIdentifier) const;
86
87 Vector<ProcFSDirectoryEntry> m_entries;
88
89 mutable Lock m_inodes_lock;
90 mutable HashMap<unsigned, ProcFSInode*> m_inodes;
91 RefPtr<ProcFSInode> m_root_inode;
92};
93
94class ProcFSInode final : public Inode {
95 friend class ProcFS;
96
97public:
98 virtual ~ProcFSInode() override;
99
100private:
101 // ^Inode
102 virtual ssize_t read_bytes(off_t, ssize_t, u8* buffer, FileDescription*) const override;
103 virtual InodeMetadata metadata() const override;
104 virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override;
105 virtual RefPtr<Inode> lookup(StringView name) override;
106 virtual void flush_metadata() override;
107 virtual ssize_t write_bytes(off_t, ssize_t, const u8* buffer, FileDescription*) override;
108 virtual KResult add_child(InodeIdentifier child_id, const StringView& name, mode_t) override;
109 virtual KResult remove_child(const StringView& name) override;
110 virtual size_t directory_entry_count() const override;
111 virtual KResult chmod(mode_t) override;
112 virtual KResult chown(uid_t, gid_t) override;
113 virtual KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody& base, RefPtr<Custody>* out_parent = nullptr, int options = 0, int symlink_recursion_level = 0) const override;
114
115 ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
116 const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
117 ProcFSInode(ProcFS&, unsigned index);
118};
119
120class ProcFSProxyInode final : public Inode {
121 friend class ProcFSInode;
122
123public:
124 virtual ~ProcFSProxyInode() override;
125
126private:
127 // ^Inode
128 virtual ssize_t read_bytes(off_t, ssize_t, u8*, FileDescription*) const override { ASSERT_NOT_REACHED(); }
129 virtual InodeMetadata metadata() const override;
130 virtual bool traverse_as_directory(Function<bool(const FS::DirectoryEntry&)>) const override { ASSERT_NOT_REACHED(); }
131 virtual RefPtr<Inode> lookup(StringView name) override;
132 virtual void flush_metadata() override {};
133 virtual ssize_t write_bytes(off_t, ssize_t, const u8*, FileDescription*) override { ASSERT_NOT_REACHED(); }
134 virtual KResult add_child(InodeIdentifier child_id, const StringView& name, mode_t) override;
135 virtual KResult remove_child(const StringView& name) override;
136 virtual size_t directory_entry_count() const override;
137 virtual KResult chmod(mode_t) override { return KResult(-EINVAL); }
138 virtual KResult chown(uid_t, gid_t) override { return KResult(-EINVAL); }
139 virtual KResultOr<NonnullRefPtr<Custody>> resolve_as_link(Custody&, RefPtr<Custody>*, int, int) const override { ASSERT_NOT_REACHED(); }
140 virtual FileDescription* preopen_fd() override { return m_fd; }
141
142 ProcFS& fs() { return static_cast<ProcFS&>(Inode::fs()); }
143 const ProcFS& fs() const { return static_cast<const ProcFS&>(Inode::fs()); }
144
145 ProcFSProxyInode(ProcFS&, FileDescription&);
146 static NonnullRefPtr<ProcFSProxyInode> create(ProcFS& fs, FileDescription& fd)
147 {
148 return adopt(*new ProcFSProxyInode(fs, fd));
149 }
150
151 NonnullRefPtr<FileDescription> m_fd;
152};
153
154}