diff options
Diffstat (limited to 'src/systemd/unit.rs')
-rw-r--r-- | src/systemd/unit.rs | 67 |
1 files changed, 67 insertions, 0 deletions
diff --git a/src/systemd/unit.rs b/src/systemd/unit.rs new file mode 100644 index 0000000..3be7fa5 --- /dev/null +++ b/src/systemd/unit.rs @@ -0,0 +1,67 @@ +use std::collections::HashMap; +use std::process::Command; + +use std::io; + +#[derive(Debug, PartialEq, Eq)] +pub struct Unit { + pub name: String, + pub type_: String +} + +pub fn parse_key_value(line: &str) -> Option<(String, String)> { + let pos = line.find('='); + pos.map(|pos| { + let (k, v) = line.split_at(pos); + (k.to_owned(), v[1..].to_owned()) + }) +} + +#[test] +fn test_parse_key_value() { + assert_eq!(None, parse_key_value("ab")); + assert_eq!(Some(("a".to_owned(), "b".to_owned())), parse_key_value("a=b")); + assert_eq!(Some(("a".to_owned(), "b=c".to_owned())), parse_key_value("a=b=c")); +} + +fn make_unit(info: HashMap<String, String>) -> Option<Unit> { + fn from_id(id: &str) -> Option<String> { + id.rsplit('.').next().map(|t| t.to_owned()) + }; + let id = info.get("Id").map(|id| id.clone()); + let type_ = id.as_ref().and_then(|id| from_id(&id)); + + if let (Some(id), Some(type_)) = (id, type_) { + Some(Unit { name: id, type_: type_ }) + } else { + None + } +} + +#[test] +fn test_make_unit() { + let s = |s: &str| -> String { s.to_owned() }; + let info = [(s("Id"), s("Test.service"))] + .iter().cloned().collect::<HashMap<String, String>>(); + assert_eq!(Some(Unit { name: s("Test.service"), type_: s("service") }), make_unit(info)); + + let info = HashMap::new(); + assert_eq!(None, make_unit(info)); +} + +pub fn get_units() -> io::Result<Vec<Unit>> { + let mut units = Vec::new(); + let status = try!(Command::new("systemctl") + .args(&["show", "*"]).output()); + + let mut unit_info = HashMap::new(); + for line in String::from_utf8_lossy(&status.stdout).split('\n') { + if let Some((k, v)) = parse_key_value(line) { + unit_info.insert(k, v); + } else { + make_unit(unit_info).map(|u| units.push(u)); + unit_info = HashMap::new(); + } + } + return Ok(units); +} |