summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--daemon/daemon.h3
-rw-r--r--daemon/guestfsd.c5
-rw-r--r--daemon/lvm-filter.c109
3 files changed, 101 insertions, 16 deletions
diff --git a/daemon/daemon.h b/daemon/daemon.h
index b4f99a81..6ed68fd8 100644
--- a/daemon/daemon.h
+++ b/daemon/daemon.h
@@ -134,6 +134,9 @@ extern int e2prog (char *name); /* Massive hack for RHEL 5. */
/*-- in lvm.c --*/
extern int lv_canonical (const char *device, char **ret);
+/*-- in lvm-filter.c --*/
+extern void copy_lvm (void);
+
/*-- in proto.c --*/
extern void main_loop (int sock) __attribute__((noreturn));
diff --git a/daemon/guestfsd.c b/daemon/guestfsd.c
index 51bb0b73..6373f34a 100644
--- a/daemon/guestfsd.c
+++ b/daemon/guestfsd.c
@@ -239,6 +239,11 @@ main (int argc, char *argv[])
_umask (0);
#endif
+ /* Make a private copy of /etc/lvm so we can change the config (see
+ * daemon/lvm-filter.c).
+ */
+ copy_lvm ();
+
/* Connect to virtio-serial channel. */
int sock = open (VIRTIO_SERIAL_CHANNEL, O_RDWR | O_CLOEXEC);
if (sock == -1) {
diff --git a/daemon/lvm-filter.c b/daemon/lvm-filter.c
index a62d40af..21e2fde4 100644
--- a/daemon/lvm-filter.c
+++ b/daemon/lvm-filter.c
@@ -23,11 +23,79 @@
#include <inttypes.h>
#include <string.h>
#include <unistd.h>
+#include <sys/stat.h>
-#include "daemon.h"
#include "c-ctype.h"
+#include "ignore-value.h"
+
+#include "daemon.h"
#include "actions.h"
+/* 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.
+ */
+static char lvm_system_dir[] = "/tmp/lvmXXXXXX";
+
+static void rm_lvm_system_dir (void);
+
+void
+copy_lvm (void)
+{
+ struct stat statbuf;
+ char cmd[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;
+ }
+
+ if (mkdtemp (lvm_system_dir) == NULL) {
+ perror (lvm_system_dir);
+ exit (EXIT_FAILURE);
+ }
+
+ /* Hopefully no dotfiles in there ... XXX */
+ snprintf (cmd, sizeof cmd, "cp -a /etc/lvm/* %s", 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. */
+ setenv ("LVM_SYSTEM_DIR", lvm_system_dir, 1);
+
+ /* Set a handler to remove the temporary directory at exit. */
+ atexit (rm_lvm_system_dir);
+}
+
+static void
+rm_lvm_system_dir (void)
+{
+ char cmd[64];
+
+ snprintf (cmd, sizeof cmd, "rm -rf %s", lvm_system_dir);
+ ignore_value (system (cmd));
+}
+
/* Does the current line match the regexp /^\s*filter\s*=/ */
static int
is_filter_line (const char *line)
@@ -52,18 +120,24 @@ is_filter_line (const char *line)
return 1;
}
-/* Rewrite the 'filter = [ ... ]' line in /etc/lvm/lvm.conf. */
+/* Rewrite the 'filter = [ ... ]' line in lvm.conf. */
static int
set_filter (const char *filter)
{
- FILE *ifp = fopen ("/etc/lvm/lvm.conf", "r");
+ char lvm_conf[64];
+ snprintf (lvm_conf, sizeof lvm_conf, "%s/lvm.conf", lvm_system_dir);
+
+ char lvm_conf_new[64];
+ snprintf (lvm_conf_new, sizeof lvm_conf, "%s/lvm.conf.new", lvm_system_dir);
+
+ FILE *ifp = fopen (lvm_conf, "r");
if (ifp == NULL) {
- reply_with_perror ("open: /etc/lvm/lvm.conf");
+ reply_with_perror ("open: %s", lvm_conf);
return -1;
}
- FILE *ofp = fopen ("/etc/lvm/lvm.conf.new", "w");
+ FILE *ofp = fopen (lvm_conf_new, "w");
if (ofp == NULL) {
- reply_with_perror ("open: /etc/lvm/lvm.conf.new");
+ reply_with_perror ("open: %s", lvm_conf_new);
fclose (ifp);
return -1;
}
@@ -79,11 +153,11 @@ set_filter (const char *filter)
}
if (r < 0) {
/* NB. fprintf doesn't set errno on error. */
- reply_with_error ("/etc/lvm/lvm.conf.new: write failed");
+ reply_with_error ("%s: write failed", lvm_conf_new);
fclose (ifp);
fclose (ofp);
free (line);
- unlink ("/etc/lvm/lvm.conf.new");
+ unlink (lvm_conf_new);
return -1;
}
}
@@ -91,20 +165,20 @@ set_filter (const char *filter)
free (line);
if (fclose (ifp) == EOF) {
- reply_with_perror ("/etc/lvm/lvm.conf.new");
- unlink ("/etc/lvm/lvm.conf.new");
+ reply_with_perror ("close: %s", lvm_conf);
+ unlink (lvm_conf_new);
fclose (ofp);
return -1;
}
if (fclose (ofp) == EOF) {
- reply_with_perror ("/etc/lvm/lvm.conf.new");
- unlink ("/etc/lvm/lvm.conf.new");
+ reply_with_perror ("close: %s", lvm_conf_new);
+ unlink (lvm_conf_new);
return -1;
}
- if (rename ("/etc/lvm/lvm.conf.new", "/etc/lvm/lvm.conf") == -1) {
- reply_with_perror ("rename: /etc/lvm/lvm.conf");
- unlink ("/etc/lvm/lvm.conf.new");
+ if (rename (lvm_conf_new, lvm_conf) == -1) {
+ reply_with_perror ("rename: %s", lvm_conf);
+ unlink (lvm_conf_new);
return -1;
}
@@ -144,7 +218,10 @@ reactivate (void)
static int
rescan (void)
{
- unlink ("/etc/lvm/cache/.cache");
+ char lvm_cache[64];
+ snprintf (lvm_cache, sizeof lvm_cache, "%s/cache/.cache", lvm_system_dir);
+
+ unlink (lvm_cache);
char *err;
int r = command (NULL, &err, "lvm", "vgscan", NULL);