linux_syscalls/env/kernel/
common.rs

1use core::{cell::UnsafeCell, fmt};
2
3#[allow(non_camel_case_types)]
4/// Structure describing the system and machine.
5#[repr(C)]
6#[derive(Copy, Clone)]
7pub struct utsname {
8    /// Name of the implementation of the operating system.
9    pub sysname: [u8; 65],
10    /// Name of this node on the network.
11    pub nodename: [u8; 65],
12    /// Current release level of this implementation.
13    pub release: [u8; 65],
14    /// Current version level of this release.
15    pub version: [u8; 65],
16    /// Name of the hardware type the system is running on.
17    pub machine: [u8; 65],
18    // Name of the domain of this node on the network.
19    pub domainname: [u8; 65],
20}
21
22#[derive(Debug, Clone, Copy, Hash, PartialEq, Eq, PartialOrd, Ord)]
23/// Structure describing the kernel version.
24pub struct Version {
25    pub major: u32,
26    pub minor: u32,
27    pub revision: u32,
28}
29
30impl fmt::Display for Version {
31    #[inline]
32    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
33        write!(f, "{}.{}.{}", self.major, self.minor, self.revision)
34    }
35}
36
37#[cfg(feature = "bare")]
38/// A macro to create/query kernel version.
39///
40/// # Create a Version
41///
42/// `kversion!(major [, minor [, revision]])`
43///
44/// # Query version
45///
46/// `kversion!( (>|<|==|>=|<=) major [, minor [, revision]])`
47///
48/// # Examples
49///
50/// ```
51/// kversion!(4);          // Create version 4.0.0
52/// kversion!(4, 11);      // Create version 4.11.0
53/// kversion!(4, 11, 6)    // Create version 4.11.6
54/// kversion!(>= 4);       // `true` if kernel version is 4.0.0 or superior
55/// kversion!(< 4, 11);    // `true` if kernel version is earlier than 4.11.0
56/// kversion!(== 5, 15, 6) // `true` if kernel is exactly 5.15.6
57/// ```
58#[macro_export]
59macro_rules! kversion {
60    (>  $($rest:tt)+) => {
61        *$crate::env::kernel_version()  > $crate::kversion!($($rest)+)
62    };
63    (<  $($rest:tt)+) => {
64        *$crate::env::kernel_version()  < $crate::kversion!($($rest)+)
65    };
66    (== $($rest:tt)+) => {
67        *$crate::env::kernel_version() == $crate::kversion!($($rest)+)
68    };
69    (>= $($rest:tt)+) => {
70        *$crate::env::kernel_version() >= $crate::kversion!($($rest)+)
71    };
72    (<= $($rest:tt)+) => {
73        *$crate::env::kernel_version() <= $crate::kversion!($($rest)+)
74    };
75    ($major:expr) => {
76        $crate::kversion!($major, 0)
77    };
78    ($major:expr, $minor:expr) => {
79        $crate::kversion!($major, $minor, 0)
80    };
81    ($major:expr, $minor:expr, $revision:expr) => {
82        $crate::env::kernel::Version {
83            major: $major,
84            minor: $minor,
85            revision: $revision,
86        }
87    };
88}
89
90#[cfg(not(feature = "bare"))]
91/// A macro to create/query kernel version.
92///
93/// # Create a Version
94///
95/// `kversion!(major [, minor [, revision]])`
96///
97/// # Query version
98///
99/// `kversion!( (>|<|==|>=|<=) major [, minor [, revision]])`
100///
101/// # Examples
102///
103/// ```
104/// kversion!(4);          // Create version 4.0.0
105/// kversion!(4, 11);      // Create version 4.11.0
106/// kversion!(4, 11, 6)    // Create version 4.11.6
107/// kversion!(>= 4);       // `true` if kernel version is 4.0.0 or superior
108/// kversion!(< 4, 11);    // `true` if kernel version is earlier than 4.11.0
109/// kversion!(== 5, 15, 6) // `true` if kernel is exactly 5.15.6
110/// ```
111#[macro_export]
112macro_rules! kversion {
113    (>  $($rest:tt)+) => {
114        *$crate::env::unchecked_kernel_version()  > $crate::kversion!($($rest)+)
115    };
116    (<  $($rest:tt)+) => {
117        *$crate::env::unchecked_kernel_version()  < $crate::kversion!($($rest)+)
118    };
119    (== $($rest:tt)+) => {
120        *$crate::env::unchecked_kernel_version() == $crate::kversion!($($rest)+)
121    };
122    (>= $($rest:tt)+) => {
123        *$crate::env::unchecked_kernel_version() >= $crate::kversion!($($rest)+)
124    };
125    (<= $($rest:tt)+) => {
126        *$crate::env::unchecked_kernel_version() <= $crate::kversion!($($rest)+)
127    };
128    ($major:expr) => {
129        $crate::kversion!($major, 0)
130    };
131    ($major:expr, $minor:expr) => {
132        $crate::kversion!($major, $minor, 0)
133    };
134    ($major:expr, $minor:expr, $revision:expr) => {
135        $crate::env::kernel::Version {
136            major: $major,
137            minor: $minor,
138            revision: $revision,
139        }
140    };
141}
142
143pub(crate) static mut UNAME: UnsafeCell<utsname> = UnsafeCell::new(utsname {
144    sysname: [0; 65],
145    nodename: [0; 65],
146    release: [0; 65],
147    version: [0; 65],
148    machine: [0; 65],
149    domainname: [0; 65],
150});
151pub(crate) static mut KERNEL_VERSION: UnsafeCell<Version> = UnsafeCell::new(kversion!(0));
152
153pub(super) unsafe fn init_version() {
154    let release = cstr(&(*UNAME.get()).release);
155
156    let (major, release) = if let Some(res) = version_rest(release) {
157        res
158    } else {
159        panic!("Invalid kernel version")
160    };
161
162    let (minor, release) = if let Some(res) = version_rest(release) {
163        res
164    } else {
165        panic!("Invalid kernel version")
166    };
167
168    let revision = if let Some(res) = version_last(release) {
169        res
170    } else {
171        panic!("Invalid kernel version")
172    };
173
174    let k = &mut *KERNEL_VERSION.get();
175    k.major = major;
176    k.minor = minor;
177    k.revision = revision;
178}
179
180fn atoi_raw(b: &[u8]) -> Option<(u32, usize)> {
181    let mut acc = 0u32;
182    let mut i = 0;
183
184    for c in b.iter().copied() {
185        if c.is_ascii_digit() {
186            acc = acc.checked_mul(10)?.checked_add((c - b'0') as u32)?;
187        } else {
188            return if i == 0 { None } else { Some((acc, i)) };
189        }
190        i += 1;
191    }
192
193    Some((acc, i))
194}
195
196fn version_rest(b: &[u8]) -> Option<(u32, &[u8])> {
197    let (n, size) = atoi_raw(b)?;
198    if Some(b'.') == b.get(size).copied() {
199        Some((n, unsafe { b.get_unchecked((size + 1)..) }))
200    } else {
201        None
202    }
203}
204
205#[inline]
206fn version_last(b: &[u8]) -> Option<u32> {
207    Some(atoi_raw(b)?.0)
208}
209
210unsafe fn cstr(s: &[u8]) -> &[u8] {
211    if let Some(i) = s.iter().copied().position(|c| c == 0) {
212        s.get_unchecked(..i)
213    } else {
214        s
215    }
216}
217
218#[inline]
219pub(crate) unsafe fn version() -> &'static Version {
220    &*KERNEL_VERSION.get()
221}
222
223#[inline]
224pub(crate) unsafe fn uname() -> &'static utsname {
225    &*UNAME.get()
226}