#[derive(Debug, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
#[derive(Deserialize, Serialize)]
#[repr(transparent)]
pub struct LinuxKernelModuleName(#[serde(with = "serde_bytes")] Box<[u8]>);
impl From<&[u8]> for LinuxKernelModuleName
{
#[inline(always)]
fn from(value: &[u8]) -> Self
{
Self::from(value.to_vec())
}
}
impl From<Box<[u8]>> for LinuxKernelModuleName
{
#[inline(always)]
fn from(value: Box<[u8]>) -> Self
{
Self(value)
}
}
impl From<Vec<u8>> for LinuxKernelModuleName
{
#[inline(always)]
fn from(value: Vec<u8>) -> Self
{
Self(value.into())
}
}
impl From<String> for LinuxKernelModuleName
{
#[inline(always)]
fn from(value: String) -> Self
{
Self::from(value.into_bytes())
}
}
impl Into<CString> for LinuxKernelModuleName
{
#[inline(always)]
fn into(self) -> CString
{
CString::new(&self.0[..]).unwrap()
}
}
impl<'a> Into<CString> for &'a LinuxKernelModuleName
{
#[inline(always)]
fn into(self) -> CString
{
CString::new(&self.0[..]).unwrap()
}
}
impl Into<OsString> for LinuxKernelModuleName
{
#[inline(always)]
fn into(self) -> OsString
{
OsString::from_vec(self.0.to_vec())
}
}
impl<'a> Into<OsString> for &'a LinuxKernelModuleName
{
#[inline(always)]
fn into(self) -> OsString
{
OsString::from_vec(self.0.clone().to_vec())
}
}
impl<'a> IntoLineFeedTerminatedByteString<'a> for &'a LinuxKernelModuleName
{
#[inline(always)]
fn into_line_feed_terminated_byte_string(self) -> Cow<'a, [u8]>
{
let mut value = self.0.clone().into_vec();
value.push(b'\n');
Cow::from(value)
}
}
impl LinuxKernelModuleName
{
#[inline(always)]
pub fn modprobe_executable_path(proc_path: &ProcPath) -> Option<PathBuf>
{
let file_path = Self::modprobe_file_path(proc_path);
if file_path.exists()
{
let bytes = file_path.read_raw_without_line_feed().unwrap();
Some(PathBuf::from(OsString::from_vec(bytes.into_vec())))
}
else
{
None
}
}
#[inline(always)]
pub fn set_modprobe_executable_path(proc_path: &ProcPath, modprobe_executable_path: &impl AsRef<Path>) -> io::Result<()>
{
assert_effective_user_id_is_root("write /proc/sys/kernel/modprobe");
let file_path = Self::modprobe_file_path(proc_path);
if file_path.exists()
{
fn validate_modprobe_path(modprobe_executable_path: &impl AsRef<Path>) -> io::Result<&Path>
{
let modprobe_executable_path = modprobe_executable_path.as_ref();
let path_file_descriptor = PathFileDescriptor::open(&path_to_cstring(modprobe_executable_path), false, false)?;
let metadata = path_file_descriptor.metadata_of_self()?;
if unlikely!(!metadata.user_identifier().is_root())
{
return Err(io_error_other("Not owned by root"))
}
if unlikely!(!metadata.file_type().is_regular_file())
{
return Err(io_error_other("Not a regular file"))
}
if unlikely!(!metadata.access_permissions().user().is_readable_and_executable())
{
return Err(io_error_other("Not a readable, executable file"))
}
Ok(modprobe_executable_path)
}
file_path.write_value(validate_modprobe_path(modprobe_executable_path)?)
}
else
{
Ok(())
}
}
#[inline(always)]
pub fn is_module_loading_and_unloading_disabled(proc_path: &ProcPath) -> bool
{
let file_path = Self::modules_disabled_file_path(proc_path);
if file_path.exists()
{
file_path.read_zero_or_one_bool().unwrap()
}
else
{
true
}
}
#[inline(always)]
pub fn disable_module_loading_and_unloading_until_reboot(proc_path: &ProcPath) -> io::Result<()>
{
assert_effective_user_id_is_root("write /proc/sys/kernel/modules_disabled");
if Self::is_module_loading_and_unloading_disabled(proc_path)
{
return Ok(())
}
Self::modules_disabled_file_path(proc_path).write_value(true)
}
#[inline(always)]
fn modprobe_file_path(proc_path: &ProcPath) -> PathBuf
{
proc_path.sys_kernel_file_path("modprobe")
}
#[inline(always)]
fn modules_disabled_file_path(proc_path: &ProcPath) -> PathBuf
{
proc_path.sys_kernel_file_path("modules_disabled")
}
pub fn load_linux_kernel_module_using_modprobe(&self, modprobe_path: &Path) -> Result<(), ModProbeError>
{
assert!(!self.0.starts_with(b"-"), "{:?} starts with a hyphen. This confuses some modprobe implementations (and some don't support `--` parsing it seems)", self);
assert_effective_user_id_is_root(&format!("modprobe of {:?}", self));
#[inline(always)]
fn new_command_in_clean_environment(modprobe_path: &Path) -> Command
{
let mut command = Command::new(modprobe_path);
command.stdin(Stdio::null()).stdout(Stdio::null()).stderr(Stdio::null()).env_clear();
if let Some(path) = var_os("PATH")
{
command.env("PATH", path);
}
command
}
let os_str = OsStr::from_bytes(&self.0[..]);
let exit_code = new_command_in_clean_environment(modprobe_path).arg("-s").arg("-b").arg(os_str).status()?;
use self::ModProbeError::*;
match exit_code.code()
{
None => Err(SignalTerminatedExitCode(self.clone())),
Some(exit_code) => match exit_code
{
0 => Ok(()),
_ => Err(NonZeroExitCode { linux_kernel_module_name: self.clone(), exit_code }),
}
}
}
pub fn unload_linux_kernel_module(&self) -> Result<bool, io::Error>
{
let name: CString = self.into();
const flags: c_long = O_NONBLOCK as c_long;
match SYS::delete_module.syscall2(name.as_ptr() as usize, flags as usize)
{
0 => Ok(true),
-1 => match errno().0
{
EPERM => Err(io_error_permission_denied("permission denied")),
EBUSY => Err(io_error_permission_denied("busy")),
ENOENT => Ok(false),
EWOULDBLOCK => Err(io_error_permission_denied("In use")),
EFAULT => panic!("EFAULT should not occur"),
unknown @ _ => panic!("syscall(SYS_delete_module) failed with illegal error code '{}'", unknown),
},
illegal @ _ => panic!("syscall(SYS_delete_module) returned illegal value '{}'", illegal),
}
}
}