[Libguestfs] [PATCH] mllib: check for executable existance in run_command (RHBZ#1362357)

Pino Toscano
Tue, 02 Aug 2016 17:14:09 -0000

run_command uses Unix.create_process which forks a child process, and
executes execve: the latter fails when the executable does not exist,
triggering the exit which, in older OCaml versions [1], also runs the
at_exit handlers.

Since there is not much that can be done to avoid this on the OCaml
side, to keep run_command working also in older OCaml version then
manually search for the existance of the given executable, exiting with
code 127 (as a shell does) in this case.

[1] http://caml.inria.fr/mantis/view.php?id=7209
---
 mllib/common_utils.ml | 32 ++++++++++++++++++++------------
 1 file changed, 20 insertions(+), 12 deletions(-)

diff --git a/mllib/common_utils.ml b/mllib/common_utils.ml
index 14f4935..fdca713 100644
--- a/mllib/common_utils.ml
+++ b/mllib/common_utils.ml
@@ -677,18 +677,26 @@ let external_command ?(echo_cmd = true) cmd  let
run_command ?(echo_cmd = true) args    if echo_cmd then
     debug "%s" (stringify_args args);
-  let pid -    Unix.create_process (List.hd args) (Array.of_list args)
Unix.stdin
-      Unix.stdout Unix.stderr in
-  let _, stat = Unix.waitpid [] pid in
-  match stat with
-  | Unix.WEXITED i -> i
-  | Unix.WSIGNALED i ->
-    error (f_"external command '%s' killed by signal %d")
-      (stringify_args args) i
-  | Unix.WSTOPPED i ->
-    error (f_"external command '%s' stopped by signal %d")
-      (stringify_args args) i
+  let app = List.hd args in
+  try
+    let app +      if Filename.is_relative app then which app
+      else (Unix.access app [Unix.X_OK]; app) in
+    let pid +      Unix.create_process app (Array.of_list args) Unix.stdin
+        Unix.stdout Unix.stderr in
+    let _, stat = Unix.waitpid [] pid in
+    match stat with
+    | Unix.WEXITED i -> i
+    | Unix.WSIGNALED i ->
+      error (f_"external command '%s' killed by signal %d")
+        (stringify_args args) i
+    | Unix.WSTOPPED i ->
+      error (f_"external command '%s' stopped by signal %d")
+        (stringify_args args) i
+  with
+  | Executable_not_found tool -> 127
+  | Unix.Unix_error (errcode, _, _) when errcode = Unix.ENOENT -> 127

 let shell_command ?(echo_cmd = true) cmd    if echo_cmd then
--
2.7.4