X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Flvm.c;h=eaa6bcea64e4c7acb39d0061724e02955440654d;hp=0df27e2f0fe6ccf100d056017287c8d79c2364ce;hb=7d4a99db87b9fe9373b482092db88610fb796012;hpb=6280ac9b987c14f89749b4b4fdfec5a647567432 diff --git a/daemon/lvm.c b/daemon/lvm.c index 0df27e2..eaa6bce 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -1,5 +1,5 @@ /* libguestfs - the guestfsd daemon - * Copyright (C) 2009 Red Hat Inc. + * Copyright (C) 2009-2011 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 @@ -24,6 +24,7 @@ #include #include #include +#include #include "daemon.h" #include "c-ctype.h" @@ -223,10 +224,12 @@ do_vgcreate (const char *volgroup, char *const *physvols) if (r == -1) { reply_with_error ("%s", err); free (err); + free (argv); return -1; } free (err); + free (argv); udev_settle (); @@ -322,6 +325,12 @@ do_lvm_remove_all (void) return -1; for (i = 0; xs[i] != NULL; ++i) { + /* Deactivate the LV first. On Ubuntu, lvremove '-f' option + * does not remove active LVs reliably. + */ + (void) command (NULL, NULL, "lvm", "lvchange", "-an", xs[i], NULL); + udev_settle (); + r = command (NULL, &err, "lvm", "lvremove", "-f", xs[i], NULL); if (r == -1) { reply_with_error ("lvremove: %s: %s", xs[i], err); @@ -339,6 +348,10 @@ do_lvm_remove_all (void) return -1; for (i = 0; xs[i] != NULL; ++i) { + /* Deactivate the VG first, see note above. */ + (void) command (NULL, NULL, "lvm", "vgchange", "-an", xs[i], NULL); + udev_settle (); + r = command (NULL, &err, "lvm", "vgremove", "-f", xs[i], NULL); if (r == -1) { reply_with_error ("vgremove: %s: %s", xs[i], err); @@ -502,10 +515,12 @@ do_vg_activate (int activate, char *const *volgroups) if (r == -1) { reply_with_error ("vgchange: %s", err); free (err); + free (argv); return -1; } free (err); + free (argv); udev_settle (); @@ -664,7 +679,8 @@ do_vgscan (void) return 0; } -/* Test if a device is a logical volume (RHBZ#619793). +/* Convert a non-canonical LV path like /dev/mapper/vg-lv or /dev/dm-0 + * to a canonical one. * * This is harder than it should be. A LV device like /dev/VG/LV is * really a symlink to a device-mapper device like /dev/dm-0. However @@ -675,9 +691,16 @@ do_vgscan (void) * * Note use of 'stat' instead of 'lstat' so that symlinks are fully * resolved. + * + * Returns: + * 1 = conversion was successful, path is an LV + * '*ret' is set to the updated path if 'ret' is non-NULL. + * 0 = path is not an LV + * -1 = error, reply_with_* has been called + * */ int -do_is_lv (const char *device) +lv_canonical (const char *device, char **ret) { struct stat stat1, stat2; @@ -700,6 +723,14 @@ do_is_lv (const char *device) return -1; } if (stat1.st_rdev == stat2.st_rdev) { /* found it */ + if (ret) { + *ret = strdup (lvs[i]); + if (*ret == NULL) { + reply_with_perror ("strdup"); + free_strings (lvs); + return -1; + } + } free_strings (lvs); return 1; } @@ -709,3 +740,104 @@ do_is_lv (const char *device) free_strings (lvs); return 0; } + +/* Test if a device is a logical volume (RHBZ#619793). */ +int +do_is_lv (const char *device) +{ + return lv_canonical (device, NULL); +} + +/* Return canonical name of LV to caller (RHBZ#638899). */ +char * +do_lvm_canonical_lv_name (const char *device) +{ + char *canonical; + int r = lv_canonical (device, &canonical); + if (r == -1) + return NULL; + + if (r == 0) { + reply_with_error ("%s: not a logical volume", device); + return NULL; + } + + return canonical; /* caller frees */ +} + +/* List everything in /dev/mapper which *isn't* an LV (RHBZ#688062). */ +char ** +do_list_dm_devices (void) +{ + char **ret = NULL; + int size = 0, alloc = 0; + struct dirent *d; + DIR *dir; + int r; + + dir = opendir ("/dev/mapper"); + if (!dir) { + reply_with_perror ("opendir: /dev/mapper"); + return NULL; + } + + while (1) { + errno = 0; + d = readdir (dir); + if (d == NULL) break; + + /* Ignore . and .. */ + if (STREQ (d->d_name, ".") || STREQ (d->d_name, "..")) + continue; + + /* Ignore /dev/mapper/control which is used internally by dm. */ + if (STREQ (d->d_name, "control")) + continue; + + size_t len = strlen (d->d_name); + char devname[len+64]; + + snprintf (devname, len+64, "/dev/mapper/%s", d->d_name); + + /* Ignore dm devices which are LVs. */ + r = lv_canonical (devname, NULL); + if (r == -1) { + free_stringslen (ret, size); + closedir (dir); + return NULL; + } + if (r) + continue; + + /* Not an LV, so add it. */ + if (add_string (&ret, &size, &alloc, devname) == -1) { + closedir (dir); + return NULL; + } + } + + /* Did readdir fail? */ + if (errno != 0) { + reply_with_perror ("readdir: /dev/mapper"); + free_stringslen (ret, size); + closedir (dir); + return NULL; + } + + /* Close the directory handle. */ + if (closedir (dir) == -1) { + reply_with_perror ("closedir: /dev/mapper"); + free_stringslen (ret, size); + return NULL; + } + + /* Sort the output (may be empty). */ + if (ret != NULL) + sort_strings (ret, size); + + /* NULL-terminate the list. */ + if (add_string (&ret, &size, &alloc, NULL) == -1) + return NULL; + + return ret; +}