11use clap:: Parser ;
22use std:: { fmt:: Display , io:: Write , path:: Path } ;
33
4- use crate :: { builtins, commands, error, shell, sys:: fs:: PathExt , ExecutionResult } ;
5-
6- /// The value for PATH when invoking `command -p`. This is only used when
7- /// the Posix.2 `confstr()` returns nothing
8- /// The value of this variable is taken from the BASH source code.
9- const STANDARD_UTILS_PATH : & [ & str ] = & [ "/bin" , "/usr/bin" , "/sbin" , "/usr/sbin" , "/etc:/usr/etc" ] ;
4+ use crate :: { builtins, commands, error, shell, sys, sys:: fs:: PathExt , ExecutionResult } ;
105
116/// Directly invokes an external command, without going through typical search order.
127#[ derive( Parser ) ]
@@ -67,7 +62,8 @@ impl builtins::Command for CommandCommand {
6762 Ok ( builtins:: ExitCode :: Custom ( 1 ) )
6863 }
6964 } else {
70- self . execute_command ( context, command_name) . await
65+ self . execute_command ( context, command_name, self . use_default_path )
66+ . await
7167 }
7268 } else {
7369 Ok ( builtins:: ExitCode :: Success )
@@ -118,34 +114,34 @@ impl CommandCommand {
118114 }
119115
120116 if use_default_path {
121- let path = confstr_path ( ) ;
122- // Without an allocation if possible.
123- let path = path. as_ref ( ) . map ( |p| String :: from_utf8_lossy ( p) ) ;
124- let path = path. as_ref ( ) . map_or (
125- itertools:: Either :: Right ( STANDARD_UTILS_PATH . iter ( ) . copied ( ) ) ,
126- |p| itertools:: Either :: Left ( p. split ( ':' ) ) ,
127- ) ;
128-
129- return shell
130- . find_executables_in ( path, command_name)
117+ let dirs = sys:: fs:: get_default_standard_utils_paths ( ) ;
118+ shell
119+ . find_executables_in ( dirs. iter ( ) , command_name)
131120 . first ( )
132- . map ( |path| FoundCommand :: External ( path. to_string_lossy ( ) . to_string ( ) ) ) ;
121+ . map ( |path| FoundCommand :: External ( path. to_string_lossy ( ) . to_string ( ) ) )
122+ } else {
123+ shell
124+ . find_first_executable_in_path_using_cache ( command_name)
125+ . map ( |path| FoundCommand :: External ( path. to_string_lossy ( ) . to_string ( ) ) )
133126 }
134-
135- shell
136- . find_first_executable_in_path_using_cache ( command_name)
137- . map ( |path| FoundCommand :: External ( path. to_string_lossy ( ) . to_string ( ) ) )
138127 }
139128 }
140129
141130 async fn execute_command (
142131 & self ,
143132 mut context : commands:: ExecutionContext < ' _ > ,
144133 command_name : & str ,
134+ use_default_path : bool ,
145135 ) -> Result < builtins:: ExitCode , error:: Error > {
146136 command_name. clone_into ( & mut context. command_name ) ;
147137 let command_and_args = self . command_and_args . iter ( ) . map ( |arg| arg. into ( ) ) . collect ( ) ;
148138
139+ let path_dirs = if use_default_path {
140+ Some ( sys:: fs:: get_default_standard_utils_paths ( ) )
141+ } else {
142+ None
143+ } ;
144+
149145 // We do not have an existing process group to place this into.
150146 let mut pgid = None ;
151147
@@ -156,6 +152,7 @@ impl CommandCommand {
156152 & mut pgid,
157153 command_and_args,
158154 false , /* use functions? */
155+ path_dirs,
159156 )
160157 . await ?
161158 {
@@ -177,38 +174,3 @@ impl CommandCommand {
177174 }
178175 }
179176}
180-
181- /// A wrapper for [`nix::libc::confstr`]. Returns a value for the default PATH variable which
182- /// indicates where all the POSIX.2 standard utilities can be found.
183- fn confstr_path ( ) -> Option < Vec < u8 > > {
184- #[ cfg( unix) ]
185- {
186- let required_size =
187- unsafe { nix:: libc:: confstr ( nix:: libc:: _CS_PATH, std:: ptr:: null_mut ( ) , 0 ) } ;
188- if required_size == 0 {
189- return None ;
190- }
191- // NOTE: Writing `c_char` (i8 or u8 depending on the platform) into `Vec<u8>` is fine,
192- // as i8 and u8 have compatible representations,
193- // and Rust does not support platforms where `c_char` is not 8-bit wide.
194- let mut buffer = Vec :: < u8 > :: with_capacity ( required_size) ;
195- let final_size = unsafe {
196- nix:: libc:: confstr (
197- nix:: libc:: _CS_PATH,
198- buffer. as_mut_ptr ( ) . cast ( ) ,
199- required_size,
200- )
201- } ;
202- if final_size == 0 {
203- return None ;
204- }
205- // ERANGE
206- if final_size > required_size {
207- return None ;
208- }
209- unsafe { buffer. set_len ( final_size - 1 ) } ; // The last byte is a null terminator.
210- return Some ( buffer) ;
211- }
212- #[ allow( unreachable_code) ]
213- None
214- }
0 commit comments