//! ProcFS - 进程文件系统
//!
//! 实现 Linux 兼容的 /proc 文件系统

use crate::mm::ucontext::AddressSpace;
use alloc::{sync::Arc, vec::Vec};
use system_error::SystemError;

use crate::{
    libs::once::Once,
    process::{cred::Cred, namespace::pid_namespace::INIT_PID_NAMESPACE, ProcessManager},
};

use super::vfs::mount::MountFlags;
use super::vfs::InodeMode;

mod cmdline;
mod cpuinfo;
pub mod klog;
pub mod kmsg;
mod kmsg_file;
mod loadavg;
mod meminfo;
mod mount;
mod net;
mod pid;
pub mod root;
mod self_;
mod stat;
mod sys;
mod syscall;
pub(super) mod template;
mod thread_self;
mod utils;
mod version;
mod version_signature;
mod vmstat;

// 重新导出 ProcFS
pub use root::ProcFS;

/// procfs 的 inode 名称的最大长度
pub(super) const PROCFS_MAX_NAMELEN: usize = 64;
/// procfs 的块大小
pub(super) const PROCFS_BLOCK_SIZE: u64 = 512;

/// 供 template 使用的 Builder trait
pub(super) use template::Builder;

/// procfs 文件私有数据
#[derive(Debug, Clone)]
pub struct ProcfsFilePrivateData {
    pub data: Vec<u8>,
    pub open_cred: Arc<Cred>,
    pub pinned_vm: Option<Arc<AddressSpace>>,
}

impl ProcfsFilePrivateData {
    pub fn new() -> Self {
        ProcfsFilePrivateData {
            data: Vec::new(),
            open_cred: ProcessManager::current_pcb().cred(),
            pinned_vm: None,
        }
    }
}

impl Default for ProcfsFilePrivateData {
    fn default() -> Self {
        Self::new()
    }
}

/// 初始化 ProcFS
pub fn procfs_init() -> Result<(), SystemError> {
    static INIT: Once = Once::new();
    let mut result = None;
    INIT.call_once(|| {
        ::log::info!("Initializing ProcFS...");
        // 创建 procfs 实例
        let procfs: Arc<ProcFS> = ProcFS::new(INIT_PID_NAMESPACE.clone());
        let root_inode = ProcessManager::current_mntns().root_inode();
        // procfs 挂载
        root_inode
            .mkdir("proc", InodeMode::from_bits_truncate(0o755))
            .expect("Unable to create /proc")
            .mount(procfs, MountFlags::empty())
            .expect("Failed to mount at /proc");
        ::log::info!("ProcFS mounted at /proc");
        result = Some(Ok(()));
    });

    return result.unwrap();
}
