Subject: [PATCH] [FEAT VS1822] libutil: Move some zdev file reading functions into util
From: Matthew Rosato <mjrosato@linux.ibm.com>

Summary:     ap_tools: add ap-check and the ap device type to zdev   
Description: This feature adds multiple components in support of persistent
             configuration of vfio-ap mediated devices.

             The ap-check utility is added as a callout function for the
             mdevctl utility.  This allows for meaningful error messages to be
             presented to end-users when vfio-ap configuration errors are
             detected while using mdevctl to create/modify vfio-ap mediated
             devices.

             Additionally, the 'ap' device type is added to zdev, providing a
             command-line interface for managing the apmask and aqmask, which
             determine what AP resources are available for vfio-ap usage.
             'chzdev' is updated to allow for modifying the active masks as
             well as to specify persistent mask values via a udev rule.
             'lszdev' is updated to allow for querying of the active and
             persistent mask values.
Upstream-ID: f64b4087dd1c9253c5eafae7736d96b5edaf18f0
Problem-ID:  VS1822

Upstream-Description:

             libutil: Move some zdev file reading functions into util

             In preparation for sharing some zdev udev code with other libraries, move
             some file operation code from zdev into util_file.

             Reviewed-by: Jan Hoeppner <hoeppner@linux.ibm.com>
             Reviewed-by: Tony Krowiak <akrowiak@linux.ibm.com>
             Reviewed-by: Peter Oberparleiter <oberpar@linux.ibm.com>
             Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
             Signed-off-by: Jan Hoeppner <hoeppner@linux.ibm.com>


Signed-off-by: Matthew Rosato <mjrosato@linux.ibm.com>
---
 include/lib/util_file.h |    8 ++
 libutil/util_file.c     |  132 ++++++++++++++++++++++++++++++++++++++++++++++++
 zdev/include/misc.h     |    1 
 zdev/src/firmware.c     |    8 ++
 zdev/src/misc.c         |   75 ++-------------------------
 5 files changed, 152 insertions(+), 72 deletions(-)

--- a/include/lib/util_file.h
+++ b/include/lib/util_file.h
@@ -11,6 +11,8 @@
 #ifndef LIB_UTIL_FILE_H
 #define LIB_UTIL_FILE_H
 
