Skip to main content

kmod/
ctx.rs

1use crate::errors::*;
2use crate::modules::{Module, ModuleIterator};
3use std::ffi::{CStr, CString, OsStr, OsString};
4use std::os::unix::ffi::OsStrExt;
5use std::path::Path;
6use std::{fmt, ptr};
7
8/// The kmod context
9///
10/// ```
11/// let ctx = kmod::Context::new().unwrap();
12/// ```
13pub struct Context {
14    ctx: *mut kmod_sys::kmod_ctx,
15}
16
17impl Drop for Context {
18    fn drop(&mut self) {
19        trace!("dropping kmod: {:?}", self.ctx);
20        let _ = unsafe { kmod_sys::kmod_unref(self.ctx) };
21    }
22}
23
24impl Context {
25    /// Create a new kmod context.
26    ///
27    /// ```
28    /// let ctx = kmod::Context::new().unwrap();
29    /// ```
30    #[inline]
31    pub fn new() -> Result<Context> {
32        let ctx = unsafe { kmod_sys::kmod_new(ptr::null(), ptr::null()) };
33        if ctx.is_null() {
34            Err(Error::NewCtx)
35        } else {
36            trace!("creating kmod: {:?}", ctx);
37            Ok(Context { ctx })
38        }
39    }
40
41    /// Create a new kmod context with given directory to search for kernel modules.
42    ///
43    /// ```
44    /// use std::path::Path;
45    /// let ctx = kmod::Context::new_with_dirname(&Path::new("/lib/modules/6.0.9")).unwrap();
46    /// ```
47    pub fn new_with_dirname(dirname: &Path) -> Result<Context> {
48        let dirname = CString::new(dirname.as_os_str().as_bytes())?;
49
50        let ctx = unsafe { kmod_sys::kmod_new(dirname.as_ptr(), ptr::null()) };
51
52        if ctx.is_null() {
53            Err(Error::NewCtx)
54        } else {
55            trace!("creating kmod: {:?}", ctx);
56            Ok(Context { ctx })
57        }
58    }
59
60    /// Get an iterator of all loaded modules.
61    ///
62    /// ```
63    /// let ctx = kmod::Context::new().unwrap();
64    /// for module in ctx.modules_loaded().unwrap() {
65    ///     // ...
66    /// }
67    /// ```
68    #[inline]
69    pub fn modules_loaded(&self) -> Result<ModuleIterator> {
70        let mut list = ptr::null::<kmod_sys::kmod_list>() as *mut kmod_sys::kmod_list;
71        let ret = unsafe { kmod_sys::kmod_module_new_from_loaded(self.ctx, &mut list) };
72
73        if ret < 0 {
74            Err(Error::LoadedModules)
75        } else {
76            trace!("kmod_module_new_from_loaded: {:?}", list);
77            Ok(ModuleIterator::new(list))
78        }
79    }
80
81    /// Create a module struct by looking up a name or alias.
82    ///
83    /// ```
84    /// # fn main() { foo(); }
85    /// # fn foo() -> anyhow::Result<()> {
86    /// use std::ffi::{OsStr, OsString};
87    /// let ctx = kmod::Context::new()?;
88    /// let module = ctx.module_new_from_lookup(&OsString::from("vfat"))?;
89    /// # Ok(())
90    /// # }
91    /// ```
92    pub fn module_new_from_lookup<S: AsRef<OsStr>>(&self, alias: S) -> Result<ModuleIterator> {
93        let mut list = ptr::null::<kmod_sys::kmod_list>() as *mut kmod_sys::kmod_list;
94        let alias = CString::new(alias.as_ref().as_bytes())?;
95        let ret =
96            unsafe { kmod_sys::kmod_module_new_from_lookup(self.ctx, alias.as_ptr(), &mut list) };
97
98        if ret < 0 {
99            Err(Error::ModuleFromLookup)
100        } else {
101            trace!("kmod_module_new_from_lookup: {:?}", list);
102            Ok(ModuleIterator::new(list))
103        }
104    }
105
106    /// Create a module struct by path.
107    ///
108    /// ```
109    /// let ctx = kmod::Context::new().unwrap();
110    /// let module = ctx.module_new_from_path("foo.ko");
111    /// ```
112    pub fn module_new_from_path<S: AsRef<OsStr>>(&self, filename: S) -> Result<Module> {
113        let mut module = ptr::null::<kmod_sys::kmod_module>() as *mut kmod_sys::kmod_module;
114
115        let filename = CString::new(filename.as_ref().as_bytes())?;
116        let ret = unsafe {
117            kmod_sys::kmod_module_new_from_path(self.ctx, filename.as_ptr(), &mut module)
118        };
119
120        if ret < 0 {
121            Err(Error::ModuleFromPath(errno::errno()))
122        } else {
123            trace!("kmod_module_new_from_path: {:?}", module);
124            Ok(Module::new(module))
125        }
126    }
127
128    /// Create a module struct by name.
129    ///
130    /// ```
131    /// let ctx = kmod::Context::new().unwrap();
132    /// let module = ctx.module_new_from_name("tun").unwrap();
133    /// ```
134    pub fn module_new_from_name(&self, name: &str) -> Result<Module> {
135        let mut module = ptr::null::<kmod_sys::kmod_module>() as *mut kmod_sys::kmod_module;
136
137        let name = CString::new(name)?;
138        let ret =
139            unsafe { kmod_sys::kmod_module_new_from_name(self.ctx, name.as_ptr(), &mut module) };
140
141        if ret < 0 {
142            Err(Error::ModuleFromName)
143        } else {
144            trace!("kmod_module_new_from_name: {:?}", module);
145            Ok(Module::new(module))
146        }
147    }
148
149    /// Get the directory where kernel modules are stored
150    ///
151    /// ```
152    /// let ctx = kmod::Context::new().unwrap();
153    /// let dirname = ctx.dirname();
154    /// ```
155    pub fn dirname(&self) -> OsString {
156        use std::os::unix::ffi::OsStringExt;
157
158        let dirname = unsafe { kmod_sys::kmod_get_dirname(self.ctx) };
159        let dirname = unsafe { CStr::from_ptr(dirname) };
160        OsString::from_vec(dirname.to_bytes().to_vec())
161    }
162}
163
164impl fmt::Debug for Context {
165    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
166        f.pad("Context { .. }")
167    }
168}