From 9a8246e91ac0fa38d96691dc6025cb8b117f9cb2 Mon Sep 17 00:00:00 2001 From: Pino Toscano Date: Mon, 4 May 2020 15:14:46 +0200 Subject: [PATCH] mltools: add run_in_guest_command helper Add an helper function to run a command in the guest, checking for the host/guest compatibility. This is mostly extracted from the internal do_run helper currently in the Customize_run module of virt-customize. (cherry picked from commit e73eca3b73f7d0a54615c5dc55eadd09dc170035 in libguestfs-common) --- common/mltools/tools_utils.ml | 50 ++++++++++++++++++++++++++++++++++ common/mltools/tools_utils.mli | 10 +++++++ 2 files changed, 60 insertions(+) diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml index 127180225..d54ec581e 100644 --- a/common/mltools/tools_utils.ml +++ b/common/mltools/tools_utils.ml @@ -679,3 +679,53 @@ let with_timeout op timeout ?(sleep = 2) fn = loop () in loop () + +let run_in_guest_command g root ?logfile ?incompatible_fn cmd = + (* Is the host_cpu compatible with the guest arch? ie. Can we + * run commands in this guest? + *) + let guest_arch = g#inspect_get_arch root in + let guest_arch_compatible = guest_arch_compatible guest_arch in + if not guest_arch_compatible then ( + match incompatible_fn with + | None -> () + | Some fn -> fn () + ) + else ( + (* Add a prologue to the scripts: + * - Pass environment variables through from the host. + * - Optionally send stdout and stderr to a log file so we capture + * all output in error messages. + * - Use setarch when running x86_64 host + i686 guest. + *) + let env_vars = + List.filter_map ( + fun name -> + try Some (sprintf "export %s=%s" name (quote (Sys.getenv name))) + with Not_found -> None + ) [ "http_proxy"; "https_proxy"; "ftp_proxy"; "no_proxy" ] in + let env_vars = String.concat "\n" env_vars ^ "\n" in + + let cmd = + match Guestfs_config.host_cpu, guest_arch with + | "x86_64", ("i386"|"i486"|"i586"|"i686") -> + sprintf "setarch i686 <<\"__EOCMD\" +%s +__EOCMD +" cmd + | _ -> cmd in + + let logfile_redirect = + match logfile with + | None -> "" + | Some logfile -> sprintf "exec >>%s 2>&1" (quote logfile) in + + let cmd = sprintf "\ +%s +%s +%s +" (logfile_redirect) env_vars cmd in + + debug "running command:\n%s" cmd; + ignore (g#sh cmd) + ) diff --git a/common/mltools/tools_utils.mli b/common/mltools/tools_utils.mli index ab70f583e..102abff4d 100644 --- a/common/mltools/tools_utils.mli +++ b/common/mltools/tools_utils.mli @@ -212,3 +212,13 @@ val with_timeout : string -> int -> ?sleep:int -> (unit -> 'a option) -> 'a calls {!error} and the program exits. The error message will contain the diagnostic string [op] to identify the operation which timed out. *) + +val run_in_guest_command : Guestfs.guestfs -> string -> ?logfile:string -> ?incompatible_fn:(unit -> unit) -> string -> unit +(** [run_in_guest_command g root ?incompatible_archs_fn cmd] + runs a command in the guest, which is already mounted for the + specified [root]. The command is run directly in case the + architecture of the host and the guest are compatible, optionally + calling [?incompatible_fn] in case they are not. + + [?logfile] is an optional file in the guest to where redirect + stdout and stderr of the command. *) -- 2.18.4