//! 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); } }