2023-09-24 12:23:20 +02:00
|
|
|
use std::{fs::read_dir, os::linux::fs::MetadataExt, path::Path};
|
2023-09-24 05:38:22 +02:00
|
|
|
|
2023-09-24 14:25:46 +02:00
|
|
|
use anyhow::{anyhow, ensure, Context, Result};
|
2023-09-24 05:38:22 +02:00
|
|
|
use clap::Parser;
|
|
|
|
|
2023-09-24 14:25:46 +02:00
|
|
|
use crate::{cli::Args, summary::Summary};
|
2023-09-24 05:38:22 +02:00
|
|
|
|
2023-09-24 12:23:20 +02:00
|
|
|
mod cli;
|
2023-09-24 14:25:46 +02:00
|
|
|
mod summary;
|
2023-09-24 05:38:22 +02:00
|
|
|
|
|
|
|
fn main() -> Result<()> {
|
|
|
|
human_panic::setup_panic!();
|
|
|
|
let args = Args::parse();
|
|
|
|
|
2023-09-24 14:25:46 +02:00
|
|
|
let mut summary = Summary::default();
|
2023-09-24 05:38:22 +02:00
|
|
|
for root in args.roots {
|
2023-09-24 14:25:46 +02:00
|
|
|
fs_entry(&root, &mut summary)?;
|
2023-09-24 05:38:22 +02:00
|
|
|
}
|
|
|
|
|
2023-09-24 14:25:46 +02:00
|
|
|
if !args.raw {
|
|
|
|
let (uf, gf) = summary.lookup_names();
|
|
|
|
|
|
|
|
for (uid, e) in uf {
|
|
|
|
eprintln!(
|
|
|
|
"{:#}",
|
|
|
|
anyhow!(e).context(format!("failed to get name for user {uid}"))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
|
|
|
|
for (gid, e) in gf {
|
|
|
|
eprintln!(
|
|
|
|
"{:#}",
|
|
|
|
anyhow!(e).context(format!("failed to get name for group {gid}"))
|
|
|
|
);
|
|
|
|
}
|
|
|
|
}
|
2023-09-24 05:38:22 +02:00
|
|
|
let output = match args.json {
|
2023-09-24 14:25:46 +02:00
|
|
|
false => summary.to_string(),
|
|
|
|
true => serde_json::to_string_pretty(&summary).context("json serialization failed")?,
|
2023-09-24 05:38:22 +02:00
|
|
|
};
|
|
|
|
println!("{output}");
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
2023-09-24 05:52:27 +02:00
|
|
|
/// Perform gid & uid gathering for a file, or a directory and its children.
|
2023-09-24 14:25:46 +02:00
|
|
|
fn fs_entry(entry: &Path, summary: &mut Summary) -> Result<()> {
|
2023-09-24 05:38:22 +02:00
|
|
|
let display = entry.display();
|
|
|
|
ensure!(
|
|
|
|
entry.is_symlink() || entry.exists(),
|
|
|
|
format!("{} doesn't exist", display)
|
|
|
|
);
|
|
|
|
|
|
|
|
let meta = entry
|
|
|
|
.symlink_metadata()
|
|
|
|
.context(format!("failed to get metadata for {}", display))?;
|
2023-09-24 14:25:46 +02:00
|
|
|
summary.add_user(meta.st_uid());
|
|
|
|
summary.add_group(meta.st_gid());
|
2023-09-24 05:38:22 +02:00
|
|
|
|
|
|
|
if entry.is_dir() {
|
|
|
|
let children = read_dir(entry).context(format!("failed to read dir {}", display))?;
|
|
|
|
for e in children {
|
|
|
|
let e = e.context(format!("invalid child for {}", display))?;
|
2023-09-24 07:51:45 +02:00
|
|
|
fs_entry(&e.path(), summary)?;
|
2023-09-24 05:38:22 +02:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
Ok(())
|
|
|
|
}
|