86 lines
2.7 KiB
Rust
86 lines
2.7 KiB
Rust
//! Creates transient unit files and optionally waits for their final state.
|
|
use sausage_init::*;
|
|
use std::{fs, io};
|
|
fn run() -> io::Result<i32> {
|
|
let mut args = std::env::args().skip(1).peekable();
|
|
let mut unit = format!(
|
|
"run-{}",
|
|
std::time::SystemTime::now()
|
|
.duration_since(std::time::UNIX_EPOCH)
|
|
.unwrap()
|
|
.as_nanos()
|
|
);
|
|
let (mut wait, mut properties, mut command) = (false, Vec::new(), Vec::new());
|
|
while let Some(arg) = args.next() {
|
|
match arg.as_str() {
|
|
"--unit" => {
|
|
unit = args
|
|
.next()
|
|
.ok_or_else(|| io::Error::other("missing unit"))?
|
|
}
|
|
"--wait" => wait = true,
|
|
"-p" => properties.push(
|
|
args.next()
|
|
.ok_or_else(|| io::Error::other("missing property"))?,
|
|
),
|
|
"--working-directory" => properties.push(format!(
|
|
"WorkingDirectory={}",
|
|
args.next()
|
|
.ok_or_else(|| io::Error::other("missing directory"))?
|
|
)),
|
|
"-E" => properties.push(format!(
|
|
"Environment={}",
|
|
args.next()
|
|
.ok_or_else(|| io::Error::other("missing environment"))?
|
|
)),
|
|
"--" => {
|
|
command.extend(args);
|
|
break;
|
|
}
|
|
_ if arg.starts_with("--unit=") => unit = arg[7..].into(),
|
|
_ if arg.starts_with('-') => return Ok(1),
|
|
_ => {
|
|
command.push(arg);
|
|
command.extend(args);
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
if command.is_empty() {
|
|
return Ok(1);
|
|
}
|
|
let unit = name(&unit);
|
|
let mut text = format!(
|
|
"[Service]\nExecStart={}\n",
|
|
shlex::try_join(command.iter().map(String::as_str)).map_err(io::Error::other)?
|
|
);
|
|
for property in properties {
|
|
text.push_str(&property);
|
|
text.push('\n');
|
|
}
|
|
fs::create_dir_all(TRANSIENT)?;
|
|
atomic(&format!("{TRANSIENT}/{unit}"), text.as_bytes())?;
|
|
let reply = request("start", &unit)?;
|
|
if reply.code != 0 {
|
|
return Ok(reply.code);
|
|
}
|
|
if wait {
|
|
let watcher = sausage_spawn::Watcher::new(&[format!("{RUN}/state/{unit}")]);
|
|
let changed = watcher.subscribe();
|
|
loop {
|
|
if let Ok(bytes) = fs::read(format!("{RUN}/state/{unit}")) {
|
|
let status: Status = serde_json::from_slice(&bytes)?;
|
|
if let Some(code) = status.code {
|
|
return Ok(code);
|
|
}
|
|
}
|
|
changed.block();
|
|
let _ = watcher.changes();
|
|
}
|
|
}
|
|
Ok(0)
|
|
}
|
|
fn main() {
|
|
sausage_init::exit(run().unwrap_or(1));
|
|
}
|