mirror of
https://github.com/hexagonal-sun/moss-kernel.git
synced 2026-01-30 09:01:44 -05:00
procfs refactor
This commit is contained in:
7
Cargo.lock
generated
7
Cargo.lock
generated
@@ -306,6 +306,7 @@ dependencies = [
|
||||
"paste",
|
||||
"rand",
|
||||
"ringbuf",
|
||||
"rustc-hash",
|
||||
"tock-registers",
|
||||
]
|
||||
|
||||
@@ -456,6 +457,12 @@ dependencies = [
|
||||
"portable-atomic-util",
|
||||
]
|
||||
|
||||
[[package]]
|
||||
name = "rustc-hash"
|
||||
version = "2.1.1"
|
||||
source = "registry+https://github.com/rust-lang/crates.io-index"
|
||||
checksum = "357703d41365b4b27c590e3ed91eabb1b663f07c4c084095e60cbed4362dff0d"
|
||||
|
||||
[[package]]
|
||||
name = "rustc-std-workspace-core"
|
||||
version = "1.0.1"
|
||||
|
||||
@@ -22,6 +22,7 @@ ringbuf = { version = "0.4.8", default-features = false, features = ["alloc"] }
|
||||
bitflags = "2.9.1"
|
||||
futures = { version = "0.3.31", default-features = false, features = ["alloc", "async-await"] }
|
||||
rand = { version = "0.9.2", default-features = false, features = ["small_rng"] }
|
||||
rustc-hash = { version = "2.1", default-features = false }
|
||||
|
||||
[features]
|
||||
default = ["smp"]
|
||||
|
||||
@@ -322,3 +322,78 @@ pub trait Inode: Send + Sync + Any {
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// A simplified trait for read-only files in procfs/sysfs that provides default implementations
|
||||
/// for common inode operations.
|
||||
#[async_trait]
|
||||
pub trait SimpleFile {
|
||||
fn id(&self) -> InodeId;
|
||||
async fn getattr(&self) -> Result<FileAttr>;
|
||||
async fn read(&self) -> Result<Vec<u8>>;
|
||||
async fn readlink(&self) -> Result<PathBuf> {
|
||||
Err(KernelError::NotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl<T> Inode for T
|
||||
where
|
||||
T: SimpleFile + Send + Sync + 'static,
|
||||
{
|
||||
fn id(&self) -> InodeId {
|
||||
self.id()
|
||||
}
|
||||
|
||||
async fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize> {
|
||||
let bytes = self.read().await?;
|
||||
let end = usize::min(bytes.len().saturating_sub(offset as usize), buf.len());
|
||||
if end == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let slice = &bytes[offset as usize..offset as usize + end];
|
||||
buf[..end].copy_from_slice(slice);
|
||||
Ok(end)
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> Result<FileAttr> {
|
||||
self.getattr().await
|
||||
}
|
||||
|
||||
async fn lookup(&self, _name: &str) -> Result<Arc<dyn Inode>> {
|
||||
Err(FsError::NotADirectory.into())
|
||||
}
|
||||
|
||||
async fn readdir(&self, _start_offset: u64) -> crate::error::Result<Box<dyn DirStream>> {
|
||||
Err(FsError::NotADirectory.into())
|
||||
}
|
||||
|
||||
async fn readlink(&self) -> Result<PathBuf> {
|
||||
self.readlink().await
|
||||
}
|
||||
}
|
||||
|
||||
pub struct SimpleDirStream {
|
||||
entries: Vec<Dirent>,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
impl SimpleDirStream {
|
||||
pub fn new(entries: Vec<Dirent>, start_offset: u64) -> Self {
|
||||
Self {
|
||||
entries,
|
||||
idx: start_offset as usize,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl DirStream for SimpleDirStream {
|
||||
async fn next_entry(&mut self) -> Result<Option<Dirent>> {
|
||||
Ok(if let Some(entry) = self.entries.get(self.idx).cloned() {
|
||||
self.idx += 1;
|
||||
Some(entry)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1,45 +1,41 @@
|
||||
#![allow(clippy::module_name_repetitions)]
|
||||
|
||||
use crate::process::find_task_by_descriptor;
|
||||
use crate::process::thread_group::Tgid;
|
||||
use crate::sched::current::current_task;
|
||||
mod root;
|
||||
mod task;
|
||||
|
||||
use crate::drivers::{Driver, FilesystemDriver};
|
||||
use crate::sync::OnceLock;
|
||||
use crate::{
|
||||
drivers::{Driver, FilesystemDriver},
|
||||
process::TASK_LIST,
|
||||
};
|
||||
use alloc::string::String;
|
||||
use alloc::{boxed::Box, format, string::ToString, sync::Arc, vec::Vec};
|
||||
use alloc::{boxed::Box, sync::Arc};
|
||||
use async_trait::async_trait;
|
||||
use core::sync::atomic::{AtomicU64, Ordering};
|
||||
use libkernel::fs::pathbuf::PathBuf;
|
||||
use core::hash::Hasher;
|
||||
use libkernel::{
|
||||
error::{FsError, KernelError, Result},
|
||||
fs::{
|
||||
BlockDevice, DirStream, Dirent, FileType, Filesystem, Inode, InodeId, PROCFS_ID,
|
||||
attr::{FileAttr, FilePermissions},
|
||||
},
|
||||
error::{KernelError, Result},
|
||||
fs::{BlockDevice, Filesystem, Inode, PROCFS_ID},
|
||||
};
|
||||
use log::warn;
|
||||
use root::ProcRootInode;
|
||||
|
||||
/// Deterministically generates an inode ID for the given path segments within the procfs filesystem.
|
||||
fn get_inode_id(path_segments: &[&str]) -> u64 {
|
||||
let mut hasher = rustc_hash::FxHasher::default();
|
||||
// Ensure non-collision if other filesystems also use this method
|
||||
hasher.write(b"procfs");
|
||||
for segment in path_segments {
|
||||
hasher.write(segment.as_bytes());
|
||||
}
|
||||
let hash = hasher.finish();
|
||||
assert_ne!(hash, 0, "Generated inode ID cannot be zero");
|
||||
hash
|
||||
}
|
||||
|
||||
pub struct ProcFs {
|
||||
root: Arc<ProcRootInode>,
|
||||
next_inode_id: AtomicU64,
|
||||
}
|
||||
|
||||
impl ProcFs {
|
||||
fn new() -> Arc<Self> {
|
||||
let root_inode = Arc::new(ProcRootInode::new());
|
||||
Arc::new(Self {
|
||||
root: root_inode,
|
||||
next_inode_id: AtomicU64::new(1),
|
||||
})
|
||||
}
|
||||
|
||||
/// Convenience helper to allocate a unique inode ID inside this filesystem.
|
||||
fn alloc_inode_id(&self) -> InodeId {
|
||||
let id = self.next_inode_id.fetch_add(1, Ordering::Relaxed);
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, id)
|
||||
Arc::new(Self { root: root_inode })
|
||||
}
|
||||
}
|
||||
|
||||
@@ -54,392 +50,6 @@ impl Filesystem for ProcFs {
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcDirStream {
|
||||
entries: Vec<Dirent>,
|
||||
idx: usize,
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl DirStream for ProcDirStream {
|
||||
async fn next_entry(&mut self) -> Result<Option<Dirent>> {
|
||||
Ok(if let Some(entry) = self.entries.get(self.idx).cloned() {
|
||||
self.idx += 1;
|
||||
Some(entry)
|
||||
} else {
|
||||
None
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcRootInode {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
}
|
||||
|
||||
impl ProcRootInode {
|
||||
fn new() -> Self {
|
||||
Self {
|
||||
id: InodeId::from_fsid_and_inodeid(PROCFS_ID, 0),
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o555),
|
||||
..FileAttr::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcRootInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
// Lookup a PID directory.
|
||||
let pid = if name == "self" {
|
||||
let current_task = current_task();
|
||||
current_task.descriptor().tgid()
|
||||
} else {
|
||||
Tgid(
|
||||
name.parse()
|
||||
.map_err(|_| FsError::NotFound)
|
||||
.map_err(Into::<KernelError>::into)?,
|
||||
)
|
||||
};
|
||||
|
||||
// Validate that the process actually exists.
|
||||
if !TASK_LIST.lock_save_irq().keys().any(|d| d.tgid() == pid) {
|
||||
return Err(FsError::NotFound.into());
|
||||
}
|
||||
|
||||
let fs = procfs();
|
||||
|
||||
let inode_id = fs.alloc_inode_id();
|
||||
Ok(Arc::new(ProcTaskInode::new(pid, inode_id)))
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn readdir(&self, start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||
let mut entries: Vec<Dirent> = Vec::new();
|
||||
// Gather task list under interrupt-safe lock.
|
||||
let task_list = TASK_LIST.lock_save_irq();
|
||||
for (idx, (desc, _)) in task_list
|
||||
.iter()
|
||||
.filter(|(_, task)| task.upgrade().is_some())
|
||||
.enumerate()
|
||||
{
|
||||
// Use offset index as dirent offset.
|
||||
let name = desc.tgid().value().to_string();
|
||||
let inode_id =
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, ((desc.tgid().0 + 1) * 100) as u64);
|
||||
entries.push(Dirent::new(
|
||||
name,
|
||||
inode_id,
|
||||
FileType::Directory,
|
||||
(idx + 1) as u64,
|
||||
));
|
||||
}
|
||||
let current_task = current_task();
|
||||
entries.push(Dirent::new(
|
||||
"self".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(
|
||||
PROCFS_ID,
|
||||
((current_task.process.tgid.0 + 1) * 100) as u64,
|
||||
),
|
||||
FileType::Directory,
|
||||
(entries.len() + 1) as u64,
|
||||
));
|
||||
|
||||
// honour start_offset
|
||||
let entries = entries.into_iter().skip(start_offset as usize).collect();
|
||||
|
||||
Ok(Box::new(ProcDirStream { entries, idx: 0 }))
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcTaskInode {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
pid: Tgid,
|
||||
}
|
||||
|
||||
impl ProcTaskInode {
|
||||
fn new(pid: Tgid, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o555),
|
||||
..FileAttr::default()
|
||||
},
|
||||
pid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcTaskInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
if let Ok(file_type) = TaskFileType::try_from(name) {
|
||||
let fs = procfs();
|
||||
let inode_id = fs.alloc_inode_id();
|
||||
Ok(Arc::new(ProcTaskFileInode::new(
|
||||
self.pid, file_type, inode_id,
|
||||
)))
|
||||
} else {
|
||||
Err(FsError::NotFound.into())
|
||||
}
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn readdir(&self, start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||
let mut entries: Vec<Dirent> = Vec::new();
|
||||
let inode_offset = ((self.pid.value() + 1) * 100) as u64;
|
||||
entries.push(Dirent::new(
|
||||
"status".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 1),
|
||||
FileType::File,
|
||||
1,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"comm".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 2),
|
||||
FileType::File,
|
||||
2,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"state".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 3),
|
||||
FileType::File,
|
||||
3,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"cwd".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 4),
|
||||
FileType::Symlink,
|
||||
4,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"stat".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, inode_offset + 5),
|
||||
FileType::File,
|
||||
5,
|
||||
));
|
||||
|
||||
// honour start_offset
|
||||
let entries = entries.into_iter().skip(start_offset as usize).collect();
|
||||
|
||||
Ok(Box::new(ProcDirStream { entries, idx: 0 }))
|
||||
}
|
||||
}
|
||||
|
||||
enum TaskFileType {
|
||||
Status,
|
||||
Comm,
|
||||
Cwd,
|
||||
State,
|
||||
Stat,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for TaskFileType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &str) -> core::result::Result<TaskFileType, Self::Error> {
|
||||
match value {
|
||||
"status" => Ok(TaskFileType::Status),
|
||||
"comm" => Ok(TaskFileType::Comm),
|
||||
"state" => Ok(TaskFileType::State),
|
||||
"stat" => Ok(TaskFileType::Stat),
|
||||
"cwd" => Ok(TaskFileType::Cwd),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
struct ProcTaskFileInode {
|
||||
id: InodeId,
|
||||
file_type: TaskFileType,
|
||||
attr: FileAttr,
|
||||
pid: Tgid,
|
||||
}
|
||||
|
||||
impl ProcTaskFileInode {
|
||||
fn new(pid: Tgid, file_type: TaskFileType, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: match file_type {
|
||||
TaskFileType::Status
|
||||
| TaskFileType::Comm
|
||||
| TaskFileType::State
|
||||
| TaskFileType::Stat => FileType::File,
|
||||
TaskFileType::Cwd => FileType::Symlink,
|
||||
},
|
||||
mode: FilePermissions::from_bits_retain(0o444),
|
||||
..FileAttr::default()
|
||||
},
|
||||
pid,
|
||||
file_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcTaskFileInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn lookup(&self, _name: &str) -> Result<Arc<dyn Inode>> {
|
||||
Err(FsError::NotADirectory.into())
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn readdir(&self, _start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||
Err(FsError::NotADirectory.into())
|
||||
}
|
||||
|
||||
async fn read_at(&self, offset: u64, buf: &mut [u8]) -> Result<usize> {
|
||||
let pid = self.pid;
|
||||
// TODO: task needs to be the main thread of the process
|
||||
let task_list = TASK_LIST.lock_save_irq();
|
||||
let id = task_list
|
||||
.iter()
|
||||
.find(|(desc, _)| desc.tgid() == pid)
|
||||
.map(|(desc, _)| *desc);
|
||||
drop(task_list);
|
||||
let task_details = if let Some(desc) = id {
|
||||
find_task_by_descriptor(&desc)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let status_string = if let Some(task) = task_details {
|
||||
let state = *task.state.lock_save_irq();
|
||||
let name = task.comm.lock_save_irq();
|
||||
match self.file_type {
|
||||
TaskFileType::Status => format!(
|
||||
"Name:\t{name}
|
||||
State:\t{state}
|
||||
Tgid:\t{tgid}
|
||||
FDSize:\t{fd_size}
|
||||
Pid:\t{pid}
|
||||
Threads:\t{tasks}\n",
|
||||
name = name.as_str(),
|
||||
tgid = task.process.tgid,
|
||||
fd_size = task.fd_table.lock_save_irq().len(),
|
||||
tasks = task.process.tasks.lock_save_irq().len(),
|
||||
),
|
||||
TaskFileType::Comm => format!("{name}\n", name = name.as_str()),
|
||||
TaskFileType::State => format!("{state}\n"),
|
||||
TaskFileType::Stat => {
|
||||
let mut output = String::new();
|
||||
output.push_str(&format!("{} ", task.process.tgid.0)); // pid
|
||||
output.push_str(&format!("({}) ", name.as_str())); // comm
|
||||
output.push_str(&format!("{state} ")); // state
|
||||
output.push_str(&format!("{} ", 0)); // ppid
|
||||
output.push_str(&format!("{} ", 0)); // pgrp
|
||||
output.push_str(&format!("{} ", task.process.sid.lock_save_irq().value())); // session
|
||||
output.push_str(&format!("{} ", 0)); // tty_nr
|
||||
output.push_str(&format!("{} ", 0)); // tpgid
|
||||
output.push_str(&format!("{} ", 0)); // flags
|
||||
output.push_str(&format!("{} ", 0)); // minflt
|
||||
output.push_str(&format!("{} ", 0)); // cminflt
|
||||
output.push_str(&format!("{} ", 0)); // majflt
|
||||
output.push_str(&format!("{} ", 0)); // cmajflt
|
||||
output.push_str(&format!("{} ", task.process.utime.load(Ordering::Relaxed))); // utime
|
||||
output.push_str(&format!("{} ", task.process.stime.load(Ordering::Relaxed))); // stime
|
||||
output.push_str(&format!("{} ", 0)); // cutime
|
||||
output.push_str(&format!("{} ", 0)); // cstime
|
||||
output.push_str(&format!("{} ", *task.process.priority.lock_save_irq())); // priority
|
||||
output.push_str(&format!("{} ", 0)); // nice
|
||||
output.push_str(&format!("{} ", 0)); // num_threads
|
||||
output.push_str(&format!("{} ", 0)); // itrealvalue
|
||||
output.push_str(&format!("{} ", 0)); // starttime
|
||||
output.push_str(&format!("{} ", 0)); // vsize
|
||||
output.push_str(&format!("{} ", 0)); // rss
|
||||
output.push_str(&format!("{} ", 0)); // rsslim
|
||||
output.push_str(&format!("{} ", 0)); // startcode
|
||||
output.push_str(&format!("{} ", 0)); // endcode
|
||||
output.push_str(&format!("{} ", 0)); // startstack
|
||||
output.push_str(&format!("{} ", 0)); // kstkesp
|
||||
output.push_str(&format!("{} ", 0)); // kstkeip
|
||||
output.push_str(&format!("{} ", 0)); // signal
|
||||
output.push_str(&format!("{} ", 0)); // blocked
|
||||
output.push_str(&format!("{} ", 0)); // sigignore
|
||||
output.push_str(&format!("{} ", 0)); // sigcatch
|
||||
output.push_str(&format!("{} ", 0)); // wchan
|
||||
output.push_str(&format!("{} ", 0)); // nswap
|
||||
output.push_str(&format!("{} ", 0)); // cnswap
|
||||
output.push_str(&format!("{} ", 0)); // exit_signal
|
||||
output.push_str(&format!("{} ", 0)); // processor
|
||||
output.push_str(&format!("{} ", 0)); // rt_priority
|
||||
output.push_str(&format!("{} ", 0)); // policy
|
||||
output.push_str(&format!("{} ", 0)); // delayacct_blkio_ticks
|
||||
output.push_str(&format!("{} ", 0)); // guest_time
|
||||
output.push_str(&format!("{} ", 0)); // cguest_time
|
||||
output.push_str(&format!("{} ", 0)); // start_data
|
||||
output.push_str(&format!("{} ", 0)); // end_data
|
||||
output.push_str(&format!("{} ", 0)); // start_brk
|
||||
output.push_str(&format!("{} ", 0)); // arg_start
|
||||
output.push_str(&format!("{} ", 0)); // arg_end
|
||||
output.push_str(&format!("{} ", 0)); // env_start
|
||||
output.push_str(&format!("{} ", 0)); // env_end
|
||||
output.push_str(&format!("{} ", 0)); // exit_code
|
||||
output.push('\n');
|
||||
output
|
||||
}
|
||||
TaskFileType::Cwd => task.cwd.lock_save_irq().clone().1.as_str().to_string(),
|
||||
}
|
||||
} else {
|
||||
"State:\tGone\n".to_string()
|
||||
};
|
||||
|
||||
let bytes = status_string.as_bytes();
|
||||
let end = usize::min(bytes.len().saturating_sub(offset as usize), buf.len());
|
||||
if end == 0 {
|
||||
return Ok(0);
|
||||
}
|
||||
let slice = &bytes[offset as usize..offset as usize + end];
|
||||
buf[..end].copy_from_slice(slice);
|
||||
Ok(end)
|
||||
}
|
||||
|
||||
async fn readlink(&self) -> Result<PathBuf> {
|
||||
if let TaskFileType::Cwd = self.file_type {
|
||||
let pid = self.pid;
|
||||
let task_list = TASK_LIST.lock_save_irq();
|
||||
let id = task_list.iter().find(|(desc, _)| desc.tgid() == pid);
|
||||
let task_details = if let Some((desc, _)) = id {
|
||||
find_task_by_descriptor(desc)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
return if let Some(task) = task_details {
|
||||
let cwd = task.cwd.lock_save_irq();
|
||||
Ok(cwd.1.clone())
|
||||
} else {
|
||||
Err(FsError::NotFound.into())
|
||||
};
|
||||
}
|
||||
Err(KernelError::NotSupported)
|
||||
}
|
||||
}
|
||||
|
||||
static PROCFS_INSTANCE: OnceLock<Arc<ProcFs>> = OnceLock::new();
|
||||
|
||||
/// Initializes and/or returns the global singleton [`ProcFs`] instance.
|
||||
|
||||
100
src/drivers/fs/proc/root.rs
Normal file
100
src/drivers/fs/proc/root.rs
Normal file
@@ -0,0 +1,100 @@
|
||||
use crate::drivers::fs::proc::get_inode_id;
|
||||
use crate::drivers::fs::proc::task::ProcTaskInode;
|
||||
use crate::process::{TASK_LIST, TaskDescriptor, Tid};
|
||||
use crate::sched::current::current_task;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use async_trait::async_trait;
|
||||
use libkernel::error;
|
||||
use libkernel::error::FsError;
|
||||
use libkernel::fs::attr::{FileAttr, FilePermissions};
|
||||
use libkernel::fs::{DirStream, Dirent, FileType, Inode, InodeId, PROCFS_ID, SimpleDirStream};
|
||||
|
||||
pub struct ProcRootInode {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
}
|
||||
|
||||
impl ProcRootInode {
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
id: InodeId::from_fsid_and_inodeid(PROCFS_ID, 0),
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o555),
|
||||
..FileAttr::default()
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcRootInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> error::Result<Arc<dyn Inode>> {
|
||||
// Lookup a PID directory.
|
||||
let desc = if name == "self" {
|
||||
let current_task = current_task();
|
||||
TaskDescriptor::from_tgid_tid(current_task.pgid(), Tid::from_tgid(current_task.pgid()))
|
||||
} else if name == "thread-self" {
|
||||
let current_task = current_task();
|
||||
current_task.descriptor()
|
||||
} else {
|
||||
let pid: u32 = name.parse().map_err(|_| FsError::NotFound)?;
|
||||
// Search for the task descriptor.
|
||||
TASK_LIST
|
||||
.lock_save_irq()
|
||||
.keys()
|
||||
.find(|d| d.tgid().value() == pid)
|
||||
.cloned()
|
||||
.ok_or(FsError::NotFound)?
|
||||
};
|
||||
|
||||
Ok(Arc::new(ProcTaskInode::new(
|
||||
desc,
|
||||
InodeId::from_fsid_and_inodeid(self.id.fs_id(), get_inode_id(&[name])),
|
||||
)))
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> error::Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn readdir(&self, start_offset: u64) -> error::Result<Box<dyn DirStream>> {
|
||||
let mut entries: Vec<Dirent> = Vec::new();
|
||||
// Gather task list under interrupt-safe lock.
|
||||
let task_list = TASK_LIST.lock_save_irq();
|
||||
for (desc, _) in task_list
|
||||
.iter()
|
||||
.filter(|(_, task)| task.upgrade().is_some())
|
||||
{
|
||||
// Use offset index as dirent offset.
|
||||
let name = desc.tgid().value().to_string();
|
||||
let inode_id =
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, ((desc.tgid().0 + 1) * 100) as u64);
|
||||
entries.push(Dirent::new(
|
||||
name,
|
||||
inode_id,
|
||||
FileType::Directory,
|
||||
get_inode_id(&[&desc.tgid().value().to_string()]),
|
||||
));
|
||||
}
|
||||
let current_task = current_task();
|
||||
entries.push(Dirent::new(
|
||||
"self".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(
|
||||
PROCFS_ID,
|
||||
get_inode_id(&[¤t_task.descriptor().tgid().value().to_string()]),
|
||||
),
|
||||
FileType::Directory,
|
||||
(entries.len() + 1) as u64,
|
||||
));
|
||||
|
||||
Ok(Box::new(SimpleDirStream::new(entries, start_offset)))
|
||||
}
|
||||
}
|
||||
153
src/drivers/fs/proc/task/fd.rs
Normal file
153
src/drivers/fs/proc/task/fd.rs
Normal file
@@ -0,0 +1,153 @@
|
||||
use crate::drivers::fs::proc::{get_inode_id, procfs};
|
||||
use crate::process::fd_table::Fd;
|
||||
use crate::process::{TaskDescriptor, find_task_by_descriptor};
|
||||
use crate::sched::current::current_task_shared;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::format;
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use async_trait::async_trait;
|
||||
use libkernel::error::Result;
|
||||
use libkernel::error::{FsError, KernelError};
|
||||
use libkernel::fs::attr::FileAttr;
|
||||
use libkernel::fs::{
|
||||
DirStream, Dirent, FileType, Filesystem, Inode, InodeId, SimpleDirStream, SimpleFile,
|
||||
};
|
||||
|
||||
pub struct ProcFdInode {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
desc: TaskDescriptor,
|
||||
fd_info: bool,
|
||||
}
|
||||
|
||||
impl ProcFdInode {
|
||||
pub fn new(desc: TaskDescriptor, fd_info: bool, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
// Define appropriate file attributes for fdinfo.
|
||||
..FileAttr::default()
|
||||
},
|
||||
desc,
|
||||
fd_info,
|
||||
}
|
||||
}
|
||||
|
||||
fn dir_name(&self) -> &str {
|
||||
if self.fd_info { "fdinfo" } else { "fd" }
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcFdInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> Result<Arc<dyn Inode>> {
|
||||
let fd: i32 = name.parse().map_err(|_| FsError::NotFound)?;
|
||||
let task = current_task_shared();
|
||||
let fd_table = task.fd_table.lock_save_irq();
|
||||
if fd_table.get(Fd(fd)).is_none() {
|
||||
return Err(FsError::NotFound.into());
|
||||
}
|
||||
let fs = procfs();
|
||||
let inode_id = InodeId::from_fsid_and_inodeid(
|
||||
fs.id(),
|
||||
get_inode_id(&[&self.desc.tid().value().to_string(), self.dir_name(), name]),
|
||||
);
|
||||
Ok(Arc::new(ProcFdFile::new(
|
||||
self.desc,
|
||||
self.fd_info,
|
||||
fd,
|
||||
inode_id,
|
||||
)))
|
||||
}
|
||||
|
||||
async fn readdir(&self, start_offset: u64) -> Result<Box<dyn DirStream>> {
|
||||
let task = find_task_by_descriptor(&self.desc).ok_or(FsError::NotFound)?;
|
||||
let fd_table = task.fd_table.lock_save_irq();
|
||||
let mut entries = Vec::new();
|
||||
for fd in 0..fd_table.len() {
|
||||
if fd_table.get(Fd(fd as i32)).is_none() {
|
||||
continue;
|
||||
}
|
||||
let fd_str = fd.to_string();
|
||||
entries.push(Dirent {
|
||||
id: InodeId::from_fsid_and_inodeid(
|
||||
self.id.fs_id(),
|
||||
get_inode_id(&[
|
||||
&self.desc.tid().value().to_string(),
|
||||
self.dir_name(),
|
||||
&fd_str,
|
||||
]),
|
||||
),
|
||||
offset: fd as _,
|
||||
file_type: FileType::File,
|
||||
name: fd_str,
|
||||
});
|
||||
}
|
||||
|
||||
Ok(Box::new(SimpleDirStream::new(entries, start_offset)))
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: Support fd links in /proc/[pid]/fd/
|
||||
|
||||
pub struct ProcFdFile {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
desc: TaskDescriptor,
|
||||
fd_info: bool,
|
||||
fd: i32,
|
||||
}
|
||||
|
||||
impl ProcFdFile {
|
||||
pub fn new(desc: TaskDescriptor, fd_info: bool, fd: i32, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: FileType::File,
|
||||
// Define appropriate file attributes for fdinfo file.
|
||||
..FileAttr::default()
|
||||
},
|
||||
desc,
|
||||
fd_info,
|
||||
fd,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SimpleFile for ProcFdFile {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn read(&self) -> Result<Vec<u8>> {
|
||||
let task = find_task_by_descriptor(&self.desc).ok_or(FsError::NotFound)?;
|
||||
let fd_entry = task
|
||||
.fd_table
|
||||
.lock_save_irq()
|
||||
.get(Fd(self.fd))
|
||||
.ok_or(FsError::NotFound)?;
|
||||
let (_, ctx) = &mut *fd_entry.lock().await;
|
||||
let info_string = format!("pos: {}\nflags: {}", ctx.pos, ctx.flags.bits());
|
||||
if self.fd_info {
|
||||
Ok(info_string.into_bytes())
|
||||
} else {
|
||||
Err(KernelError::NotSupported)
|
||||
}
|
||||
}
|
||||
}
|
||||
134
src/drivers/fs/proc/task/mod.rs
Normal file
134
src/drivers/fs/proc/task/mod.rs
Normal file
@@ -0,0 +1,134 @@
|
||||
mod fd;
|
||||
// TODO: allowlist this across the codebase
|
||||
#[expect(clippy::module_inception)]
|
||||
mod task;
|
||||
mod task_file;
|
||||
|
||||
use crate::drivers::fs::proc::task::task_file::{ProcTaskFileInode, TaskFileType};
|
||||
use crate::drivers::fs::proc::{get_inode_id, procfs};
|
||||
use crate::process::TaskDescriptor;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use async_trait::async_trait;
|
||||
use libkernel::error::FsError;
|
||||
use libkernel::fs::attr::{FileAttr, FilePermissions};
|
||||
use libkernel::fs::{
|
||||
DirStream, Dirent, FileType, Filesystem, Inode, InodeId, PROCFS_ID, SimpleDirStream,
|
||||
};
|
||||
|
||||
pub struct ProcTaskInode {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
desc: TaskDescriptor,
|
||||
}
|
||||
|
||||
impl ProcTaskInode {
|
||||
pub fn new(desc: TaskDescriptor, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
mode: FilePermissions::from_bits_retain(0o555),
|
||||
..FileAttr::default()
|
||||
},
|
||||
desc,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcTaskInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> libkernel::error::Result<Arc<dyn Inode>> {
|
||||
let fs = procfs();
|
||||
let inode_id = InodeId::from_fsid_and_inodeid(
|
||||
fs.id(),
|
||||
get_inode_id(&[&self.desc.tid().value().to_string(), name]),
|
||||
);
|
||||
if name == "fdinfo" {
|
||||
return Ok(Arc::new(fd::ProcFdInode::new(self.desc, true, inode_id)));
|
||||
} else if name == "fd" {
|
||||
return Ok(Arc::new(fd::ProcFdInode::new(self.desc, false, inode_id)));
|
||||
} else if name == "task" && self.desc.tid().value() == self.desc.tgid().value() {
|
||||
return Ok(Arc::new(task::ProcTaskDirInode::new(
|
||||
self.desc.tgid(),
|
||||
inode_id,
|
||||
)));
|
||||
}
|
||||
if let Ok(file_type) = TaskFileType::try_from(name) {
|
||||
Ok(Arc::new(ProcTaskFileInode::new(
|
||||
self.desc.tid(),
|
||||
file_type,
|
||||
inode_id,
|
||||
)))
|
||||
} else {
|
||||
Err(FsError::NotFound.into())
|
||||
}
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> libkernel::error::Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn readdir(&self, start_offset: u64) -> libkernel::error::Result<Box<dyn DirStream>> {
|
||||
let mut entries: Vec<Dirent> = Vec::new();
|
||||
let initial_str = self.desc.tid().value().to_string();
|
||||
entries.push(Dirent::new(
|
||||
"status".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "status"])),
|
||||
FileType::File,
|
||||
1,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"comm".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "comm"])),
|
||||
FileType::File,
|
||||
2,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"state".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "state"])),
|
||||
FileType::File,
|
||||
3,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"cwd".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "cwd"])),
|
||||
FileType::Symlink,
|
||||
4,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"stat".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "stat"])),
|
||||
FileType::File,
|
||||
5,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"fd".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "fd"])),
|
||||
FileType::Directory,
|
||||
6,
|
||||
));
|
||||
entries.push(Dirent::new(
|
||||
"fdinfo".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "fdinfo"])),
|
||||
FileType::Directory,
|
||||
7,
|
||||
));
|
||||
if self.desc.tid().value() == self.desc.tgid().value() {
|
||||
entries.push(Dirent::new(
|
||||
"task".to_string(),
|
||||
InodeId::from_fsid_and_inodeid(PROCFS_ID, get_inode_id(&[&initial_str, "task"])),
|
||||
FileType::Directory,
|
||||
8,
|
||||
));
|
||||
}
|
||||
|
||||
Ok(Box::new(SimpleDirStream::new(entries, start_offset)))
|
||||
}
|
||||
}
|
||||
87
src/drivers/fs/proc/task/task.rs
Normal file
87
src/drivers/fs/proc/task/task.rs
Normal file
@@ -0,0 +1,87 @@
|
||||
use crate::drivers::fs::proc::task::ProcTaskInode;
|
||||
use crate::drivers::fs::proc::{get_inode_id, procfs};
|
||||
use crate::process::thread_group::Tgid;
|
||||
use crate::process::{TaskDescriptor, Tid, find_task_by_descriptor};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
use alloc::sync::Arc;
|
||||
use alloc::vec::Vec;
|
||||
use async_trait::async_trait;
|
||||
use libkernel::error::FsError;
|
||||
use libkernel::fs::attr::FileAttr;
|
||||
use libkernel::fs::{DirStream, Dirent, FileType, Filesystem, Inode, InodeId, SimpleDirStream};
|
||||
|
||||
pub struct ProcTaskDirInode {
|
||||
id: InodeId,
|
||||
attr: FileAttr,
|
||||
tgid: Tgid,
|
||||
}
|
||||
|
||||
impl ProcTaskDirInode {
|
||||
pub fn new(tgid: Tgid, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: FileType::Directory,
|
||||
// Define appropriate file attributes for fdinfo.
|
||||
..FileAttr::default()
|
||||
},
|
||||
tgid,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl Inode for ProcTaskDirInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> libkernel::error::Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn lookup(&self, name: &str) -> libkernel::error::Result<Arc<dyn Inode>> {
|
||||
let tid = match name.parse::<u32>() {
|
||||
Ok(tid) => Tid(tid),
|
||||
Err(_) => return Err(FsError::NotFound.into()),
|
||||
};
|
||||
let fs = procfs();
|
||||
let inode_id = InodeId::from_fsid_and_inodeid(
|
||||
fs.id(),
|
||||
get_inode_id(&[&self.tgid.value().to_string(), &tid.value().to_string()]),
|
||||
);
|
||||
let desc = TaskDescriptor::from_tgid_tid(self.tgid, tid);
|
||||
find_task_by_descriptor(&desc).ok_or(FsError::NotFound)?;
|
||||
Ok(Arc::new(ProcTaskInode::new(desc, inode_id)))
|
||||
}
|
||||
|
||||
async fn readdir(&self, start_offset: u64) -> libkernel::error::Result<Box<dyn DirStream>> {
|
||||
let task = find_task_by_descriptor(&TaskDescriptor::from_tgid_tid(
|
||||
self.tgid,
|
||||
Tid::from_tgid(self.tgid),
|
||||
))
|
||||
.ok_or(FsError::NotFound)?;
|
||||
let tasks = task.process.tasks.lock_save_irq();
|
||||
let mut entries = Vec::new();
|
||||
for (i, (_tid, task)) in tasks.iter().enumerate().skip(start_offset as usize) {
|
||||
let Some(task) = task.upgrade() else {
|
||||
continue;
|
||||
};
|
||||
let id = InodeId::from_fsid_and_inodeid(
|
||||
procfs().id(),
|
||||
get_inode_id(&[
|
||||
&self.tgid.value().to_string(),
|
||||
&task.tid.value().to_string(),
|
||||
]),
|
||||
);
|
||||
entries.push(Dirent {
|
||||
id,
|
||||
offset: (i + 1) as u64,
|
||||
file_type: FileType::Directory,
|
||||
name: task.tid.value().to_string(),
|
||||
});
|
||||
}
|
||||
Ok(Box::new(SimpleDirStream::new(entries, start_offset)))
|
||||
}
|
||||
}
|
||||
191
src/drivers/fs/proc/task/task_file.rs
Normal file
191
src/drivers/fs/proc/task/task_file.rs
Normal file
@@ -0,0 +1,191 @@
|
||||
use crate::process::{TASK_LIST, Tid, find_task_by_descriptor};
|
||||
use alloc::boxed::Box;
|
||||
use alloc::format;
|
||||
use alloc::string::{String, ToString};
|
||||
use alloc::vec::Vec;
|
||||
use async_trait::async_trait;
|
||||
use core::sync::atomic::Ordering;
|
||||
use libkernel::error::{FsError, KernelError};
|
||||
use libkernel::fs::attr::{FileAttr, FilePermissions};
|
||||
use libkernel::fs::pathbuf::PathBuf;
|
||||
use libkernel::fs::{FileType, InodeId, SimpleFile};
|
||||
|
||||
pub enum TaskFileType {
|
||||
Status,
|
||||
Comm,
|
||||
Cwd,
|
||||
State,
|
||||
Stat,
|
||||
}
|
||||
|
||||
impl TryFrom<&str> for TaskFileType {
|
||||
type Error = ();
|
||||
|
||||
fn try_from(value: &str) -> Result<TaskFileType, Self::Error> {
|
||||
match value {
|
||||
"status" => Ok(TaskFileType::Status),
|
||||
"comm" => Ok(TaskFileType::Comm),
|
||||
"state" => Ok(TaskFileType::State),
|
||||
"stat" => Ok(TaskFileType::Stat),
|
||||
"cwd" => Ok(TaskFileType::Cwd),
|
||||
_ => Err(()),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct ProcTaskFileInode {
|
||||
id: InodeId,
|
||||
file_type: TaskFileType,
|
||||
attr: FileAttr,
|
||||
tid: Tid,
|
||||
}
|
||||
|
||||
impl ProcTaskFileInode {
|
||||
pub fn new(tid: Tid, file_type: TaskFileType, inode_id: InodeId) -> Self {
|
||||
Self {
|
||||
id: inode_id,
|
||||
attr: FileAttr {
|
||||
file_type: match file_type {
|
||||
TaskFileType::Status
|
||||
| TaskFileType::Comm
|
||||
| TaskFileType::State
|
||||
| TaskFileType::Stat => FileType::File,
|
||||
TaskFileType::Cwd => FileType::Symlink,
|
||||
},
|
||||
mode: FilePermissions::from_bits_retain(0o444),
|
||||
..FileAttr::default()
|
||||
},
|
||||
tid,
|
||||
file_type,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[async_trait]
|
||||
impl SimpleFile for ProcTaskFileInode {
|
||||
fn id(&self) -> InodeId {
|
||||
self.id
|
||||
}
|
||||
|
||||
async fn getattr(&self) -> libkernel::error::Result<FileAttr> {
|
||||
Ok(self.attr.clone())
|
||||
}
|
||||
|
||||
async fn read(&self) -> libkernel::error::Result<Vec<u8>> {
|
||||
let tid = self.tid;
|
||||
let task_list = TASK_LIST.lock_save_irq();
|
||||
let id = task_list
|
||||
.iter()
|
||||
.find(|(desc, _)| desc.tid() == tid)
|
||||
.map(|(desc, _)| *desc);
|
||||
drop(task_list);
|
||||
let task_details = if let Some(desc) = id {
|
||||
find_task_by_descriptor(&desc)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
|
||||
let status_string = if let Some(task) = task_details {
|
||||
let state = *task.state.lock_save_irq();
|
||||
let name = task.comm.lock_save_irq();
|
||||
match self.file_type {
|
||||
TaskFileType::Status => format!(
|
||||
"Name:\t{name}
|
||||
State:\t{state}
|
||||
Tgid:\t{tgid}
|
||||
FDSize:\t{fd_size}
|
||||
Pid:\t{pid}
|
||||
Threads:\t{tasks}\n",
|
||||
name = name.as_str(),
|
||||
tgid = task.process.tgid,
|
||||
fd_size = task.fd_table.lock_save_irq().len(),
|
||||
pid = task.tid.value(),
|
||||
tasks = task.process.tasks.lock_save_irq().len(),
|
||||
),
|
||||
TaskFileType::Comm => format!("{name}\n", name = name.as_str()),
|
||||
TaskFileType::State => format!("{state}\n"),
|
||||
TaskFileType::Stat => {
|
||||
let mut output = String::new();
|
||||
output.push_str(&format!("{} ", task.process.tgid.value())); // pid
|
||||
output.push_str(&format!("({}) ", name.as_str())); // comm
|
||||
output.push_str(&format!("{} ", state)); // state
|
||||
output.push_str(&format!("{} ", 0)); // ppid
|
||||
output.push_str(&format!("{} ", 0)); // pgrp
|
||||
output.push_str(&format!("{} ", task.process.sid.lock_save_irq().value())); // session
|
||||
output.push_str(&format!("{} ", 0)); // tty_nr
|
||||
output.push_str(&format!("{} ", 0)); // tpgid
|
||||
output.push_str(&format!("{} ", 0)); // flags
|
||||
output.push_str(&format!("{} ", 0)); // minflt
|
||||
output.push_str(&format!("{} ", 0)); // cminflt
|
||||
output.push_str(&format!("{} ", 0)); // majflt
|
||||
output.push_str(&format!("{} ", 0)); // cmajflt
|
||||
output.push_str(&format!("{} ", task.process.utime.load(Ordering::Relaxed))); // utime
|
||||
output.push_str(&format!("{} ", task.process.stime.load(Ordering::Relaxed))); // stime
|
||||
output.push_str(&format!("{} ", 0)); // cutime
|
||||
output.push_str(&format!("{} ", 0)); // cstime
|
||||
output.push_str(&format!("{} ", *task.process.priority.lock_save_irq())); // priority
|
||||
output.push_str(&format!("{} ", 0)); // nice
|
||||
output.push_str(&format!("{} ", 0)); // num_threads
|
||||
output.push_str(&format!("{} ", 0)); // itrealvalue
|
||||
output.push_str(&format!("{} ", 0)); // starttime
|
||||
output.push_str(&format!("{} ", 0)); // vsize
|
||||
output.push_str(&format!("{} ", 0)); // rss
|
||||
output.push_str(&format!("{} ", 0)); // rsslim
|
||||
output.push_str(&format!("{} ", 0)); // startcode
|
||||
output.push_str(&format!("{} ", 0)); // endcode
|
||||
output.push_str(&format!("{} ", 0)); // startstack
|
||||
output.push_str(&format!("{} ", 0)); // kstkesp
|
||||
output.push_str(&format!("{} ", 0)); // kstkeip
|
||||
output.push_str(&format!("{} ", 0)); // signal
|
||||
output.push_str(&format!("{} ", 0)); // blocked
|
||||
output.push_str(&format!("{} ", 0)); // sigignore
|
||||
output.push_str(&format!("{} ", 0)); // sigcatch
|
||||
output.push_str(&format!("{} ", 0)); // wchan
|
||||
output.push_str(&format!("{} ", 0)); // nswap
|
||||
output.push_str(&format!("{} ", 0)); // cnswap
|
||||
output.push_str(&format!("{} ", 0)); // exit_signal
|
||||
output.push_str(&format!("{} ", 0)); // processor
|
||||
output.push_str(&format!("{} ", 0)); // rt_priority
|
||||
output.push_str(&format!("{} ", 0)); // policy
|
||||
output.push_str(&format!("{} ", 0)); // delayacct_blkio_ticks
|
||||
output.push_str(&format!("{} ", 0)); // guest_time
|
||||
output.push_str(&format!("{} ", 0)); // cguest_time
|
||||
output.push_str(&format!("{} ", 0)); // start_data
|
||||
output.push_str(&format!("{} ", 0)); // end_data
|
||||
output.push_str(&format!("{} ", 0)); // start_brk
|
||||
output.push_str(&format!("{} ", 0)); // arg_start
|
||||
output.push_str(&format!("{} ", 0)); // arg_end
|
||||
output.push_str(&format!("{} ", 0)); // env_start
|
||||
output.push_str(&format!("{} ", 0)); // env_end
|
||||
output.push_str(&format!("{} ", 0)); // exit_code
|
||||
output.push('\n');
|
||||
output
|
||||
}
|
||||
TaskFileType::Cwd => task.cwd.lock_save_irq().clone().1.as_str().to_string(),
|
||||
}
|
||||
} else {
|
||||
"State:\tGone\n".to_string()
|
||||
};
|
||||
Ok(status_string.into_bytes())
|
||||
}
|
||||
|
||||
async fn readlink(&self) -> libkernel::error::Result<PathBuf> {
|
||||
if let TaskFileType::Cwd = self.file_type {
|
||||
let tid = self.tid;
|
||||
let task_list = TASK_LIST.lock_save_irq();
|
||||
let id = task_list.iter().find(|(desc, _)| desc.tid() == tid);
|
||||
let task_details = if let Some((desc, _)) = id {
|
||||
find_task_by_descriptor(desc)
|
||||
} else {
|
||||
None
|
||||
};
|
||||
return if let Some(task) = task_details {
|
||||
let cwd = task.cwd.lock_save_irq();
|
||||
Ok(cwd.1.clone())
|
||||
} else {
|
||||
Err(FsError::NotFound.into())
|
||||
};
|
||||
}
|
||||
Err(KernelError::NotSupported)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user