0
0
Fork 0
tree-owners/src/main.rs

82 lines
2.2 KiB
Rust
Raw Normal View History

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:46:17 +02:00
use anyhow::{anyhow, Context, Error, 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 {
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();
uf.into_iter()
.for_each(|(uid, e)| print_err(e, format!("failed to get name for user {uid}")));
gf.into_iter()
.for_each(|(gid, e)| print_err(e, format!("failed to get name for group {gid}")));
2023-09-24 14:25:46 +02:00
}
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.
fn fs_entry(entry: &Path, summary: &mut Summary) {
2023-09-24 05:38:22 +02:00
let display = entry.display();
if !entry.exists() && !entry.is_symlink() {
print_root_err(format!("{display} doesn't exist"));
}
let meta = match entry.symlink_metadata() {
Ok(meta) => meta,
Err(e) => {
print_err(e, format!("failed to get metadata for {display}"));
return;
}
};
2023-09-24 05:38:22 +02:00
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 = match read_dir(entry) {
Ok(children) => children,
Err(e) => {
print_err(e, format!("failed to read dir {display}"));
return;
}
};
for child in children {
match child {
Ok(child) => fs_entry(&child.path(), summary),
Err(e) => {
print_err(e, format!("invalid child for {display}"));
return;
}
}
2023-09-24 05:38:22 +02:00
}
}
}
2023-09-24 05:38:22 +02:00
fn print_root_err(message: String) {
eprintln!("{:#}", anyhow!("{message}"));
}
fn print_err(err: impl Into<Error>, message: String) {
eprintln!("{:#}", err.into().context(message));
2023-09-24 05:38:22 +02:00
}