Files
sausage/userland/init/src/systemctl.rs
T

124 lines
4.1 KiB
Rust

//! Controls init and reads its public unit state files.
use sausage_init::*;
use std::{fs, io};
fn run() -> io::Result<i32> {
let args: Vec<_> = std::env::args().skip(1).collect();
let action = args.first().map(String::as_str).unwrap_or("list-units");
if action == "daemon-reload" {
return Ok(0);
}
if action == "list-units" {
for entry in fs::read_dir(format!("{RUN}/state"))? {
let entry = entry?;
let status: Status = serde_json::from_slice(&fs::read(entry.path())?)?;
println!("{} {}", entry.file_name().to_string_lossy(), status.state);
}
return Ok(0);
}
let now = args.iter().any(|a| a == "--now");
let units: Vec<_> = args
.iter()
.skip(1)
.filter(|a| !a.starts_with('-'))
.map(|a| name(a))
.collect();
if units.is_empty() {
return Ok(1);
}
let mut result = 0;
for unit in units {
let status = fs::read(format!("{RUN}/state/{unit}"))
.ok()
.and_then(|b| serde_json::from_slice::<Status>(&b).ok())
.unwrap_or_default();
let code = match action {
"is-active" => {
println!(
"{}",
if status.state.is_empty() {
"unknown"
} else {
&status.state
}
);
if status.state == "active" { 0 } else { 3 }
}
"is-failed" => {
println!(
"{}",
if status.state.is_empty() {
"unknown"
} else {
&status.state
}
);
if status.state == "failed" { 0 } else { 1 }
}
"is-enabled" => {
println!(
"{}",
if enabled(&unit) {
"enabled"
} else {
"disabled"
}
);
if enabled(&unit) { 0 } else { 1 }
}
"status" => {
println!("{unit}: {}", status.state);
if status.state == "active" {
0
} else if status.state.is_empty() {
4
} else {
3
}
}
"cat" => {
print!("{}", fs::read_to_string(unit_path(&unit))?);
0
}
"enable" | "disable" => {
let spec = Unit::parse(fs::read_to_string(unit_path(&unit))?)?;
let targets: Vec<_> = spec
.get("Install.WantedBy")
.split_whitespace()
.filter(|t| matches!(*t, "default.target" | "multi-user.target"))
.collect();
if action == "enable" && targets.is_empty() {
return Ok(1);
}
for target in ["default.target", "multi-user.target"] {
let dir = format!("{UNITS}/{target}.wants");
let path = format!("{dir}/{unit}");
if action == "enable" && targets.contains(&target) {
fs::create_dir_all(dir)?;
fs::write(path, b"")?;
} else if action == "disable" {
let _ = fs::remove_file(path);
}
}
if now {
request(if action == "enable" { "start" } else { "stop" }, &unit)?.code
} else {
0
}
}
"start" | "stop" | "restart" => {
let reply = request(action, &unit)?;
if !reply.text.is_empty() {
println!("{}", reply.text);
}
reply.code
}
_ => 1,
};
result = result.max(code);
}
Ok(result)
}
fn main() {
sausage_init::exit(run().unwrap_or(1));
}