os/kernel/syscall/
util.rs1use core::ffi::{CStr, c_char};
4
5use alloc::{
6 format,
7 string::{String, ToString},
8 sync::Arc,
9 vec::Vec,
10};
11
12use crate::{
13 kernel::current_task,
14 uapi::{errno::EINVAL, log::SyslogAction},
15 vfs::{
16 DENTRY_CACHE, Dentry, File, FileMode, FsError, InodeType, OpenFlags, get_root_dentry,
17 impls::{BlockDeviceFile, CharDeviceFile, RegFile},
18 split_path, vfs_lookup_from,
19 },
20};
21
22pub fn get_path_safe(path: *const c_char) -> Result<&'static str, &'static str> {
29 let c_str = unsafe {
31 if path.is_null() {
33 return Err("Path pointer is NULL");
34 }
35 CStr::from_ptr(path)
37 };
38
39 match c_str.to_str() {
41 Ok(s) => Ok(s),
42 Err(_) => Err("Path is not valid UTF-8"),
43 }
44}
45
46pub fn get_args_safe(
54 ptr_array: *const *const c_char,
55 name: &str, ) -> Result<Vec<String>, String> {
57 let mut args = Vec::new();
58
59 if ptr_array.is_null() {
61 return Ok(Vec::new()); }
63
64 unsafe {
66 let mut current_ptr = ptr_array;
67
68 while !(*current_ptr).is_null() {
70 let c_str = {
71 CStr::from_ptr(*current_ptr)
73 };
74
75 match c_str.to_str() {
77 Ok(s) => args.push(s.to_string()),
78 Err(_) => {
79 return Err(format!("{} contains non-UTF-8 string", name));
80 }
81 }
82
83 current_ptr = current_ptr.add(1);
85 }
86 }
87
88 Ok(args)
89}
90
91pub fn resolve_at_path(dirfd: i32, path: &str) -> Result<Option<Arc<Dentry>>, FsError> {
95 let base_dentry = if path.starts_with('/') {
96 get_root_dentry()?
97 } else if dirfd == super::fs::AT_FDCWD {
98 current_task()
99 .lock()
100 .fs
101 .lock()
102 .cwd
103 .clone()
104 .ok_or(FsError::NotSupported)?
105 } else {
106 let task = current_task();
108 let file = task.lock().fd_table.get(dirfd as usize)?;
109
110 let meta = file.metadata()?;
112 if meta.inode_type != InodeType::Directory {
113 return Err(FsError::NotDirectory);
114 }
115
116 if let Ok(dentry) = file.dentry() {
117 dentry
118 } else {
119 return Err(FsError::NotDirectory);
120 }
121 };
122
123 match vfs_lookup_from(base_dentry, path) {
124 Ok(d) => Ok(Some(d)),
125 Err(FsError::NotFound) => Ok(None),
126 Err(e) => Err(e),
127 }
128}
129
130pub fn create_file_at(dirfd: i32, path: &str, mode: u32) -> Result<Arc<Dentry>, FsError> {
137 let (dir_path, filename) = split_path(path)?;
138 let parent_dentry = match resolve_at_path(dirfd, &dir_path)? {
139 Some(d) => d,
140 None => return Err(FsError::NotFound),
141 };
142
143 let meta = parent_dentry.inode.metadata()?;
144 if meta.inode_type != InodeType::Directory {
145 return Err(FsError::NotDirectory);
146 }
147
148 let file_mode = FileMode::from_bits_truncate(mode) | FileMode::S_IFREG;
149 let child_inode = parent_dentry.inode.create(&filename, file_mode)?;
150
151 let child_dentry = Dentry::new(filename.clone(), child_inode);
152 parent_dentry.add_child(child_dentry.clone());
153 DENTRY_CACHE.insert(&child_dentry);
154
155 Ok(child_dentry)
156}
157
158pub fn validate_syslog_args(action: SyslogAction, bufp: *mut u8, len: i32) -> Result<(), i32> {
171 match action {
172 SyslogAction::Read | SyslogAction::ReadAll | SyslogAction::ReadClear => {
173 if bufp.is_null() {
175 return Err(EINVAL);
176 }
177 if len < 0 {
178 return Err(EINVAL);
179 }
180 }
182
183 SyslogAction::ConsoleLevel => {
184 if len < 1 || len > 8 {
187 return Err(EINVAL);
188 }
189 }
190
191 _ => {
192 }
194 }
195
196 Ok(())
197}
198
199pub fn check_syslog_permission(action: SyslogAction) -> Result<(), i32> {
215 if matches!(action, SyslogAction::ReadAll | SyslogAction::SizeBuffer) {
227 let dmesg_restrict = get_dmesg_restrict();
229 if dmesg_restrict == 0 {
230 return Ok(()); }
232 }
233
234 Ok(())
237
238 }
263
264#[inline]
273fn get_dmesg_restrict() -> u32 {
274 0
277}
278
279pub fn get_first_block_device() -> Result<Arc<dyn crate::device::block::BlockDriver>, i32> {
287 use crate::device::BLK_DRIVERS;
288 use crate::uapi::errno::ENODEV;
289
290 let drivers = BLK_DRIVERS.read();
291
292 if drivers.is_empty() {
293 return Err(-ENODEV);
294 }
295
296 Ok(drivers[0].clone())
297}
298
299pub fn flush_all_block_devices() -> Result<(), isize> {
304 use crate::{device::BLK_DRIVERS, uapi::errno::EIO};
305
306 let drivers = BLK_DRIVERS.read();
307
308 if drivers.is_empty() {
309 return Ok(());
311 }
312
313 for driver in drivers.iter() {
314 if !driver.flush() {
315 return Err(-EIO as isize);
317 }
318 }
319
320 Ok(())
321}
322
323pub fn flush_block_device_by_fd(fd: usize) -> Result<(), isize> {
336 use crate::{uapi::errno::EIO, vfs::MOUNT_TABLE};
337
338 let task = current_task();
340 let file = task.lock().fd_table.get(fd).map_err(|e| e.to_errno())?;
341
342 let dentry = file.dentry().map_err(|e| e.to_errno())?;
344
345 let path = dentry.full_path();
347
348 let mount_point = MOUNT_TABLE
350 .find_mount(&path)
351 .ok_or_else(|| FsError::NotSupported.to_errno())?;
352
353 mount_point.fs.sync().map_err(|_| -EIO as isize)?;
355
356 Ok(())
357}
358
359pub fn resolve_at_path_with_flags(
381 dirfd: i32,
382 path: &str,
383 follow_symlink: bool,
384) -> Result<Arc<Dentry>, FsError> {
385 use crate::vfs::vfs_lookup_no_follow;
386
387 if follow_symlink {
388 resolve_at_path(dirfd, path)?.ok_or(FsError::NotFound)
390 } else {
391 if path.starts_with('/') {
393 vfs_lookup_no_follow(path)
395 } else {
396 let base_dentry = if dirfd == super::fs::AT_FDCWD {
398 current_task()
400 .lock()
401 .fs
402 .lock()
403 .cwd
404 .clone()
405 .ok_or(FsError::NotFound)?
406 } else {
407 let task = current_task();
409 let file = task.lock().fd_table.get(dirfd as usize)?;
410 file.dentry()?
411 };
412
413 let full_path = if base_dentry.full_path() == "/" {
415 format!("/{}", path)
416 } else {
417 format!("{}/{}", base_dentry.full_path(), path)
418 };
419
420 vfs_lookup_no_follow(&full_path)
421 }
422 }
423}
424
425pub fn create_file_from_dentry(
427 dentry: Arc<Dentry>,
428 flags: OpenFlags,
429) -> Result<Arc<dyn File>, FsError> {
430 let inode_type = dentry.inode.metadata()?.inode_type;
431
432 let file: Arc<dyn File> = match inode_type {
433 InodeType::File | InodeType::Directory | InodeType::Symlink => {
434 Arc::new(RegFile::new(dentry, flags))
436 }
437 InodeType::CharDevice => {
438 Arc::new(CharDeviceFile::new(dentry, flags)?)
440 }
441 InodeType::BlockDevice => {
442 Arc::new(BlockDeviceFile::new(dentry, flags)?)
444 }
445 InodeType::Socket | InodeType::Fifo => {
446 return Err(FsError::NotSupported);
448 }
449 };
450
451 Ok(file)
452}