Skip to content

Commit a9dc522

Browse files
committed
cli: Factor out helper to parse "callname"
No functional changes; prep for further work. Signed-off-by: Colin Walters <[email protected]>
1 parent 7c8121a commit a9dc522

File tree

1 file changed

+50
-4
lines changed

1 file changed

+50
-4
lines changed

lib/src/cli.rs

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,8 +2,7 @@
22
//!
33
//! Command line tool to manage bootable ostree-based containers.
44
5-
use std::ffi::CString;
6-
use std::ffi::OsString;
5+
use std::ffi::{CString, OsStr, OsString};
76
use std::io::Seek;
87
use std::os::unix::process::CommandExt;
98
use std::process::Command;
@@ -879,6 +878,18 @@ where
879878
run_from_opt(Opt::parse_including_static(args)).await
880879
}
881880

881+
/// Find the base binary name from argv0 (without a full path). The empty string
882+
/// is never returned; instead a fallback string is used. If the input is not valid
883+
/// UTF-8, a default is used.
884+
fn callname_from_argv0(argv0: &OsStr) -> &str {
885+
let default = "bootc";
886+
std::path::Path::new(argv0)
887+
.file_name()
888+
.and_then(|s| s.to_str())
889+
.filter(|s| !s.is_empty())
890+
.unwrap_or(default)
891+
}
892+
882893
impl Opt {
883894
/// In some cases (e.g. systemd generator) we dispatch specifically on argv0. This
884895
/// requires some special handling in clap.
@@ -890,9 +901,9 @@ impl Opt {
890901
let mut args = args.into_iter();
891902
let first = if let Some(first) = args.next() {
892903
let first: OsString = first.into();
893-
let argv0 = first.to_str().and_then(|s| s.rsplit_once('/')).map(|s| s.1);
904+
let argv0 = callname_from_argv0(&first);
894905
tracing::debug!("argv0={argv0:?}");
895-
if matches!(argv0, Some(InternalsOpts::GENERATOR_BIN)) {
906+
if argv0 == InternalsOpts::GENERATOR_BIN {
896907
let base_args = ["bootc", "internals", "systemd-generator"]
897908
.into_iter()
898909
.map(OsString::from);
@@ -1022,6 +1033,41 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
10221033
}
10231034
}
10241035

1036+
#[test]
1037+
fn test_callname() {
1038+
use std::os::unix::ffi::OsStrExt;
1039+
1040+
// Cases that change
1041+
let mapped_cases = [
1042+
("", "bootc"),
1043+
("/foo/bar", "bar"),
1044+
("/foo/bar/", "bar"),
1045+
("foo/bar", "bar"),
1046+
("../foo/bar", "bar"),
1047+
("usr/bin/ostree-container", "ostree-container"),
1048+
];
1049+
for (input, output) in mapped_cases {
1050+
assert_eq!(
1051+
output,
1052+
callname_from_argv0(OsStr::new(input)),
1053+
"Handling mapped case {input}"
1054+
);
1055+
}
1056+
1057+
// Invalid UTF-8
1058+
assert_eq!("bootc", callname_from_argv0(OsStr::from_bytes(b"foo\x80")));
1059+
1060+
// Cases that are identical
1061+
let ident_cases = ["foo", "bootc"];
1062+
for case in ident_cases {
1063+
assert_eq!(
1064+
case,
1065+
callname_from_argv0(OsStr::new(case)),
1066+
"Handling ident case {case}"
1067+
);
1068+
}
1069+
}
1070+
10251071
#[test]
10261072
fn test_parse_install_args() {
10271073
// Verify we still process the legacy --target-no-signature-verification

0 commit comments

Comments
 (0)