File s390-tools-sles15sp2-01-libutil-add-function-to-get-base-device-for-bloc.patch of Package s390-tools.19134
Subject: [PATCH] [BZ 190371] libutil: add function to get base device for blockdevice
From: Stefan Haberland <sth@linux.ibm.com>
Description: zipl: fix multi volume dump creation
Symptom: zipl -M is not working.
Problem: util_sys_get_dev_addr() returns the device address for
a given blockdevice. This does not work for partitions
but some tools like zipl rely on the ability to get the
device address for partitions.
Solution: Add code that determines the base device for a partition.
Reproduction: Run zipl -M.
Upstream-ID: fa7a4dafa3d89b2e8787de102e4362e895d44b05
Problem-ID: 190371
Upstream-Description:
libutil: add function to get base device for blockdevice
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 <sth@linux.ibm.com>
Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Reviewed-by: Philipp Rudo <prudo@linux.ibm.com>
Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
Signed-off-by: Stefan Haberland <sth@linux.ibm.com>
---
include/lib/util_sys.h | 5 ++
libutil/util_sys.c | 97 +++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 102 insertions(+)
--- 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 <stdbool.h>
+
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 @} */
--- a/libutil/util_sys.c
+++ b/libutil/util_sys.c
@@ -11,17 +11,114 @@
#include <err.h>
#include <errno.h>
+#include <linux/fs.h>
#include <stdlib.h>
+#include <stdio.h>
#include <string.h>
#include <sys/stat.h>
#include <sys/sysmacros.h>
#include <unistd.h>
+#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