LVM recently broke filters (https://bugzilla.redhat.com/1957040) This fixes them using the new lvmdevices command.
Incidental to this change, the code is reimplemented in OCaml. Reported-by: Yongkui Guo Fixes: https://bugzilla.redhat.com/show_bug.cgi?id=1965941 --- .gitignore | 1 + daemon/Makefile.am | 3 +- daemon/lvm-filter.c | 243 -------------------------------------- daemon/lvm_filter.ml | 45 +++++++ docs/C_SOURCE_FILES | 1 - generator/actions_core.ml | 2 + generator/daemon.ml | 26 ++-- 7 files changed, 68 insertions(+), 253 deletions(-) diff --git a/.gitignore b/.gitignore index ebb67850c..3c28f4340 100644 --- a/.gitignore +++ b/.gitignore @@ -98,6 +98,7 @@ Makefile.in /daemon/listfs.mli /daemon/lvm.mli /daemon/lvm_dm.mli +/daemon/lvm_filter.mli /daemon/lvm-tokenization.c /daemon/md.mli /daemon/mount.mli diff --git a/daemon/Makefile.am b/daemon/Makefile.am index 6f13bd43c..5ceb4094d 100644 --- a/daemon/Makefile.am +++ b/daemon/Makefile.am @@ -150,7 +150,6 @@ guestfsd_SOURCES = \ ls.c \ luks.c \ lvm.c \ - lvm-filter.c \ lvm-tokenization.c \ md.c \ mkfs.c \ @@ -297,6 +296,7 @@ SOURCES_MLI = \ listfs.mli \ lvm.mli \ lvm_dm.mli \ + lvm_filter.mli \ lvm_utils.mli \ md.mli \ mount.mli \ @@ -332,6 +332,7 @@ SOURCES_ML = \ lvm.ml \ lvm_utils.ml \ lvm_dm.ml \ + lvm_filter.ml \ findfs.ml \ md.ml \ mount.ml \ diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c deleted file mode 100644 index c6dd35156..000000000 --- a/daemon/lvm-filter.c +++ /dev/null @@ -1,243 +0,0 @@ -/* libguestfs - the guestfsd daemon - * Copyright (C) 2010-2012 Red Hat Inc. - * - * This program is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. - */ - -#include <config.h> - -#include <stdio.h> -#include <stdlib.h> -#include <inttypes.h> -#include <string.h> -#include <unistd.h> -#include <errno.h> -#include <error.h> -#include <sys/stat.h> -#include <sys/wait.h> - -#include <augeas.h> - -#include "c-ctype.h" -#include "ignore-value.h" - -#include "daemon.h" -#include "actions.h" - -static void debug_lvm_config (void); - -/* Read LVM_SYSTEM_DIR environment variable, or set it to a default - * value if the environment variable is not set. - */ -static char *lvm_system_dir; -static void get_lvm_system_dir (void) __attribute__((constructor)); -static void free_lvm_system_dir (void) __attribute__((destructor)); - -static void -get_lvm_system_dir (void) -{ - const char *p; - - p = getenv ("LVM_SYSTEM_DIR"); - if (p) { - lvm_system_dir = strdup (p); - if (lvm_system_dir == NULL) abort (); - } - if (!lvm_system_dir) { - lvm_system_dir = strdup ("/etc/lvm"); - if (lvm_system_dir == NULL) abort (); - } - fprintf (stderr, "lvm_system_dir = %s\n", lvm_system_dir); -} - -static void -free_lvm_system_dir (void) -{ - free (lvm_system_dir); -} - -/* Rewrite the 'filter = [ ... ]' line in lvm.conf. */ -static int -set_filter (char *const *filters) -{ - const char *filter_types[] = { "filter", "global_filter", NULL }; - CLEANUP_FREE char *conf = NULL; - FILE *fp; - size_t i, j; - - if (asprintf (&conf, "%s/lvm.conf", lvm_system_dir) == -1) { - reply_with_perror ("asprintf"); - return -1; - } - fp = fopen (conf, "we"); - if (fp == NULL) { - reply_with_perror ("open: %s", conf); - return -1; - } - - fprintf (fp, "devices {\n"); - for (j = 0; filter_types[j] != NULL; ++j) { - fprintf (fp, " %s = [\n", filter_types[j]); - fprintf (fp, " "); - - for (i = 0; filters[i] != NULL; ++i) { - if (i > 0) - fprintf (fp, ",\n "); - fprintf (fp, "\"%s\"", filters[i]); - } - - fprintf (fp, "\n"); - fprintf (fp, " ]\n"); - } - fprintf (fp, "}\n"); - - fclose (fp); - - debug_lvm_config (); - - return 0; -} - -static int -vgchange (const char *vgchange_flag) -{ - CLEANUP_FREE char *err = NULL; - int r = command (NULL, &err, "lvm", "vgchange", vgchange_flag, NULL); - if (r == -1) { - reply_with_error ("vgchange %s: %s", vgchange_flag, err); - return -1; - } - - return 0; -} - -/* Deactivate all VGs. */ -static int -deactivate (void) -{ - return vgchange ("-an"); -} - -/* Reactivate all VGs. */ -static int -reactivate (void) -{ - return vgchange ("-ay"); -} - -/* Clear the cache and rescan. */ -static int -rescan (void) -{ - char lvm_cache[64]; - snprintf (lvm_cache, sizeof lvm_cache, "%s/cache/.cache", lvm_system_dir); - - unlink (lvm_cache); - - CLEANUP_FREE char *err = NULL; - int r = command (NULL, &err, "lvm", "vgscan", "--cache", NULL); - if (r == -1) { - reply_with_error ("vgscan: %s", err); - return -1; - } - - return 0; -} - -/* Show what lvm thinks is the current config. Useful for debugging. */ -static void -debug_lvm_config (void) -{ - if (verbose) { - fprintf (stderr, "lvm config:\n"); - ignore_value (system ("lvm config")); - } -} - -/* Construct the new, specific filter strings. We can assume that - * the 'devices' array does not contain any regexp metachars, - * because it's already been checked by the stub code. - */ -static char ** -make_filter_strings (char *const *devices) -{ - size_t i; - CLEANUP_FREE_STRINGSBUF DECLARE_STRINGSBUF (ret); - - for (i = 0; devices[i] != NULL; ++i) { - /* Because of the way matching works in LVM (yes, they wrote their - * own regular expression engine!), each match clause should be either: - * - * for single partitions: - * "a|^/dev/sda1$|", - * for whole block devices: - * "a|^/dev/sda$|", "a|^/dev/sda[0-9]|", - */ - const size_t slen = strlen (devices[i]); - - if (add_sprintf (&ret, "a|^%s$|", devices[i]) == -1) - return NULL; - - if (!c_isdigit (devices[i][slen-1])) { - /* whole block device */ - if (add_sprintf (&ret, "a|^%s[0-9]|", devices[i]) == -1) - return NULL; - } - } - if (add_string (&ret, "r|.*|") == -1) - return NULL; - - if (end_stringsbuf (&ret) == -1) - return NULL; - - return take_stringsbuf (&ret); -} - -int -do_lvm_set_filter (char *const *devices) -{ - CLEANUP_FREE_STRING_LIST char **filters = make_filter_strings (devices); - if (filters == NULL) - return -1; - - if (deactivate () == -1) - return -1; - - int r = set_filter (filters); - if (r == -1) - return -1; - - if (rescan () == -1) - return -1; - - return reactivate (); -} - -int -do_lvm_clear_filter (void) -{ - const char *const filters[2] = { "a/.*/", NULL }; - - if (deactivate () == -1) - return -1; - - if (set_filter ((char *const *) filters) == -1) - return -1; - - if (rescan () == -1) - return -1; - - return reactivate (); -} diff --git a/daemon/lvm_filter.ml b/daemon/lvm_filter.ml new file mode 100644 index 000000000..9893b164f --- /dev/null +++ b/daemon/lvm_filter.ml @@ -0,0 +1,45 @@ +(* guestfs-inspection + * Copyright (C) 2009-2021 Red Hat Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + *) + +open Unix +open Printf + +open Std_utils + +open Utils + +let lvm_system_dir = + try getenv "LVM_SYSTEM_DIR" with Not_found -> "/etc/lvm" + +let devices_file = lvm_system_dir ^ "/devices/system.devices" + +let rec set_filter devices = + empty_filter (); + Array.iter add_device_to_filter devices + +and add_device_to_filter device = + ignore (command "lvmdevices" ["--adddev"; device ]) + +(* Make the filter an empty file so no devices can be seen. *) +and empty_filter () = + with_openfile devices_file [O_WRONLY; O_TRUNC; O_CREAT; + O_NOCTTY; O_CLOEXEC] 0 + (fun _ -> ()) + +(* Clear the filter so all devices can be seen. *) +and clear_filter () = try unlink devices_file with Unix_error _ -> () diff --git a/docs/C_SOURCE_FILES b/docs/C_SOURCE_FILES index 6a97d8b0e..bd3953c8c 100644 --- a/docs/C_SOURCE_FILES +++ b/docs/C_SOURCE_FILES @@ -109,7 +109,6 @@ daemon/ldm.c daemon/link.c daemon/ls.c daemon/luks.c -daemon/lvm-filter.c daemon/lvm-tokenization.c daemon/lvm.c daemon/md.c diff --git a/generator/actions_core.ml b/generator/actions_core.ml index bb602ee02..a434e035d 100644 --- a/generator/actions_core.ml +++ b/generator/actions_core.ml @@ -5625,6 +5625,7 @@ To find a filesystem from the UUID, use C<guestfs_findfs_uuid>." }; { defaults with name = "lvm_set_filter"; added = (1, 5, 1); style = RErr, [StringList (Device, "devices")], []; + impl = OCaml "Lvm_filter.set_filter"; optional = Some "lvm2"; test_excuse = "cannot be tested with the current framework because the VG is being used by the mounted filesystem, so the 'vgchange -an' command we do first will fail"; shortdesc = "set LVM device filter"; @@ -5655,6 +5656,7 @@ filtering out that VG." }; { defaults with name = "lvm_clear_filter"; added = (1, 5, 1); style = RErr, [], []; + impl = OCaml "Lvm_filter.clear_filter"; test_excuse = "cannot be tested with the current framework because the VG is being used by the mounted filesystem, so the 'vgchange -an' command we do first will fail"; shortdesc = "clear LVM device filter"; longdesc = "\ diff --git a/generator/daemon.ml b/generator/daemon.ml index b1047427b..6c555f85d 100644 --- a/generator/daemon.ml +++ b/generator/daemon.ml @@ -788,23 +788,33 @@ let generate_daemon_caml_stubs () = ) optargs; List.iter ( fun arg -> - pr " args[%d] = " !i; + incr i; + let i = !i - 1 in (match arg with - | Bool n -> pr "Val_bool (%s)" n - | Int n -> pr "Val_int (%s)" n - | Int64 n -> pr "caml_copy_int64 (%s)" n + | Bool n -> pr " args[%d] = Val_bool (%s);\n" i n + | Int n -> pr " args[%d] = Val_int (%s);\n" i n + | Int64 n -> pr " args[%d] = caml_copy_int64 (%s);\n" i n | String ((PlainString|Device|Pathname|Dev_or_Path|Key), n) -> - pr "caml_copy_string (%s)" n + pr " args[%d] = caml_copy_string (%s);\n" i n | String ((Mountable|Mountable_or_Path), n) -> - pr "guestfs_int_daemon_copy_mountable (%s)" n + pr " args[%d] = guestfs_int_daemon_copy_mountable (%s);\n" i n | String _ -> assert false | OptString _ -> assert false + | StringList ((PlainString|Device|Pathname|Dev_or_Path|Key), n) -> + pr " {\n"; + pr " size_t i, n;\n"; + pr "\n"; + pr " n = guestfs_int_count_strings (%s);\n" n; + pr " args[%d] = caml_alloc (n, 0);\n" i; + pr " for (i = 0; i < n; ++i) {\n"; + pr " v = caml_copy_string (%s[i]);\n" n; + pr " Store_field (args[%d], i, v);\n" i; + pr " }\n"; + pr " }\n" | StringList _ -> assert false | BufferIn _ -> assert false | Pointer _ -> assert false ); - pr ";\n"; - incr i ) args; assert (!i = nr_args); -- 2.31.1 _______________________________________________ Libguestfs mailing list [email protected] https://listman.redhat.com/mailman/listinfo/libguestfs
