Skip to content

Commit 45c0961

Browse files
peffgitster
authored andcommitted
run_command(): handle missing command errors more gracefully
When run_command() was asked to run a non-existant command, its behavior varied depending on the platform: - on POSIX systems, we would fork, and then after the execvp call failed, we could call die(), which prints a message to stderr and exits with code 128. - on Windows, we do a PATH lookup, realize the program isn't there, and then return ERR_RUN_COMMAND_FORK The goal of this patch is to make it clear to callers that the specific error was a missing command. To do this, we will return the error code ERR_RUN_COMMAND_EXEC, which is already defined in run-command.h, checked for in several places, but never actually gets set. The new behavior is: - on POSIX systems, we exit the forked process with code 127 (the same as the shell uses to report missing commands). The parent process recognizes this code and returns an EXEC error. The stderr message is silenced, since the caller may be speculatively trying to run a command. Instead, we use trace_printf so that somebody interested in debugging can see the error that occured. - on Windows, we check errno, which is already set correctly by mingw_spawnvpe, and report an EXEC error instead of a FORK error Thus it is safe to speculatively run a command: int r = run_command_v_opt(argv, 0); if (r == -ERR_RUN_COMMAND_EXEC) /* oops, it wasn't found; try something else */ else /* we failed for some other reason, error is in r */ Signed-off-by: Jeff King <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent f172f33 commit 45c0961

File tree

1 file changed

+14
-4
lines changed

1 file changed

+14
-4
lines changed

run-command.c

Lines changed: 14 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -118,7 +118,9 @@ int start_command(struct child_process *cmd)
118118
} else {
119119
execvp(cmd->argv[0], (char *const*) cmd->argv);
120120
}
121-
die("exec %s failed.", cmd->argv[0]);
121+
trace_printf("trace: exec '%s' failed: %s\n", cmd->argv[0],
122+
strerror(errno));
123+
exit(127);
122124
}
123125
#else
124126
int s0 = -1, s1 = -1, s2 = -1; /* backups of stdin, stdout, stderr */
@@ -187,6 +189,7 @@ int start_command(struct child_process *cmd)
187189
#endif
188190

189191
if (cmd->pid < 0) {
192+
int err = errno;
190193
if (need_in)
191194
close_pair(fdin);
192195
else if (cmd->in)
@@ -197,7 +200,9 @@ int start_command(struct child_process *cmd)
197200
close(cmd->out);
198201
if (need_err)
199202
close_pair(fderr);
200-
return -ERR_RUN_COMMAND_FORK;
203+
return err == ENOENT ?
204+
-ERR_RUN_COMMAND_EXEC :
205+
-ERR_RUN_COMMAND_FORK;
201206
}
202207

203208
if (need_in)
@@ -236,9 +241,14 @@ static int wait_or_whine(pid_t pid)
236241
if (!WIFEXITED(status))
237242
return -ERR_RUN_COMMAND_WAITPID_NOEXIT;
238243
code = WEXITSTATUS(status);
239-
if (code)
244+
switch (code) {
245+
case 127:
246+
return -ERR_RUN_COMMAND_EXEC;
247+
case 0:
248+
return 0;
249+
default:
240250
return -code;
241-
return 0;
251+
}
242252
}
243253
}
244254

0 commit comments

Comments
 (0)