Subject: [PATCH] [BZ 189020] libutil: add util_file_read_i()/util_file_read_ui()
From: Jan Hoeppner <hoeppner@linux.ibm.com>

Description:   zgetdump: Fix device node determination via sysfs
Symptom:       When using zgetdump on a multi-volume device dump, the sysfs
               path to  determine the device node is incomplete, resulting in
               the following error:

               $ zgetdump -i /dev/dasdb1
               zgetdump: Could not open
               "/sys/bus/ccw/devices/0.0.9300/dasdb/dev"
               (No such file or directory)
Problem:       The sysfs path to determine the device node is incomplete.
Solution:      A simple fix would be to add the missing "block" part in the
               sysfs path. However, the logic still assumes sysfs links like
               "block:" that have been deprecated a decade ago and are no
               longer present on modern systems anyway.
               Therefore, the logic can greatly be improved. Create a separate
               function to determine whether a device is online, remove the
               logic for "block:" entries, and use libutil functions to reduce
               the complexity even further.
Reproduction:  Set up a multi-volume dump using zipl -M (See man page and
               corresponding Dump Tool Documentation for more details).
               Then simply run:
               $ zgetdump -i /dev/dasdb1
               on the multi-volume setup.
Upstream-ID:   37348ef662a7052dae798e500ca8c9b769fff3e6
Problem-ID:    189020

Upstream-Description:

              libutil: add util_file_read_i()/util_file_read_ui()

              These functions parse a sysfs file and return either an
              unsigned integer or signed integer.

              Signed-off-by: Sven Schnelle <svens@linux.ibm.com>
              Reviewed-by: Niklas Schnelle <schnelle@linux.ibm.com>
              Acked-by: Jan Hoeppner <hoeppner@linux.ibm.com>
              Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>


Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>
---
 include/lib/util_file.h |    2 +
 libutil/util_file.c     |   76 ++++++++++++++++++++++++++++++++++++++++++++++++
 2 files changed, 78 insertions(+)

--- a/include/lib/util_file.h
+++ b/include/lib/util_file.h
@@ -12,8 +12,10 @@
 #define LIB_UITL_FILE_H
 
 int util_file_read_line(char *str, size_t size, const char *fmt, ...);
+int util_file_read_i(int *val, int base, const char *fmt, ...);
 int util_file_read_l(long *val, int base, const char *fmt, ...);
 int util_file_read_ll(long long *val, int base, const char *fmt, ...);
+int util_file_read_ui(unsigned int *val, int base, const char *fmt, ...);
 int util_file_read_ul(unsigned long *val, int base, const char *fmt, ...);
 int util_file_read_ull(unsigned long long *val, int base, const char *fmt, ...);
 
--- a/libutil/util_file.c
+++ b/libutil/util_file.c
@@ -282,6 +282,44 @@ int util_file_write_ull(unsigned long lo
 }
 
 /**
+ * Read a file and convert it to signed int according to given base
+ *
+ * @param[out] val      Buffer for value
+ * @param[in]  base     Base for conversion, either 8, 10, or 16
+ * @param[in]  fmt      Format string for generation of the path name
+ * @param[in]  ...      Parameters for format string
+ *
+ * @retval     0        Integer has been read correctly
+ * @retval    -1        Error while reading file
+ */
+int util_file_read_i(int *val, int base, const char *fmt, ...)
+{
+	char path[PATH_MAX], buf[512];
+	va_list ap;
+	int count;
+
+	/* Construct the file name */
+	UTIL_VSPRINTF(path, fmt, ap);
+
+	if (file_gets(buf, sizeof(buf), path))
+		return -1;
+	switch (base) {
+	case 8:
+		count = sscanf(buf, "%do", val);
+		break;
+	case 10:
+		count = sscanf(buf, "%dd", val);
+		break;
+	case 16:
+		count = sscanf(buf, "%dx", val);
+		break;
+	default:
+		util_panic("Invalid base: %d\n", base);
+	}
+	return (count == 1) ? 0 : -1;
+}
+
+/**
  * Read a file and convert it to signed long according to given base
  *
  * @param[out] val      Buffer for value
@@ -353,6 +391,44 @@ int util_file_read_ll(long long *val, in
 		break;
 	default:
 		util_panic("Invalid base: %d\n", base);
+	}
+	return (count == 1) ? 0 : -1;
+}
+
+/**
+ * Read a file and convert it to unsigned int according to given base
+ *
+ * @param[out] val      Buffer for value
+ * @param[in]  base     Base for conversion, either 8, 10, or 16
+ * @param[in]  fmt      Format string for generation of the path name
+ * @param[in]  ...      Parameters for format string
+ *
+ * @retval     0        Integer has been read correctly
+ * @retval    -1        Error while reading file
+ */
+int util_file_read_ui(unsigned int *val, int base, const char *fmt, ...)
+{
+	char path[PATH_MAX], buf[512];
+	va_list ap;
+	int count;
+
+	/* Construct the file name */
+	UTIL_VSPRINTF(path, fmt, ap);
+
+	if (file_gets(buf, sizeof(buf), path))
+		return -1;
+	switch (base) {
+	case 8:
+		count = sscanf(buf, "%uo", val);
+		break;
+	case 10:
+		count = sscanf(buf, "%uu", val);
+		break;
+	case 16:
+		count = sscanf(buf, "%ux", val);
+		break;
+	default:
+		util_panic("Invalid base: %d\n", base);
 	}
 	return (count == 1) ? 0 : -1;
 }