+#include "lib/util_exit_code.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, ...);
@@ -26,4 +28,10 @@ int util_file_write_ul(unsigned long val
 int util_file_write_ull(unsigned long long val, int base, const char *fmt, ...);
 
 int util_file_read_va(const char *path, const char *fmt, ...);
+
+util_exit_code_t util_file_read_fd_buf(FILE *fd, void **buffer_ptr,
+				       size_t *size_ptr);
+char *util_file_read_fd(FILE *fd, int chomp);
+char *util_file_read_text_file(const char *path, int chomp);
+
 #endif /** LIB_UTIL_FILE_H @} */
--- a/libutil/util_file.c
+++ b/libutil/util_file.c
@@ -9,6 +9,7 @@
  * it under the terms of the MIT license. See LICENSE for details.
  */
 
+#include <ctype.h>
 #include <errno.h>
 #include <limits.h>
 #include <linux/limits.h>
@@ -21,11 +22,16 @@
 #include <unistd.h>
 
 #include "lib/util_base.h"
+#include "lib/util_exit_code.h"
 #include "lib/util_file.h"
 #include "lib/util_libc.h"
 #include "lib/util_panic.h"
 #include "lib/util_prg.h"
 
+#define READ_CHUNK_SIZE		4096
+
+extern const char *toolname;
+
 /*
  * Read the first line of a file into given buffer
  */
@@ -536,3 +542,129 @@ int util_file_read_va(const char *path,
 		return -1;
 	return ret;
 }
+
+/**
+ * Print an error message indicating an out-of-memory situation and exit.
+ */
+static void oom(void)
+{
+	fprintf(stderr, "Out of memory\n");
+
+	/* We can't rely on our clean-up routines to work reliably during an
+	 * OOM situation, so just exit here.
+	 */
+	exit(UTIL_EXIT_OUT_OF_MEMORY);
+}
+
+/**
+ * Read all data from @fd and return address of resulting buffer in
+ * @buffer_ptr. If @size_ptr is non-zero, use it to store the size of the
+ * resulting buffer. Return %UTIL_EXIT_OK on success.
+ *
+ * @param[in]      fd         File descriptor to read data from
+ * @param[in, out] buffer_ptr Buffer to read data into
+ * @param[in, out] size_ptr   Buffer to save size of data read into buffer_ptr
+ *
+ * @retval         0                       read was successful
+ * @retval         UTIL_EXIT_RUNTIME_ERROR error while reading file
+ */
+util_exit_code_t util_file_read_fd_buf(FILE *fd, void **buffer_ptr,
+				       size_t *size_ptr)
+{
+	char *buffer = NULL;
+	size_t done = 0;
+
+	while (!feof(fd)) {
+		buffer = realloc(buffer, done + READ_CHUNK_SIZE);
+		if (!buffer)
+			oom();
+		done += fread(&buffer[done], 1, READ_CHUNK_SIZE, fd);
+		if (ferror(fd)) {
+			free(buffer);
+			return UTIL_EXIT_RUNTIME_ERROR;
+		}
+	}
+
+	buffer = realloc(buffer, done);
+	if (!buffer && done > 0)
+		oom();
+
+	*buffer_ptr = buffer;
+	if (size_ptr)
+		*size_ptr = done;
+
+	return UTIL_EXIT_OK;
+}
+
+/**
+ * Read text from @fd and return resulting NULL-terminated text buffer.
+ * If @chomp is non-zero, remove trailing newline character. Return %NULL
+ * on error or when unprintable characters are read.
+ *
+ * @param[in]  fd         File descriptor to read data from
+ * @param[in]  chomp      Flag to indicate trailing newlines should be removed
+ *
+ * @retval     NULL       Error reading from fd
+ * @retval     != 0       Data read successfully, buffer returned
+ */
+char *util_file_read_fd(FILE *fd, int chomp)
+{
+	char *buffer;
+	size_t done, i;
+
+	if (util_file_read_fd_buf(fd, (void **) &buffer, &done))
+		return NULL;
+
+	/* Check if this is a text file at all (required to filter out
+	 * binary sysfs attributes).
+	 */
+	for (i = 0; i < done; i++) {
+		if (!isgraph(buffer[i]) && !isspace(buffer[i])) {
+			free(buffer);
+			return NULL;
+		}
+	}
+
+	/* Remove trailing new-line character if requested. */
+	if (chomp && done > 0 && buffer[done - 1] == '\n')
+		done--;
+
+	/* NULL-terminate. */
+	buffer = realloc(buffer, done + 1);
+	if (!buffer)
+		oom();
+	buffer[done] = 0;
+
+	return buffer;
+}
+
+/**
+ * Read file as text and return NULL-terminated contents. Remove trailing
+ * newline if CHOMP is specified.
+ *
+ * @param[in]  path       Path to the file that will be read from
+ * @param[in]  chomp      Flag to indicate trailing newlines should be removed
+ *
+ * @retval     NULL       Error reading from file
+ * @retval     != 0       File read successfully, contents returned in buffer
+ */
+char *util_file_read_text_file(const char *path, int chomp)
+{
+	char *buffer = NULL;
+	FILE *fd;
+
+	fd = fopen(path, "r");
+	if (!fd)
+		goto out;
+
+	buffer = util_file_read_fd(fd, chomp);
+	fclose(fd);
+
+out:
+	if (!buffer) {
+		fprintf(stderr, "Could not read file %s: %s\n", path,
+			strerror(errno));
+	}
+
+	return buffer;
+}
--- a/zdev/include/misc.h
+++ b/zdev/include/misc.h
@@ -173,7 +173,6 @@ bool misc_read_dir(const char *, struct
 		       bool (*)(const char *, void *), void *);
 bool file_is_devnode(const char *);
 exit_code_t remove_file(const char *);
-exit_code_t misc_read_fd(FILE *fd, void **buffer, size_t *size_ptr);
 char *misc_read_text_file(const char *, int, err_t);
 char *misc_read_cmd_output(const char *, int, err_t);
 char *config_read_cmd_output(const char *, int, err_t);
--- a/zdev/src/firmware.c
+++ b/zdev/src/firmware.c
@@ -19,6 +19,8 @@
 #include <sys/types.h>
 #include <unistd.h>
 
+#include "lib/util_file.h"
+
 #include "attrib.h"
 #include "ccw.h"
 #include "ccwgroup.h"
@@ -187,7 +189,8 @@ static exit_code_t read_fw(struct fw_fil
 
 	for (retry = 0; retry < READ_RETRY; retry++) {
 		/* Read complete file once */
-		rc = misc_read_fd(fd, (void **) &buffer, &size);
+		rc = (exit_code_t) util_file_read_fd_buf(fd, (void **) &buffer,
+							 &size);
 		if (rc) {
 			warn("%s: Could not read file", filename);
 			return rc;
@@ -203,7 +206,8 @@ static exit_code_t read_fw(struct fw_fil
 			/* Could be a pipe, socket, or FIFO - accept v1. */
 			break;
 		}
-		rc = misc_read_fd(fd, (void **) &buffer2, &size2);
+		rc = (exit_code_t) util_file_read_fd_buf(fd, (void **) &buffer2,
+							 &size2);
 		if (rc || !buffer2) {
 			/* Could not get second version - accept v1. */
 			break;
--- a/zdev/src/misc.c
+++ b/zdev/src/misc.c
@@ -26,6 +26,8 @@
 #include <time.h>
 #include <unistd.h>
 
+#include "lib/util_file.h"
+
 #include "dasd.h"
 #include "device.h"
 #include "devtype.h"
@@ -97,71 +99,6 @@ static void dryrun_end_data(void)
 		fprintf(fd, "%c", DRYRUN_DATA_END);
 }
 
-#define READ_CHUNK_SIZE		4096
-
-/* Read all data from @fd and return address of resulting buffer in
- * @buffer_ptr. If @size_ptr is non-zero, use it to store the size of the
- * resulting buffer. Return %EXIT_OK on success. */
-exit_code_t misc_read_fd(FILE *fd, void **buffer_ptr, size_t *size_ptr)
-{
-	char *buffer = NULL;
-	size_t done = 0;
-
-	while (!feof(fd)) {
-		buffer = realloc(buffer, done + READ_CHUNK_SIZE);
-		if (!buffer)
-			oom();
-		done += fread(&buffer[done], 1, READ_CHUNK_SIZE, fd);
-		if (ferror(fd)) {
-			free(buffer);
-			return EXIT_RUNTIME_ERROR;
-		}
-	}
-
-	buffer = realloc(buffer, done);
-	if (!buffer && done > 0)
-		oom();
-
-	*buffer_ptr = buffer;
-	if (size_ptr)
-		*size_ptr = done;
-
-	return EXIT_OK;
-}
-
-/* Read text from @fd and return resulting NULL-terminated text buffer.
- * If @chomp is non-zero, remove trailing newline character. Return %NULL
- * on error or when unprintable characters are read. */
-static char *read_fd(FILE *fd, int chomp)
-{
-	char *buffer;
-	size_t done, i;
-
-	if (misc_read_fd(fd, (void **) &buffer, &done))
-		return NULL;
-
-	/* Check if this is a text file at all (required to filter out
-	 * binary sysfs attributes). */
-	for (i = 0; i < done; i++) {
-		if (!isgraph(buffer[i]) && !isspace(buffer[i])) {
-			free(buffer);
-			return NULL;
-		}
-	}
-
-	/* Remove trailing new-line character if requested. */
-	if (chomp && done > 0 && buffer[done - 1] == '\n')
-		done--;
-
-	/* NULL-terminate. */
-	buffer = realloc(buffer, done + 1);
-	if (!buffer)
-		oom();
-	buffer[done] = 0;
-
-	return buffer;
-}
-
 static int count_newline(const char *str)
 {
 	int i, newline;
@@ -182,7 +119,7 @@ static void dryrun_print(void)
 	int cmd, newline;
 
 	fseek(dryrun_file, 0, SEEK_SET);
-	txt = read_fd(dryrun_file, 0);
+	txt = util_file_read_fd(dryrun_file, 0);
 
 	if (!txt)
 		return;
@@ -979,7 +916,7 @@ char *misc_read_text_file(const char *pa
 	if (!fd)
 		goto out;
 
-	buffer = read_fd(fd, chomp);
+	buffer = util_file_read_fd(fd, chomp);
 	misc_fclose(fd);
 
 out:
@@ -1003,7 +940,7 @@ char *misc_read_cmd_output(const char *c
 	if (!fd)
 		goto out;
 
-	buffer = read_fd(fd, chomp);
+	buffer = util_file_read_fd(fd, chomp);
 	pclose(fd);
 
 out:
@@ -1027,7 +964,7 @@ char *config_read_cmd_output(const char
 	if (!fd)
 		goto out;
 
-	buffer = read_fd(fd, chomp);
+	buffer = util_file_read_fd(fd, chomp);
 	misc_pclose(fd);
 
 out:
