ifstat_rs/net_stats/linux_impl.rs
1// network_utils.rs
2// This module provides utility functions to retrieve network device statistics
3// and map device strings to friendly names on a Unix-based system.
4
5use std::collections::HashMap;
6use std::fs::File;
7use std::io::{BufRead, BufReader};
8
9use indexmap::IndexMap;
10
11use crate::test_debug;
12
13/// Retrieves network device statistics from the `/proc/net/dev` file.
14///
15/// # Returns
16///
17/// A result containing an IndexMap where the keys are the device names and the values are tuples of (received bytes, transmitted bytes).
18/// In case of an error, returns an io::Error.
19pub fn get_net_dev_stats() -> Result<IndexMap<String, (u64, u64)>, std::io::Error> {
20 // Open the `/proc/net/dev` file for reading
21 let file = File::open("/proc/net/dev")?;
22 let reader = BufReader::new(file);
23 // Parse the network device statistics from the file
24 parse_net_dev_stats(reader)
25}
26
27/// Parses network device statistics from a given reader.
28///
29/// # Arguments
30///
31/// * `reader` - A reader that provides lines of network device statistics.
32///
33/// # Returns
34///
35/// A result containing an IndexMap where the keys are the device names and the values are tuples of (received bytes, transmitted bytes).
36/// In case of an error, returns an io::Error.
37pub fn parse_net_dev_stats<R: BufRead>(
38 reader: R,
39) -> Result<IndexMap<String, (u64, u64)>, std::io::Error> {
40 let mut stats = IndexMap::new();
41 let lines: Vec<_> = reader.lines().collect::<Result<_, _>>()?;
42 test_debug!("Parsing {} lines", lines.len());
43
44 // Skip the first two lines as they are headers
45 for (_index, line) in lines.into_iter().enumerate().skip(2) {
46 test_debug!("Parsing line: {}", line);
47 // Split the line into interface name and the rest of the statistics
48 if let Some((iface, rest)) = line.split_once(':') {
49 let fields: Vec<&str> = rest.split_whitespace().collect();
50 if fields.len() >= 9 {
51 // Parse the received and transmitted bytes
52 let rx_bytes: u64 = fields[0].parse().map_err(|_| {
53 std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid RX bytes")
54 })?;
55 let tx_bytes: u64 = fields[8].parse().map_err(|_| {
56 std::io::Error::new(std::io::ErrorKind::InvalidData, "Invalid TX bytes")
57 })?;
58 stats.insert(iface.trim().to_string(), (rx_bytes, tx_bytes));
59 } else {
60 test_debug!(
61 "Invalid line format: '{}' ({} fields: {:?})",
62 line,
63 fields.len(),
64 fields
65 );
66 return Err(std::io::Error::new(
67 std::io::ErrorKind::InvalidData,
68 format!("Invalid line format: {} fields", fields.len()),
69 ));
70 }
71 } else {
72 test_debug!("Invalid line format: '{}' (no colon found)", line);
73 return Err(std::io::Error::new(
74 std::io::ErrorKind::InvalidData,
75 "Invalid line format (no colon found)",
76 ));
77 }
78 }
79 Ok(stats)
80}
81
82/// Retrieves a map of device strings to friendly names.
83///
84/// # Returns
85///
86/// A HashMap where the keys are device strings and the values are friendly names.
87pub fn get_device_string_to_name_map() -> HashMap<String, String> {
88 HashMap::new() // This isn't really crucial on linux but we *could* implement it.
89}