@@ -76,6 +76,68 @@ static inline void dup_devnull(int to)
7676}
7777#endif
7878
79+ static char * locate_in_PATH (const char * file )
80+ {
81+ const char * p = getenv ("PATH" );
82+ struct strbuf buf = STRBUF_INIT ;
83+
84+ if (!p || !* p )
85+ return NULL ;
86+
87+ while (1 ) {
88+ const char * end = strchrnul (p , ':' );
89+
90+ strbuf_reset (& buf );
91+
92+ /* POSIX specifies an empty entry as the current directory. */
93+ if (end != p ) {
94+ strbuf_add (& buf , p , end - p );
95+ strbuf_addch (& buf , '/' );
96+ }
97+ strbuf_addstr (& buf , file );
98+
99+ if (!access (buf .buf , F_OK ))
100+ return strbuf_detach (& buf , NULL );
101+
102+ if (!* end )
103+ break ;
104+ p = end + 1 ;
105+ }
106+
107+ strbuf_release (& buf );
108+ return NULL ;
109+ }
110+
111+ static int exists_in_PATH (const char * file )
112+ {
113+ char * r = locate_in_PATH (file );
114+ free (r );
115+ return r != NULL ;
116+ }
117+
118+ int sane_execvp (const char * file , char * const argv [])
119+ {
120+ if (!execvp (file , argv ))
121+ return 0 ; /* cannot happen ;-) */
122+
123+ /*
124+ * When a command can't be found because one of the directories
125+ * listed in $PATH is unsearchable, execvp reports EACCES, but
126+ * careful usability testing (read: analysis of occasional bug
127+ * reports) reveals that "No such file or directory" is more
128+ * intuitive.
129+ *
130+ * We avoid commands with "/", because execvp will not do $PATH
131+ * lookups in that case.
132+ *
133+ * The reassignment of EACCES to errno looks like a no-op below,
134+ * but we need to protect against exists_in_PATH overwriting errno.
135+ */
136+ if (errno == EACCES && !strchr (file , '/' ))
137+ errno = exists_in_PATH (file ) ? EACCES : ENOENT ;
138+ return -1 ;
139+ }
140+
79141static const char * * prepare_shell_cmd (const char * * argv )
80142{
81143 int argc , nargc = 0 ;
@@ -114,7 +176,7 @@ static int execv_shell_cmd(const char **argv)
114176{
115177 const char * * nargv = prepare_shell_cmd (argv );
116178 trace_argv_printf (nargv , "trace: exec:" );
117- execvp (nargv [0 ], (char * * )nargv );
179+ sane_execvp (nargv [0 ], (char * * )nargv );
118180 free (nargv );
119181 return -1 ;
120182}
@@ -339,7 +401,7 @@ int start_command(struct child_process *cmd)
339401 } else if (cmd -> use_shell ) {
340402 execv_shell_cmd (cmd -> argv );
341403 } else {
342- execvp (cmd -> argv [0 ], (char * const * ) cmd -> argv );
404+ sane_execvp (cmd -> argv [0 ], (char * const * ) cmd -> argv );
343405 }
344406 if (errno == ENOENT ) {
345407 if (!cmd -> silent_exec_failure )
0 commit comments