diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:24 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:59:24 +0000 |
commit | 023939b627b7dc93b01471f7d41fb8553ddb4ffa (patch) | |
tree | 60fc59477c605c72b0a1051409062ddecc43f877 /vendor/sysinfo/src/linux | |
parent | Adding debian version 1.72.1+dfsg1-1. (diff) | |
download | rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.tar.xz rustc-023939b627b7dc93b01471f7d41fb8553ddb4ffa.zip |
Merging upstream version 1.73.0+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'vendor/sysinfo/src/linux')
-rw-r--r-- | vendor/sysinfo/src/linux/component.rs | 12 | ||||
-rw-r--r-- | vendor/sysinfo/src/linux/cpu.rs | 474 | ||||
-rw-r--r-- | vendor/sysinfo/src/linux/disk.rs | 24 | ||||
-rw-r--r-- | vendor/sysinfo/src/linux/network.rs | 14 | ||||
-rw-r--r-- | vendor/sysinfo/src/linux/process.rs | 173 | ||||
-rw-r--r-- | vendor/sysinfo/src/linux/system.rs | 58 | ||||
-rw-r--r-- | vendor/sysinfo/src/linux/utils.rs | 4 |
7 files changed, 508 insertions, 251 deletions
diff --git a/vendor/sysinfo/src/linux/component.rs b/vendor/sysinfo/src/linux/component.rs index 7815103b4..3286829f4 100644 --- a/vendor/sysinfo/src/linux/component.rs +++ b/vendor/sysinfo/src/linux/component.rs @@ -31,7 +31,7 @@ pub struct Component { /// - Read in: `temp[1-*]_input`. /// - Unit: read as millidegree Celsius converted to Celsius. temperature: Option<f32>, - /// Maximum value computed by sysinfo + /// Maximum value computed by `sysinfo`. max: Option<f32>, /// Max threshold provided by the chip/kernel /// - Read in:`temp[1-*]_max` @@ -60,7 +60,7 @@ pub struct Component { sensor_type: Option<TermalSensorType>, /// Component Label /// - /// For formating detail see `Component::label` function docstring. + /// For formatting detail see `Component::label` function docstring. /// /// ## Linux implementation details /// @@ -89,7 +89,7 @@ pub struct Component { /// File to read current temperature shall be `temp[1-*]_input` /// It may be absent but we don't continue if absent. input_file: Option<PathBuf>, - /// `temp[1-*]_highest file` to read if disponnible highest value. + /// `temp[1-*]_highest file` to read if available highest value. highest_file: Option<PathBuf>, } @@ -132,14 +132,14 @@ fn get_temperature_from_file(file: &Path) -> Option<f32> { convert_temp_celsius(temp) } -/// Takes a raw temperature in mili-celsius and convert it to celsius +/// Takes a raw temperature in mili-celsius and convert it to celsius. #[inline] fn convert_temp_celsius(temp: Option<i32>) -> Option<f32> { temp.map(|n| (n as f32) / 1000f32) } /// Information about thermal sensor. It may be unavailable as it's -/// kernel module and chip dependant. +/// kernel module and chip dependent. enum TermalSensorType { /// 1: CPU embedded diode CPUEmbeddedDiode, @@ -228,7 +228,7 @@ impl Component { /// - Optional: max threshold value defined in `tempN_max` /// - Optional: critical threshold value defined in `tempN_crit` /// - /// Where `N` is a u32 associated to a sensor like `temp1_max`, `temp1_input`. + /// Where `N` is a `u32` associated to a sensor like `temp1_max`, `temp1_input`. /// /// ## Doc to Linux kernel API. /// diff --git a/vendor/sysinfo/src/linux/cpu.rs b/vendor/sysinfo/src/linux/cpu.rs index 103f5362a..d99b325c1 100644 --- a/vendor/sysinfo/src/linux/cpu.rs +++ b/vendor/sysinfo/src/linux/cpu.rs @@ -5,9 +5,10 @@ use std::collections::HashSet; use std::fs::File; use std::io::{BufRead, BufReader, Read}; +use std::time::Instant; use crate::sys::utils::to_u64; -use crate::{CpuExt, CpuRefreshKind}; +use crate::{CpuExt, CpuRefreshKind, SystemExt}; macro_rules! to_str { ($e:expr) => { @@ -24,6 +25,8 @@ pub(crate) struct CpusWrapper { /// For example when running `refresh_all` or `refresh_specifics`. need_cpus_update: bool, got_cpu_frequency: bool, + /// This field is needed to prevent updating when not enough time passed since last update. + last_update: Option<Instant>, } impl CpusWrapper { @@ -48,6 +51,7 @@ impl CpusWrapper { cpus: Vec::with_capacity(4), need_cpus_update: true, got_cpu_frequency: false, + last_update: None, } } @@ -62,90 +66,101 @@ impl CpusWrapper { } pub(crate) fn refresh(&mut self, only_update_global_cpu: bool, refresh_kind: CpuRefreshKind) { - let f = match File::open("/proc/stat") { - Ok(f) => f, - Err(_e) => { - sysinfo_debug!("failed to retrieve CPU information: {:?}", _e); - return; - } - }; - let buf = BufReader::new(f); + let need_cpu_usage_update = self + .last_update + .map(|last_update| last_update.elapsed() > crate::System::MINIMUM_CPU_UPDATE_INTERVAL) + .unwrap_or(true); - self.need_cpus_update = false; - let mut i: usize = 0; let first = self.cpus.is_empty(); - let mut it = buf.split(b'\n'); let (vendor_id, brand) = if first { get_vendor_id_and_brand() } else { (String::new(), String::new()) }; - if first || refresh_kind.cpu_usage() { - if let Some(Ok(line)) = it.next() { - if &line[..4] != b"cpu " { + // If the last CPU usage update is too close (less than `MINIMUM_CPU_UPDATE_INTERVAL`), + // we don't want to update CPUs times. + if need_cpu_usage_update { + self.last_update = Some(Instant::now()); + let f = match File::open("/proc/stat") { + Ok(f) => f, + Err(_e) => { + sysinfo_debug!("failed to retrieve CPU information: {:?}", _e); return; } - let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); - if first { - self.global_cpu.name = to_str!(parts.next().unwrap_or(&[])).to_owned(); - } else { - parts.next(); - } - self.global_cpu.set( - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - ); - } - if first || !only_update_global_cpu { - while let Some(Ok(line)) = it.next() { - if &line[..3] != b"cpu" { - break; - } + }; + let buf = BufReader::new(f); + + self.need_cpus_update = false; + let mut i: usize = 0; + let mut it = buf.split(b'\n'); + if first || refresh_kind.cpu_usage() { + if let Some(Ok(line)) = it.next() { + if &line[..4] != b"cpu " { + return; + } let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); if first { - self.cpus.push(Cpu::new_with_values( - to_str!(parts.next().unwrap_or(&[])), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - 0, - vendor_id.clone(), - brand.clone(), - )); + self.global_cpu.name = to_str!(parts.next().unwrap_or(&[])).to_owned(); } else { - parts.next(); // we don't want the name again - self.cpus[i].set( - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - parts.next().map(to_u64).unwrap_or(0), - ); + parts.next(); + } + self.global_cpu.set( + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + ); + } + if first || !only_update_global_cpu { + while let Some(Ok(line)) = it.next() { + if &line[..3] != b"cpu" { + break; + } + + let mut parts = line.split(|x| *x == b' ').filter(|s| !s.is_empty()); + if first { + self.cpus.push(Cpu::new_with_values( + to_str!(parts.next().unwrap_or(&[])), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + 0, + vendor_id.clone(), + brand.clone(), + )); + } else { + parts.next(); // we don't want the name again + self.cpus[i].set( + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + parts.next().map(to_u64).unwrap_or(0), + ); + } + + i += 1; } - - i += 1; } } } @@ -219,8 +234,8 @@ pub(crate) struct CpuValues { irq: u64, softirq: u64, steal: u64, - _guest: u64, - _guest_nice: u64, + guest: u64, + guest_nice: u64, } impl CpuValues { @@ -235,44 +250,11 @@ impl CpuValues { irq: 0, softirq: 0, steal: 0, - _guest: 0, - _guest_nice: 0, - } - } - - /// Creates a new instance of `CpuValues` with everything set to the corresponding argument. - pub fn new_with_values( - user: u64, - nice: u64, - system: u64, - idle: u64, - iowait: u64, - irq: u64, - softirq: u64, - steal: u64, - guest: u64, - guest_nice: u64, - ) -> CpuValues { - CpuValues { - user, - nice, - system, - idle, - iowait, - irq, - softirq, - steal, - _guest: guest, - _guest_nice: guest_nice, + guest: 0, + guest_nice: 0, } } - /*pub fn is_zero(&self) -> bool { - self.user == 0 && self.nice == 0 && self.system == 0 && self.idle == 0 && - self.iowait == 0 && self.irq == 0 && self.softirq == 0 && self.steal == 0 && - self.guest == 0 && self.guest_nice == 0 - }*/ - /// Sets the given argument to the corresponding fields. pub fn set( &mut self, @@ -287,16 +269,18 @@ impl CpuValues { guest: u64, guest_nice: u64, ) { - self.user = user; - self.nice = nice; + // `guest` is already accounted in `user`. + self.user = user.saturating_sub(guest); + // `guest_nice` is already accounted in `nice`. + self.nice = nice.saturating_sub(guest_nice); self.system = system; self.idle = idle; self.iowait = iowait; self.irq = irq; self.softirq = softirq; self.steal = steal; - self._guest = guest; - self._guest_nice = guest_nice; + self.guest = guest; + self.guest_nice = guest_nice; } /// Returns work time. @@ -306,16 +290,18 @@ impl CpuValues { .saturating_add(self.system) .saturating_add(self.irq) .saturating_add(self.softirq) - .saturating_add(self.steal) } /// Returns total time. pub fn total_time(&self) -> u64 { - // `guest` is already included in `user` - // `guest_nice` is already included in `nice` self.work_time() .saturating_add(self.idle) .saturating_add(self.iowait) + // `steal`, `guest` and `guest_nice` are only used if we want to account the "guest" + // into the computation. + .saturating_add(self.guest) + .saturating_add(self.guest_nice) + .saturating_add(self.steal) } } @@ -349,12 +335,14 @@ impl Cpu { vendor_id: String, brand: String, ) -> Cpu { + let mut new_values = CpuValues::new(); + new_values.set( + user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, + ); Cpu { name: name.to_owned(), old_values: CpuValues::new(), - new_values: CpuValues::new_with_values( - user, nice, system, idle, iowait, irq, softirq, steal, guest, guest_nice, - ), + new_values, cpu_usage: 0f32, total_time: 0, old_total_time: 0, @@ -378,11 +366,11 @@ impl Cpu { guest_nice: u64, ) { macro_rules! min { - ($a:expr, $b:expr) => { + ($a:expr, $b:expr, $def:expr) => { if $a > $b { ($a - $b) as f32 } else { - 1. + $def } }; } @@ -392,8 +380,8 @@ impl Cpu { ); self.total_time = self.new_values.total_time(); self.old_total_time = self.old_values.total_time(); - self.cpu_usage = min!(self.new_values.work_time(), self.old_values.work_time()) - / min!(self.total_time, self.old_total_time) + self.cpu_usage = min!(self.new_values.work_time(), self.old_values.work_time(), 0.) + / min!(self.total_time, self.old_total_time, 1.) * 100.; if self.cpu_usage > 100. { self.cpu_usage = 100.; // to prevent the percentage to go above 100% @@ -427,8 +415,7 @@ impl CpuExt for Cpu { pub(crate) fn get_cpu_frequency(cpu_core_index: usize) -> u64 { let mut s = String::new(); if File::open(format!( - "/sys/devices/system/cpu/cpu{}/cpufreq/scaling_cur_freq", - cpu_core_index + "/sys/devices/system/cpu/cpu{cpu_core_index}/cpufreq/scaling_cur_freq", )) .and_then(|mut f| f.read_to_string(&mut s)) .is_ok() @@ -517,6 +504,216 @@ pub(crate) fn get_physical_core_count() -> Option<usize> { Some(core_ids_and_physical_ids.len()) } +/// Obtain the implementer of this CPU core. +/// +/// This has been obtained from util-linux's lscpu implementation, see +/// https://github.com/util-linux/util-linux/blob/7076703b529d255600631306419cca1b48ab850a/sys-utils/lscpu-arm.c#L240 +/// +/// This list will have to be updated every time a new vendor appears, please keep it synchronized +/// with util-linux and update the link above with the commit you have used. +fn get_arm_implementer(implementer: u32) -> Option<&'static str> { + Some(match implementer { + 0x41 => "ARM", + 0x42 => "Broadcom", + 0x43 => "Cavium", + 0x44 => "DEC", + 0x46 => "FUJITSU", + 0x48 => "HiSilicon", + 0x49 => "Infineon", + 0x4d => "Motorola/Freescale", + 0x4e => "NVIDIA", + 0x50 => "APM", + 0x51 => "Qualcomm", + 0x53 => "Samsung", + 0x56 => "Marvell", + 0x61 => "Apple", + 0x66 => "Faraday", + 0x69 => "Intel", + 0x70 => "Phytium", + 0xc0 => "Ampere", + _ => return None, + }) +} + +/// Obtain the part of this CPU core. +/// +/// This has been obtained from util-linux's lscpu implementation, see +/// https://github.com/util-linux/util-linux/blob/7076703b529d255600631306419cca1b48ab850a/sys-utils/lscpu-arm.c#L34 +/// +/// This list will have to be updated every time a new core appears, please keep it synchronized +/// with util-linux and update the link above with the commit you have used. +fn get_arm_part(implementer: u32, part: u32) -> Option<&'static str> { + Some(match (implementer, part) { + // ARM + (0x41, 0x810) => "ARM810", + (0x41, 0x920) => "ARM920", + (0x41, 0x922) => "ARM922", + (0x41, 0x926) => "ARM926", + (0x41, 0x940) => "ARM940", + (0x41, 0x946) => "ARM946", + (0x41, 0x966) => "ARM966", + (0x41, 0xa20) => "ARM1020", + (0x41, 0xa22) => "ARM1022", + (0x41, 0xa26) => "ARM1026", + (0x41, 0xb02) => "ARM11 MPCore", + (0x41, 0xb36) => "ARM1136", + (0x41, 0xb56) => "ARM1156", + (0x41, 0xb76) => "ARM1176", + (0x41, 0xc05) => "Cortex-A5", + (0x41, 0xc07) => "Cortex-A7", + (0x41, 0xc08) => "Cortex-A8", + (0x41, 0xc09) => "Cortex-A9", + (0x41, 0xc0d) => "Cortex-A17", // Originally A12 + (0x41, 0xc0f) => "Cortex-A15", + (0x41, 0xc0e) => "Cortex-A17", + (0x41, 0xc14) => "Cortex-R4", + (0x41, 0xc15) => "Cortex-R5", + (0x41, 0xc17) => "Cortex-R7", + (0x41, 0xc18) => "Cortex-R8", + (0x41, 0xc20) => "Cortex-M0", + (0x41, 0xc21) => "Cortex-M1", + (0x41, 0xc23) => "Cortex-M3", + (0x41, 0xc24) => "Cortex-M4", + (0x41, 0xc27) => "Cortex-M7", + (0x41, 0xc60) => "Cortex-M0+", + (0x41, 0xd01) => "Cortex-A32", + (0x41, 0xd02) => "Cortex-A34", + (0x41, 0xd03) => "Cortex-A53", + (0x41, 0xd04) => "Cortex-A35", + (0x41, 0xd05) => "Cortex-A55", + (0x41, 0xd06) => "Cortex-A65", + (0x41, 0xd07) => "Cortex-A57", + (0x41, 0xd08) => "Cortex-A72", + (0x41, 0xd09) => "Cortex-A73", + (0x41, 0xd0a) => "Cortex-A75", + (0x41, 0xd0b) => "Cortex-A76", + (0x41, 0xd0c) => "Neoverse-N1", + (0x41, 0xd0d) => "Cortex-A77", + (0x41, 0xd0e) => "Cortex-A76AE", + (0x41, 0xd13) => "Cortex-R52", + (0x41, 0xd20) => "Cortex-M23", + (0x41, 0xd21) => "Cortex-M33", + (0x41, 0xd40) => "Neoverse-V1", + (0x41, 0xd41) => "Cortex-A78", + (0x41, 0xd42) => "Cortex-A78AE", + (0x41, 0xd43) => "Cortex-A65AE", + (0x41, 0xd44) => "Cortex-X1", + (0x41, 0xd46) => "Cortex-A510", + (0x41, 0xd47) => "Cortex-A710", + (0x41, 0xd48) => "Cortex-X2", + (0x41, 0xd49) => "Neoverse-N2", + (0x41, 0xd4a) => "Neoverse-E1", + (0x41, 0xd4b) => "Cortex-A78C", + (0x41, 0xd4c) => "Cortex-X1C", + (0x41, 0xd4d) => "Cortex-A715", + (0x41, 0xd4e) => "Cortex-X3", + + // Broadcom + (0x42, 0x00f) => "Brahma-B15", + (0x42, 0x100) => "Brahma-B53", + (0x42, 0x516) => "ThunderX2", + + // Cavium + (0x43, 0x0a0) => "ThunderX", + (0x43, 0x0a1) => "ThunderX-88XX", + (0x43, 0x0a2) => "ThunderX-81XX", + (0x43, 0x0a3) => "ThunderX-83XX", + (0x43, 0x0af) => "ThunderX2-99xx", + + // DEC + (0x44, 0xa10) => "SA110", + (0x44, 0xa11) => "SA1100", + + // Fujitsu + (0x46, 0x001) => "A64FX", + + // HiSilicon + (0x48, 0xd01) => "Kunpeng-920", // aka tsv110 + + // NVIDIA + (0x4e, 0x000) => "Denver", + (0x4e, 0x003) => "Denver 2", + (0x4e, 0x004) => "Carmel", + + // APM + (0x50, 0x000) => "X-Gene", + + // Qualcomm + (0x51, 0x00f) => "Scorpion", + (0x51, 0x02d) => "Scorpion", + (0x51, 0x04d) => "Krait", + (0x51, 0x06f) => "Krait", + (0x51, 0x201) => "Kryo", + (0x51, 0x205) => "Kryo", + (0x51, 0x211) => "Kryo", + (0x51, 0x800) => "Falkor-V1/Kryo", + (0x51, 0x801) => "Kryo-V2", + (0x51, 0x802) => "Kryo-3XX-Gold", + (0x51, 0x803) => "Kryo-3XX-Silver", + (0x51, 0x804) => "Kryo-4XX-Gold", + (0x51, 0x805) => "Kryo-4XX-Silver", + (0x51, 0xc00) => "Falkor", + (0x51, 0xc01) => "Saphira", + + // Samsung + (0x53, 0x001) => "exynos-m1", + + // Marvell + (0x56, 0x131) => "Feroceon-88FR131", + (0x56, 0x581) => "PJ4/PJ4b", + (0x56, 0x584) => "PJ4B-MP", + + // Apple + (0x61, 0x020) => "Icestorm-A14", + (0x61, 0x021) => "Firestorm-A14", + (0x61, 0x022) => "Icestorm-M1", + (0x61, 0x023) => "Firestorm-M1", + (0x61, 0x024) => "Icestorm-M1-Pro", + (0x61, 0x025) => "Firestorm-M1-Pro", + (0x61, 0x028) => "Icestorm-M1-Max", + (0x61, 0x029) => "Firestorm-M1-Max", + (0x61, 0x030) => "Blizzard-A15", + (0x61, 0x031) => "Avalanche-A15", + (0x61, 0x032) => "Blizzard-M2", + (0x61, 0x033) => "Avalanche-M2", + + // Faraday + (0x66, 0x526) => "FA526", + (0x66, 0x626) => "FA626", + + // Intel + (0x69, 0x200) => "i80200", + (0x69, 0x210) => "PXA250A", + (0x69, 0x212) => "PXA210A", + (0x69, 0x242) => "i80321-400", + (0x69, 0x243) => "i80321-600", + (0x69, 0x290) => "PXA250B/PXA26x", + (0x69, 0x292) => "PXA210B", + (0x69, 0x2c2) => "i80321-400-B0", + (0x69, 0x2c3) => "i80321-600-B0", + (0x69, 0x2d0) => "PXA250C/PXA255/PXA26x", + (0x69, 0x2d2) => "PXA210C", + (0x69, 0x411) => "PXA27x", + (0x69, 0x41c) => "IPX425-533", + (0x69, 0x41d) => "IPX425-400", + (0x69, 0x41f) => "IPX425-266", + (0x69, 0x682) => "PXA32x", + (0x69, 0x683) => "PXA930/PXA935", + (0x69, 0x688) => "PXA30x", + (0x69, 0x689) => "PXA31x", + (0x69, 0xb11) => "SA1110", + (0x69, 0xc12) => "IPX1200", + + // Phytium + (0x70, 0x660) => "FTC660", + (0x70, 0x661) => "FTC661", + (0x70, 0x662) => "FTC662", + (0x70, 0x663) => "FTC663", + + _ => return None, + }) +} + /// Returns the brand/vendor string for the first CPU (which should be the same for all CPUs). pub(crate) fn get_vendor_id_and_brand() -> (String, String) { let mut s = String::new(); @@ -534,20 +731,49 @@ pub(crate) fn get_vendor_id_and_brand() -> (String, String) { .unwrap_or_default() } + fn get_hex_value(s: &str) -> u32 { + s.split(':') + .last() + .map(|x| x.trim()) + .filter(|x| x.starts_with("0x")) + .map(|x| u32::from_str_radix(&x[2..], 16).unwrap()) + .unwrap_or_default() + } + let mut vendor_id = None; let mut brand = None; + let mut implementer = None; + let mut part = None; for it in s.split('\n') { if it.starts_with("vendor_id\t") { vendor_id = Some(get_value(it)); } else if it.starts_with("model name\t") { brand = Some(get_value(it)); + } else if it.starts_with("CPU implementer\t") { + implementer = Some(get_hex_value(it)); + } else if it.starts_with("CPU part\t") { + part = Some(get_hex_value(it)); } else { continue; } - if brand.is_some() && vendor_id.is_some() { + if (brand.is_some() && vendor_id.is_some()) || (implementer.is_some() && part.is_some()) { break; } } + if let (Some(implementer), Some(part)) = (implementer, part) { + vendor_id = get_arm_implementer(implementer).map(String::from); + // It's possible to "model name" even with an ARM CPU, so just in case we can't retrieve + // the brand from "CPU part", we will then use the value from "model name". + // + // Example from raspberry pi 3B+: + // + // ``` + // model name : ARMv7 Processor rev 4 (v7l) + // CPU implementer : 0x41 + // CPU part : 0xd03 + // ``` + brand = get_arm_part(implementer, part).map(String::from).or(brand); + } (vendor_id.unwrap_or_default(), brand.unwrap_or_default()) } diff --git a/vendor/sysinfo/src/linux/disk.rs b/vendor/sysinfo/src/linux/disk.rs index 6d7fc083c..23871d57f 100644 --- a/vendor/sysinfo/src/linux/disk.rs +++ b/vendor/sysinfo/src/linux/disk.rs @@ -1,7 +1,7 @@ // Take a look at the license at the top of the repository in the LICENSE file. use crate::sys::utils::{get_all_data, to_cpath}; -use crate::{DiskExt, DiskType}; +use crate::{DiskExt, DiskKind}; use libc::statvfs; use std::ffi::{OsStr, OsString}; @@ -19,7 +19,7 @@ macro_rules! cast { #[doc = include_str!("../../md_doc/disk.md")] #[derive(PartialEq, Eq)] pub struct Disk { - type_: DiskType, + type_: DiskKind, device_name: OsString, file_system: Vec<u8>, mount_point: PathBuf, @@ -29,7 +29,7 @@ pub struct Disk { } impl DiskExt for Disk { - fn type_(&self) -> DiskType { + fn kind(&self) -> DiskKind { self.type_ } @@ -61,7 +61,7 @@ impl DiskExt for Disk { unsafe { let mut stat: statvfs = mem::zeroed(); let mount_point_cpath = to_cpath(&self.mount_point); - if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 { + if retry_eintr!(statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat)) == 0 { let tmp = cast!(stat.f_bsize).saturating_mul(cast!(stat.f_bavail)); self.available_space = cast!(tmp); true @@ -84,7 +84,7 @@ fn new_disk( let mut available = 0; unsafe { let mut stat: statvfs = mem::zeroed(); - if statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat) == 0 { + if retry_eintr!(statvfs(mount_point_cpath.as_ptr() as *const _, &mut stat)) == 0 { let bsize = cast!(stat.f_bsize); let blocks = cast!(stat.f_blocks); let bavail = cast!(stat.f_bavail); @@ -111,7 +111,7 @@ fn new_disk( } #[allow(clippy::manual_range_contains)] -fn find_type_for_device_name(device_name: &OsStr) -> DiskType { +fn find_type_for_device_name(device_name: &OsStr) -> DiskKind { // The format of devices are as follows: // - device_name is symbolic link in the case of /dev/mapper/ // and /dev/root, and the target is corresponding device under @@ -171,13 +171,13 @@ fn find_type_for_device_name(device_name: &OsStr) -> DiskType { .ok() { // The disk is marked as rotational so it's a HDD. - Some(1) => DiskType::HDD, + Some(1) => DiskKind::HDD, // The disk is marked as non-rotational so it's very likely a SSD. - Some(0) => DiskType::SSD, + Some(0) => DiskKind::SSD, // Normally it shouldn't happen but welcome to the wonderful world of IT! :D - Some(x) => DiskType::Unknown(x), + Some(x) => DiskKind::Unknown(x), // The information isn't available... - None => DiskType::Unknown(-1), + None => DiskKind::Unknown(-1), } } @@ -234,7 +234,9 @@ fn get_all_disks_inner(content: &str) -> Vec<Disk> { "pstore" | // https://www.kernel.org/doc/Documentation/ABI/testing/pstore "squashfs" | // squashfs is a compressed read-only file system (for snaps) "rpc_pipefs" | // The pipefs pseudo file system service - "iso9660" // optical media + "iso9660" | // optical media + "nfs4" | // calling statvfs on a mounted NFS may hang + "nfs" // nfs2 or nfs3 ); !(filtered || diff --git a/vendor/sysinfo/src/linux/network.rs b/vendor/sysinfo/src/linux/network.rs index c8da2bcb3..3b89fdc57 100644 --- a/vendor/sysinfo/src/linux/network.rs +++ b/vendor/sysinfo/src/linux/network.rs @@ -1,9 +1,11 @@ // Take a look at the license at the top of the repository in the LICENSE file. -use std::fs::File; use std::io::Read; use std::path::Path; +use std::{fs::File, u8}; +use crate::common::MacAddr; +use crate::network::refresh_networks_addresses; use crate::{NetworkExt, NetworksExt, NetworksIter}; use std::collections::{hash_map, HashMap}; @@ -77,7 +79,7 @@ fn refresh_networks_list_from_sysfs( // let tx_compressed = read(parent, "tx_compressed", &mut data); match interfaces.entry(entry) { hash_map::Entry::Occupied(mut e) => { - let mut interface = e.get_mut(); + let interface = e.get_mut(); old_and_new!(interface, rx_bytes, old_rx_bytes); old_and_new!(interface, tx_bytes, old_tx_bytes); old_and_new!(interface, rx_packets, old_rx_packets); @@ -102,6 +104,7 @@ fn refresh_networks_list_from_sysfs( old_rx_errors: rx_errors, tx_errors, old_tx_errors: tx_errors, + mac_addr: MacAddr::UNSPECIFIED, // rx_compressed, // old_rx_compressed: rx_compressed, // tx_compressed, @@ -132,6 +135,7 @@ impl NetworksExt for Networks { fn refresh_networks_list(&mut self) { refresh_networks_list_from_sysfs(&mut self.interfaces, Path::new("/sys/class/net/")); + refresh_networks_addresses(&mut self.interfaces); } } @@ -157,6 +161,8 @@ pub struct NetworkData { /// similar to `rx_errors` tx_errors: u64, old_tx_errors: u64, + /// MAC address + pub(crate) mac_addr: MacAddr, // /// Indicates the number of compressed packets received by this // /// network device. This value might only be relevant for interfaces // /// that support packet compression (e.g: PPP). @@ -263,6 +269,10 @@ impl NetworkExt for NetworkData { fn total_errors_on_transmitted(&self) -> u64 { self.tx_errors } + + fn mac_address(&self) -> MacAddr { + self.mac_addr + } } #[cfg(test)] diff --git a/vendor/sysinfo/src/linux/process.rs b/vendor/sysinfo/src/linux/process.rs index d7d61b5bc..55893ce8f 100644 --- a/vendor/sysinfo/src/linux/process.rs +++ b/vendor/sysinfo/src/linux/process.rs @@ -5,7 +5,6 @@ use std::collections::HashMap; use std::fmt; use std::fs::{self, File}; use std::io::Read; -use std::mem::MaybeUninit; use std::path::{Path, PathBuf}; use std::str::FromStr; @@ -19,26 +18,13 @@ use crate::utils::into_iter; use crate::{DiskUsage, Gid, Pid, ProcessExt, ProcessRefreshKind, ProcessStatus, Signal, Uid}; #[doc(hidden)] -impl From<u32> for ProcessStatus { - fn from(status: u32) -> ProcessStatus { - match status { - 1 => ProcessStatus::Idle, - 2 => ProcessStatus::Run, - 3 => ProcessStatus::Sleep, - 4 => ProcessStatus::Stop, - 5 => ProcessStatus::Zombie, - x => ProcessStatus::Unknown(x), - } - } -} - -#[doc(hidden)] impl From<char> for ProcessStatus { fn from(status: char) -> ProcessStatus { match status { 'R' => ProcessStatus::Run, 'S' => ProcessStatus::Sleep, - 'D' => ProcessStatus::Idle, + 'I' => ProcessStatus::Idle, + 'D' => ProcessStatus::UninterruptibleDiskSleep, 'Z' => ProcessStatus::Zombie, 'T' => ProcessStatus::Stop, 't' => ProcessStatus::Tracing, @@ -64,6 +50,7 @@ impl fmt::Display for ProcessStatus { ProcessStatus::Wakekill => "Wakekill", ProcessStatus::Waking => "Waking", ProcessStatus::Parked => "Parked", + ProcessStatus::UninterruptibleDiskSleep => "UninterruptibleDiskSleep", _ => "Unknown", }) } @@ -91,7 +78,9 @@ pub struct Process { pub(crate) updated: bool, cpu_usage: f32, user_id: Option<Uid>, + effective_user_id: Option<Uid>, group_id: Option<Gid>, + effective_group_id: Option<Gid>, pub(crate) status: ProcessStatus, /// Tasks run by this process. pub tasks: HashMap<Pid, Process>, @@ -125,7 +114,9 @@ impl Process { start_time: 0, run_time: 0, user_id: None, + effective_user_id: None, group_id: None, + effective_group_id: None, status: ProcessStatus::Unknown(0), tasks: if pid.0 == 0 { HashMap::with_capacity(1000) @@ -216,15 +207,23 @@ impl ProcessExt for Process { self.user_id.as_ref() } + fn effective_user_id(&self) -> Option<&Uid> { + self.effective_user_id.as_ref() + } + fn group_id(&self) -> Option<Gid> { self.group_id } + fn effective_group_id(&self) -> Option<Gid> { + self.effective_group_id + } + fn wait(&self) { let mut status = 0; // attempt waiting unsafe { - if libc::waitpid(self.pid.0, &mut status, 0) < 0 { + if retry_eintr!(libc::waitpid(self.pid.0, &mut status, 0)) < 0 { // attempt failed (non-child process) so loop until process ends let duration = std::time::Duration::from_millis(10); while kill(self.pid.0, 0) == 0 { @@ -233,6 +232,17 @@ impl ProcessExt for Process { } } } + + fn session_id(&self) -> Option<Pid> { + unsafe { + let session_id = libc::getsid(self.pid.0); + if session_id < 0 { + None + } else { + Some(Pid(session_id)) + } + } + } } pub(crate) fn compute_cpu_usage(p: &mut Process, total_time: f32, max_value: f32) { @@ -248,6 +258,17 @@ pub(crate) fn compute_cpu_usage(p: &mut Process, total_time: f32, max_value: f32 / total_time * 100.) .min(max_value); + + for task in p.tasks.values_mut() { + compute_cpu_usage(task, total_time, max_value); + } +} + +pub(crate) fn unset_updated(p: &mut Process) { + p.updated = false; + for task in p.tasks.values_mut() { + unset_updated(task); + } } pub(crate) fn set_time(p: &mut Process, utime: u64, stime: u64) { @@ -327,9 +348,13 @@ fn get_status(p: &mut Process, part: &str) { } fn refresh_user_group_ids<P: PathPush>(p: &mut Process, path: &mut P) { - if let Some((user_id, group_id)) = get_uid_and_gid(path.join("status")) { + if let Some(((user_id, effective_user_id), (group_id, effective_group_id))) = + get_uid_and_gid(path.join("status")) + { p.user_id = Some(Uid(user_id)); + p.effective_user_id = Some(Uid(effective_user_id)); p.group_id = Some(Gid(group_id)); + p.effective_group_id = Some(Gid(effective_group_id)); } } @@ -366,35 +391,24 @@ fn retrieve_all_new_process_info( refresh_user_group_ids(&mut p, &mut tmp); } - if proc_list.pid.0 != 0 { - // If we're getting information for a child, no need to get those info since we - // already have them... - p.cmd = proc_list.cmd.clone(); - p.name = proc_list.name.clone(); - p.environ = proc_list.environ.clone(); - p.exe = proc_list.exe.clone(); - p.cwd = proc_list.cwd.clone(); - p.root = proc_list.root.clone(); - } else { - p.name = name.into(); + p.name = name.into(); - match tmp.join("exe").read_link() { - Ok(exe_path) => { - p.exe = exe_path; - } - Err(_) => { - // Do not use cmd[0] because it is not the same thing. - // See https://github.com/GuillaumeGomez/sysinfo/issues/697. - p.exe = PathBuf::new() - } + match tmp.join("exe").read_link() { + Ok(exe_path) => { + p.exe = exe_path; + } + Err(_) => { + // Do not use cmd[0] because it is not the same thing. + // See https://github.com/GuillaumeGomez/sysinfo/issues/697. + p.exe = PathBuf::new() } - - p.cmd = copy_from_file(tmp.join("cmdline")); - p.environ = copy_from_file(tmp.join("environ")); - p.cwd = realpath(tmp.join("cwd")); - p.root = realpath(tmp.join("root")); } + p.cmd = copy_from_file(tmp.join("cmdline")); + p.environ = copy_from_file(tmp.join("environ")); + p.cwd = realpath(tmp.join("cwd")); + p.root = realpath(tmp.join("root")); + update_time_and_memory( path, &mut p, @@ -420,6 +434,11 @@ pub(crate) fn _get_process_data( refresh_kind: ProcessRefreshKind, ) -> Result<(Option<Process>, Pid), ()> { let pid = match path.file_name().and_then(|x| x.to_str()).map(Pid::from_str) { + // If `pid` and `nb` are the same, it means the file is linking to itself so we skip it. + // + // It's because when reading `/proc/[PID]` folder, we then go through the folders inside it. + // Then, if we encounter a sub-folder with the same PID as the parent, then it's a link to + // the current folder we already did read so no need to do anything. Some(Ok(nb)) if nb != pid => nb, _ => return Err(()), }; @@ -609,10 +628,12 @@ pub(crate) fn refresh_procs( fn copy_from_file(entry: &Path) -> Vec<String> { match File::open(entry) { Ok(mut f) => { - let mut data = vec![0; 16_384]; + let mut data = Vec::with_capacity(16_384); - if let Ok(size) = f.read(&mut data) { - data.truncate(size); + if let Err(_e) = f.read_to_end(&mut data) { + sysinfo_debug!("Failed to read file in `copy_from_file`: {:?}", _e); + Vec::new() + } else { let mut out = Vec::with_capacity(20); let mut start = 0; for (pos, x) in data.iter().enumerate() { @@ -628,51 +649,47 @@ fn copy_from_file(entry: &Path) -> Vec<String> { } } out - } else { - Vec::new() } } - Err(_) => Vec::new(), - } -} - -fn get_uid_and_gid(file_path: &Path) -> Option<(uid_t, gid_t)> { - use std::os::unix::ffi::OsStrExt; - - unsafe { - let mut sstat: MaybeUninit<libc::stat> = MaybeUninit::uninit(); - - let mut file_path: Vec<u8> = file_path.as_os_str().as_bytes().to_vec(); - file_path.push(0); - if libc::stat(file_path.as_ptr() as *const _, sstat.as_mut_ptr()) == 0 { - let sstat = sstat.assume_init(); - - return Some((sstat.st_uid, sstat.st_gid)); + Err(_e) => { + sysinfo_debug!("Failed to open file in `copy_from_file`: {:?}", _e); + Vec::new() } } +} +// Fetch tuples of real and effective UID and GID. +fn get_uid_and_gid(file_path: &Path) -> Option<((uid_t, uid_t), (gid_t, gid_t))> { let status_data = get_all_data(file_path, 16_385).ok()?; // We're only interested in the lines starting with Uid: and Gid: - // here. From these lines, we're looking at the second entry to get - // the effective u/gid. + // here. From these lines, we're looking at the first and second entries to get + // the real u/gid. - let f = |h: &str, n: &str| -> Option<uid_t> { + let f = |h: &str, n: &str| -> (Option<uid_t>, Option<uid_t>) { if h.starts_with(n) { - h.split_whitespace().nth(2).unwrap_or("0").parse().ok() + let mut ids = h.split_whitespace(); + let real = ids.nth(1).unwrap_or("0").parse().ok(); + let effective = ids.next().unwrap_or("0").parse().ok(); + + (real, effective) } else { - None + (None, None) } }; let mut uid = None; + let mut effective_uid = None; let mut gid = None; + let mut effective_gid = None; for line in status_data.lines() { - if let Some(u) = f(line, "Uid:") { - assert!(uid.is_none()); - uid = Some(u); - } else if let Some(g) = f(line, "Gid:") { - assert!(gid.is_none()); - gid = Some(g); + if let (Some(real), Some(effective)) = f(line, "Uid:") { + debug_assert!(uid.is_none() && effective_uid.is_none()); + uid = Some(real); + effective_uid = Some(effective); + } else if let (Some(real), Some(effective)) = f(line, "Gid:") { + debug_assert!(gid.is_none() && effective_gid.is_none()); + gid = Some(real); + effective_gid = Some(effective); } else { continue; } @@ -680,8 +697,10 @@ fn get_uid_and_gid(file_path: &Path) -> Option<(uid_t, gid_t)> { break; } } - match (uid, gid) { - (Some(u), Some(g)) => Some((u, g)), + match (uid, effective_uid, gid, effective_gid) { + (Some(uid), Some(effective_uid), Some(gid), Some(effective_gid)) => { + Some(((uid, effective_uid), (gid, effective_gid))) + } _ => None, } } diff --git a/vendor/sysinfo/src/linux/system.rs b/vendor/sysinfo/src/linux/system.rs index 3c4fce345..bbb6b24c4 100644 --- a/vendor/sysinfo/src/linux/system.rs +++ b/vendor/sysinfo/src/linux/system.rs @@ -16,6 +16,7 @@ use std::io::{BufRead, BufReader, Read}; use std::path::Path; use std::str::FromStr; use std::sync::{Arc, Mutex}; +use std::time::Duration; // This whole thing is to prevent having too many files open at once. It could be problematic // for processes using a lot of files and using sysinfo at the same time. @@ -28,7 +29,7 @@ pub(crate) static mut REMAINING_FILES: once_cell::sync::Lazy<Arc<Mutex<isize>>> rlim_max: 0, }; if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { - // Most linux system now defaults to 1024. + // Most Linux system now defaults to 1024. return Arc::new(Mutex::new(1024 / 2)); } // We save the value in case the update fails. @@ -55,7 +56,7 @@ pub(crate) fn get_max_nb_fds() -> isize { rlim_max: 0, }; if libc::getrlimit(libc::RLIMIT_NOFILE, &mut limits) != 0 { - // Most linux system now defaults to 1024. + // Most Linux system now defaults to 1024. 1024 / 2 } else { limits.rlim_max as isize / 2 @@ -81,11 +82,8 @@ fn boot_time() -> u64 { } } // Either we didn't find "btime" or "/proc/stat" wasn't available for some reason... - let mut up = libc::timespec { - tv_sec: 0, - tv_nsec: 0, - }; unsafe { + let mut up: libc::timespec = std::mem::zeroed(); if libc::clock_gettime(libc::CLOCK_BOOTTIME, &mut up) == 0 { up.tv_sec as u64 } else { @@ -207,7 +205,7 @@ impl System { if compute_cpu { compute_cpu_usage(proc_, total_time, max_value); } - proc_.updated = false; + unset_updated(proc_); true }); } @@ -220,6 +218,7 @@ impl System { impl SystemExt for System { const IS_SUPPORTED: bool = true; const SUPPORTED_SIGNALS: &'static [Signal] = supported_signals(); + const MINIMUM_CPU_UPDATE_INTERVAL: Duration = Duration::from_millis(200); fn new_with_specifics(refreshes: RefreshKind) -> System { let process_list = Process::new(Pid(0)); @@ -311,7 +310,7 @@ impl SystemExt for System { fn refresh_process_specifics(&mut self, pid: Pid, refresh_kind: ProcessRefreshKind) -> bool { let uptime = self.uptime(); - let found = match _get_process_data( + match _get_process_data( &Path::new("/proc/").join(pid.to_string()), &mut self.process_list, Pid(0), @@ -321,32 +320,33 @@ impl SystemExt for System { ) { Ok((Some(p), pid)) => { self.process_list.tasks.insert(pid, p); - true } - Ok(_) => true, - Err(_) => false, + Ok(_) => {} + Err(_e) => { + sysinfo_debug!("Cannot get information for PID {:?}: {:?}", pid, _e); + return false; + } }; - if found { - if refresh_kind.cpu() { - self.refresh_cpus(true, CpuRefreshKind::new().with_cpu_usage()); + if refresh_kind.cpu() { + self.refresh_cpus(true, CpuRefreshKind::new().with_cpu_usage()); - if self.cpus.is_empty() { - sysinfo_debug!("Cannot compute process CPU usage: no cpus found..."); - return found; - } - let (new, old) = self.cpus.get_global_raw_times(); - let total_time = (if old >= new { 1 } else { new - old }) as f32; - - let max_cpu_usage = self.get_max_process_cpu_usage(); - if let Some(p) = self.process_list.tasks.get_mut(&pid) { - compute_cpu_usage(p, total_time / self.cpus.len() as f32, max_cpu_usage); - p.updated = false; - } - } else if let Some(p) = self.process_list.tasks.get_mut(&pid) { - p.updated = false; + if self.cpus.is_empty() { + eprintln!("Cannot compute process CPU usage: no cpus found..."); + return true; + } + let (new, old) = self.cpus.get_global_raw_times(); + let total_time = (if old >= new { 1 } else { new - old }) as f32; + let total_time = total_time / self.cpus.len() as f32; + + let max_cpu_usage = self.get_max_process_cpu_usage(); + if let Some(p) = self.process_list.tasks.get_mut(&pid) { + compute_cpu_usage(p, total_time, max_cpu_usage); + unset_updated(p); } + } else if let Some(p) = self.process_list.tasks.get_mut(&pid) { + unset_updated(p); } - found + true } fn refresh_disks_list(&mut self) { diff --git a/vendor/sysinfo/src/linux/utils.rs b/vendor/sysinfo/src/linux/utils.rs index 60a9aa2b0..486682210 100644 --- a/vendor/sysinfo/src/linux/utils.rs +++ b/vendor/sysinfo/src/linux/utils.rs @@ -1,14 +1,14 @@ // Take a look at the license at the top of the repository in the LICENSE file. use std::fs::File; -use std::io::{self, Read, Seek, SeekFrom}; +use std::io::{self, Read, Seek}; use std::path::{Path, PathBuf}; use crate::sys::system::REMAINING_FILES; pub(crate) fn get_all_data_from_file(file: &mut File, size: usize) -> io::Result<String> { let mut buf = String::with_capacity(size); - file.seek(SeekFrom::Start(0))?; + file.rewind()?; file.read_to_string(&mut buf)?; Ok(buf) } |