@@ -27,7 +27,7 @@ use std::path::{Path, PathBuf};
2727fn main ( ) -> Result < ( ) > {
2828 env_logger:: init ( ) ;
2929 // Find out what is the executable name the execution was started with
30- let executable = std :: env :: args ( ) . next ( ) . unwrap ( ) ;
30+ let executable = file_name_from_arguments ( ) ? ;
3131 log:: info!( "Executable as called: {:?}" , executable) ;
3232 // Read the PATH variable and find the next executable with the same name
3333 let real_executable = next_in_path ( & executable) ?;
@@ -48,19 +48,43 @@ fn main() -> Result<()> {
4848 std:: process:: exit ( status. code ( ) . unwrap_or ( 1 ) ) ;
4949}
5050
51+ /// Get the file name of the executable from the arguments.
52+ ///
53+ /// Since the executable will be called via soft link, the first argument
54+ /// will be the name of the soft link. This function returns the file name
55+ /// of the soft link.
56+ fn file_name_from_arguments ( ) -> Result < PathBuf > {
57+ std:: env:: args ( ) . next ( )
58+ . ok_or_else ( || anyhow:: anyhow!( "Cannot get first argument" ) )
59+ . and_then ( |arg| match PathBuf :: from ( arg) . file_name ( ) {
60+ Some ( file_name) => Ok ( PathBuf :: from ( file_name) ) ,
61+ None => Err ( anyhow:: anyhow!( "Cannot get the file name from the argument" ) ) ,
62+ } )
63+ }
64+
5165/// Find the next executable in the PATH variable.
5266///
5367/// The function reads the PATH variable and tries to find the next executable
5468/// with the same name as the given executable. It returns the path to the
5569/// executable.
56- fn next_in_path ( executable : & String ) -> Result < PathBuf > {
70+ fn next_in_path ( target : & Path ) -> Result < PathBuf > {
5771 let path = std:: env:: var ( "PATH" ) ?;
72+ log:: debug!( "PATH: {}" , path) ;
73+ // The `current_exe` is a canonical path to the current executable.
5874 let current_exe = std:: env:: current_exe ( ) ?;
5975
6076 path. split ( ':' )
61- . map ( |dir| Path :: new ( dir) . join ( & executable) )
62- . filter ( |path| path. is_file ( ) ) // TODO: check if it is executable
63- . filter ( |path| path != & current_exe)
77+ . map ( |dir| Path :: new ( dir) . join ( target) )
78+ . filter ( |path| path. is_file ( ) ) // TODO: check if it is executable
79+ . filter ( |path| {
80+ // We need to compare it with the real path of the candidate executable to avoid
81+ // calling the same executable again.
82+ let real_path = match path. canonicalize ( ) {
83+ Ok ( path) => path,
84+ Err ( _) => return false ,
85+ } ;
86+ real_path != current_exe
87+ } )
6488 . nth ( 0 )
6589 . ok_or_else ( || anyhow:: anyhow!( "Cannot find the real executable" ) )
6690}
0 commit comments