[Libguestfs] [libguestfs-common PATCH 2/2] options/keys: introduce unescape_device_mapper_lvm()

Richard W.M. Jones rjones at redhat.com
Tue May 16 12:17:42 UTC 2023


On Mon, May 15, 2023 at 07:49:24PM +0200, Laszlo Ersek wrote:
> Introduce unescape_device_mapper_lvm() for turning
> 
>   /dev/mapper/VG-LV
> 
> key IDs into
> 
>   /dev/VG/LV
> 
> ones, unescaping doubled hyphens to single hyphens in both VG and LV in
> the process. Libguestfs uses the /dev/VG/LV format internally, for
> identifying devices, but the user might want to specify the
> /dev/mapper/VG-LV ID format with the "--key ID:..." options.
> 
> Call unescape_device_mapper_lvm() from key_store_import_key(). That is,
> translate the ID as soon as the "--key" option is processed -- let the
> keystore only know about the usual /dev/VG/LV format, for later matching.
> 
> Bugzilla: https://bugzilla.redhat.com/show_bug.cgi?id=2168506
> Signed-off-by: Laszlo Ersek <lersek at redhat.com>
> ---
> 
> Notes:
>     regcomp() must definitely allocate memory dynamically, and we
>     (intentionally) never free that -- we never call regfree(). I assume
>     valgrind will catch this as a leak, so we might have to extend
>     "valgrind-suppressions" in each dependent superproject. However, I'm
>     unable to run "make check-valgrind" successfully in e.g. virt-v2v even
>     before these patches; see also
>     <https://listman.redhat.com/archives/libguestfs/2023-May/031496.html>.
> 
>  options/keys.c | 86 ++++++++++++++++++++
>  1 file changed, 86 insertions(+)
> 
> diff --git a/options/keys.c b/options/keys.c
> index bc7459749276..f0164a6ed987 100644
> --- a/options/keys.c
> +++ b/options/keys.c
> @@ -27,6 +27,7 @@
>  #include <errno.h>
>  #include <error.h>
>  #include <assert.h>
> +#include <regex.h>
>  
>  #include "guestfs.h"
>  
> @@ -260,6 +261,90 @@ key_store_add_from_selector (struct key_store *ks, const char *selector)
>    return key_store_import_key (ks, &key);
>  }
>  
> +/* A /dev/mapper/ escaped character is:
> + * - either any character except a slash or a hyphen,
> + * - or a double hyphen.
> + *
> + * Note that parens are deliberately not included here -- they will be included
> + * in the full pattern, for making them more easily countable.
> + *
> + * Also note that the bracket expression below does not contain a range
> + * expression, therefore it should not be locale-sensitive.
> + */
> +#define ESC_CH "[^-/]|--"
> +
> +/* Turn /dev/mapper/VG-LV into /dev/VG/LV. */
> +static void
> +unescape_device_mapper_lvm (char *id)
> +{
> +  static bool compiled;
> +  int rc;
> +  static regex_t regex;
> +  regmatch_t match[5];
> +  char *output;
> +  const char *vg_start, *vg_end, *lv_start, *lv_end;
> +  const char *input;
> +
> +  if (!compiled) {
> +    /* Recognize /dev/mapper/VG-LV pathnames, where VG and LV don't contain
> +     * slashes, plus any original hyphens in them are doubled for escaping.
> +     */
> +    static const char pattern[] = "^/dev/("
> +                                    "mapper/"
> +                                    "((" ESC_CH ")+)"
> +                                    "-"
> +                                    "((" ESC_CH ")+)"
> +                                  ")$";
> +
> +    rc = regcomp (&regex, pattern, REG_EXTENDED);
> +    if (rc != 0) {
> +      char errbuf[256];
> +
> +      /* When regcomp() fails, the contents of "regex" are undefined, so we
> +       * cannot pass "regex" to regerror().
> +       */
> +      (void)regerror (rc, NULL, errbuf, sizeof errbuf);
> +      error (EXIT_FAILURE, 0,
> +             _("%s: Failed to compile pattern (%s).  Please report a bug for "
> +               "libguestfs -- refer to guestfs(3) section BUGS."),
> +             __func__, errbuf);
> +    }
> +    compiled = true;
> +  }

Any reason not to use PCRE and the COMPILE_REGEXP macro?

We also have macros like CLEANUP_PCRE2_MATCH_DATA_FREE to free match
data automaticaly.

In general PCRE regexps are a lot more usable than the POSIX stuff.

Rich.

> +  rc = regexec (&regex, id, 5, match, 0);
> +
> +  /* If there's no match, just leave "id" alone. */
> +  if (rc != 0)
> +    return;
> +
> +  /* Start outputting after "/dev/". */
> +  output   = id + match[1].rm_so;
> +  vg_start = id + match[2].rm_so;
> +  vg_end   = id + match[2].rm_eo;
> +  lv_start = id + match[4].rm_so;
> +  lv_end   = id + match[4].rm_eo;
> +
> +  /* Each of the following two loops produces at most as many bytes as it
> +   * consumes, so we unescape "id" in-place.
> +   */
> +  input = vg_start;
> +  while (input < vg_end)
> +    if ((*output++ = *input++) == '-')
> +      input++;
> +
> +  *output++ = '/';
> +
> +  input = lv_start;
> +  while (input < lv_end)
> +    if ((*output++ = *input++) == '-')
> +      input++;
> +
> +  *output++ = '\0';
> +}
> +
> +#undef ESC_CH
> +
>  struct key_store *
>  key_store_import_key (struct key_store *ks, struct key_store_key *key)
>  {
> @@ -278,6 +363,7 @@ key_store_import_key (struct key_store *ks, struct key_store_key *key)
>      error (EXIT_FAILURE, errno, "realloc");
>  
>    ks->keys = new_keys;
> +  unescape_device_mapper_lvm (key->id);
>    ks->keys[ks->nr_keys] = *key;
>    ++ks->nr_keys;
>  
> _______________________________________________
> Libguestfs mailing list
> Libguestfs at redhat.com
> https://listman.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
libguestfs lets you edit virtual machines.  Supports shell scripting,
bindings from many languages.  http://libguestfs.org


More information about the Libguestfs mailing list