When searching for an executable to run, Unix shells check every directory on PATH and stop at the first matching executable found. GNAT.OS_Lib.Locate_Exec_On_Path, however, returned the first matching regular file, even if it wasn't executable. As a result, when an executable tries to find where it is run from, we could end up with a discrepency.
To test the issue: create two directories bin1 and bin2. The first one should contain a non-executable "exec" file, the second should contain the result of compiling the following program. Add the directories in that order on the PATH, and run "exec" from the command line. The Unix shell will execute the one from bin2/ (since the one in bin1/ is not executable), and the result of the execution should show that the file was executed from bin2/ with GNAT.OS_Lib; use GNAT.OS_Lib; with Ada.Text_IO; use Ada.Text_IO; procedure Exec is begin Put_Line ("Installed in " & Locate_Exec_On_Path ("exec").all); end Exec; Tested on x86_64-pc-linux-gnu, committed on trunk 2011-08-02 Emmanuel Briot <br...@adacore.com> * adaint.c (__gnat_locate_exec_on_path): only returns executable files, not any regular file. (__gnat_locate_file_with_predicate): new subprogram.
Index: adaint.c =================================================================== --- adaint.c (revision 177121) +++ adaint.c (working copy) @@ -2700,10 +2700,11 @@ exit (status); } -/* Locate a regular file, give a Path value. */ +/* Locate file on path, that matches a predicate */ char * -__gnat_locate_regular_file (char *file_name, char *path_val) +__gnat_locate_file_with_predicate + (char *file_name, char *path_val, int (*predicate)(char*)) { char *ptr; char *file_path = (char *) alloca (strlen (file_name) + 1); @@ -2733,7 +2734,7 @@ if (absolute) { - if (__gnat_is_regular_file (file_path)) + if (predicate (file_path)) return xstrdup (file_path); return 0; @@ -2746,7 +2747,7 @@ if (*ptr != 0) { - if (__gnat_is_regular_file (file_name)) + if (predicate (file_name)) return xstrdup (file_name); } @@ -2787,7 +2788,7 @@ strcpy (++ptr, file_name); - if (__gnat_is_regular_file (file_path)) + if (predicate (file_path)) return xstrdup (file_path); if (*path_val == 0) @@ -2802,6 +2803,24 @@ return 0; } +/* Locate an executable file, give a Path value. */ + +char * +__gnat_locate_executable_file (char *file_name, char *path_val) +{ + return __gnat_locate_file_with_predicate + (file_name, path_val, &__gnat_is_executable_file); +} + +/* Locate a regular file, give a Path value. */ + +char * +__gnat_locate_regular_file (char *file_name, char *path_val) +{ + return __gnat_locate_file_with_predicate + (file_name, path_val, &__gnat_is_regular_file); +} + /* Locate an executable given a Path argument. This routine is only used by gnatbl and should not be used otherwise. Use locate_exec_on_path instead. */ @@ -2818,14 +2837,14 @@ strcpy (full_exec_name, exec_name); strcat (full_exec_name, HOST_EXECUTABLE_SUFFIX); - ptr = __gnat_locate_regular_file (full_exec_name, path_val); + ptr = __gnat_locate_executable_file (full_exec_name, path_val); if (ptr == 0) - return __gnat_locate_regular_file (exec_name, path_val); + return __gnat_locate_executable_file (exec_name, path_val); return ptr; } else - return __gnat_locate_regular_file (exec_name, path_val); + return __gnat_locate_executable_file (exec_name, path_val); } /* Locate an executable using the Systems default PATH. */