Coverage Report

Created: 2025-02-21 07:11

/rust/registry/src/index.crates.io-6f17d22bba15001f/sysinfo-0.33.1/src/lib.rs
Line
Count
Source (jump to first uncovered line)
1
// Take a look at the license at the top of the repository in the LICENSE file.
2
3
#![cfg_attr(
4
    all(feature = "system", feature = "disk", feature = "component", feature = "system"),
5
    doc = include_str!("../README.md")
6
)]
7
#![cfg_attr(
8
    not(all(
9
        feature = "system",
10
        feature = "disk",
11
        feature = "component",
12
        feature = "system"
13
    )),
14
    doc = "For crate-level documentation, all features need to be enabled."
15
)]
16
#![cfg_attr(feature = "serde", doc = include_str!("../md_doc/serde.md"))]
17
#![allow(unknown_lints)]
18
#![deny(missing_docs)]
19
#![deny(rustdoc::broken_intra_doc_links)]
20
#![allow(clippy::upper_case_acronyms)]
21
#![allow(clippy::non_send_fields_in_send_ty)]
22
#![allow(renamed_and_removed_lints)]
23
#![allow(clippy::assertions_on_constants)]
24
25
#[macro_use]
26
mod macros;
27
28
cfg_if! {
29
    if #[cfg(feature = "unknown-ci")] {
30
        // This is used in CI to check that the build for unknown targets is compiling fine.
31
        mod unknown;
32
        use crate::unknown as sys;
33
34
        #[cfg(test)]
35
        pub(crate) const MIN_USERS: usize = 0;
36
    } else if #[cfg(any(
37
        target_os = "macos", target_os = "ios",
38
        target_os = "linux", target_os = "android",
39
        target_os = "freebsd"))]
40
    {
41
        mod unix;
42
        use crate::unix::sys as sys;
43
44
        #[cfg(feature = "network")]
45
        mod network;
46
        #[cfg(feature = "network")]
47
        use crate::unix::network_helper;
48
49
        #[cfg(test)]
50
        pub(crate) const MIN_USERS: usize = 1;
51
    } else if #[cfg(windows)] {
52
        mod windows;
53
        use crate::windows as sys;
54
55
        #[cfg(feature = "network")]
56
        mod network;
57
        #[cfg(feature = "network")]
58
        use crate::windows::network_helper;
59
60
        #[cfg(test)]
61
        pub(crate) const MIN_USERS: usize = 1;
62
    } else {
63
        mod unknown;
64
        use crate::unknown as sys;
65
66
        #[cfg(test)]
67
        pub(crate) const MIN_USERS: usize = 0;
68
    }
