X-Git-Url: http://git.annexia.org/?p=libguestfs.git;a=blobdiff_plain;f=daemon%2Flvm.c;h=216c9c44ab5d6bc7938947cf5e85dad9e1c7b6fc;hp=70c3c9047a97c9400f162ef27987824d22f42d39;hb=8022d46e5e2d9c3ab664ace6c9f185976e34dc20;hpb=9be89728f2a0ff17d54a0dba981015fa6405eb50 diff --git a/daemon/lvm.c b/daemon/lvm.c index 70c3c90..216c9c4 100644 --- a/daemon/lvm.c +++ b/daemon/lvm.c @@ -23,6 +23,7 @@ #include #include #include +#include #include "daemon.h" #include "c-ctype.h" @@ -662,3 +663,89 @@ do_vgscan (void) free (err); return 0; } + +/* 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 + * at the device-mapper (kernel) level, nothing is really known about + * LVM (a userspace concept). Therefore we use a convoluted method to + * determine this, by listing out known LVs and checking whether the + * rdev (major/minor) of the device we are passed matches any of them. + * + * 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 +lv_canonical (const char *device, char **ret) +{ + struct stat stat1, stat2; + + int r = stat (device, &stat1); + if (r == -1) { + reply_with_perror ("stat: %s", device); + return -1; + } + + char **lvs = do_lvs (); + if (lvs == NULL) + return -1; + + size_t i; + for (i = 0; lvs[i] != NULL; ++i) { + r = stat (lvs[i], &stat2); + if (r == -1) { + reply_with_perror ("stat: %s", lvs[i]); + free_strings (lvs); + 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; + } + } + + /* not found */ + 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 */ +}