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

67 lines
1.9 KiB
Rust

//! Reads a unit journal, with optional live output through the world watcher.
use sausage_init::name;
use std::{
fs,
io::{self, Write},
};
fn run() -> io::Result<()> {
let mut args = std::env::args().skip(1);
let (mut unit, mut lines, mut follow) = (String::new(), 10usize, false);
while let Some(arg) = args.next() {
match arg.as_str() {
"-u" => {
unit = name(
&args
.next()
.ok_or_else(|| io::Error::other("missing unit"))?,
)
}
"-n" => {
lines = args
.next()
.and_then(|n| n.parse().ok())
.ok_or_else(|| io::Error::other("missing count"))?
}
"-f" => follow = true,
"--no-pager" => (),
_ => return Err(io::Error::other("unknown argument")),
}
}
let path = format!("/var/log/journal/{unit}.log");
let watcher = sausage_spawn::Watcher::new(&[path.clone()]);
let bytes = fs::read(&path).unwrap_or_default();
let mut starts = vec![0];
for (i, b) in bytes.iter().enumerate() {
if *b == b'\n' && i + 1 < bytes.len() {
starts.push(i + 1);
}
}
let start = if lines == 0 {
bytes.len()
} else {
starts[starts.len().saturating_sub(lines)]
};
io::stdout().write_all(&bytes[start..])?;
io::stdout().flush()?;
let mut offset = bytes.len();
while follow {
let pollable = watcher.subscribe();
pollable.block();
drop(pollable);
watcher.changes();
let bytes = fs::read(&path).unwrap_or_default();
if bytes.len() < offset {
offset = 0;
}
io::stdout().write_all(&bytes[offset..])?;
io::stdout().flush()?;
offset = bytes.len();
}
Ok(())
}
fn main() {
if run().is_err() {
std::process::exit(1);
}
}