69
}
70
71
#[cfg(feature = "component")]
72
pub use crate::common::component::{Component, Components};
73
#[cfg(feature = "disk")]
74
pub use crate::common::disk::{Disk, DiskKind, DiskRefreshKind, Disks};
75
#[cfg(feature = "network")]
76
pub use crate::common::network::{IpNetwork, MacAddr, NetworkData, Networks};
77
#[cfg(feature = "system")]
78
pub use crate::common::system::{
79
    get_current_pid, CGroupLimits, Cpu, CpuRefreshKind, LoadAvg, MemoryRefreshKind, Pid, Process,
80
    ProcessRefreshKind, ProcessStatus, ProcessesToUpdate, RefreshKind, Signal, System, ThreadKind,
81
    UpdateKind,
82
};
83
#[cfg(feature = "user")]
84
pub use crate::common::user::{Group, Groups, User, Users};
85
#[cfg(any(feature = "user", feature = "system"))]
86
pub use crate::common::{Gid, Uid};
87
#[cfg(feature = "system")]
88
pub use crate::sys::{MINIMUM_CPU_UPDATE_INTERVAL, SUPPORTED_SIGNALS};
89
90
#[cfg(any(feature = "system", feature = "disk"))]
91
pub use crate::common::DiskUsage;
92
93
#[cfg(feature = "user")]
94
pub(crate) use crate::common::user::GroupInner;
95
#[cfg(feature = "user")]
96
pub(crate) use crate::sys::UserInner;
97
#[cfg(feature = "component")]
98
pub(crate) use crate::sys::{ComponentInner, ComponentsInner};
99
#[cfg(feature = "system")]
100
pub(crate) use crate::sys::{CpuInner, ProcessInner, SystemInner};
101
#[cfg(feature = "disk")]
102
pub(crate) use crate::sys::{DiskInner, DisksInner};
103
#[cfg(feature = "network")]
104
pub(crate) use crate::sys::{NetworkDataInner, NetworksInner};
105
106
pub use crate::sys::IS_SUPPORTED_SYSTEM;
107
108
#[cfg(feature = "c-interface")]
109
pub use crate::c_interface::*;
110
111
#[cfg(feature = "c-interface")]
112
mod c_interface;
113
mod common;
114
mod debug;
115
#[cfg(feature = "serde")]
116
mod serde;
117
pub(crate) mod utils;
118
119
// Make formattable by rustfmt.
120
#[cfg(any())]
121
mod network;
122
#[cfg(any())]
123
mod unix;
124
#[cfg(any())]
125
mod unknown;
126
#[cfg(any())]
127
mod windows;
128
129
/// This function is only used on Linux targets, when the `system` feature is enabled. In other
130
/// cases, it does nothing and returns `false`.
131
///
132
/// On Linux, to improve performance, we keep a `/proc` file open for each process we index with
133
/// a maximum number of files open equivalent to half of the system limit.
134
///
135
/// The problem is that some users might need all the available file descriptors so we need to
136
/// allow them to change this limit.
137
///
138
/// Note that if you set a limit bigger than the system limit, the system limit will be set.
139
///
140
/// Returns `true` if the new value has been set.
141
///
142
#[cfg_attr(feature = "system", doc = "```no_run")]
143
#[cfg_attr(not(feature = "system"), doc = "```ignore")]
144
/// use sysinfo::{System, set_open_files_limit};
145
///
146
/// // We call the function before any call to the processes update.
147
/// if !set_open_files_limit(10) {
148
///     // It'll always return false on non-linux targets.
149
///     eprintln!("failed to update the open files limit...");
150
/// }
151
/// let s = System::new_all();
152
/// ```
153
0
pub fn set_open_files_limit(mut _new_limit: isize) -> bool {
154
    cfg_if! {
155
        if #[cfg(all(feature = "system", not(feature = "unknown-ci"), any(target_os = "linux", target_os = "android")))]
156
        {
157
            use crate::sys::system::remaining_files;
158
            use std::sync::atomic::Ordering;
159
160
0
            if _new_limit < 0 {
161
0
                _new_limit = 0;
162
0
            }
163
0
            let max = sys::system::get_max_nb_fds();
164
0
            if _new_limit > max {
165
0
                _new_limit = max;
166
0
            }
167
168
            // If files are already open, to be sure that the number won't be bigger when those
169
            // files are closed, we subtract the current number of opened files to the new
170
            // limit.
171
0
            remaining_files().fetch_update(Ordering::SeqCst, Ordering::SeqCst, |remaining| {
172
0
                let diff = max.saturating_sub(remaining);
173
0
                Some(_new_limit.saturating_sub(diff))
174
0
            }).unwrap();
175
0
176
0
            true
177
0
        } else {
178
0
            false
179
0
        }
180
0
    }
181
0
}
182
183
#[cfg(doctest)]
184
mod doctest {
185
    macro_rules! compile_fail_import {
186
        ($mod_name:ident => $($imports:ident),+ $(,)?) => {
187
            $(#[doc = concat!(r"```compile_fail
188
use sysinfo::", stringify!($imports), r";
189
```
190
")])+
191
            mod $mod_name {}
192
        };
193
    }
194
195
    #[cfg(not(feature = "system"))]
196
    compile_fail_import!(
197
        no_system_feature =>
198
        get_current_pid,
199
        CGroupLimits,
200
        Cpu,
201
        CpuRefreshKind,
202
        DiskUsage,
203
        LoadAvg,
204
        MemoryRefreshKind,
205
        Pid,
206
        Process,
207
        ProcessesToUpdate,
208
        ProcessRefreshKind,
209
        ProcessStatus,
210
        RefreshKind,
211
        Signal,
212
        System,
213
        ThreadKind,
214
        UpdateKind,
215
    );
216
217
    #[cfg(not(feature = "disk"))]
218
    compile_fail_import!(
219
        no_disk_feature =>
220
        Disk,
221
        Disks,
222
        DiskKind,
223
    );
224
225
    #[cfg(not(feature = "component"))]
226
    compile_fail_import!(
227
        no_component_feature =>
228
        Component,
229
        Components,
230
    );
231
232
    #[cfg(not(feature = "network"))]
233
    compile_fail_import!(
234
        no_network_feature =>
235
        IpNetwork,
236
        MacAddr,
237
        NetworkData,
238
        Networks,
239
    );
240
241
    #[cfg(not(feature = "user"))]
242
    compile_fail_import!(
243
        no_user_feature =>
244
        Group,
245
        Groups,
246
        User,
247
        Users,
248
    );
249
}
250
251
#[cfg(test)]
252
mod test {
253
    use crate::*;
254
255
    #[cfg(feature = "unknown-ci")]
256
    #[test]
257
    fn check_unknown_ci_feature() {
258
        assert!(!IS_SUPPORTED_SYSTEM);
259
    }
260
261
    // If this test doesn't compile, it means the current OS doesn't implement them correctly.
262
    #[test]
263
    fn check_macro_types() {
264
        fn check_is_supported(_: bool) {}
265
266
        check_is_supported(IS_SUPPORTED_SYSTEM);
267
    }
268
269
    // If this test doesn't compile, it means the current OS doesn't implement them correctly.
270
    #[cfg(feature = "system")]
271
    #[test]
272
    fn check_macro_types2() {
273
        fn check_supported_signals(_: &'static [Signal]) {}
274
        fn check_minimum_cpu_update_interval(_: std::time::Duration) {}
275
276
        check_supported_signals(SUPPORTED_SIGNALS);
277
        check_minimum_cpu_update_interval(MINIMUM_CPU_UPDATE_INTERVAL);
278
    }
279
280
    #[cfg(feature = "user")]
281
    #[test]
282
    fn check_uid_gid() {
283
        let mut users = Users::new();
284
        assert!(users.list().is_empty());
285
        users.refresh();
286
        let user_list = users.list();
287
        assert!(user_list.len() >= MIN_USERS);
288
289
        if IS_SUPPORTED_SYSTEM {
290
            #[cfg(not(target_os = "windows"))]
291
            {
292
                let user = user_list
293
                    .iter()
294
                    .find(|u| u.name() == "root")
295
                    .expect("no root user");
296
                assert_eq!(**user.id(), 0);
297
                assert_eq!(*user.group_id(), 0);
298
                if let Some(user) = users.iter().find(|u| *u.group_id() > 0) {
299
                    assert!(**user.id() > 0);
300
                    assert!(*user.group_id() > 0);
301
                }
302
                assert!(user_list.iter().filter(|u| **u.id() > 0).count() > 0);
303
            }
304
305
            #[cfg(feature = "system")]
306
            {
307
                // And now check that our `get_user_by_id` method works.
308
                let s =
309
                    System::new_with_specifics(RefreshKind::nothing().with_processes(
310
                        ProcessRefreshKind::nothing().with_user(UpdateKind::Always),
311
                    ));
312
                assert!(s
313
                    .processes()
314
                    .iter()
315
                    .filter_map(|(_, p)| p.user_id())
316
                    .any(|uid| users.get_user_by_id(uid).is_some()));
317
            }
318
        }
319
    }
320
321
    #[cfg(feature = "system")]
322
    #[test]
323
    fn check_all_process_uids_resolvable() {
324
        // On linux, some user IDs don't have an associated user (no idea why though).
325
        // If `getent` doesn't find them, we can assume it's a dark secret from the linux land.
326
        if IS_SUPPORTED_SYSTEM && cfg!(not(target_os = "linux")) {
327
            let s = System::new_with_specifics(
328
                RefreshKind::nothing()
329
                    .with_processes(ProcessRefreshKind::nothing().with_user(UpdateKind::Always)),
330
            );
331
            let users = Users::new_with_refreshed_list();
332
333
            // For every process where we can get a user ID, we should also be able
334
            // to find that user ID in the global user list
335
            for process in s.processes().values() {
336
                if let Some(uid) = process.user_id() {
337
                    assert!(
338
                        users.get_user_by_id(uid).is_some(),
339
                        "No UID {:?} found",
340
                        uid
341
                    );
342
                }
343
            }
344
        }
345
    }
346
347
    #[test]
348
    fn ensure_is_supported_is_set_correctly() {
349
        if MIN_USERS > 0 {
350
            assert!(IS_SUPPORTED_SYSTEM);
351
        } else {
352
            assert!(!IS_SUPPORTED_SYSTEM);
353
        }
354
    }
355
}