Commit 8d7253dc authored by Benjamin Gray's avatar Benjamin Gray Committed by Michael Ellerman
Browse files

selftests/powerpc: Add automatically allocating read_file



A couple of tests roll their own auto-allocating file read logic.

Add a generic implementation and convert them to use it.

Signed-off-by: default avatarBenjamin Gray <bgray@linux.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
Link: https://lore.kernel.org/r/20230203003947.38033-6-bgray@linux.ibm.com
parent 5c20de57
Loading
Loading
Loading
Loading
+1 −0
Original line number Diff line number Diff line
@@ -42,6 +42,7 @@ int parse_ulong(const char *buffer, size_t count, unsigned long *result, int bas

int read_file(const char *path, char *buf, size_t count, size_t *len);
int write_file(const char *path, const char *buf, size_t count);
int read_file_alloc(const char *path, char **buf, size_t *len);
int read_long(const char *path, long *result, int base);
int write_long(const char *path, long result, int base);
int read_ulong(const char *path, unsigned long *result, int base);
+1 −37
Original line number Diff line number Diff line
@@ -143,42 +143,6 @@ int gzip_header_blank(char *buf)
	return i;
}

/* Caller must free the allocated buffer return nonzero on error. */
int read_alloc_input_file(char *fname, char **buf, size_t *bufsize)
{
	int err;
	struct stat statbuf;
	char *p;
	size_t num_bytes;

	if (stat(fname, &statbuf)) {
		perror(fname);
		return -1;
	}

	assert(NULL != (p = (char *) malloc(statbuf.st_size)));

	err = read_file(fname, p, statbuf.st_size, &num_bytes);
	if (err) {
		perror(fname);
		goto fail;
	}

	if (num_bytes != statbuf.st_size) {
		fprintf(stderr, "Actual bytes != expected bytes\n");
		err = -1;
		goto fail;
	}

	*buf = p;
	*bufsize = num_bytes;
	return 0;

fail:
	free(p);
	return err;
}

/*
 * Z_SYNC_FLUSH as described in zlib.h.
 * Returns number of appended bytes
@@ -245,7 +209,7 @@ int compress_file(int argc, char **argv, void *handle)
		fprintf(stderr, "usage: %s <fname>\n", argv[0]);
		exit(-1);
	}
	if (read_alloc_input_file(argv[1], &inbuf, &inlen))
	if (read_file_alloc(argv[1], &inbuf, &inlen))
		exit(-1);
	fprintf(stderr, "file %s read, %ld bytes\n", argv[1], inlen);

+1 −1
Original line number Diff line number Diff line
@@ -6,4 +6,4 @@ CFLAGS += -I../../../../../usr/include
top_srcdir = ../../../../..
include ../../lib.mk

$(TEST_GEN_PROGS): ../harness.c
$(TEST_GEN_PROGS): ../harness.c ../utils.c
+10 −71
Original line number Diff line number Diff line
@@ -8,6 +8,7 @@
#include <byteswap.h>
#include <stdint.h>
#include <inttypes.h>
#include <linux/limits.h>
#include <stdio.h>
#include <string.h>
#include <sys/syscall.h>
@@ -50,70 +51,16 @@ struct region {
	struct region *next;
};

int read_entire_file(int fd, char **buf, size_t *len)
{
	size_t buf_size = 0;
	size_t off = 0;
	int rc;

	*buf = NULL;
	do {
		buf_size += BLOCK_SIZE;
		if (*buf == NULL)
			*buf = malloc(buf_size);
		else
			*buf = realloc(*buf, buf_size);

		if (*buf == NULL)
			return -ENOMEM;

		rc = read(fd, *buf + off, BLOCK_SIZE);
		if (rc < 0)
			return -EIO;

		off += rc;
	} while (rc == BLOCK_SIZE);

	if (len)
		*len = off;

	return 0;
}

static int open_prop_file(const char *prop_path, const char *prop_name, int *fd)
{
	char *path;
	int len;

	/* allocate enough for two string, a slash and trailing NULL */
	len = strlen(prop_path) + strlen(prop_name) + 1 + 1;
	path = malloc(len);
	if (path == NULL)
		return -ENOMEM;

	snprintf(path, len, "%s/%s", prop_path, prop_name);

	*fd = open(path, O_RDONLY);
	free(path);
	if (*fd < 0)
		return -errno;

	return 0;
}

static int get_property(const char *prop_path, const char *prop_name,
			char **prop_val, size_t *prop_len)
{
	int rc, fd;

	rc = open_prop_file(prop_path, prop_name, &fd);
	if (rc)
		return rc;
	char path[PATH_MAX];

	rc = read_entire_file(fd, prop_val, prop_len);
	close(fd);
	int len = snprintf(path, sizeof(path), "%s/%s", prop_path, prop_name);
	if (len < 0 || len >= sizeof(path))
		return -ENOMEM;

	return rc;
	return read_file_alloc(path, prop_val, prop_len);
}

int rtas_token(const char *call_name)
@@ -138,22 +85,14 @@ int rtas_token(const char *call_name)
static int read_kregion_bounds(struct region *kregion)
{
	char *buf;
	int fd;
	int rc;
	int err;

	fd = open("/proc/ppc64/rtas/rmo_buffer", O_RDONLY);
	if (fd < 0) {
		printf("Could not open rmo_buffer file\n");
	err = read_file_alloc("/proc/ppc64/rtas/rmo_buffer", &buf, NULL);
	if (err) {
		perror("Could not open rmo_buffer file");
		return RTAS_IO_ASSERT;
	}

	rc = read_entire_file(fd, &buf, NULL);
	close(fd);
	if (rc) {
		free(buf);
		return rc;
	}

	sscanf(buf, "%" SCNx64 " %x", &kregion->addr, &kregion->size);
	free(buf);

+58 −0
Original line number Diff line number Diff line
@@ -65,6 +65,64 @@ int read_file(const char *path, char *buf, size_t count, size_t *len)
	return err;
}

int read_file_alloc(const char *path, char **buf, size_t *len)
{
	size_t read_offset = 0;
	size_t buffer_len = 0;
	char *buffer = NULL;
	int err;
	int fd;

	fd = open(path, O_RDONLY);
	if (fd < 0)
		return -errno;

	/*
	 * We don't use stat & preallocate st_size because some non-files
	 * report 0 file size. Instead just dynamically grow the buffer
	 * as needed.
	 */
	while (1) {
		ssize_t rc;

		if (read_offset >= buffer_len / 2) {
			char *next_buffer;

			buffer_len = buffer_len ? buffer_len * 2 : 4096;
			next_buffer = realloc(buffer, buffer_len);
			if (!next_buffer) {
				err = -errno;
				goto out;
			}
			buffer = next_buffer;
		}

		rc = read(fd, buffer + read_offset, buffer_len - read_offset);
		if (rc < 0) {
			err = -errno;
			goto out;
		}

		if (rc == 0)
			break;

		read_offset += rc;
	}

	*buf = buffer;
	if (len)
		*len = read_offset;

	err = 0;

out:
	close(fd);
	if (err)
		free(buffer);
	errno = -err;
	return err;
}

int write_file(const char *path, const char *buf, size_t count)
{
	int fd;