From fa7a4dafa3d89b2e8787de102e4362e895d44b05 Mon Sep 17 00:00:00 2001 From: Stefan Haberland Date: Wed, 29 Jul 2020 11:24:55 +0200 Subject: [PATCH] libutil: add function to get base device for blockdevice MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Some operations are only possible on base devices not on partitions. Add functions to determine if a given device is a partition or a base device and to get the base device to a given partition. Signed-off-by: Stefan Haberland Reviewed-by: Jan Hoeppner Reviewed-by: Philipp Rudo Signed-off-by: Jan Höppner --- include/lib/util_sys.h | 5 +++ libutil/util_sys.c | 97 ++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 102 insertions(+) diff --git a/include/lib/util_sys.h b/include/lib/util_sys.h index e0f078b0..cf6f862a 100644 --- a/include/lib/util_sys.h +++ b/include/lib/util_sys.h @@ -12,6 +12,11 @@ #ifndef LIB_UTIL_SYS_H #define LIB_UTIL_SYS_H +#include + int util_sys_get_dev_addr(const char *dev, char *addr); +bool util_sys_dev_is_partition(dev_t dev); +int util_sys_get_partnum(dev_t dev); +int util_sys_get_base_dev(dev_t dev, dev_t *base_dev); #endif /** LIB_UTIL_SYS_H @} */ diff --git a/libutil/util_sys.c b/libutil/util_sys.c index 024dac78..96f1548e 100644 --- a/libutil/util_sys.c +++ b/libutil/util_sys.c @@ -11,17 +11,114 @@ #include #include +#include #include +#include #include #include #include #include +#include "lib/util_file.h" +#include "lib/util_libc.h" #include "lib/util_path.h" #include "lib/util_sys.h" /* lstat() doesn't work for sysfs files, a fixed size is therefore inevitable */ #define READLINK_SIZE 256 +#define PAGE_SIZE 4096 + +/** + * Return the partition number of a given partition. + * + * @param[in] dev Device node of interest + * + * @retval int Partition number of the device + * @retval -1 Error when trying to read the partition number. + */ +int util_sys_get_partnum(dev_t dev) +{ + int partnum = -1; + char *path; + + path = util_path_sysfs("dev/block/%u:%u/partition", + major(dev), minor(dev)); + if (util_file_read_i(&partnum, 10, path)) { + warnx("Could not read from path '%s'", path); + goto out; + } + if (partnum <= 0) { + warnx("Bad partition number in '%s'", path); + partnum = -1; + goto out; + } + +out: + free(path); + return partnum; +} + +/** + * Determine if the given device is a partition. + * + * @param[in] dev Device node of interest + * + * @retval true Device is partition + * @retval false Device is not a partition + */ +bool util_sys_dev_is_partition(dev_t dev) +{ + bool is_part; + char *path; + + path = util_path_sysfs("dev/block/%u:%u/partition", + major(dev), minor(dev)); + is_part = util_path_exists(path); + free(path); + + return is_part; +} + +/** + * Determine base device + * + * This function determines the base device \p base_dev of a given + * device \p dev. If \p dev is a base device, \p base_dev becomes \p dev. + * + * @param[in] dev Device node of interest + * @param[out] base_dev Identified base device + * + * @retval 0 Success + * @retval -1 Error while reading device information or + * constructed path + */ +int util_sys_get_base_dev(dev_t dev, dev_t *base_dev) +{ + int base_major, base_minor; + char buf[PAGE_SIZE]; + char *path; + + /* check if the device already is a base device */ + if (!util_sys_dev_is_partition(dev)) { + *base_dev = makedev(major(dev), minor(dev)); + return 0; + } + path = util_path_sysfs("dev/block/%d:%d/../dev", + major(dev), minor(dev)); + if (util_file_read_line(buf, sizeof(buf), path)) { + warnx("Could not read from path '%s'", path); + free(path); + return -1; + } + free(path); + if (sscanf(buf, "%i:%i", &base_major, &base_minor) != 2) { + warn("Could not parse major:minor from string '%s'", buf); + return -1; + } + *base_dev = makedev(base_major, base_minor); + + return 0; +} /** * Identify device address