diff --git a/etc/syscalls_linux_aarch64.md b/etc/syscalls_linux_aarch64.md index f2b94e7..2b925b0 100644 --- a/etc/syscalls_linux_aarch64.md +++ b/etc/syscalls_linux_aarch64.md @@ -161,7 +161,7 @@ | 0x9e (158) | getgroups | (int gidsetsize, gid_t *grouplist) | __arm64_sys_getgroups | false | | 0x9f (159) | setgroups | (int gidsetsize, gid_t *grouplist) | __arm64_sys_setgroups | false | | 0xa0 (160) | newuname | (struct new_utsname *name) | __arm64_sys_newuname | true | -| 0xa1 (161) | sethostname | (char *name, int len) | __arm64_sys_sethostname | false | +| 0xa1 (161) | sethostname | (char *name, int len) | __arm64_sys_sethostname | true | | 0xa2 (162) | setdomainname | (char *name, int len) | __arm64_sys_setdomainname | false | | 0xa3 (163) | getrlimit | (unsigned int resource, struct rlimit *rlim) | __arm64_sys_getrlimit | dummy | | 0xa4 (164) | setrlimit | (unsigned int resource, struct rlimit *rlim) | __arm64_sys_setrlimit | false | diff --git a/libkernel/src/error.rs b/libkernel/src/error.rs index c8ae7c3..ec08335 100644 --- a/libkernel/src/error.rs +++ b/libkernel/src/error.rs @@ -195,6 +195,9 @@ pub enum KernelError { #[error("Interrupted system call")] Interrupted, + #[error("Name too long")] + NameTooLong, + #[error("{0}")] Other(&'static str), } diff --git a/src/arch/arm64/exceptions/syscall.rs b/src/arch/arm64/exceptions/syscall.rs index 39eeda1..1038e19 100644 --- a/src/arch/arm64/exceptions/syscall.rs +++ b/src/arch/arm64/exceptions/syscall.rs @@ -42,7 +42,10 @@ use crate::{ trunc::{sys_ftruncate, sys_truncate}, }, }, - kernel::{power::sys_reboot, rand::sys_getrandom, sysinfo::sys_sysinfo, uname::sys_uname}, + kernel::{ + hostname::sys_sethostname, power::sys_reboot, rand::sys_getrandom, sysinfo::sys_sysinfo, + uname::sys_uname, + }, memory::{ brk::sys_brk, mincore::sys_mincore, @@ -488,6 +491,7 @@ pub async fn handle_syscall() { 0x9c => sys_getsid().await, 0x9d => sys_setsid().await, 0xa0 => sys_uname(TUA::from_value(arg1 as _)).await, + 0xa1 => sys_sethostname(TUA::from_value(arg1 as _), arg2 as _).await, 0xa3 => Err(KernelError::InvalidValue), 0xa6 => sys_umask(arg1 as _).map_err(|e| match e {}), 0xa7 => sys_prctl(arg1 as _, arg2, arg3).await, diff --git a/src/kernel/hostname.rs b/src/kernel/hostname.rs new file mode 100644 index 0000000..fbb53ed --- /dev/null +++ b/src/kernel/hostname.rs @@ -0,0 +1,49 @@ +use crate::memory::uaccess::copy_from_user_slice; +use crate::sched::current::current_task_shared; +use crate::sync::OnceLock; +use crate::sync::SpinLock; +use alloc::string::String; +use alloc::vec; +use core::ffi::c_char; +use libkernel::error::{KernelError, Result}; +use libkernel::memory::address::TUA; +use libkernel::proc::caps::CapabilitiesFlags; + +static HOSTNAME: OnceLock> = OnceLock::new(); + +pub fn hostname() -> &'static SpinLock { + HOSTNAME.get_or_init(|| SpinLock::new(String::from("moss-machine"))) +} + +const HOST_NAME_MAX: usize = 64; + +pub async fn sys_sethostname(name_ptr: TUA, name_len: usize) -> Result { + { + let task = current_task_shared(); + let creds = task.creds.lock_save_irq(); + creds + .caps() + .check_capable(CapabilitiesFlags::CAP_SYS_ADMIN)?; + } + + if name_len > HOST_NAME_MAX { + return Err(KernelError::NameTooLong); + } + let mut buf = vec![0u8; name_len]; + copy_from_user_slice(name_ptr.to_untyped(), &mut buf).await?; + let name = String::from_utf8(buf).map_err(|_| KernelError::InvalidValue)?; + *hostname().lock_save_irq() = name; + Ok(0) +} + +// pub async fn sys_gethostname(name_ptr: TUA, name_len: usize) -> Result { +// let hostname = hostname().lock_save_irq(); +// let bytes = hostname.as_bytes(); +// let len = core::cmp::min(bytes.len(), name_len); +// copy_to_user_slice(&bytes[..len], name_ptr.to_untyped()).await?; +// // Null-terminate if there's space +// if name_len > len { +// copy_to_user(name_ptr.add_bytes(len), 0u8).await?; +// } +// Ok(0) +// } diff --git a/src/kernel/mod.rs b/src/kernel/mod.rs index 175c7de..8e3471c 100644 --- a/src/kernel/mod.rs +++ b/src/kernel/mod.rs @@ -1,4 +1,5 @@ pub mod cpu_id; +pub mod hostname; pub mod kpipe; pub mod power; pub mod rand; diff --git a/src/kernel/uname.rs b/src/kernel/uname.rs index 467a9b2..30a1b2b 100644 --- a/src/kernel/uname.rs +++ b/src/kernel/uname.rs @@ -1,8 +1,10 @@ +use crate::kernel::hostname::hostname; use crate::{ arch::{Arch, ArchImpl}, memory::uaccess::{UserCopyable, copy_to_user}, }; use alloc::ffi::CString; +use core::str::FromStr; use core::{ffi::c_char, mem}; use libkernel::{error::Result, memory::address::TUA}; @@ -37,13 +39,16 @@ pub async fn sys_uname(uts_ptr: TUA) -> Result { let sysname = c"Moss".to_bytes_with_nul(); copy_str_to_c_char_arr(&mut uts.sysname, sysname); - let nodename = c"moss-machine".to_bytes_with_nul(); - copy_str_to_c_char_arr(&mut uts.nodename, nodename); + let nodename = CString::from_str(&hostname().lock_save_irq()).unwrap(); + copy_str_to_c_char_arr(&mut uts.nodename, nodename.as_c_str().to_bytes_with_nul()); let release = c"4.2.3".to_bytes_with_nul(); copy_str_to_c_char_arr(&mut uts.release, release); + #[cfg(feature = "smp")] let version = c"#1 Moss SMP Tue Feb 20 12:34:56 UTC 2024".to_bytes_with_nul(); + #[cfg(not(feature = "smp"))] + let version = c"#1 Moss Tue Feb 20 12:34:56 UTC 2024".to_bytes_with_nul(); copy_str_to_c_char_arr(&mut uts.version, version); let machine = CString::new(ArchImpl::name()).unwrap();