From 5541f8d5e6d621778f118d9c9a262e0080c9e265 Mon Sep 17 00:00:00 2001 From: Andrea Mazzoleni Date: Thu, 10 Dec 2015 22:50:20 +0100 Subject: [PATCH] Add UUID reading support using libblkid This fixes the Btrfs case where the root UUIDs are not present in the /dev/disk/by-uuid directory. --- HISTORY | 5 +++ cmdline/mingw.c | 1 + cmdline/portable.h | 7 ++++ cmdline/unix.c | 89 +++++++++++++++++++++++++++++++++++++++++----- configure.ac | 5 +++ 5 files changed, 99 insertions(+), 8 deletions(-) diff --git a/HISTORY b/HISTORY index 71261f33..07ababf7 100644 --- a/HISTORY +++ b/HISTORY @@ -1,6 +1,11 @@ SnapRAID HISTORY ================ +9.2 2015/12 +=========== + * Adds UUID support to Btrfs filesystems. It's available only if the + libblkid library is available on the system. + 9.1 2015/11 =========== * Fixes a bug when reading a content file with a deleted entry bigger diff --git a/cmdline/mingw.c b/cmdline/mingw.c index dde0b2f5..89ae82b7 100644 --- a/cmdline/mingw.c +++ b/cmdline/mingw.c @@ -1537,6 +1537,7 @@ int windows_readlink(const char* file, char* buffer, size_t size) int devuuid(uint64_t device, char* uuid, size_t uuid_size) { /* just use the volume serial number returned in the device parameter */ + log_tag("uuid:windows:%08x:%u:\n", (unsigned)device, (unsigned)device); snprintf(uuid, uuid_size, "%08x", (unsigned)device); return 0; diff --git a/cmdline/portable.h b/cmdline/portable.h index 81f2e789..f0f92989 100644 --- a/cmdline/portable.h +++ b/cmdline/portable.h @@ -122,6 +122,13 @@ #include #endif +#if HAVE_BLKID_BLKID_H +#include +#if HAVE_BLKID_DEVNO_TO_DEVNAME && HAVE_BLKID_GET_TAG_VALUE +#define HAVE_BLKID 1 +#endif +#endif + /** * Includes some standard headers. */ diff --git a/cmdline/unix.c b/cmdline/unix.c index 7ea37c9e..6f399a80 100644 --- a/cmdline/unix.c +++ b/cmdline/unix.c @@ -68,12 +68,21 @@ const char* stat_desc(struct stat* st) return "unknown"; } -#if HAVE_FSTATAT /** - * This function get the UUID using the /dev/disk/by-uuid/ links. - * Comparing with the libblkid library, it works also from not root processes. + * Cache used by blkid. */ -int devuuid(uint64_t device, char* uuid, size_t uuid_size) +#if HAVE_BLKID +static blkid_cache cache = 0; +#endif + +/** + * Get the UUID using the /dev/disk/by-uuid/ links. + * It doesn't require root permission, and the uuid are always updated. + * It doesn't work with Btrfs filesystems that don't export the main UUID + * in /dev/disk/by-uuid/. + */ +#if HAVE_FSTATAT +static int devuuid_dev(uint64_t device, char* uuid, size_t uuid_size) { int ret; DIR* d; @@ -98,6 +107,8 @@ int devuuid(uint64_t device, char* uuid, size_t uuid_size) continue; } + log_tag("uuid:dev:%s:%u:%u:\n", dd->d_name, major(st.st_rdev), minor(st.st_rdev)); + /* if it matches, we have the uuid */ if (S_ISBLK(st.st_mode) && st.st_rdev == (dev_t)device) { /* found */ @@ -111,17 +122,65 @@ int devuuid(uint64_t device, char* uuid, size_t uuid_size) closedir(d); return -1; } -#else +#endif + +/** + * Get the UUID using liblkid. + * It uses a cache to work without root permission, resultin in UUID + * not necessarely recent. + * We could call blkid_probe_all() to refresh the UUID, but it would + * require root permission to read the superblocks, and to have + * all the disks spinning. + */ +#if HAVE_BLKID +static int devuuid_blkid(uint64_t device, char* uuid, size_t uuid_size) +{ + char* devname; + char* uuidname; + + devname = blkid_devno_to_devname(device); + if (!devname) { + /* device mapping failed */ + return -1; + } + + uuidname = blkid_get_tag_value(cache, "UUID", devname); + if (!uuidname) { + /* uuid mapping failed */ + free(devname); + return -1; + } + + log_tag("uuid:blkid:%s:%u:%u:\n", uuidname, major(device), minor(device)); + + pathcpy(uuid, uuid_size, uuidname); + + free(devname); + free(uuidname); + return 0; +} +#endif + int devuuid(uint64_t device, char* uuid, size_t uuid_size) { + /* first try with the /dev/disk/by-uuid version */ +#if HAVE_FSTATAT + if (devuuid_dev(device, uuid, uuid_size) == 0) + return 0; +#endif + + /* fall back to blkid for other cases */ +#if HAVE_BLKID + if (devuuid_blkid(device, uuid, uuid_size) == 0) + return 0; +#endif + + /* not supported */ (void)device; (void)uuid; (void)uuid_size; - - /* not supported */ return -1; } -#endif int filephy(const char* path, uint64_t size, uint64_t* physical) { @@ -1005,11 +1064,25 @@ int devquery(tommy_list* high, tommy_list* low, int operation) void os_init(int opt) { +#if HAVE_BLKID + int ret; + ret = blkid_get_cache(&cache, NULL); + if (ret != 0) { + /* LCOV_EXCL_START */ + log_fatal("WARNING Failed to get blkid cache\n"); + /* LCOV_EXCL_STOP */ + } +#endif + (void)opt; } void os_done(void) { +#if HAVE_BLKID + if (cache != 0) + blkid_put_cache(cache); +#endif } void os_abort(void) diff --git a/configure.ac b/configure.ac index 20f263fc..2e0ec34e 100644 --- a/configure.ac +++ b/configure.ac @@ -93,6 +93,11 @@ AC_CHECK_CC_OPT([-pthread], CFLAGS="$CFLAGS -pthread", []) AC_CHECK_FUNCS([pthread_create]) AC_SEARCH_LIBS([exp], [m]) +dnl Checks for libblkid +AC_CHECK_HEADERS([blkid/blkid.h]) +AC_SEARCH_LIBS([blkid_probe_all], [blkid]) +AC_CHECK_FUNCS([blkid_devno_to_devname blkid_get_tag_value]) + dnl Checks for architecture AC_C_BIGENDIAN