eutils_rs/
kernel_version.rs1use anyhow::{bail, Result};
2
3fn get_current_kernel_version() -> Result<String> {
4 let mut info = unsafe { std::mem::MaybeUninit::<libc::utsname>::zeroed().assume_init() };
5 let mut release_version = Vec::with_capacity(info.release.len());
6 let ret = unsafe { libc::uname(&mut info as *mut libc::utsname) };
7 if ret < 0 {
8 bail!("failed to call function: libc::uname, error code: {}", ret)
9 }
10
11 for i in info.release {
12 release_version.push(i as u8);
13 }
14
15 Ok(String::from_utf8(release_version)?)
16}
17
18#[derive(Debug, Clone, Copy, PartialEq, PartialOrd, Eq, Ord)]
20pub struct KernelVersion {
21 major_revision: i32,
22 minor_revision: i32,
23 patch_number: i32,
24}
25
26impl TryFrom<&str> for KernelVersion {
27 type Error = anyhow::Error;
28 fn try_from(version_string: &str) -> Result<Self> {
29 let mut start_pos = 0;
30 let mut major_revision = 0;
31 let mut minor_revision = 0;
32 let mut patch_number = 0;
33
34 if let Some(pos) = version_string[start_pos..version_string.len()].find('.') {
35 let part = &version_string[start_pos..pos];
36 major_revision = part.parse()?;
37
38 start_pos = pos + 1;
39 } else {
40 bail!("failed to parse {}", version_string)
41 }
42
43 if let Some(pos) = version_string[start_pos..version_string.len()].find('.') {
44 let part = &version_string[start_pos..start_pos + pos];
45 minor_revision = part.parse()?;
46
47 start_pos = start_pos + pos + 1;
48 } else {
49 bail!("failed to parse {}", version_string)
50 }
51
52 for i in start_pos..version_string.len() + 1 {
53 let mut char = '-' as u8;
54
55 if i < version_string.len() {
56 char = version_string.as_bytes()[i];
57 }
58 if char < '0' as u8 || char > '9' as u8 {
59 let part = &version_string[start_pos..i];
60 patch_number = part.parse()?;
61 break;
62 }
63 }
64
65 Ok(KernelVersion {
66 major_revision,
67 minor_revision,
68 patch_number,
69 })
70 }
71}
72
73impl KernelVersion {
74 pub fn current() -> Result<KernelVersion> {
75 let str = get_current_kernel_version()?;
76 KernelVersion::try_from(str.as_str())
77 }
78}
79
80#[cfg(test)]
81mod tests {
82 use super::*;
83 #[test]
84 fn test_get_current_kernel_version() {
85 assert_eq!(get_current_kernel_version().is_ok(), true);
86 }
87
88 #[test]
89 fn test_kernel_version_try_from1() {
90 let kv = KernelVersion::try_from("3.10.10").unwrap();
91 assert_eq!(kv.major_revision, 3);
92 assert_eq!(kv.minor_revision, 10);
93 assert_eq!(kv.patch_number, 10);
94 }
95
96 #[test]
97 fn test_kernel_version_try_from2() {
98 let kv = KernelVersion::try_from("3.10.10-xx").unwrap();
99 assert_eq!(kv.major_revision, 3);
100 assert_eq!(kv.minor_revision, 10);
101 assert_eq!(kv.patch_number, 10);
102 }
103
104 #[test]
105 fn test_kernel_version_current() {
106 assert_eq!(
107 KernelVersion::current().is_ok(),
108 true,
109 "{:?}",
110 KernelVersion::current()
111 );
112 }
113
114 #[test]
115 fn test_kernel_version_ord_eq() {
116 let v1 = KernelVersion::try_from("3.10.10").unwrap();
117 let v2 = KernelVersion::try_from("3.10.10").unwrap();
118 assert_eq!(v1, v2);
119 }
120
121 #[test]
122 fn test_kernel_version_ord_lt() {
123 let v1 = KernelVersion::try_from("2.10.10").unwrap();
124 let v2 = KernelVersion::try_from("3.10.10").unwrap();
125 assert_eq!(v1 < v2, true);
126 }
127}