1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67
use std::io::{BufRead, BufReader, Read}; use std::process::Command; #[derive(Default, Debug, PartialEq)] pub struct FileSystem { pub name: String, pub used: u64, pub size: u64, } impl FileSystem { pub fn get() -> std::io::Result<Vec<FileSystem>> { let output = Command::new("df") .arg("-Pkl") .output() .expect("failed to run"); Self::collect_filesystem_stats(std::io::Cursor::new(output.stdout)) } fn collect_filesystem_stats<R: Read>(buf: R) -> std::io::Result<Vec<FileSystem>> { let reader = BufReader::new(buf); let file_systems = reader .lines() .skip(1) .map(|line| line.unwrap()) .filter(|line| { line.starts_with("/dev/") && !line.starts_with("/dev/mapper/docker-") && !line.starts_with("/dev/dm-") && !line.contains("devicemapper/mnt") }) .map(|line| { let columns: Vec<_> = line.split_ascii_whitespace().collect(); if columns.len() < 4 { unimplemented!() } let used_kb = columns[2].parse::<u64>().unwrap(); let available_kb = columns[3].parse::<u64>().unwrap(); FileSystem { name: columns[0].trim_start_matches("/dev/").to_owned(), used: used_kb * 1024, size: (used_kb + available_kb) * 1024, } }) .collect(); Ok(file_systems) } } #[test] fn test_collect_filesystem_stats() { let output = "Filesystem 1024-blocks Used Available Capacity Mounted on /dev/sda1 19734388 16868164 1863772 91% / tmpfs 517224 0 517224 0% /lib/init/rw udev 512780 96 512684 1% /dev tmpfs 517224 4 517220 1% /dev/shm /dev/mapper/docker-000:0-000-00000 10190136 168708 9480756 2% /var/lib/docker/devicemapper/mnt/00000 /dev/dm-4 10474496 149684 10324812 2% /var/lib/docker/devicemapper/mnt/11111".as_bytes(); let expected = vec![FileSystem { name: "sda1".to_owned(), used: 17272999936, size: 19181502464, }]; let r = FileSystem::collect_filesystem_stats(output); assert!(r.is_ok()); assert_eq!(r.unwrap(), expected); }