src/tools/disks/zfs.rs: parse more infos (dedup, fragmentation, health)
This commit is contained in:
		| @ -8,7 +8,7 @@ use lazy_static::lazy_static; | |||||||
| use nom::{ | use nom::{ | ||||||
|     error::VerboseError, |     error::VerboseError, | ||||||
|     bytes::complete::{take_while, take_while1, take_till, take_till1}, |     bytes::complete::{take_while, take_while1, take_till, take_till1}, | ||||||
|     combinator::{map_res, all_consuming, recognize}, |     combinator::{map_res, all_consuming, recognize, opt}, | ||||||
|     sequence::{preceded, tuple}, |     sequence::{preceded, tuple}, | ||||||
|     character::complete::{space1, digit1, char, line_ending}, |     character::complete::{space1, digit1, char, line_ending}, | ||||||
|     multi::{many0, many1}, |     multi::{many0, many1}, | ||||||
| @ -32,11 +32,14 @@ pub struct ZFSPoolUsage { | |||||||
|     total: u64, |     total: u64, | ||||||
|     used: u64, |     used: u64, | ||||||
|     free: u64, |     free: u64, | ||||||
|  |     dedup: f64, | ||||||
|  |     fragmentation: u64, | ||||||
| } | } | ||||||
|  |  | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub struct ZFSPoolStatus { | pub struct ZFSPoolStatus { | ||||||
|     name: String, |     name: String, | ||||||
|  |     health: String, | ||||||
|     usage: Option<ZFSPoolUsage>, |     usage: Option<ZFSPoolUsage>, | ||||||
|     devices: Vec<String>, |     devices: Vec<String>, | ||||||
| } | } | ||||||
| @ -91,6 +94,11 @@ fn multispace1(i: &str)  -> IResult<&str, &str> { | |||||||
|     take_while1(|c| c == ' ' || c == '\t')(i) |     take_while1(|c| c == ' ' || c == '\t')(i) | ||||||
| } | } | ||||||
|  |  | ||||||
|  | /// Recognizes one or more non-whitespace-characters | ||||||
|  | fn notspace1(i: &str)  -> IResult<&str, &str> { | ||||||
|  |     take_while1(|c| !(c == ' ' || c == '\t' || c == '\n'))(i) | ||||||
|  | } | ||||||
|  |  | ||||||
| fn parse_optional_u64(i: &str) -> IResult<&str, Option<u64>> { | fn parse_optional_u64(i: &str) -> IResult<&str, Option<u64>> { | ||||||
|     if i.starts_with('-') { |     if i.starts_with('-') { | ||||||
|         Ok((&i[1..], None)) |         Ok((&i[1..], None)) | ||||||
| @ -100,6 +108,15 @@ fn parse_optional_u64(i: &str) -> IResult<&str, Option<u64>> { | |||||||
|     } |     } | ||||||
| } | } | ||||||
|  |  | ||||||
|  | fn parse_optional_f64(i: &str) -> IResult<&str, Option<f64>> { | ||||||
|  |     if i.starts_with('-') { | ||||||
|  |         Ok((&i[1..], None)) | ||||||
|  |     } else { | ||||||
|  |         let (i, value) = nom::number::complete::double(i)?; | ||||||
|  |         Ok((i, Some(value))) | ||||||
|  |     } | ||||||
|  | } | ||||||
|  |  | ||||||
| fn parse_pool_device(i: &str) -> IResult<&str, String> { | fn parse_pool_device(i: &str) -> IResult<&str, String> { | ||||||
|     let (i, (device, _, _rest)) = tuple(( |     let (i, (device, _, _rest)) = tuple(( | ||||||
|         preceded(multispace1, take_till1(|c| c == ' ' || c == '\t')), |         preceded(multispace1, take_till1(|c| c == ' ' || c == '\t')), | ||||||
| @ -111,24 +128,38 @@ fn parse_pool_device(i: &str) -> IResult<&str, String> { | |||||||
| } | } | ||||||
|  |  | ||||||
| fn parse_pool_header(i: &str) -> IResult<&str, ZFSPoolStatus> { | fn parse_pool_header(i: &str) -> IResult<&str, ZFSPoolStatus> { | ||||||
|     let (i, (text, total, used, free, _, _eol)) = tuple(( |     // name, size, allocated, free, checkpoint, expandsize, fragmentation, capacity, dedupratio, health, altroot. | ||||||
|         take_while1(|c| char::is_alphanumeric(c)), |  | ||||||
|         preceded(multispace1, parse_optional_u64), |     let (i, (text, total, used, free, _, _, | ||||||
|         preceded(multispace1, parse_optional_u64), |              fragmentation, _, dedup, health, | ||||||
|         preceded(multispace1, parse_optional_u64), |              _, _eol)) = tuple(( | ||||||
|         preceded(space1, take_till(|c| c == '\n')), |         take_while1(|c| char::is_alphanumeric(c)), // name | ||||||
|  |         preceded(multispace1, parse_optional_u64), // size | ||||||
|  |         preceded(multispace1, parse_optional_u64), // allocated | ||||||
|  |         preceded(multispace1, parse_optional_u64), // free | ||||||
|  |         preceded(multispace1, notspace1), // checkpoint | ||||||
|  |         preceded(multispace1, notspace1), // expandsize | ||||||
|  |         preceded(multispace1, parse_optional_u64), // fragmentation | ||||||
|  |         preceded(multispace1, notspace1), // capacity | ||||||
|  |         preceded(multispace1, parse_optional_f64), // dedup | ||||||
|  |         preceded(multispace1, notspace1), // health | ||||||
|  |         opt(preceded(space1, take_till(|c| c == '\n'))), // skip rest | ||||||
|         line_ending, |         line_ending, | ||||||
|     ))(i)?; |     ))(i)?; | ||||||
|  |  | ||||||
|     let status = if let (Some(total), Some(used), Some(free)) = (total, used, free)  { |     let status = if let (Some(total), Some(used), Some(free), Some(fragmentation), Some(dedup)) = (total, used, free, fragmentation, dedup)  { | ||||||
|         ZFSPoolStatus { |         ZFSPoolStatus { | ||||||
|             name: text.into(), |             name: text.into(), | ||||||
|             usage: Some(ZFSPoolUsage { total, used, free }), |             health: health.into(), | ||||||
|  |             usage: Some(ZFSPoolUsage { total, used, free, fragmentation, dedup }), | ||||||
|             devices: Vec::new(), |             devices: Vec::new(), | ||||||
|         } |         } | ||||||
|     } else { |     } else { | ||||||
|          ZFSPoolStatus { |          ZFSPoolStatus { | ||||||
|             name: text.into(), usage: None, devices: Vec::new(), |              name: text.into(), | ||||||
|  |              health: health.into(), | ||||||
|  |              usage: None, | ||||||
|  |              devices: Vec::new(), | ||||||
|          } |          } | ||||||
|     }; |     }; | ||||||
|  |  | ||||||
|  | |||||||
		Reference in New Issue
	
	Block a user