[Libguestfs] [PATCH] v2v: Fix RPM file owned test (RHBZ#1503958).

Pino Toscano ptoscano at redhat.com
Thu Oct 19 16:51:34 UTC 2017


On Thursday, 19 October 2017 13:08:38 CEST Richard W.M. Jones wrote:
> Linux.file_owner is not used by any other function, so remove it.
> 
> Linux.is_file_owned is only used when removing kmod-xenpv on old RHEL
> releases, and so is only required to work for RPM.
> 
> The old file_owner/is_file_owned functions were completely broken.
> This replaces them with a simpler, working implementation that only
> covers the narrow use case of removing kmod-xenpv non-owned
> directories.

To be precise: only the RPM implementation did not work on unowned
files.  The dpkg implementation, added as part of the work to support
Debian/Ubuntu guests in v2v, works in both the cases.

> diff --git a/v2v/linux.ml b/v2v/linux.ml
> index bc4af1ad2..d759bf7e6 100644
> --- a/v2v/linux.ml
> +++ b/v2v/linux.ml
> @@ -99,58 +99,26 @@ let file_list_of_package (g : Guestfs.guestfs) inspect app =
>      error (f_"don’t know how to get list of files from package using %s")
>        format
>  
> -let rec file_owner (g : G.guestfs) { i_package_format = package_format } path =
> +let is_file_owned (g : G.guestfs) { i_package_format = package_format } path =
>    match package_format with
> -  | "deb" ->
> -      (* With dpkg usually the directories are owned by all the packages
> -       * that install anything in them.  Also with multiarch the same
> -       * package is allowed (although with different architectures).
> -       * This function returns only one package in all the cases.
> -       *)
> -      let cmd = [| "dpkg"; "-S"; path |] in
> -      debug "%s" (String.concat " " (Array.to_list cmd));
> -      let lines =
> -        try g#command_lines cmd
> -        with Guestfs.Error msg as exn ->
> -          if String.find msg "no path found matching pattern" >= 0 then
> -            raise Not_found
> -          else
> -            raise exn in
> -      if Array.length lines = 0 then
> -        error (f_"internal error: file_owner: dpkg command returned no output");
> -      let line = lines.(0) in
> -      let line =
> -        try String.sub line 0 (String.rindex line ':')
> -        with Invalid_argument _ ->
> -          error (f_"internal error: file_owner: invalid dpkg output: ‘%s’")
> -                line in
> -      fst (String.split "," line)
> -

I'd still leave the dpkg implementation, since code in v2v is not
specific to RPM-based systems.  It can be slightly simplified:

  let cmd = [| "dpkg"; "-S"; path |] in
  debug "%s" (String.concat " " (Array.to_list cmd));
  let lines =
    try g#command_lines cmd
    with Guestfs.Error msg as exn ->
      if String.find msg "no path found matching pattern" >= 0 then
        false
      else
        raise exn in
  if Array.length lines = 0 then
    error (f_"internal error: file_owner: dpkg command returned no output")
  else
    true

>    | "rpm" ->
> -      (* Although it is possible in RPM for multiple packages to own
> -       * a file, this deliberately only returns one package.
> -       *)
> -      let cmd = [| "rpm"; "-qf"; "--qf"; "%{NAME}\\n"; path |] in
> -      debug "%s" (String.concat " " (Array.to_list cmd));
> -      (try
> -         let pkgs = g#command_lines cmd in
> -         pkgs.(0)
> -       with Guestfs.Error msg as exn ->
> -         if String.find msg "is not owned" >= 0 then
> -           raise Not_found
> -         else
> -           raise exn
> -       | Invalid_argument _ (* pkgs.(0) raises index out of bounds *) ->
> -         error (f_"internal error: file_owner: rpm command returned no output")
> -      )
> +     (* Run rpm -qf and print a magic string if the file is owned.
> +      * If not owned, rpm will print "... is not owned by any package"
> +      * and exit with an error.  Unfortunately the string is sent to
> +      * stdout, so here we ignore the exit status of rpm and just
> +      * look for one of the two strings.
> +      *)
> +     let magic = "FILE_OWNED_TEST" in
> +     let cmd = sprintf "rpm -qf --qf %s %s 2>&1 ||:"
> +                       (quote (magic ^ "\n")) (quote path) in
> +     let r = g#sh cmd in
> +     if String.find r magic >= 0 then true
> +     else if String.find r "is not owned" >= 0 then false
> +     else failwithf "RPM file owned test failed: %s" r

Another option could be redirecting stdout to stderr, and assuming
that a successful run means the file is owned.  Something like the
following untested:

  let cmd = sprintf "rpm -qf --qf FOUND %s >&2" (quote path) in
  debug "%s" cmd;
  (try
     ignore (g#sh cmd);
     true
   with Guestfs.Error msg as exn ->
     if String.find msg "is not owned" >= 0 then
       false
     else
       raise exn
  )

This way, we do not need to ignore the RPM return value in all the
cases, and just let it raise the exception.

-- 
Pino Toscano
-------------- next part --------------
A non-text attachment was scrubbed...
Name: signature.asc
Type: application/pgp-signature
Size: 833 bytes
Desc: This is a digitally signed message part.
URL: <http://listman.redhat.com/archives/libguestfs/attachments/20171019/95a4502e/attachment.sig>


More information about the Libguestfs mailing list