xref: /DragonOS/kernel/src/filesystem/devpts/mod.rs (revision 2b7818e80e00fcfe4d03533f587cc125ea5e4bec)
1 use core::sync::atomic::{AtomicU32, Ordering};
2 
3 use alloc::{
4     collections::BTreeMap,
5     string::{String, ToString},
6     sync::{Arc, Weak},
7     vec::Vec,
8 };
9 use ida::IdAllocator;
10 use log::info;
11 use system_error::SystemError;
12 use unified_init::macros::unified_init;
13 
14 use crate::{
15     driver::{
16         base::device::{
17             device_number::{DeviceNumber, Major},
18             IdTable,
19         },
20         tty::{
21             pty::unix98pty::NR_UNIX98_PTY_MAX,
22             tty_device::{PtyType, TtyDevice, TtyType},
23         },
24     },
25     filesystem::vfs::{core::do_mount_mkdir, syscall::ModeType, FileType},
26     init::initcall::INITCALL_FS,
27     libs::spinlock::{SpinLock, SpinLockGuard},
28     time::PosixTimeSpec,
29 };
30 
31 use super::vfs::{
32     core::generate_inode_id, FilePrivateData, FileSystem, FsInfo, IndexNode, Metadata,
33 };
34 
35 const DEV_PTYFS_MAX_NAMELEN: usize = 16;
36 
37 #[allow(dead_code)]
38 const PTY_NR_LIMIT: usize = 4096;
39 
40 #[derive(Debug)]
41 pub struct DevPtsFs {
42     /// 根节点
43     root_inode: Arc<LockedDevPtsFSInode>,
44     pts_ida: IdAllocator,
45     pts_count: AtomicU32,
46 }
47 
48 impl DevPtsFs {
49     pub fn new() -> Arc<Self> {
50         let root_inode = Arc::new(LockedDevPtsFSInode::new());
51         let ret = Arc::new(Self {
52             root_inode,
53             pts_ida: IdAllocator::new(1, NR_UNIX98_PTY_MAX as usize),
54             pts_count: AtomicU32::new(0),
55         });
56 
57         ret.root_inode.set_fs(Arc::downgrade(&ret));
58 
59         ret
60     }
61 
62     pub fn alloc_index(&self) -> Result<usize, SystemError> {
63         self.pts_ida.alloc().ok_or(SystemError::ENOSPC)
64     }
65 }
66 
67 impl FileSystem for DevPtsFs {
68     fn root_inode(&self) -> Arc<dyn IndexNode> {
69         self.root_inode.clone()
70     }
71 
72     fn info(&self) -> super::vfs::FsInfo {
73         return FsInfo {
74             blk_dev_id: 0,
75             max_name_len: DEV_PTYFS_MAX_NAMELEN,
76         };
77     }
78 
79     fn as_any_ref(&self) -> &dyn core::any::Any {
80         self
81     }
82 
83     fn name(&self) -> &str {
84         "devpts"
85     }
86 
87     fn super_block(&self) -> super::vfs::SuperBlock {
88         todo!()
89     }
90 }
91 
92 #[derive(Debug)]
93 pub struct LockedDevPtsFSInode {
94     inner: SpinLock<PtsDevInode>,
95 }
96 
97 impl LockedDevPtsFSInode {
98     pub fn new() -> Self {
99         Self {
100             inner: SpinLock::new(PtsDevInode {
101                 fs: Weak::new(),
102                 children: Some(BTreeMap::new()),
103                 metadata: Metadata {
104                     dev_id: 0,
105                     inode_id: generate_inode_id(),
106                     size: 0,
107                     blk_size: 0,
108                     blocks: 0,
109                     atime: PosixTimeSpec::default(),
110                     mtime: PosixTimeSpec::default(),
111                     ctime: PosixTimeSpec::default(),
112                     file_type: FileType::Dir,
113                     mode: ModeType::from_bits_truncate(0o777),
114                     nlinks: 1,
115                     uid: 0,
116                     gid: 0,
117                     raw_dev: DeviceNumber::default(),
118                 },
119             }),
120         }
121     }
122 
123     pub fn set_fs(&self, fs: Weak<DevPtsFs>) {
124         self.inner.lock().fs = fs;
125     }
126 }
127 
128 #[derive(Debug)]
129 pub struct PtsDevInode {
130     fs: Weak<DevPtsFs>,
131     children: Option<BTreeMap<String, Arc<TtyDevice>>>,
132     metadata: Metadata,
133 }
134 
135 impl PtsDevInode {
136     pub fn children_unchecked(&self) -> &BTreeMap<String, Arc<TtyDevice>> {
137         self.children.as_ref().unwrap()
138     }
139 
140     pub fn children_unchecked_mut(&mut self) -> &mut BTreeMap<String, Arc<TtyDevice>> {
141         self.children.as_mut().unwrap()
142     }
143 }
144 
145 impl IndexNode for LockedDevPtsFSInode {
146     fn open(
147         &self,
148         _data: SpinLockGuard<FilePrivateData>,
149         _mode: &super::vfs::file::FileMode,
150     ) -> Result<(), SystemError> {
151         Ok(())
152     }
153 
154     fn metadata(&self) -> Result<super::vfs::Metadata, SystemError> {
155         let inode = self.inner.lock();
156         let metadata = inode.metadata.clone();
157 
158         return Ok(metadata);
159     }
160 
161     fn close(&self, _data: SpinLockGuard<FilePrivateData>) -> Result<(), SystemError> {
162         // TODO: 回收
163         Ok(())
164     }
165 
166     fn read_at(
167         &self,
168         _offset: usize,
169         _len: usize,
170         _buf: &mut [u8],
171         _data: SpinLockGuard<FilePrivateData>,
172     ) -> Result<usize, system_error::SystemError> {
173         todo!()
174     }
175 
176     fn write_at(
177         &self,
178         _offset: usize,
179         _len: usize,
180         _buf: &[u8],
181         _data: SpinLockGuard<FilePrivateData>,
182     ) -> Result<usize, system_error::SystemError> {
183         todo!()
184     }
185 
186     fn fs(&self) -> alloc::sync::Arc<dyn super::vfs::FileSystem> {
187         self.inner.lock().fs.upgrade().unwrap()
188     }
189 
190     fn as_any_ref(&self) -> &dyn core::any::Any {
191         todo!()
192     }
193 
194     fn list(&self) -> Result<alloc::vec::Vec<alloc::string::String>, system_error::SystemError> {
195         let info = self.metadata()?;
196         if info.file_type != FileType::Dir {
197             return Err(SystemError::ENOTDIR);
198         }
199 
200         let mut keys: Vec<String> = Vec::new();
201         keys.push(String::from("."));
202         keys.push(String::from(".."));
203         keys.append(
204             &mut self
205                 .inner
206                 .lock()
207                 .children_unchecked()
208                 .keys()
209                 .cloned()
210                 .collect(),
211         );
212 
213         return Ok(keys);
214     }
215 
216     fn create_with_data(
217         &self,
218         name: &str,
219         file_type: FileType,
220         _mode: super::vfs::syscall::ModeType,
221         _data: usize,
222     ) -> Result<Arc<dyn IndexNode>, SystemError> {
223         if file_type != FileType::CharDevice {
224             return Err(SystemError::ENOSYS);
225         }
226 
227         let mut guard = self.inner.lock();
228 
229         if guard.children_unchecked_mut().contains_key(name) {
230             return Err(SystemError::EEXIST);
231         }
232 
233         let fs = guard.fs.upgrade().unwrap();
234 
235         let result = TtyDevice::new(
236             name.to_string(),
237             IdTable::new(name.to_string(), None),
238             TtyType::Pty(PtyType::Pts),
239         );
240 
241         let mut metadata = result.metadata()?;
242 
243         metadata.mode.insert(ModeType::S_IFCHR);
244         metadata.raw_dev =
245             DeviceNumber::new(Major::UNIX98_PTY_SLAVE_MAJOR, name.parse::<u32>().unwrap());
246 
247         result.set_metadata(&metadata)?;
248 
249         guard
250             .children_unchecked_mut()
251             .insert(name.to_string(), result.clone());
252 
253         fs.pts_count.fetch_add(1, Ordering::SeqCst);
254 
255         Ok(result)
256     }
257 
258     fn find(&self, name: &str) -> Result<Arc<dyn IndexNode>, SystemError> {
259         let guard = self.inner.lock();
260 
261         if let Some(dev) = guard.children_unchecked().get(name) {
262             Ok(dev.clone() as Arc<dyn IndexNode>)
263         } else {
264             Err(SystemError::ENOENT)
265         }
266     }
267 
268     fn unlink(&self, name: &str) -> Result<(), SystemError> {
269         let mut guard = self.inner.lock();
270         guard.children_unchecked_mut().remove(name);
271         Ok(())
272     }
273 }
274 
275 #[unified_init(INITCALL_FS)]
276 #[inline(never)]
277 pub fn devpts_init() -> Result<(), SystemError> {
278     // 创建 devptsfs 实例
279     let ptsfs: Arc<DevPtsFs> = DevPtsFs::new();
280 
281     do_mount_mkdir(ptsfs, "/dev/pts").expect("Failed to mount DevPtsFS");
282     info!("DevPtsFs mounted.");
283 
284     Ok(())
285 }
286