logo

deblob

remove binary executables from a directory git clone https://hacktivis.me/git/deblob.git
commit: f2893cbeda686082b8f627016ad89358eefbb314
parent 7efb9b47340165b450ec1671f6b5afb148c3eef4
Author: Haelwenn (lanodan) Monnier <contact@hacktivis.me>
Date:   Sat, 16 Nov 2024 06:26:13 +0100

Add -j option

Diffstat:

Mdeblob.115+++++++++------
Mmain.ha61+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 70 insertions(+), 6 deletions(-)

diff --git a/deblob.1 b/deblob.1 @@ -1,6 +1,6 @@ .\" SPDX-FileCopyrightText: 2019 deblob Authors <https://hacktivis.me/projects/deblob> .\" SPDX-License-Identifier: BSD-3-Clause -.Dd 2024-10-31 +.Dd 2024-11-16 .Dt DEBLOB 1 .Os .Sh NAME @@ -9,8 +9,9 @@ .Sh SYNOPSIS .Nm .Op Fl cn -.Op Fl e Ar excluded path ... .Op Fl d Ar working directory +.Op Fl e Ar excluded path ... +.Op Fl j Ar file .Sh DESCRIPTION The .Nm @@ -25,13 +26,15 @@ The options are as follows: .Bl -tag -width Ds .It Fl c Return error if any non-excluded blobs were found. -.It Fl n -Scan the files but do not actually delete them. +.It Fl d Ar working directory +Directory to be scanned rather than the current working directory on execution. .It Fl e Ar excluded path Paths to be excluded from removal, accepts shell-style globbing. Pass the option multiple times to do multiple exclusions. -.It Fl d Ar working directory -Directory to be scanned rather than the current working directory on execution. +.It Fl j Ar file +JSON file to log actions taken and metadata into, intended to be used by other programs. +.It Fl n +Scan the files but do not actually delete them. .El .Sh EXIT STATUS The diff --git a/main.ha b/main.ha @@ -1,6 +1,7 @@ // Copyright © 2019 deblob Authors <https://hacktivis.me/projects/deblob> // SPDX-License-Identifier: BSD-3-Clause use bytes; +use encoding::json; use endian; use errors; use fmt; @@ -15,6 +16,7 @@ use strings; let excludes: []str = []; let noop: bool = false; let check: bool = false; +let json: bool = false; const beam: []u8 = ['F', 'O', 'R', '1']; // Erlang BEAM const magic: [_](str, []u8) = [ @@ -87,6 +89,7 @@ const jar: []u8 = [0xFE, 0xCA, 0, 0]; const shebang: []u8 = ['#', '!']; let found: bool = false; +let json_out: io::handle = 0; fn id_blob(filename: str) (void | str | fs::error | io::error) = { static let buffer: [4096]u8 = [0...]; @@ -267,6 +270,33 @@ fn is_excluded(filename: str) bool = { return false; }; +fn append_action(action: str, filename: str, format: str) void = { + if(!json) return; + + let obj = json::object { ... }; + + json::put(&obj, "action", action); + defer json::take(&obj, "action"); + json::put(&obj, "path", filename); + defer json::take(&obj, "path"); + json::put(&obj, "format", format); + defer json::take(&obj, "format"); + + let obj_s = json::dumpstr(obj); + defer free(obj_s); + + static let first_obj: bool = true; + if(first_obj) + { + fmt::fprintf(json_out, "\n\t{}", obj_s)!; + first_obj = false; + } + else + { + fmt::fprintf(json_out, ",\n\t{}", obj_s)!; + }; +}; + fn check_dir(dirname: str) (void | errors::invalid | io::error) = { const iter = match (os::iter(dirname)) { case let iter: *fs::iterator => @@ -310,6 +340,7 @@ fn check_dir(dirname: str) (void | errors::invalid | io::error) = { }; if (is_excluded(filename)) { + append_action("ignoring", filename, blob_id); fmt::printfln("ignoring {}:\t{}", blob_id, filename)!; continue; }; @@ -317,10 +348,12 @@ fn check_dir(dirname: str) (void | errors::invalid | io::error) = { found = true; if (noop) { + append_action("detected", filename, blob_id); fmt::printfln("detected {}:\t{}", blob_id, filename)!; continue; }; + append_action("removing", filename, blob_id); fmt::printfln("removing {}:\t{}", blob_id, filename)!; match (os::remove(filename)) { @@ -366,12 +399,14 @@ export fn main() void = { ('c', "Return error if any non-excluded blobs were found"), ('e', "NAME", "Exclude filename from removal (defaults to none)"), ('d', "PATH", "Set working directory (default to current dir)"), + ('j', "PATH", "JSON output file"), ('n', "No actual removal, only scan and log"), ); defer getopt::finish(&cmd); defer free(excludes); let opt_d = ""; + let json_out_path = ""; for (let i = 0z; i < len(cmd.opts); i += 1) { const opt = cmd.opts[i]; @@ -384,11 +419,25 @@ export fn main() void = { opt_d = opt.1; case 'n' => noop = true; + case 'j' => + json = true; + json_out_path = opt.1; case => fmt::fatalf("deblob: Unhandled option -{}", opt.0); }; }; + if(json_out_path != "") + { + json_out = match (os::create(json_out_path, fs::mode::USER_RW | fs::mode::GROUP_R | fs::mode::OTHER_R)) { + case let f: io::file => + yield f; + case let e: fs::error => + fmt::fatalf("deblob: error: Failed creating/opening file '{}' for JSON output: {}", json_out_path, fs::strerror(e)); + }; + + fmt::fprint(json_out, "[")!; + }; if(opt_d != "") { @@ -406,6 +455,18 @@ export fn main() void = { fmt::println(":: Done checking for blobs")!; + if(json_out_path != "") + { + fmt::fprint(json_out, "\n]")!; + + match(io::close(json_out)) { + case void => + void; + case let e: io::error => + fmt::fatalf("deblob: error: Failed closing JSON output file '{}': {}", json_out_path, io::strerror(e)); + }; + }; + match (ret) { case void => if(check && found) os::exit(2);