1use std::io::{BufRead, Read};
2use std::os::raw::c_int;
3use std::{fs, io};
4
5use rustix::process::*;
6#[cfg(feature = "thread")]
7use rustix::thread::Capability;
8
9#[test]
10fn test_parent_process_death_signal() {
11    dbg!(parent_process_death_signal().unwrap());
12}
13
14#[test]
15fn test_dumpable_behavior() {
16    dbg!(dumpable_behavior().unwrap());
17}
18
19#[test]
20fn test_timing_method() {
21    dbg!(timing_method().unwrap());
22}
23
24#[test]
25fn test_machine_check_memory_corruption_kill_policy() {
26    dbg!(machine_check_memory_corruption_kill_policy().unwrap());
27}
28
29#[cfg(target_arch = "x86")]
30#[test]
31fn test_time_stamp_counter_readability() {
32    dbg!(time_stamp_counter_readability().unwrap());
33}
34
35#[cfg(target_arch = "powerpc")]
36#[test]
37fn test_unaligned_access_control() {
38    dbg!(unaligned_access_control().unwrap());
39}
40
41#[cfg(target_arch = "powerpc")]
42#[test]
43fn test_floating_point_exception_mode() {
44    dbg!(floating_point_exception_mode().unwrap());
45}
46
47#[cfg(target_arch = "powerpc")]
48#[test]
49fn test_endian_mode() {
50    dbg!(endian_mode().unwrap());
51}
52
53#[cfg(target_arch = "mips")]
54#[test]
55fn test_floating_point_mode() {
56    dbg!(floating_point_mode().unwrap());
57}
58
59#[cfg(target_arch = "aarch64")]
60#[test]
61#[ignore = "Only on ARMv8.3 and later"]
62fn test_enabled_pointer_authentication_keys() {
63    dbg!(enabled_pointer_authentication_keys().unwrap());
64}
65
66#[test]
67#[ignore = "?"]
68fn test_child_subreaper() {
69    dbg!(child_subreaper().unwrap());
70}
71
72#[test]
73#[ignore = "?"]
74fn test_speculative_feature_state() {
75    dbg!(speculative_feature_state(SpeculationFeature::SpeculativeStoreBypass).unwrap());
76    dbg!(speculative_feature_state(SpeculationFeature::IndirectBranchSpeculation).unwrap());
77    dbg!(
78        speculative_feature_state(SpeculationFeature::FlushL1DCacheOnContextSwitchOutOfTask)
79            .unwrap()
80    );
81}
82
83#[cfg(feature = "thread")]
84#[test]
85fn test_is_io_flusher() {
86    if !thread_has_capability(Capability::SystemResource).unwrap() {
87        eprintln!("test_is_io_flusher: Test skipped due to missing capability: CAP_SYS_RESOURCE.");
88        return;
89    }
90
91    dbg!(is_io_flusher().unwrap());
92}
93
94#[cfg(feature = "thread")]
95#[test]
96fn test_virtual_memory_map_config_struct_size() {
97    if !thread_has_capability(Capability::SystemResource).unwrap() {
98        eprintln!(
99            "test_virtual_memory_map_config_struct_size: Test skipped due to missing capability: CAP_SYS_RESOURCE."
100        );
101        return;
102    }
103
104    if !linux_kernel_config_item_is_enabled("CONFIG_CHECKPOINT_RESTORE").unwrap_or(false) {
105        eprintln!("test_virtual_memory_map_config_struct_size: Test skipped due to missing kernel feature: CONFIG_CHECKPOINT_RESTORE.");
106        return;
107    }
108
109    dbg!(virtual_memory_map_config_struct_size().unwrap());
110}
111
112#[test]
113#[ignore = "Only on ia64"]
114fn test_floating_point_emulation_control() {
115    dbg!(floating_point_emulation_control().unwrap());
116}
117
118/*
119 * Helper functions.
120 */
121
122#[cfg(feature = "thread")]
123pub(crate) fn thread_has_capability(capability: Capability) -> io::Result<bool> {
124    const _LINUX_CAPABILITY_VERSION_3: u32 = 0x20080522;
125
126    #[repr(C)]
127    struct cap_user_header_t {
128        version: u32,
129        pid: c_int,
130    }
131
132    #[repr(C)]
133    struct cap_user_data_t {
134        effective: u32,
135        permitted: u32,
136        inheritable: u32,
137    }
138
139    let header = cap_user_header_t {
140        version: _LINUX_CAPABILITY_VERSION_3,
141        pid: 0,
142    };
143
144    let mut data: [cap_user_data_t; 2] = [
145        cap_user_data_t {
146            effective: 0,
147            permitted: 0,
148            inheritable: 0,
149        },
150        cap_user_data_t {
151            effective: 0,
152            permitted: 0,
153            inheritable: 0,
154        },
155    ];
156
157    let r = unsafe {
158        libc::syscall(
159            libc::SYS_capget,
160            &header as *const cap_user_header_t,
161            data.as_mut_ptr() as *mut cap_user_data_t,
162        )
163    };
164
165    if r == -1 {
166        return Err(io::Error::last_os_error());
167    }
168
169    let cap_index = capability as u32;
170    let (data_index, cap_index) = if cap_index < 32 {
171        (0, cap_index)
172    } else {
173        (1, cap_index - 32)
174    };
175    let flag = 1_u32 << cap_index;
176    Ok((flag & data[data_index].effective) != 0)
177}
178
179fn load_linux_kernel_config() -> io::Result<Vec<u8>> {
180    if let Ok(compressed_bytes) = fs::read("/proc/config.gz") {
181        let mut decoder = flate2::bufread::GzDecoder::new(compressed_bytes.as_slice());
182        let mut bytes = Vec::default();
183        decoder.read_to_end(&mut bytes)?;
184        return Ok(bytes);
185    }
186
187    let info = rustix::process::uname();
188    let release = info
189        .release()
190        .to_str()
191        .map_err(|_r| io::Error::from(io::ErrorKind::InvalidData))?;
192
193    fs::read(format!("/boot/config-{}", release))
194}
195
196fn is_linux_kernel_config_item_enabled(config: &[u8], name: &str) -> io::Result<bool> {
197    for line in io::Cursor::new(config).lines() {
198        let line = line?;
199        let line = line.trim();
200        if line.is_empty() || line.starts_with('#') {
201            continue;
202        }
203
204        let mut iter = line.splitn(2, '=');
205        if let Some(current_name) = iter.next().map(str::trim) {
206            if current_name == name {
207                if let Some(mut value) = iter.next().map(str::trim) {
208                    if value.starts_with('"') && value.ends_with('"') {
209                        // Just remove the quotes, but don't bother unescaping the inner string
210                        // because we are only trying to find out if the option is an true boolean.
211                        value = &value[1..(value.len() - 2)];
212                    }
213
214                    return Ok(value == "y" || value == "m");
215                }
216            }
217        }
218    }
219    Ok(false)
220}
221
222pub(crate) fn linux_kernel_config_item_is_enabled(name: &str) -> io::Result<bool> {
223    let config = load_linux_kernel_config()?;
224    is_linux_kernel_config_item_enabled(&config, name)
225}
226