1use anyhow::Result;
2use serde::Serialize;
3use std::path::PathBuf;
4use std::process::Command;
5
6#[derive(Debug, Clone, Serialize)]
7pub struct LogSource {
8 pub label: String,
9 pub path: Option<PathBuf>,
10 pub size_bytes: u64,
11}
12
13pub fn scan_logs() -> Vec<LogSource> {
14 let mut out = Vec::new();
15
16 if let Some(size) = journald_size() {
17 out.push(LogSource { label: "journald".into(), path: Some(PathBuf::from("/var/log/journal")), size_bytes: size });
18 }
19 for p in ["/var/log/syslog", "/var/log/syslog.1", "/var/log/kern.log"] {
20 if let Ok(meta) = std::fs::metadata(p) {
21 out.push(LogSource { label: p.to_string(), path: Some(PathBuf::from(p)), size_bytes: meta.len() });
22 }
23 }
24 if let Some(home) = dirs::home_dir() {
25 let share = home.join(".local/share");
26 if let Ok(entries) = std::fs::read_dir(&share) {
27 for e in entries.flatten() {
28 let p = e.path();
29 if p.extension().and_then(|x| x.to_str()) == Some("log") {
30 if let Ok(meta) = e.metadata() {
31 out.push(LogSource { label: p.display().to_string(), path: Some(p), size_bytes: meta.len() });
32 }
33 }
34 }
35 }
36 }
37 out.sort_by(|a, b| b.size_bytes.cmp(&a.size_bytes));
38 out
39}
40
41fn journald_size() -> Option<u64> {
42 let out = Command::new("journalctl").arg("--disk-usage").output().ok()?;
43 let text = String::from_utf8_lossy(&out.stdout);
44 let mb = text.split_whitespace().find(|w| w.parse::<f64>().is_ok())?.parse::<f64>().ok()?;
45 Some((mb * 1024.0 * 1024.0) as u64)
46}
47
48pub fn vacuum_journald(keep: &str) -> Result<()> {
49 Command::new("journalctl").arg(format!("--vacuum-time={keep}")).status()?;
50 Ok(())
51}