124 lines
4.1 KiB
Rust
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));
|
|
}
|