2#include "pedigree/kernel/process/Scheduler.h"
3#include "pedigree/kernel/process/Thread.h"
4#include "pedigree/kernel/processor/Processor.h"
5#include "pedigree/kernel/syscallError.h"
6#include "pedigree/kernel/utilities/StaticString.h"
7#include "pedigree/kernel/utilities/utility.h"
9#include "PosixProcess.h"
10#include "PosixSubsystem.h"
12#include "descriptor-path.h"
13#include "modules/system/vfs/MountView.h"
14#include "modules/system/vfs/Symlink.h"
15#include "modules/system/vfs/VFS.h"
16#include "namespace-file.h"
17#include "uts-namespace.h"
20constexpr uint32_t DirectoryPermissions = FILE_UR | FILE_UX | FILE_GR | FILE_GX | FILE_OR | FILE_OX;
22bool taskNumber(
const StringView& name,
size_t& result) {
23 if (!name.length() || name[0] ==
'0')
26 for (
size_t i = 0; i < name.length(); ++i) {
27 if (name[i] <
'0' || name[i] >
'9')
29 const size_t digit = name[i] -
'0';
30 if (value > (~
size_t(0) - digit) / 10)
32 value = value * 10 + digit;
38class NamespaceLink final :
public Symlink {
41 :
Symlink(
String(
"uts"), 0, 0, 0, inode, &filesystem, 0, parent), m_Target(target) {
42 setPermissions(DirectoryPermissions | FILE_UW | FILE_GW | FILE_OW);
51 UtsStatus status = posix_uts_acquire_target(m_Target, space);
52 if (status != UtsStatus::Success) {
53 posix_uts_error(status);
57 status = posix_uts_make_file(space, file);
58 if (status != UtsStatus::Success) {
59 posix_uts_error(status);
64 SYSCALL_ERROR(NoSuchDevice);
67 return view->anonymousPath(file.get(), result);
70 int followLink(
char* buffer,
size_t length)
override {
72 const UtsStatus status = posix_uts_acquire_target(m_Target, space);
73 if (status != UtsStatus::Success)
74 return posix_uts_error(status);
76 name.append(space->identity());
78 const size_t copied = length < name.length() ? length : name.length();
79 MemoryCopy(buffer,
static_cast<const char*
>(name), copied);
80 return static_cast<int>(copied);
92 m_LinkInode(filesystem.getNextInode()) {
93 setPermissions(DirectoryPermissions);
100 return LookupStatus::NotFound;
101 child =
new NamespaceLink(*
static_cast<ProcFs*
>(getFilesystem()), m_LinkInode,
this, m_Target);
102 return child ? LookupStatus::Found : LookupStatus::IoError;
105 ReadStatus
readDirectory(uint64_t& cookie, DirectoryEntryEmitter emitter,
106 void* context)
override {
108 DirectoryEntryView entry{
StringView(
"uts"), m_LinkInode, EntryType::Symlink, 0, 1};
109 if (!emitter(context, entry))
110 return ReadStatus::Stopped;
113 return ReadStatus::Complete;
118 const uintptr_t m_LinkInode;
123 TaskDirectory(
ProcFs& filesystem,
File* parent,
size_t pid,
128 setPermissions(DirectoryPermissions);
131 void invalidate(
size_t taskId) {
152 auto& filesystem = *
static_cast<ProcFs*
>(getFilesystem());
155 if (!taskNumber(name, taskId) ||
157 filesystem.pidNamespace().get()) ||
158 !process->acquireThreadByUserspaceId(thread, taskId, filesystem.pidNamespace().get()) ||
159 !m_Context->taskTarget(thread->getTaskId(), target)) {
160 return LookupStatus::NotFound;
165 return LookupStatus::IoError;
166 directory->setPermissions(DirectoryPermissions);
167 auto* namespaces =
new NamespaceDirectory(filesystem, directory, target);
170 return LookupStatus::IoError;
172 directory->addEntry(
String(
"ns"), namespaces);
174 return LookupStatus::Found;
177 ReadStatus
readDirectory(uint64_t& cookie, DirectoryEntryEmitter emitter,
178 void* context)
override {
179 auto& filesystem = *
static_cast<ProcFs*
>(getFilesystem());
182 filesystem.pidNamespace().get())) {
183 return ReadStatus::Complete;
193 if (
id > cookie && (!selected ||
id < selected)) {
198 return ReadStatus::Complete;
201 name.append(selected);
204 if (status == LookupStatus::IoError)
205 return ReadStatus::IoError;
206 if (status == LookupStatus::Found) {
207 DirectoryEntryView entry{
StringView(name, name.length()), child.get()->getInode(),
208 EntryType::Directory, cookie, selected};
209 if (!emitter(context, entry))
210 return ReadStatus::Stopped;
221class ProcessPathLink final :
public Symlink {
223 enum class Kind { Executable, Cwd, Root };
225 ProcessPathLink(
ProcFs& filesystem,
File* parent,
size_t pid, Kind kind)
227 : kind == Kind::Cwd ?
"cwd"
229 0, 0, 0, filesystem.getNextInode(), &filesystem, 0, parent),
232 setPermissions(DirectoryPermissions | FILE_UW | FILE_GW | FILE_OW);
242 process, m_Pid,
static_cast<ProcFs*
>(getFilesystem())->pidNamespace().get()) ||
243 process->getType() != Process::Posix) {
244 SYSCALL_ERROR(DoesNotExist);
247 if (m_Kind == Kind::Executable) {
248 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
249 return subsystem && subsystem->executablePath(result);
251 auto context = process->acquireFilesystemContext();
253 if (!context || !context->snapshot(snapshot)) {
254 SYSCALL_ERROR(DoesNotExist);
257 result = m_Kind == Kind::Cwd ? snapshot.cwd : snapshot.root;
258 return static_cast<bool>(result);
261 int followLink(
char* buffer,
size_t length)
override {
263 if (!followPath(path))
267 process, m_Pid,
static_cast<ProcFs*
>(getFilesystem())->pidNamespace().get())) {
268 SYSCALL_ERROR(DoesNotExist);
271 auto context = process->acquireFilesystemContext();
275 if (!context || !context->snapshot(snapshot) || !view ||
276 !view->formatPath(snapshot, path, target)) {
277 SYSCALL_ERROR(DoesNotExist);
280 const size_t copied = length < target.length() ? length : target.length();
281 MemoryCopy(buffer, target.cstr(), copied);
282 return static_cast<int>(copied);
292 ProcessDirectory(
ProcFs& filesystem,
const String& name,
294 :
ProcFsDirectory(name, 0, 0, 0, filesystem.getNextInode(), &filesystem, 0,
295 filesystem.getRoot()),
296 m_Context(context) {}
298 bool initialise(
ProcFs& filesystem,
size_t pid) {
302 if (!m_Context->leaderTarget(leader))
304 auto* namespaces =
new NamespaceDirectory(filesystem,
this, leader);
307 addEntry(
String(
"ns"), namespaces);
308 m_Tasks =
new TaskDirectory(filesystem,
this, pid, m_Context);
311 addEntry(
String(
"task"), m_Tasks);
312 auto* descriptors = posix_make_descriptor_directory(filesystem,
this, pid, m_Context);
315 addEntry(
String(
"fd"), descriptors);
317 new ProcessPathLink(filesystem,
this, pid, ProcessPathLink::Kind::Executable);
318 auto* cwd =
new ProcessPathLink(filesystem,
this, pid, ProcessPathLink::Kind::Cwd);
319 auto* root =
new ProcessPathLink(filesystem,
this, pid, ProcessPathLink::Kind::Root);
320 if (!executable || !cwd || !root) {
326 addEntry(executable->getName(), executable);
327 addEntry(cwd->getName(), cwd);
328 addEntry(root->getName(), root);
329 return procfsAddProcessStatusFiles(filesystem, *
this, pid);
333 if (context.
get() != m_Context.get() || !m_Tasks)
335 m_Tasks->invalidate(taskId);
340 TaskDirectory* m_Tasks =
nullptr;
343class SelfLink final :
public Symlink {
345 SelfLink(
ProcFs& filesystem,
bool thread)
346 :
Symlink(
String(thread ?
"thread-self" :
"self"), 0, 0, 0, filesystem.getNextInode(),
347 &filesystem, 0, filesystem.getRoot()),
349 setPermissions(DirectoryPermissions | FILE_UW | FILE_GW | FILE_OW);
352 int followLink(
char* buffer,
size_t length)
override {
357 const size_t copied = length < target.length() ? length : target.length();
358 MemoryCopy(buffer,
static_cast<const char*
>(target), copied);
359 return static_cast<int>(copied);
365 auto* process = thread ? thread->
getParent() :
nullptr;
366 if (!process || process->getType() != Process::Posix) {
367 SYSCALL_ERROR(DoesNotExist);
373 result.append(
"/task/");
383bool ProcFs::initialiseNamespaceLinks() {
384 auto* self =
new SelfLink(*
this,
false);
385 auto* threadSelf =
new SelfLink(*
this,
true);
386 if (!self || !threadSelf) {
391 m_pRoot->addEntry(self->getName(), self);
392 m_pRoot->addEntry(threadSelf->getName(), threadSelf);
397 auto* subsystem =
static_cast<PosixSubsystem*
>(process->getSubsystem());
401 auto* directory =
new ProcessDirectory(*
this,
String(name, name.length()), context);
402 if (directory && !directory->initialise(*
this, process->
getUserspaceId(m_PidNamespace.
get()))) {
406 if (directory && !procfsAddUserMaps(*
this, *directory, *process)) {
414 size_t pid,
size_t taskId) {
415 if (!context || !pid || !taskId)
424 static_cast<ProcessDirectory*
>(directory.get())->invalidate(context, taskId);
432 if (!vfs.acquireMount(key, mount))
434 static_cast<ProcFs*
>(mount.filesystem())->invalidateNamespaceTask(context, pid, taskId);
virtual bool cacheResolvedChildren() const
void remove(const HashedStringView &s)
virtual ReadStatus readDirectory(uint64_t &cookie, DirectoryEntryEmitter emitter, void *context)
virtual LookupStatus resolveChild(const StringView &name, File *&child)
MUST_USE_RESULT LookupStatus lookupChild(const HashedStringView &s, ChildLease &child) const
size_t getUserspaceId() const
MUST_USE_RESULT bool acquireThread(ThreadLease &lease, size_t n)
static ProcessorInformation & information()
static Scheduler & instance()
virtual int followLink(char *pBuffer, size_t bufLen)
virtual bool isPathLink() const
Process * getParent() const
size_t getUserspaceTaskId(const UserspacePidNamespace *space=nullptr) const