[Libguestfs] [PATCH 3/4] common/mltools: allow fd for machine readable output

Richard W.M. Jones rjones at redhat.com
Mon Mar 25 14:08:59 UTC 2019


On Fri, Mar 22, 2019 at 04:33:42PM +0100, Pino Toscano wrote:
> Allow to specify a file descriptor for the machine readable output.
> 
> Sadly, the OCaml C glue for the channels is not public API, so enable
> the internals for this...
> ---
>  common/mltools/tools_utils-c.c | 17 +++++++++++++++++
>  common/mltools/tools_utils.ml  | 10 +++++++++-
>  lib/guestfs.pod                |  5 +++++
>  3 files changed, 31 insertions(+), 1 deletion(-)
> 
> diff --git a/common/mltools/tools_utils-c.c b/common/mltools/tools_utils-c.c
> index c88c95082..553aa6631 100644
> --- a/common/mltools/tools_utils-c.c
> +++ b/common/mltools/tools_utils-c.c
> @@ -29,6 +29,9 @@
>  #include <caml/memory.h>
>  #include <caml/mlvalues.h>
>  #include <caml/unixsupport.h>
> +/* Evil ... */
> +#define CAML_INTERNALS
> +#include <caml/io.h>

I think this is not necessary.  On Unix-like platforms,
Unix.file_descr is really just an int, so you can cast between the two
using Val_int/Int_val (from C) or Obj.magic (from OCaml).  Note we
already rely on this in libguestfs, in
v2v/qemuopts-c.c:guestfs_int_qemuopts_to_chan

So I think this should work:

  | Fd of Unix.file_descr

...

  | Fd fd -> Some (Unix.out_channel_of_descr fd)

...

  | "fd" ->
    machine_readable_output := Fd (Obj.magic (int_of_string outname))

If you don't want to use Obj.magic, then something using /dev/fd/<N>
is another possibility.

Rich.

>  
>  #include <guestfs.h>
>  
> @@ -37,6 +40,7 @@
>  extern value guestfs_int_mllib_inspect_decrypt (value gv, value gpv, value keysv);
>  extern value guestfs_int_mllib_set_echo_keys (value unitv);
>  extern value guestfs_int_mllib_set_keys_from_stdin (value unitv);
> +extern value guestfs_int_mllib_open_out_channel_from_fd (value fdv);
>  
>  /* Interface with the guestfish inspection and decryption code. */
>  int echo_keys = 0;
> @@ -103,3 +107,16 @@ guestfs_int_mllib_set_keys_from_stdin (value unitv)
>    keys_from_stdin = 1;
>    return Val_unit;
>  }
> +
> +value
> +guestfs_int_mllib_open_out_channel_from_fd (value fdv)
> +{
> +  CAMLparam1 (fdv);
> +  struct channel *chan;
> +
> +  chan = caml_open_descriptor_out (Int_val (fdv));
> +  if (!chan)
> +    caml_raise_out_of_memory ();
> +
> +  CAMLreturn (caml_alloc_channel (chan));
> +}
> diff --git a/common/mltools/tools_utils.ml b/common/mltools/tools_utils.ml
> index ade4cb37f..3c54cd4a0 100644
> --- a/common/mltools/tools_utils.ml
> +++ b/common/mltools/tools_utils.ml
> @@ -32,6 +32,7 @@ and key_store_key =
>  external c_inspect_decrypt : Guestfs.t -> int64 -> (string * key_store_key) list -> unit = "guestfs_int_mllib_inspect_decrypt"
>  external c_set_echo_keys : unit -> unit = "guestfs_int_mllib_set_echo_keys" "noalloc"
>  external c_set_keys_from_stdin : unit -> unit = "guestfs_int_mllib_set_keys_from_stdin" "noalloc"
> +external c_out_channel_from_fd : int -> out_channel = "guestfs_int_mllib_open_out_channel_from_fd"
>  
>  type machine_readable_fn = {
>    pr : 'a. ('a, unit, string, unit) format4 -> 'a;
> @@ -41,6 +42,7 @@ type machine_readable_output_type =
>    | NoOutput
>    | Channel of out_channel
>    | File of string
> +  | Fd of int
>  let machine_readable_output = ref NoOutput
>  let machine_readable_channel = ref None
>  let machine_readable () =
> @@ -50,7 +52,8 @@ let machine_readable () =
>          match !machine_readable_output with
>          | NoOutput -> None
>          | Channel chan -> Some chan
> -        | File f -> Some (open_out f) in
> +        | File f -> Some (open_out f)
> +        | Fd fd -> Some (c_out_channel_from_fd fd) in
>        machine_readable_channel := chan
>      );
>      !machine_readable_channel
> @@ -296,6 +299,11 @@ let create_standard_options argspec ?anon_fun ?(key_opts = false) ?(machine_read
>            | n ->
>              error (f_"invalid output stream for --machine-readable: %s") fmt in
>          machine_readable_output := Channel chan
> +      | "fd" ->
> +        (try
> +          machine_readable_output := Fd (int_of_string outname)
> +        with Failure _ ->
> +          error (f_"invalid output fd for --machine-readable: %s") fmt)
>        | n ->
>          error (f_"invalid output for --machine-readable: %s") fmt
>        )
> diff --git a/lib/guestfs.pod b/lib/guestfs.pod
> index 53cece2da..f11028466 100644
> --- a/lib/guestfs.pod
> +++ b/lib/guestfs.pod
> @@ -3287,6 +3287,11 @@ The possible values are:
>  
>  =over 4
>  
> +=item B<fd:>I<fd>
> +
> +The output goes to the specified I<fd>, which is a file descriptor
> +already opened for writing.
> +
>  =item B<file:>F<filename>
>  
>  The output goes to the specified F<filename>.
> -- 
> 2.20.1
> 
> _______________________________________________
> Libguestfs mailing list
> Libguestfs at redhat.com
> https://www.redhat.com/mailman/listinfo/libguestfs

-- 
Richard Jones, Virtualization Group, Red Hat http://people.redhat.com/~rjones
Read my programming and virtualization blog: http://rwmj.wordpress.com
virt-df lists disk usage of guests without needing to install any
software inside the virtual machine.  Supports Linux and Windows.
http://people.redhat.com/~rjones/virt-df/




More information about the Libguestfs mailing list