2
2
//!
3
3
//! Command line tool to manage bootable ostree-based containers.
4
4
5
- use std:: ffi:: CString ;
6
- use std:: ffi:: OsString ;
5
+ use std:: ffi:: { CString , OsStr , OsString } ;
7
6
use std:: io:: Seek ;
8
7
use std:: os:: unix:: process:: CommandExt ;
9
8
use std:: process:: Command ;
@@ -879,6 +878,18 @@ where
879
878
run_from_opt ( Opt :: parse_including_static ( args) ) . await
880
879
}
881
880
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
+
882
893
impl Opt {
883
894
/// In some cases (e.g. systemd generator) we dispatch specifically on argv0. This
884
895
/// requires some special handling in clap.
@@ -890,9 +901,9 @@ impl Opt {
890
901
let mut args = args. into_iter ( ) ;
891
902
let first = if let Some ( first) = args. next ( ) {
892
903
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 ) ;
894
905
tracing:: debug!( "argv0={argv0:?}" ) ;
895
- if matches ! ( argv0, Some ( InternalsOpts :: GENERATOR_BIN ) ) {
906
+ if argv0 == InternalsOpts :: GENERATOR_BIN {
896
907
let base_args = [ "bootc" , "internals" , "systemd-generator" ]
897
908
. into_iter ( )
898
909
. map ( OsString :: from) ;
@@ -1022,6 +1033,41 @@ async fn run_from_opt(opt: Opt) -> Result<()> {
1022
1033
}
1023
1034
}
1024
1035
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
+
1025
1071
#[ test]
1026
1072
fn test_parse_install_args ( ) {
1027
1073
// Verify we still process the legacy --target-no-signature-verification
0 commit comments