LVM is fine with a completely empty configuration file (meaning "all
defaults"), so start with one instead of copying the system
configuration file.
Also this means we can very easily implement lvm_set_filter
functionality without using Augeas, since we no longer have to worry
about existing filters being present.
---
appliance/Makefile.am | 4 +-
appliance/guestfs_lvm_conf.aug | 74 -----------------
daemon/daemon.h | 2 +-
daemon/guestfsd.c | 2 +-
daemon/lvm-filter.c | 178 +++++++++++++----------------------------
5 files changed, 59 insertions(+), 201 deletions(-)
diff --git a/appliance/Makefile.am b/appliance/Makefile.am
index 05b9d42e9..42896b9a7 100644
--- a/appliance/Makefile.am
+++ b/appliance/Makefile.am
@@ -32,7 +32,6 @@ include $(top_srcdir)/subdir-rules.mk
EXTRA_DIST = \
99-guestfs-serial.rules \
excludefiles.in \
- guestfs_lvm_conf.aug \
guestfs_shadow.aug \
hostfiles.in \
init \
@@ -87,12 +86,11 @@ packagelist: packagelist.in Makefile
cmp -s $@ $@-t || mv $@-t $@
rm -f $@-t
-supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_lvm_conf.aug guestfs_shadow.aug
+supermin.d/daemon.tar.gz: ../daemon/guestfsd guestfs_shadow.aug
rm -f $@ $@-t
rm -rf tmp-d
mkdir -p tmp-d$(DAEMON_SUPERMIN_DIR) tmp-d/etc tmp-d/usr/share/guestfs
ln ../daemon/guestfsd tmp-d$(DAEMON_SUPERMIN_DIR)/guestfsd
- ln $(srcdir)/guestfs_lvm_conf.aug tmp-d/usr/share/guestfs/guestfs_lvm_conf.aug
ln $(srcdir)/guestfs_shadow.aug tmp-d/usr/share/guestfs/guestfs_shadow.aug
( cd tmp-d && tar zcf - * ) > $@-t
rm -r tmp-d
diff --git a/appliance/guestfs_lvm_conf.aug b/appliance/guestfs_lvm_conf.aug
deleted file mode 100644
index ffa5b01f7..000000000
--- a/appliance/guestfs_lvm_conf.aug
+++ /dev/null
@@ -1,74 +0,0 @@
-(*
-Module: LVM
- Parses LVM metadata.
-
-Author: Gabriel de Perthuis <g2p.code+augeas(a)gmail.com>
-
-About: License
- This file is licensed under the LGPL v2+.
-
-About: Configuration files
- This lens applies to files in /etc/lvm/backup and /etc/lvm/archive.
-
-About: Examples
- The <Test_LVM> file contains various examples and tests.
-*)
-
-module Guestfs_LVM_conf =
- autoload xfm
-
- (* See lvm2/libdm/libdm-config.c for tokenisation;
- * libdm uses a blacklist but I prefer the safer whitelist approach. *)
- (* View: identifier
- * The left hand side of a definition *)
- let identifier = /[a-zA-Z0-9_-]+/
-
- (* strings can contain backslash-escaped dquotes, but I don't know
- * how to get the message across to augeas *)
- let str = [label "str". Quote.do_dquote (store /([^\"]|\\\\.)*/)]
- let int = [label "int". store Rx.relinteger]
- (* View: flat_literal
- * A literal without structure *)
- let flat_literal = int|str
-
- (* allow multiline and mixed int/str, used for raids and stripes *)
- (* View: list
- * A list containing flat literals *)
- let list = [
- label "list" . counter "list"
- . del /\[[ \t\n]*/ "["
- .([seq "list". flat_literal . del /,[ \t\n]*/ ", "]*
- . [seq "list". flat_literal . del /[ \t\n]*/ ""])?
- . Util.del_str "]"]
-
- (* View: val
- * Any value that appears on the right hand side of an assignment *)
- let val = flat_literal | list
-
- (* View: nondef
- * A line that doesn't contain a statement *)
- let nondef =
- Util.empty
- | Util.comment
-
- (* Build.block couldn't be reused, because of recursion and
- * a different philosophy of whitespace handling. *)
- (* View: def
- * An assignment, or a block containing definitions *)
- let rec def = [
- Util.indent . key identifier . (
- del /[ \t]*\{\n/ " {\n"
- .[label "dict".(nondef | def)*]
- . Util.indent . Util.del_str "}\n"
- |Sep.space_equal . val . Util.comment_or_eol)]
-
- (* View: lns
- * The main lens *)
- let lns = (nondef | def)*
-
- let filter =
- incl "/etc/lvm/archive/*.vg"
- . incl "/etc/lvm/backup/*"
- . Util.stdexcl
-
- let xfm = transform lns filter
diff --git a/daemon/daemon.h b/daemon/daemon.h
index 0f0d42836..610168ed8 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -255,7 +255,7 @@ extern char *get_blkid_tag (const char *device, const char *tag);
extern int lv_canonical (const char *device, char **ret);
/* lvm-filter.c */
-extern void copy_lvm (void);
+extern void clean_lvm_config (void);
extern void start_lvmetad (void);
/* zero.c */
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 86592e8dc..a209098d4 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -289,7 +289,7 @@ main (int argc, char *argv[])
* daemon/lvm-filter.c).
*/
if (!test_mode) {
- copy_lvm ();
+ clean_lvm_config ();
start_lvmetad ();
}
diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c
index deaecfb67..aff3c68ed 100644
--- a/daemon/lvm-filter.c
+++ b/daemon/lvm-filter.c
@@ -36,67 +36,49 @@
#include "daemon.h"
#include "actions.h"
-DECLARE_EXTERNAL_COMMANDS ("lvm", "cp", "rm",
"lvmetad")
+DECLARE_EXTERNAL_COMMANDS ("lvm", "rm", "lvmetad")
-/* This runs during daemon start up and creates a complete copy of
- * /etc/lvm so that we can modify it as we desire. We set
- * LVM_SYSTEM_DIR to point to the copy. Note that the final directory
- * layout is:
+/* This runs during daemon start up and creates a fresh LVM
+ * configuration which we can modify as we desire. LVM allows
+ * configuration to be completely empty (meaning "all defaults").
+ *
+ * The final directory layout is:
+ *
* /tmp/lvmXXXXXX (lvm_system_dir set to this)
* /tmp/lvmXXXXXX/lvm ($LVM_SYSTEM_DIR set to this)
- * /tmp/lvmXXXXXX/lvm/lvm.conf (configuration file)
- * /tmp/lvmXXXXXX/lvm/cache
- * etc.
+ * /tmp/lvmXXXXXX/lvm/lvm.conf (configuration file - initially empty)
*/
static char lvm_system_dir[] = "/tmp/lvmXXXXXX";
static void rm_lvm_system_dir (void);
+static void debug_lvm_config (void);
void
-copy_lvm (void)
+clean_lvm_config (void)
{
- struct stat statbuf;
- char cmd[64], env[64];
- int r;
-
- /* If /etc/lvm directory doesn't exist (or isn't a directory) assume
- * that this system doesn't support LVM and do nothing.
- */
- r = stat ("/etc/lvm", &statbuf);
- if (r == -1) {
- perror ("copy_lvm: stat: /etc/lvm");
- return;
- }
- if (! S_ISDIR (statbuf.st_mode)) {
- fprintf (stderr, "copy_lvm: warning: /etc/lvm is not a directory\n");
- return;
- }
+ char env[64], conf[64];
+ FILE *fp;
if (mkdtemp (lvm_system_dir) == NULL)
error (EXIT_FAILURE, errno, "mkdtemp: %s", lvm_system_dir);
- /* Copy the entire directory */
- snprintf (cmd, sizeof cmd, "%s -a /etc/lvm/ %s", "cp",
lvm_system_dir);
- r = system (cmd);
- if (r == -1) {
- perror (cmd);
- rmdir (lvm_system_dir);
- exit (EXIT_FAILURE);
- }
-
- if (WEXITSTATUS (r) != 0) {
- fprintf (stderr, "cp command failed with return code %d\n",
- WEXITSTATUS (r));
- rmdir (lvm_system_dir);
- exit (EXIT_FAILURE);
- }
-
- /* Set environment variable so we use the copy. */
snprintf (env, sizeof env, "%s/lvm", lvm_system_dir);
+ mkdir (env, 0755);
+ snprintf (conf, sizeof conf, "%s/lvm/lvm.conf", lvm_system_dir);
+ fp = fopen (conf, "w");
+ if (fp == NULL) {
+ perror ("clean_lvm_config: cannot create empty lvm.conf");
+ exit (EXIT_FAILURE);
+ }
+ fclose (fp);
+
+ /* Set environment variable so we use the clean configuration. */
setenv ("LVM_SYSTEM_DIR", env, 1);
/* Set a handler to remove the temporary directory at exit. */
atexit (rm_lvm_system_dir);
+
+ debug_lvm_config ();
}
/* Try to run lvmetad, without failing if it couldn't. */
@@ -127,98 +109,40 @@ rm_lvm_system_dir (void)
static int
set_filter (char *const *filters)
{
- CLEANUP_AUG_CLOSE augeas *aug = NULL;
- int r;
- int count;
+ const char *filter_types[] = { "filter", "global_filter", NULL };
+ CLEANUP_FREE char *conf = NULL;
+ FILE *fp;
+ size_t i, j;
- /* Small optimization: do not load the files at init time,
- * but do that only after having applied the transformation.
- */
- const int flags = AUG_NO_ERR_CLOSE | AUG_NO_LOAD;
- aug = aug_init (lvm_system_dir, "/usr/share/guestfs/", flags);
- if (!aug) {
- reply_with_error ("augeas initialization failed");
+ if (asprintf (&conf, "%s/lvm/lvm.conf", lvm_system_dir) == -1) {
+ reply_with_perror ("asprintf");
return -1;
}
-
- if (aug_error (aug) != AUG_NOERROR) {
- AUGEAS_ERROR ("aug_init");
- return -1;
- }
-
- r = aug_transform (aug, "guestfs_lvm_conf", "/lvm/lvm.conf",
- 0 /* = included */);
- if (r == -1) {
- AUGEAS_ERROR ("aug_transform");
- return -1;
- }
-
- if (aug_load (aug) == -1) {
- AUGEAS_ERROR ("aug_load");
+ fp = fopen (conf, "we");
+ if (fp == NULL) {
+ reply_with_perror ("open: %s", conf);
return -1;
}
- /* Remove all the old filters ... */
- r = aug_rm (aug, "/files/lvm/lvm.conf/devices/dict/filter/list/*");
- if (r == -1) {
- AUGEAS_ERROR ("aug_rm/filter");
- return -1;
- }
- r = aug_rm (aug, "/files/lvm/lvm.conf/devices/dict/global_filter/list/*");
- if (r == -1) {
- AUGEAS_ERROR ("aug_rm/global_filter");
- return -1;
- }
-
- /* ... and add the new ones. */
- for (count = 0; filters[count] != NULL; ++count) {
- char buf[128];
-
- snprintf (buf, sizeof buf,
- "/files/lvm/lvm.conf/devices/dict/filter/list/%d/str",
- count + 1);
+ fprintf (fp, "devices {\n");
+ for (j = 0; filter_types[j] != NULL; ++j) {
+ fprintf (fp, " %s = [\n", filter_types[j]);
+ fprintf (fp, " ");
- if (aug_set (aug, buf, filters[count]) == -1) {
- AUGEAS_ERROR ("aug_set/filter: %d: %s", count, filters[count]);
- return -1;
+ for (i = 0; filters[i] != NULL; ++i) {
+ if (i > 0)
+ fprintf (fp, ",\n ");
+ fprintf (fp, "\"%s\"", filters[i]);
}
- snprintf (buf, sizeof buf,
- "/files/lvm/lvm.conf/devices/dict/global_filter/list/%d/str",
- count + 1);
-
- if (aug_set (aug, buf, filters[count]) == -1) {
- AUGEAS_ERROR ("aug_set/global_filter: %d: %s", count, filters[count]);
- return -1;
- }
+ fprintf (fp, "\n");
+ fprintf (fp, " ]\n");
}
+ fprintf (fp, "}\n");
- /* Safety check for the written filter nodes. */
- r = aug_match (aug, "/files/lvm/lvm.conf/devices/dict/filter/list/*/str",
- NULL);
- if (r == -1) {
- AUGEAS_ERROR ("aug_match/filter");
- return -1;
- }
- if (r != count) {
- reply_with_error ("filters# vs matches mismatch: %d vs %d", count, r);
- return -1;
- }
- r = aug_match (aug,
"/files/lvm/lvm.conf/devices/dict/global_filter/list/*/str",
- NULL);
- if (r == -1) {
- AUGEAS_ERROR ("aug_match/global_filter");
- return -1;
- }
- if (r != count) {
- reply_with_error ("global_filter# vs matches mismatch: %d vs %d", count,
r);
- return -1;
- }
+ fclose (fp);
- if (aug_save (aug) == -1) {
- AUGEAS_ERROR ("aug_save");
- return -1;
- }
+ debug_lvm_config ();
return 0;
}
@@ -269,6 +193,16 @@ rescan (void)
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.
--
2.13.2