linapi/system/modules.rs
1//! Interface to Dynamically Loaded Linux Kernel Modules.
2//!
3//! # Examples
4//!
5//! Print all currently loaded system modules
6//!
7//! ```rust
8//! # use linapi::system::modules::*;
9//!
10//! let mods = LoadedModule::get_loaded().unwrap();
11//!
12//! for m in mods {
13//! println!("Module: {}", m.name());
14//! }
15//! ```
16//!
17//! Load a module
18//!
19//! ```rust,no_run
20//! # use linapi::system::modules::*;
21//!
22//! let m = ModuleFile::from_name("MyModule").unwrap();
23//! let loaded = m.load("my_param=1").unwrap();
24//! println!(
25//! "Loaded module {}. my_param={}",
26//! loaded.name(),
27//! std::str::from_utf8(&loaded.parameters()["my_param"]).unwrap()
28//! );
29//! ```
30//!
31//! # Implementation
32//!
33//! This uses the sysfs interface, documented [here][1] and [here][2], and
34//! various undocumented interfaces where noted.
35//!
36//! [1]: https://www.kernel.org/doc/Documentation/ABI/stable/sysfs-module
37//! [2]: https://www.kernel.org/doc/Documentation/ABI/testing/sysfs-module
38use crate::{
39 error::{text::*, ModuleError},
40 extensions::FileExt,
41 system::{UEvent, UEventAction},
42 util::{read_uevent, write_uevent, MODULE_PATH, SYSFS_PATH},
43};
44#[cfg(feature = "gz")]
45use flate2::bufread::GzDecoder;
46use nix::{
47 kmod::{delete_module, finit_module, init_module, DeleteModuleFlags, ModuleInitFlags},
48 sys::utsname::uname,
49};
50use std::{
51 collections::HashMap,
52 ffi::CString,
53 fs,
54 fs::DirEntry,
55 io::{prelude::*, BufRead},
56 path::{Path, PathBuf},
57};
58use walkdir::WalkDir;
59use xmas_elf::ElfFile;
60#[cfg(feature = "xz")]
61use xz2::bufread::XzDecoder;
62#[cfg(feature = "zst")]
63use zstd::stream::read::Decoder as ZstDecoder;
64
65const SIGNATURE_MAGIC: &[u8] = b"~Module signature appended~\n";
66
67pub type Result<T, E = ModuleError> = std::result::Result<T, E>;
68
69/// Kernel modules can be "tainted", which serve as a marker for debugging
70/// purposes.
71#[derive(Debug, Clone, Copy)]
72pub enum Taint {
73 /// Proprietary Module.
74 Proprietary,
75
76 /// Out of tree, third party Module.
77 OutOfTree,
78
79 /// Module was force loaded.
80 Forced,
81
82 /// Unstable Staging Module.
83 Staging,
84
85 /// Unsigned Module.
86 Unsigned,
87}
88
89/// Module type
90#[derive(Debug, Clone, Copy)]
91pub enum Type {
92 /// Built in to the kernel.
93 ///
94 /// These only show up if they have a version or one run-time parameter, and
95 /// are missing most values.
96 ///
97 /// # Note
98 ///
99 /// The fact these show up isn't intentional and technically may change, or
100 /// so claim the kernel docs.
101 BuiltIn,
102
103 /// Dynamically loaded.
104 Dynamic,
105}
106
107/// Module Init Status
108#[derive(Debug, Clone)]
109pub enum Status {
110 /// Normal state, fully loaded.
111 Live,
112
113 /// Running module init
114 Coming,
115
116 /// Going away, running module exit?
117 Going,
118
119 /// Unknown
120 Unknown(String),
121}
122
123/// Describes a loaded Linux kernel Module
124#[derive(Debug)]
125pub struct LoadedModule {
126 /// The name of the Module
127 name: String,
128
129 /// Type of module
130 module_type: Type,
131
132 /// Path to the module
133 path: PathBuf,
134
135 /// Module parameters and their contents
136 parameters: HashMap<String, Vec<u8>>,
137
138 /// Module ref count
139 ref_count: Option<u32>,
140
141 /// Module taint
142 taint: Option<Taint>,
143
144 /// Module status
145 status: Option<Status>,
146
147 /// Module size in bytes
148 size: u64,
149
150 /// Module users
151 holders: Vec<Self>,
152}
153
154// Public
155impl LoadedModule {
156 /// Refresh information on the module
157 ///
158 /// # Errors
159 ///
160 /// - If any expected module attribute couldn't be read
161 /// - If any expected module attribute was invalid
162 pub fn refresh(&mut self) -> Result<()> {
163 let mut map = HashMap::new();
164 let par = self.path.join("parameters");
165 if par.exists() {
166 for entry in fs::read_dir(par)? {
167 let entry: DirEntry = entry?;
168 map.insert(
169 entry
170 .file_name()
171 .into_string()
172 .map_err(|_| ModuleError::InvalidModule(PARAMETER.into()))?,
173 fs::read(entry.path()).unwrap_or_default(),
174 );
175 }
176 }
177 self.parameters = map;
178 self.ref_count = fs::read_to_string(self.path.join("refcnt"))
179 .map(|s| s.trim().parse())?
180 .ok();
181 self.taint = match fs::read_to_string(self.path.join("taint"))?.trim() {
182 "P" => Some(Taint::Proprietary),
183 "O" => Some(Taint::OutOfTree),
184 "F" => Some(Taint::Forced),
185 "C" => Some(Taint::Staging),
186 "E" => Some(Taint::Unsigned),
187 _ => None,
188 };
189 self.status = Some(
190 match fs::read_to_string(self.path.join("initstate"))?.trim() {
191 "live" => Status::Live,
192 "coming" => Status::Coming,
193 "going" => Status::Going,
194 s => Status::Unknown(s.into()),
195 },
196 );
197 self.size = fs::read_to_string(self.path.join("coresize"))
198 .map(|s| s.trim().parse())?
199 .map_err(|_| ModuleError::InvalidModule(PARAMETER.into()))?;
200 let mut v = Vec::new();
201 for re in fs::read_dir(self.path.join("holders"))? {
202 let re: DirEntry = re?;
203 v.push(Self::from_dir(&re.path())?)
204 }
205 self.holders = v;
206 //
207 Ok(())
208 }
209
210 /// Get an already loaded module by name
211 ///
212 /// # Errors
213 ///
214 /// - If no such module exists
215 /// - If the module is invalid in some way
216 pub fn from_name(name: &str) -> Result<Self> {
217 Self::from_dir(&Path::new(SYSFS_PATH).join("module").join(name))
218 }
219
220 /// Get currently loaded dynamic kernel modules.
221 ///
222 /// # Errors
223 ///
224 /// - IO
225 /// - If any modules couldn't be read
226 pub fn get_loaded() -> Result<Vec<Self>> {
227 let dir = Path::new(SYSFS_PATH).join("module");
228 let mut mods = Vec::new();
229 //
230 for module in fs::read_dir(dir)? {
231 let module: DirEntry = module?;
232 let m = Self::from_dir(&module.path())?;
233 if let Type::BuiltIn = m.module_type() {
234 continue;
235 }
236 mods.push(m);
237 }
238 Ok(mods)
239 }
240
241 /// Unload the module.
242 ///
243 /// # Errors
244 ///
245 /// - On failure
246 pub fn unload(self) -> Result<()> {
247 delete_module(
248 // This unwrap should be okay, `name` is from the file path which shouldn't have nul
249 // bytes
250 &CString::new(self.name.as_str()).unwrap(),
251 DeleteModuleFlags::O_NONBLOCK,
252 )
253 .map_err(|e| ModuleError::UnloadError(self.name, e.to_string()))?;
254 //
255 Ok(())
256 }
257
258 /// Forcefully unload a kernel module.
259 ///
260 /// # Safety
261 ///
262 /// Force unloading is wildly dangerous and will taint your kernel.
263 ///
264 /// It can cause modules to be unloaded while still in use, or unload
265 /// modules not designed to be unloaded.
266 ///
267 /// # Errors
268 ///
269 /// - On failure
270 pub unsafe fn force_unload(self) -> Result<()> {
271 delete_module(
272 // This unwrap should be okay, `name` is from the file path which shouldn't have nul
273 // bytes
274 &CString::new(self.name.as_str()).unwrap(),
275 DeleteModuleFlags::O_NONBLOCK | DeleteModuleFlags::O_TRUNC,
276 )
277 .map_err(|e| ModuleError::UnloadError(self.name, e.to_string()))?;
278 //
279 Ok(())
280 }
281
282 /// Name of the module
283 pub fn name(&self) -> &str {
284 &self.name
285 }
286
287 /// Module type, Builtin or Dynamic
288 pub fn module_type(&self) -> Type {
289 self.module_type
290 }
291
292 /// Module parameters.
293 ///
294 /// The kernel exposes these as files in a directory, and their contents are
295 /// entirely module specific, hence `HashMap<String, Vec<u8>>`, which can
296 /// be [`std::io::Read`].
297 ///
298 /// The key will be the parameter name and the value is it's data
299 ///
300 /// # Stability
301 ///
302 /// The stability of parameters depends entirely on the specific module.
303 pub fn parameters(&self) -> &HashMap<String, Vec<u8>> {
304 &self.parameters
305 }
306
307 /// Module reference count.
308 ///
309 /// If the module is built-in, or if the kernel was not built with
310 /// `CONFIG_MODULE_UNLOAD`, this will be [`None`]
311 pub fn ref_count(&self) -> Option<u32> {
312 self.ref_count
313 }
314
315 /// Module size in bytes
316 pub fn size(&self) -> u64 {
317 self.size
318 }
319
320 /// Module taint, or [`None`] if untainted.
321 ///
322 /// See [`Taint`] for details.
323 pub fn taint(&self) -> Option<Taint> {
324 self.taint
325 }
326
327 /// List of other modules that use/reference this one.
328 ///
329 /// # Note
330 ///
331 /// This uses the `holders` sysfs folder, which is completely undocumented
332 /// by the kernel, beware.
333 pub fn holders(&self) -> &Vec<Self> {
334 &self.holders
335 }
336
337 /// Get a [`ModuleFile`] from a [`LoadedModule`]
338 ///
339 /// This can be useful to get information, such as parameter types, about a
340 /// module.
341 ///
342 /// # Note
343 ///
344 /// There is no guarantee the returned path is the same module. The file may
345 /// have changed on disk, or been removed.
346 ///
347 /// This is equivalent to `ModuleFile::from_name(&self.name)`
348 pub fn module_file(&self) -> Result<ModuleFile> {
349 ModuleFile::from_name(&self.name)
350 }
351
352 /// Module status.
353 ///
354 /// # Note
355 ///
356 /// This uses the undocumented `initstate` file, which is probably
357 /// `module_state` from `linux/module.h`.
358 pub fn status(&self) -> &Status {
359 // Should be fine, refresh sets it to `Some`.
360 self.status.as_ref().unwrap()
361 }
362}
363
364// Private
365impl LoadedModule {
366 /// Create from module directory
367 ///
368 /// # Errors
369 ///
370 /// - If module doesn't exist
371 /// - If module is invalid
372 ///
373 /// # Note
374 ///
375 /// Built-in modules may appear in `/sys/modules` and they are ill-formed,
376 /// missing required files.
377 ///
378 /// In this case `refcnt` is [`None`], `coresize` is 0, and `taint` is
379 /// [`None`]
380 ///
381 /// This method performs automatic underscore conversion.
382 fn from_dir(path: &Path) -> Result<Self> {
383 let name = path
384 .file_name()
385 .expect("Missing module name")
386 .to_str()
387 .expect("Invalid module name");
388 // `/sys/modules` seems to always use `_` in paths?
389 let path = path.with_file_name(name.replace('-', "_"));
390 if !path.exists() {
391 return Err(ModuleError::Io(std::io::Error::new(
392 std::io::ErrorKind::NotFound,
393 format!("Couldn't find loaded module at {}", path.display()),
394 )));
395 }
396 let module_type = if path.join("coresize").exists() {
397 Type::Dynamic
398 } else {
399 Type::BuiltIn
400 };
401 let mut s = Self {
402 name: path
403 .file_stem()
404 .and_then(|s| s.to_str())
405 .map(|s| s.trim().to_owned())
406 .ok_or_else(|| ModuleError::InvalidModule(NAME.into()))?,
407 module_type,
408 path,
409 parameters: HashMap::new(),
410 ref_count: None,
411 taint: None,
412 status: None,
413 size: 0,
414 holders: Vec::new(),
415 };
416 if let Type::Dynamic = s.module_type {
417 s.refresh()?;
418 }
419 Ok(s)
420 }
421}
422
423impl UEvent for LoadedModule {
424 fn write(&self, action: UEventAction, uuid: Option<String>, args: HashMap<String, String>) {
425 write_uevent(&self.path.join("uevent"), action, uuid, args)
426 }
427 fn read(&self) -> HashMap<String, String> {
428 read_uevent(&self.path.join("uevent"))
429 }
430}
431
432/// A Linux Kernel Module file on disk.
433///
434/// On construction information about the module is read and saved.
435///
436/// But the file may change on disk or even be removed, so you can use
437/// `ModuleFile::refresh` to update the information or show an error if it's
438/// been removed.
439#[derive(Debug)]
440pub struct ModuleFile {
441 name: String,
442 path: PathBuf,
443 //
444 info: Option<ModInfo>,
445 signature: bool,
446}
447
448// Public methods
449impl ModuleFile {
450 /// Refresh information on the module
451 ///
452 /// # Errors
453 ///
454 /// - If the file no longer exists
455 /// - If the module or any of it's information is invalid
456 pub fn refresh(&mut self) -> Result<()> {
457 let img = self.read()?;
458 self.info = Some(self._info(&img)?);
459 self.signature = img.ends_with(SIGNATURE_MAGIC);
460 //
461 Ok(())
462 }
463
464 /// Search `/lib/modules/(uname -r)` for the module `name`.
465 ///
466 /// # Errors
467 ///
468 /// - If the module couldn't be found
469 /// - See [`ModuleFile::refresh`]
470 pub fn from_name(name: &str) -> Result<Self> {
471 Self::from_name_with_uname(name, uname().release())
472 }
473
474 /// Search `lib/modules/<uname>` for the module `name`.
475 ///
476 /// See [`ModuleFile::from_name`] for more details.
477 pub fn from_name_with_uname(name: &str, uname: &str) -> Result<Self> {
478 let path = Path::new(MODULE_PATH).join(uname);
479 for entry in WalkDir::new(path) {
480 let entry = entry.map_err(|e| ModuleError::Io(e.into()))?;
481 if !entry.file_type().is_file() {
482 continue;
483 }
484 // Get the module filename without any extensions.
485 // Modules are `.ko` but can be compressed, `.ko.xz`.
486 let m_name = entry
487 .path()
488 .file_stem()
489 .and_then(|s| s.to_str())
490 .and_then(|s| s.splitn(2, '.').next())
491 .ok_or_else(|| ModuleError::InvalidModule(INVALID_EXTENSION.into()))?;
492 if m_name == name {
493 let mut s = Self {
494 name: name.into(),
495 path: entry.into_path(),
496 info: None,
497 signature: false,
498 };
499 s.refresh()?;
500 return Ok(s);
501 }
502 }
503 Err(ModuleError::LoadError(name.into(), NOT_FOUND.into()))
504 }
505
506 /// Use the file at `path` as a module.
507 ///
508 /// # Errors
509 ///
510 /// - if `path` does not exist
511 /// - if `path` is not a valid module.
512 pub fn from_path(path: &Path) -> Result<Self> {
513 let mut s = Self {
514 name: path
515 .file_stem()
516 .and_then(|s| s.to_str())
517 .ok_or_else(|| {
518 ModuleError::LoadError(path.display().to_string(), NOT_FOUND.into())
519 })?
520 .into(),
521 path: path.into(),
522 info: None,
523 signature: false,
524 };
525 s.refresh()?;
526 //
527 Ok(s)
528 }
529
530 /// Load this kernel module, and return the [`LoadedModule`] describing it.
531 ///
532 /// # Arguments
533 ///
534 /// - `param`eters for the kernel module. See module documentation for
535 /// details, and `init_module(2)` for details on formatting.
536 ///
537 /// # Errors
538 ///
539 /// - If the file no longer exists
540 /// - If the file can't be decompressed
541 /// - If the module fails to load
542 ///
543 /// # Panics
544 ///
545 /// - if `param` has any `0` bytes.
546 ///
547 /// # Note
548 ///
549 /// Kernel modules may be compressed, and depending on crate features this
550 /// function may automatically decompress it.
551 pub fn load(&self, param: &str) -> Result<LoadedModule> {
552 let img = self.read()?;
553 // FIXME: ModuleError::AlreadyLoaded
554 init_module(
555 &img,
556 &CString::new(param).expect("param can't have internal null bytes"),
557 )
558 .map_err(|e| ModuleError::LoadError(self.name.clone(), e.to_string()))?;
559
560 Ok(LoadedModule::from_dir(
561 &Path::new(SYSFS_PATH).join("module").join(&self.name),
562 )?)
563 }
564
565 /// Force load this kernel module, and return the [`LoadedModule`]
566 /// describing it.
567 ///
568 /// See [`ModuleFile::load`] for more details.
569 ///
570 /// # Safety
571 ///
572 /// Force loading a kernel module is dangerous, it skips important safety
573 /// checks that help ensure module compatibility with your kernel.
574 pub unsafe fn force_load(&self, param: &str) -> Result<LoadedModule> {
575 let mut file = fs::File::create_memory("decompressed module");
576 file.write_all(&self.read()?)?;
577 //
578 finit_module(
579 &file,
580 &CString::new(param).expect("param can't have internal null bytes"),
581 ModuleInitFlags::MODULE_INIT_IGNORE_MODVERSIONS
582 | ModuleInitFlags::MODULE_INIT_IGNORE_VERMAGIC,
583 )
584 .map_err(|e| ModuleError::LoadError(self.name.clone(), e.to_string()))?;
585 //
586 Ok(LoadedModule::from_dir(
587 &Path::new(SYSFS_PATH).join("module").join(&self.name),
588 )?)
589 }
590
591 pub fn path(&self) -> &Path {
592 &self.path
593 }
594
595 pub fn name(&self) -> &str {
596 &self.name
597 }
598
599 /// Get information embedded in the module file.
600 pub fn info(&self) -> &ModInfo {
601 // This unwrap should be okay, as `refresh` should be called by all constructors
602 // and ensure this is `Some`
603 self.info.as_ref().unwrap()
604 }
605
606 /// Whether the module has a signature.
607 ///
608 /// This does not check if it's valid.
609 ///
610 /// # Note
611 ///
612 /// This is a temporary API, as `rust-openssl` does not expose the APIs
613 /// required for properly reading module signatures.
614 // FIXME: rust-openssl does not expose the APIs we need, so this isn't possible.
615 // When/if they do, see `module_signature.h` for details on structure.
616 pub fn has_signature(&self) -> bool {
617 self.signature
618 }
619}
620
621// Private methods
622impl ModuleFile {
623 fn read(&self) -> Result<Vec<u8>> {
624 self.decompress(fs::read(&self.path)?)
625 }
626
627 fn _info(&self, img: &[u8]) -> Result<ModInfo> {
628 let elf = ElfFile::new(img).map_err(|e| ModuleError::InvalidModule(e.to_string()))?;
629 let sect = elf
630 .find_section_by_name(".modinfo")
631 .ok_or_else(|| ModuleError::InvalidModule(MODINFO.into()))?;
632 let data = sect.raw_data(&elf);
633 //
634 let mut map = HashMap::new();
635 for kv in BufRead::split(data, b'\0') {
636 let kv = kv?;
637 let s = String::from_utf8(kv).map_err(|e| ModuleError::InvalidModule(e.to_string()))?;
638 let mut s = s.splitn(2, '=');
639 //
640 let key = s
641 .next()
642 .map(|s| s.to_string())
643 .ok_or_else(|| ModuleError::InvalidModule(MODINFO.into()))?;
644 let value = s
645 .next()
646 .map(|s| s.to_string())
647 .ok_or_else(|| ModuleError::InvalidModule(MODINFO.into()))?;
648 let vec = map.entry(key).or_insert_with(Vec::new);
649 if !value.is_empty() {
650 vec.push(value);
651 }
652 }
653 fn y_n(s: &str) -> bool {
654 s == "Y" || s == "y"
655 }
656 fn one(map: &mut HashMap<String, Vec<String>>, key: &str) -> String {
657 map.remove(key).map(|mut v| v.remove(0)).unwrap_or_default()
658 }
659 fn more(map: &mut HashMap<String, Vec<String>>, key: &str) -> Vec<String> {
660 map.remove(key).unwrap_or_default()
661 }
662 //
663 let mut x = HashMap::new();
664 for (name, typ) in map
665 .remove("parmtype")
666 .unwrap_or_default()
667 .into_iter()
668 .map(|s| {
669 let mut i = s.splitn(2, ':').map(|s| s.trim().to_owned());
670 (i.next(), i.next())
671 })
672 {
673 let name: Option<String> = name;
674 let typ: Option<String> = typ;
675
676 // Types are reasonably guaranteed to exist because
677 // `linux/moduleparam.h` adds them for all the `module_param`
678 // macros, which define parameters.
679 // FIXME: loop module param hw_queue_depth has no type
680 let name = name.ok_or_else(|| ModuleError::InvalidModule(MODINFO.into()))?;
681 let typ = typ.ok_or_else(|| ModuleError::InvalidModule(MODINFO.into()))?;
682
683 // Parameters should not have multiple types.
684 if x.insert(name, (typ, None)).is_some() {
685 return Err(ModuleError::InvalidModule(MODINFO.into()));
686 };
687 }
688
689 for (name, desc) in map.remove("parm").unwrap_or_default().into_iter().map(|s| {
690 let mut i = s.splitn(2, ':').map(|s| s.trim().to_owned());
691 (i.next(), i.next())
692 }) {
693 let name: Option<String> = name;
694 let desc: Option<String> = desc;
695
696 let name = name.ok_or_else(|| ModuleError::InvalidModule(MODINFO.into()))?;
697
698 // Add parameter descriptions
699 x.entry(name).or_insert(("Unknown".into(), None)).1 = desc;
700 }
701 let mut parameters = Vec::new();
702 for (name, (type_, description)) in x {
703 parameters.push(ModParam {
704 name,
705 type_,
706 description,
707 })
708 }
709 //
710 Ok(ModInfo {
711 alias: more(&mut map, "alias"),
712 soft_dependencies: more(&mut map, "softdep"),
713 license: one(&mut map, "license"),
714 authors: more(&mut map, "author"),
715 description: one(&mut map, "description"),
716 version: one(&mut map, "version"),
717 firmware: more(&mut map, "firmware"),
718 version_magic: one(&mut map, "vermagic"),
719 name: one(&mut map, "name"),
720 in_tree: y_n(&one(&mut map, "intree")),
721 retpoline: y_n(&one(&mut map, "retpoline")),
722 staging: y_n(&one(&mut map, "staging")),
723 dependencies: more(&mut map, "depends"),
724 source_checksum: one(&mut map, "srcversion"),
725 parameters,
726 })
727 }
728
729 /// Decompresses a kernel module
730 ///
731 /// Returns `data` unchanged if not compressed.
732 fn decompress(&self, data: Vec<u8>) -> Result<Vec<u8>> {
733 #[cfg(any(feature = "xz", feature = "gz", feature = "zst"))]
734 let mut v = Vec::new();
735 let ext = self
736 .path
737 .extension()
738 .and_then(|e| e.to_str())
739 .ok_or_else(|| ModuleError::InvalidModule(INVALID_EXTENSION.into()))?;
740 match ext {
741 #[cfg(feature = "xz")]
742 "xz" => {
743 let mut data = XzDecoder::new(data.as_slice());
744 data.read_to_end(&mut v)
745 .map_err(|e| ModuleError::InvalidModule(e.to_string()))?;
746 Ok(v)
747 }
748 #[cfg(feature = "gz")]
749 "gz" => {
750 let mut data = GzDecoder::new(data.as_slice());
751 data.read_to_end(&mut v)
752 .map_err(|e| ModuleError::InvalidModule(e.to_string()))?;
753 Ok(v)
754 }
755 #[cfg(feature = "zst")]
756 "zst" => {
757 let mut data = ZstDecoder::new(data.as_slice())
758 .map_err(|_| ModuleError::InvalidModule(COMPRESSION.into()))?;
759 data.read_to_end(&mut v)
760 .map_err(|e| ModuleError::InvalidModule(e.to_string()))?;
761 Ok(v)
762 }
763 "ko" => Ok(data),
764 _ => Err(ModuleError::InvalidModule(COMPRESSION.into())),
765 }
766 }
767}
768
769#[derive(Debug, Clone)]
770pub struct ModParam {
771 /// Parameter name
772 pub name: String,
773
774 /// Parameter name
775 ///
776 /// See `module_param` in `linux/moduleparam.h` for details
777 // TODO: Replace with enum for standard types
778 pub type_: String,
779
780 pub description: Option<String>,
781}
782
783/// Information on a [`ModuleFile`]
784///
785/// # Notes
786///
787/// This uses the `.modinfo` ELF section, which is semi-documented in
788/// `linux/modules.h` and `MODULE_INFO`.
789#[derive(Debug)]
790pub struct ModInfo {
791 /// Module Aliases. Alternative names for this module.
792 pub alias: Vec<String>,
793
794 /// Soft Dependencies. Not required, but may provide additional features.
795 pub soft_dependencies: Vec<String>,
796
797 /// Module License
798 ///
799 /// See `MODULE_LICENSE` for details on this value.
800 pub license: String,
801
802 /// Module Author and email
803 pub authors: Vec<String>,
804
805 /// What the module does
806 pub description: String,
807
808 /// Module version
809 pub version: String,
810
811 /// Optional firmware file(s) needed by the module
812 pub firmware: Vec<String>,
813
814 /// Version magic string, used by the kernel for compatibility checking.
815 pub version_magic: String,
816
817 /// Module name, self-reported.
818 pub name: String,
819
820 /// Whether the module is from the kernel source tree.
821 pub in_tree: bool,
822
823 /// The retpoline security feature
824 pub retpoline: bool,
825
826 /// If the module is staging
827 pub staging: bool,
828
829 /// Other modules this one depends on
830 pub dependencies: Vec<String>,
831
832 /// Source Checksum.
833 pub source_checksum: String,
834
835 /// Module Parameters
836 pub parameters: Vec<ModParam>,
837}