From b2569b6d5cc513cf0dacbe4c6bc577133d0054a2 Mon Sep 17 00:00:00 2001 From: Milan Broz Date: Tue, 24 May 2011 11:19:21 +0000 Subject: [PATCH] Handle even non-standard and non-udev /dev in devpath. git-svn-id: https://cryptsetup.googlecode.com/svn/trunk@531 36d66b0a-2a48-0410-832c-cd162a569da5 --- lib/libdevmapper.c | 13 ++++++------ lib/utils_devpath.c | 59 +++++++++++++++++++++++++++++++---------------------- lib/utils_dm.h | 8 ++++++-- 3 files changed, 48 insertions(+), 32 deletions(-) diff --git a/lib/libdevmapper.c b/lib/libdevmapper.c index 0fa03c6..34b1767 100644 --- a/lib/libdevmapper.c +++ b/lib/libdevmapper.c @@ -206,16 +206,12 @@ void dm_exit(void) } /* Return path to DM device */ -char *dm_device_path(const char *dev_id) +char *dm_device_path(int major, int minor) { - int major, minor; struct dm_task *dmt; const char *name; char path[PATH_MAX]; - if (sscanf(dev_id, "%d:%d", &major, &minor) != 2) - return NULL; - if (!(dmt = dm_task_create(DM_DEVICE_STATUS))) return NULL; if (!dm_task_set_minor(dmt, minor) || @@ -759,7 +755,12 @@ const char *dm_get_dir(void) return dm_dir(); } -int dm_is_dm_device(int major) +int dm_is_dm_device(int major, int minor) { return dm_is_dm_major((uint32_t)major); } + +int dm_is_dm_kernel_name(const char *name) +{ + return strncmp(name, "dm-", 3) ? 0 : 1; +} diff --git a/lib/utils_devpath.c b/lib/utils_devpath.c index 35b639e..af6cec0 100644 --- a/lib/utils_devpath.c +++ b/lib/utils_devpath.c @@ -21,12 +21,12 @@ #include #include +#include +#include #include #include #include -#include "internal.h" - -#define DEVICE_DIR "/dev" +#include "utils_dm.h" static char *__lookup_dev(char *path, dev_t dev, int dir_level, const int max_level) { @@ -66,7 +66,7 @@ static char *__lookup_dev(char *path, dev_t dev, int dir_level, const int max_le break; } else if (S_ISBLK(st.st_mode)) { /* workaround: ignore dm-X devices, these are internal kernel names */ - if (dir_level == 0 && !strncmp(entry->d_name, "dm-", 3)) + if (dir_level == 0 && dm_is_dm_kernel_name(entry->d_name)) continue; if (st.st_rdev == dev) { result = strdup(path); @@ -82,17 +82,13 @@ static char *__lookup_dev(char *path, dev_t dev, int dir_level, const int max_le /* * Non-udev systemd need to scan for device here. */ -static char *lookup_dev_old(const char *dev_id) +static char *lookup_dev_old(int major, int minor) { - int major, minor; dev_t dev; char *result = NULL, buf[PATH_MAX + 1]; - if (sscanf(dev_id, "%d:%d", &major, &minor) != 2) - return NULL; - dev = makedev(major, minor); - strncpy(buf, DEVICE_DIR, PATH_MAX); + strncpy(buf, "/dev", PATH_MAX); buf[PATH_MAX] = '\0'; /* First try low level device */ @@ -100,32 +96,37 @@ static char *lookup_dev_old(const char *dev_id) return result; /* If it is dm, try DM dir */ - if (dm_is_dm_device(major)) { + if (dm_is_dm_device(major, minor)) { strncpy(buf, dm_get_dir(), PATH_MAX); if ((result = __lookup_dev(buf, dev, 0, 0))) return result; } - strncpy(buf, DEVICE_DIR, PATH_MAX); - result = __lookup_dev(buf, dev, 0, 4); - - /* If not found, return NULL */ - return result; + strncpy(buf, "/dev", PATH_MAX); + return __lookup_dev(buf, dev, 0, 4); } +/* + * Returns string pointing to device in /dev according to "major:minor" dev_id + */ char *crypt_lookup_dev(const char *dev_id) { - char link[PATH_MAX], path[PATH_MAX], *devname; + int major, minor; + char link[PATH_MAX], path[PATH_MAX], *devname, *devpath = NULL; struct stat st; ssize_t len; + if (sscanf(dev_id, "%d:%d", &major, &minor) != 2) + return NULL; + if (snprintf(path, sizeof(path), "/sys/dev/block/%s", dev_id) < 0) return NULL; len = readlink(path, link, sizeof(link)); if (len < 0) { + /* Without /sys use old scan */ if (stat("/sys/dev/block", &st) < 0) - return lookup_dev_old(dev_id); + return lookup_dev_old(major, minor); return NULL; } @@ -135,11 +136,21 @@ char *crypt_lookup_dev(const char *dev_id) return NULL; devname++; - if (!strncmp(devname, "dm-", 3)) - return dm_device_path(dev_id); - - if (snprintf(path, sizeof(path), "/dev/%s", devname) < 0) - return NULL; + if (dm_is_dm_kernel_name(devname)) + devpath = dm_device_path(major, minor); + else if (snprintf(path, sizeof(path), "/dev/%s", devname) > 0) + devpath = strdup(path); + + /* + * Check that path is correct. + */ + if (devpath && ((stat(devpath, &st) < 0) || + !S_ISBLK(st.st_mode) || + (st.st_rdev != makedev(major, minor)))) { + free(devpath); + /* Should never happen unless user mangles with dev nodes. */ + return lookup_dev_old(major, minor); + } - return strdup(path); + return devpath; } diff --git a/lib/utils_dm.h b/lib/utils_dm.h index 6cbd732..585df44 100644 --- a/lib/utils_dm.h +++ b/lib/utils_dm.h @@ -2,6 +2,9 @@ #define _UTILS_DM_H /* device-mapper library helpers */ +#include + +struct crypt_device; /* Device mapper backend - kernel support flags */ #define DM_KEY_WIPE_SUPPORTED (1 << 0) /* key wipe message */ @@ -35,7 +38,8 @@ int dm_suspend_and_wipe_key(const char *name); int dm_resume_and_reinstate_key(const char *name, size_t key_size, const char *key); -char *dm_device_path(const char *dev_id); -int dm_is_dm_device(int major); +char *dm_device_path(int major, int minor); +int dm_is_dm_device(int major, int minor); +int dm_is_dm_kernel_name(const char *name); #endif /* _UTILS_DM_H */ -- 2.7.4