* [PATCH 0/5] Expand selftest utils
@ 2023-02-03 0:39 Benjamin Gray
2023-02-03 0:39 ` [PATCH 1/5] selftests/powerpc: Add generic read/write file util Benjamin Gray
` (5 more replies)
0 siblings, 6 replies; 7+ messages in thread
From: Benjamin Gray @ 2023-02-03 0:39 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Benjamin Gray
Started this when writing tests for a feature I'm working on, needing a way to
read/write numbers to system files. After writing some utils to safely handle
file IO and parsing, I realised I'd made the ~6th file read/write implementation
and only(?) number parser that checks all the failure modes when expecting to
parse a single number from a file.
So these utils ended up becoming this series. I also modified some other test
utils I came across while doing so. My understanding is selftests are not expected
to be backported, so I wasn't concerned about only introducing new utils and leaving
the existing implementations be.
V3: * Add reviewed-by from previous version
* Fix write(2) call to include creation mode
V4: * Drop patches merged in v3
* Miscellaneous refactoring
* Bigger changes mentioned on the relevant patch
Benjamin Gray (5):
selftests/powerpc: Add generic read/write file util
selftests/powerpc: Add read/write debugfs file, int
selftests/powerpc: Parse long/unsigned long value safely
selftests/powerpc: Add {read,write}_{long,ulong}
selftests/powerpc: Add automatically allocating read_file
tools/testing/selftests/powerpc/dscr/dscr.h | 34 +-
.../selftests/powerpc/dscr/dscr_sysfs_test.c | 25 +-
.../testing/selftests/powerpc/include/utils.h | 20 +-
.../selftests/powerpc/nx-gzip/gzfht_test.c | 52 +--
tools/testing/selftests/powerpc/pmu/lib.c | 34 +-
.../selftests/powerpc/ptrace/core-pkey.c | 28 +-
.../selftests/powerpc/security/entry_flush.c | 12 +-
.../selftests/powerpc/security/rfi_flush.c | 12 +-
.../powerpc/security/uaccess_flush.c | 18 +-
.../selftests/powerpc/syscalls/Makefile | 2 +-
.../selftests/powerpc/syscalls/rtas_filter.c | 81 +---
tools/testing/selftests/powerpc/utils.c | 412 +++++++++++++++---
12 files changed, 431 insertions(+), 299 deletions(-)
base-commit: ca272751ba18ca8f137af631cbc9f3f987fab6e3
--
2.39.1
^ permalink raw reply [flat|nested] 7+ messages in thread
* [PATCH 1/5] selftests/powerpc: Add generic read/write file util
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
@ 2023-02-03 0:39 ` Benjamin Gray
2023-02-03 0:39 ` [PATCH 2/5] selftests/powerpc: Add read/write debugfs file, int Benjamin Gray
` (4 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gray @ 2023-02-03 0:39 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Benjamin Gray
File read/write is reimplemented in about 5 different ways in the
various PowerPC selftests. This indicates it should be a common util.
Add a common read_file / write_file implementation and convert users
to it where (easily) possible.
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
v4: * Set errno as expected by many users that call perror() if
it fails (e.g., read_debugfs_file users in powerpc/security)
---
tools/testing/selftests/powerpc/dscr/dscr.h | 33 ++---
.../selftests/powerpc/dscr/dscr_sysfs_test.c | 21 +--
.../testing/selftests/powerpc/include/utils.h | 2 +
.../selftests/powerpc/nx-gzip/gzfht_test.c | 48 +++----
tools/testing/selftests/powerpc/pmu/lib.c | 31 ++--
.../selftests/powerpc/ptrace/core-pkey.c | 28 ++--
tools/testing/selftests/powerpc/utils.c | 133 +++++++++++-------
7 files changed, 128 insertions(+), 168 deletions(-)
diff --git a/tools/testing/selftests/powerpc/dscr/dscr.h b/tools/testing/selftests/powerpc/dscr/dscr.h
index b703714e7d98..aaa2b0d89f7e 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr.h
+++ b/tools/testing/selftests/powerpc/dscr/dscr.h
@@ -64,48 +64,31 @@ inline void set_dscr_usr(unsigned long val)
/* Default DSCR access */
unsigned long get_default_dscr(void)
{
- int fd = -1, ret;
- char buf[16];
+ int err;
+ char buf[16] = {0};
unsigned long val;
- if (fd == -1) {
- fd = open(DSCR_DEFAULT, O_RDONLY);
- if (fd == -1) {
- perror("open() failed");
- exit(1);
- }
- }
- memset(buf, 0, sizeof(buf));
- lseek(fd, 0, SEEK_SET);
- ret = read(fd, buf, sizeof(buf));
- if (ret == -1) {
+ err = read_file(DSCR_DEFAULT, buf, sizeof(buf) - 1, NULL);
+ if (err) {
perror("read() failed");
exit(1);
}
sscanf(buf, "%lx", &val);
- close(fd);
return val;
}
void set_default_dscr(unsigned long val)
{
- int fd = -1, ret;
+ int err;
char buf[16];
- if (fd == -1) {
- fd = open(DSCR_DEFAULT, O_RDWR);
- if (fd == -1) {
- perror("open() failed");
- exit(1);
- }
- }
sprintf(buf, "%lx\n", val);
- ret = write(fd, buf, strlen(buf));
- if (ret == -1) {
+
+ err = write_file(DSCR_DEFAULT, buf, strlen(buf));
+ if (err) {
perror("write() failed");
exit(1);
}
- close(fd);
}
double uniform_deviate(int seed)
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c b/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
index f20d1c166d1e..c350f193830a 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
@@ -12,24 +12,13 @@
static int check_cpu_dscr_default(char *file, unsigned long val)
{
- char buf[10];
- int fd, rc;
+ char buf[10] = {0};
+ int rc;
- fd = open(file, O_RDWR);
- if (fd == -1) {
- perror("open() failed");
- return 1;
- }
+ rc = read_file(file, buf, sizeof(buf) - 1, NULL);
+ if (rc)
+ return rc;
- rc = read(fd, buf, sizeof(buf));
- if (rc == -1) {
- perror("read() failed");
- close(fd);
- return 1;
- }
- close(fd);
-
- buf[rc] = '\0';
if (strtol(buf, NULL, 16) != val) {
printf("DSCR match failed: %ld (system) %ld (cpu)\n",
val, strtol(buf, NULL, 16));
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index e222a5858450..70885e5814a8 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -33,6 +33,8 @@ void *get_auxv_entry(int type);
int pick_online_cpu(void);
+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_debugfs_file(char *debugfs_file, int *result);
int write_debugfs_file(char *debugfs_file, int result);
int read_sysfs_file(char *debugfs_file, char *result, size_t result_size);
diff --git a/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c b/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c
index 095195a25687..fbc3d265155b 100644
--- a/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c
+++ b/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c
@@ -146,49 +146,37 @@ int gzip_header_blank(char *buf)
/* 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;
- FILE *fp;
char *p;
size_t num_bytes;
if (stat(fname, &statbuf)) {
perror(fname);
- return(-1);
- }
- fp = fopen(fname, "r");
- if (fp == NULL) {
- perror(fname);
- return(-1);
+ return -1;
}
+
assert(NULL != (p = (char *) malloc(statbuf.st_size)));
- num_bytes = fread(p, 1, statbuf.st_size, fp);
- if (ferror(fp) || (num_bytes != statbuf.st_size)) {
+
+ err = read_file(fname, p, statbuf.st_size, &num_bytes);
+ if (err) {
perror(fname);
- return(-1);
+ 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;
-}
-/* Returns nonzero on error */
-int write_output_file(char *fname, char *buf, size_t bufsize)
-{
- FILE *fp;
- size_t num_bytes;
-
- fp = fopen(fname, "w");
- if (fp == NULL) {
- perror(fname);
- return(-1);
- }
- num_bytes = fwrite(buf, 1, bufsize, fp);
- if (ferror(fp) || (num_bytes != bufsize)) {
- perror(fname);
- return(-1);
- }
- fclose(fp);
- return 0;
+fail:
+ free(p);
+ return err;
}
/*
@@ -399,7 +387,7 @@ int compress_file(int argc, char **argv, void *handle)
assert(FNAME_MAX > (strlen(argv[1]) + strlen(FEXT)));
strcpy(outname, argv[1]);
strcat(outname, FEXT);
- if (write_output_file(outname, outbuf, dsttotlen)) {
+ if (write_file(outname, outbuf, dsttotlen)) {
fprintf(stderr, "write error: %s\n", outname);
exit(-1);
}
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index 88690b97b7b9..960915304a65 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -190,38 +190,23 @@ int parse_proc_maps(void)
bool require_paranoia_below(int level)
{
+ int err;
long current;
- char *end, buf[16];
- FILE *f;
- bool rc;
+ char *end;
+ char buf[16] = {0};
- rc = false;
-
- f = fopen(PARANOID_PATH, "r");
- if (!f) {
- perror("fopen");
- goto out;
- }
-
- if (!fgets(buf, sizeof(buf), f)) {
+ err = read_file(PARANOID_PATH, buf, sizeof(buf) - 1, NULL);
+ if (err) {
printf("Couldn't read " PARANOID_PATH "?\n");
- goto out_close;
+ return false;
}
current = strtol(buf, &end, 10);
if (end == buf) {
printf("Couldn't parse " PARANOID_PATH "?\n");
- goto out_close;
+ return false;
}
- if (current >= level)
- goto out_close;
-
- rc = true;
-out_close:
- fclose(f);
-out:
- return rc;
+ return current < level;
}
-
diff --git a/tools/testing/selftests/powerpc/ptrace/core-pkey.c b/tools/testing/selftests/powerpc/ptrace/core-pkey.c
index 4e8d0ce1ff58..f6f8596ce8e1 100644
--- a/tools/testing/selftests/powerpc/ptrace/core-pkey.c
+++ b/tools/testing/selftests/powerpc/ptrace/core-pkey.c
@@ -348,15 +348,11 @@ static int parent(struct shared_info *info, pid_t pid)
static int write_core_pattern(const char *core_pattern)
{
- size_t len = strlen(core_pattern), ret;
- FILE *f;
+ int err;
- f = fopen(core_pattern_file, "w");
- SKIP_IF_MSG(!f, "Try with root privileges");
-
- ret = fwrite(core_pattern, 1, len, f);
- fclose(f);
- if (ret != len) {
+ err = write_file(core_pattern_file, core_pattern, strlen(core_pattern));
+ if (err) {
+ SKIP_IF_MSG(err == -EPERM, "Try with root privileges");
perror("Error writing to core_pattern file");
return TEST_FAIL;
}
@@ -366,8 +362,8 @@ static int write_core_pattern(const char *core_pattern)
static int setup_core_pattern(char **core_pattern_, bool *changed_)
{
- FILE *f;
char *core_pattern;
+ size_t len;
int ret;
core_pattern = malloc(PATH_MAX);
@@ -376,22 +372,14 @@ static int setup_core_pattern(char **core_pattern_, bool *changed_)
return TEST_FAIL;
}
- f = fopen(core_pattern_file, "r");
- if (!f) {
- perror("Error opening core_pattern file");
- ret = TEST_FAIL;
- goto out;
- }
-
- ret = fread(core_pattern, 1, PATH_MAX - 1, f);
- fclose(f);
- if (!ret) {
+ ret = read_file(core_pattern_file, core_pattern, PATH_MAX - 1, &len);
+ if (ret) {
perror("Error reading core_pattern file");
ret = TEST_FAIL;
goto out;
}
- core_pattern[ret] = '\0';
+ core_pattern[len] = '\0';
/* Check whether we can predict the name of the core file. */
if (!strcmp(core_pattern, "core") || !strcmp(core_pattern, "core.%p"))
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index 1f36ee1a909a..22ba13425b2c 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -26,34 +26,83 @@
static char auxv[4096];
+int read_file(const char *path, char *buf, size_t count, size_t *len)
+{
+ ssize_t rc;
+ int fd;
+ int err;
+ char eof;
+
+ fd = open(path, O_RDONLY);
+ if (fd < 0)
+ return -errno;
+
+ rc = read(fd, buf, count);
+ if (rc < 0) {
+ err = -errno;
+ goto out;
+ }
+
+ if (len)
+ *len = rc;
+
+ /* Overflow if there are still more bytes after filling the buffer */
+ if (rc == count) {
+ rc = read(fd, &eof, 1);
+ if (rc != 0) {
+ err = -EOVERFLOW;
+ goto out;
+ }
+ }
+
+ err = 0;
+
+out:
+ close(fd);
+ errno = -err;
+ return err;
+}
+
+int write_file(const char *path, const char *buf, size_t count)
+{
+ int fd;
+ int err;
+ ssize_t rc;
+
+ fd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0644);
+ if (fd < 0)
+ return -errno;
+
+ rc = write(fd, buf, count);
+ if (rc < 0) {
+ err = -errno;
+ goto out;
+ }
+
+ if (rc != count) {
+ err = -EOVERFLOW;
+ goto out;
+ }
+
+ err = 0;
+
+out:
+ close(fd);
+ errno = -err;
+ return err;
+}
+
int read_auxv(char *buf, ssize_t buf_size)
{
- ssize_t num;
- int rc, fd;
+ int err;
- fd = open("/proc/self/auxv", O_RDONLY);
- if (fd == -1) {
- perror("open");
- return -errno;
+ err = read_file("/proc/self/auxv", buf, buf_size, NULL);
+ if (err) {
+ perror("Error reading /proc/self/auxv");
+ return err;
}
- num = read(fd, buf, buf_size);
- if (num < 0) {
- perror("read");
- rc = -EIO;
- goto out;
- }
-
- if (num > buf_size) {
- printf("overflowed auxv buffer\n");
- rc = -EOVERFLOW;
- goto out;
- }
-
- rc = 0;
-out:
- close(fd);
- return rc;
+ return 0;
}
void *find_auxv_entry(int type, char *auxv)
@@ -142,65 +191,41 @@ bool is_ppc64le(void)
int read_sysfs_file(char *fpath, char *result, size_t result_size)
{
char path[PATH_MAX] = "/sys/";
- int rc = -1, fd;
strncat(path, fpath, PATH_MAX - strlen(path) - 1);
- if ((fd = open(path, O_RDONLY)) < 0)
- return rc;
-
- rc = read(fd, result, result_size);
-
- close(fd);
-
- if (rc < 0)
- return rc;
-
- return 0;
+ return read_file(path, result, result_size, NULL);
}
int read_debugfs_file(char *debugfs_file, int *result)
{
- int rc = -1, fd;
+ int err;
char path[PATH_MAX];
- char value[16];
+ char value[16] = {0};
strcpy(path, "/sys/kernel/debug/");
strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
- if ((fd = open(path, O_RDONLY)) < 0)
- return rc;
+ err = read_file(path, value, sizeof(value) - 1, NULL);
+ if (err)
+ return err;
- if ((rc = read(fd, value, sizeof(value))) < 0)
- return rc;
-
- value[15] = 0;
*result = atoi(value);
- close(fd);
return 0;
}
int write_debugfs_file(char *debugfs_file, int result)
{
- int rc = -1, fd;
char path[PATH_MAX];
char value[16];
strcpy(path, "/sys/kernel/debug/");
strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
- if ((fd = open(path, O_WRONLY)) < 0)
- return rc;
-
snprintf(value, 16, "%d", result);
- if ((rc = write(fd, value, strlen(value))) < 0)
- return rc;
-
- close(fd);
-
- return 0;
+ return write_file(path, value, strlen(value));
}
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
--
2.39.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 2/5] selftests/powerpc: Add read/write debugfs file, int
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
2023-02-03 0:39 ` [PATCH 1/5] selftests/powerpc: Add generic read/write file util Benjamin Gray
@ 2023-02-03 0:39 ` Benjamin Gray
2023-02-03 0:39 ` [PATCH 3/5] selftests/powerpc: Parse long/unsigned long value safely Benjamin Gray
` (3 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gray @ 2023-02-03 0:39 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Andrew Donnellan, Benjamin Gray
Debugfs files are not always integers, so make *_file return/write a
byte buffer, and *_int deal with int values specifically. This increases
consistency with the other file read/write helpers.
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
Reviewed-by: Andrew Donnellan <ajd@linux.ibm.com>
---
v4: * Add reviewed-by
---
.../testing/selftests/powerpc/include/utils.h | 6 ++--
.../selftests/powerpc/security/entry_flush.c | 12 +++----
.../selftests/powerpc/security/rfi_flush.c | 12 +++----
.../powerpc/security/uaccess_flush.c | 18 +++++-----
tools/testing/selftests/powerpc/utils.c | 34 ++++++++++++-------
5 files changed, 47 insertions(+), 35 deletions(-)
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index 70885e5814a8..de5e3790f397 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -35,8 +35,10 @@ int pick_online_cpu(void);
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_debugfs_file(char *debugfs_file, int *result);
-int write_debugfs_file(char *debugfs_file, int result);
+int read_debugfs_file(const char *debugfs_file, char *buf, size_t count);
+int write_debugfs_file(const char *debugfs_file, const char *buf, size_t count);
+int read_debugfs_int(const char *debugfs_file, int *result);
+int write_debugfs_int(const char *debugfs_file, int result);
int read_sysfs_file(char *debugfs_file, char *result, size_t result_size);
int perf_event_open_counter(unsigned int type,
unsigned long config, int group_fd);
diff --git a/tools/testing/selftests/powerpc/security/entry_flush.c b/tools/testing/selftests/powerpc/security/entry_flush.c
index 68ce377b205e..e01c573deadd 100644
--- a/tools/testing/selftests/powerpc/security/entry_flush.c
+++ b/tools/testing/selftests/powerpc/security/entry_flush.c
@@ -34,18 +34,18 @@ int entry_flush_test(void)
// The PMU event we use only works on Power7 or later
SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
- if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
perror("Unable to read powerpc/rfi_flush debugfs file");
SKIP_IF(1);
}
- if (read_debugfs_file("powerpc/entry_flush", &entry_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/entry_flush", &entry_flush_orig) < 0) {
perror("Unable to read powerpc/entry_flush debugfs file");
SKIP_IF(1);
}
if (rfi_flush_orig != 0) {
- if (write_debugfs_file("powerpc/rfi_flush", 0) < 0) {
+ if (write_debugfs_int("powerpc/rfi_flush", 0) < 0) {
perror("error writing to powerpc/rfi_flush debugfs file");
FAIL_IF(1);
}
@@ -105,7 +105,7 @@ int entry_flush_test(void)
if (entry_flush == entry_flush_orig) {
entry_flush = !entry_flush_orig;
- if (write_debugfs_file("powerpc/entry_flush", entry_flush) < 0) {
+ if (write_debugfs_int("powerpc/entry_flush", entry_flush) < 0) {
perror("error writing to powerpc/entry_flush debugfs file");
return 1;
}
@@ -120,12 +120,12 @@ int entry_flush_test(void)
set_dscr(0);
- if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/rfi_flush", rfi_flush_orig) < 0) {
perror("unable to restore original value of powerpc/rfi_flush debugfs file");
return 1;
}
- if (write_debugfs_file("powerpc/entry_flush", entry_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/entry_flush", entry_flush_orig) < 0) {
perror("unable to restore original value of powerpc/entry_flush debugfs file");
return 1;
}
diff --git a/tools/testing/selftests/powerpc/security/rfi_flush.c b/tools/testing/selftests/powerpc/security/rfi_flush.c
index f73484a6470f..6bedc86443a6 100644
--- a/tools/testing/selftests/powerpc/security/rfi_flush.c
+++ b/tools/testing/selftests/powerpc/security/rfi_flush.c
@@ -34,18 +34,18 @@ int rfi_flush_test(void)
// The PMU event we use only works on Power7 or later
SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
- if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
perror("Unable to read powerpc/rfi_flush debugfs file");
SKIP_IF(1);
}
- if (read_debugfs_file("powerpc/entry_flush", &entry_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/entry_flush", &entry_flush_orig) < 0) {
have_entry_flush = 0;
} else {
have_entry_flush = 1;
if (entry_flush_orig != 0) {
- if (write_debugfs_file("powerpc/entry_flush", 0) < 0) {
+ if (write_debugfs_int("powerpc/entry_flush", 0) < 0) {
perror("error writing to powerpc/entry_flush debugfs file");
return 1;
}
@@ -105,7 +105,7 @@ int rfi_flush_test(void)
if (rfi_flush == rfi_flush_orig) {
rfi_flush = !rfi_flush_orig;
- if (write_debugfs_file("powerpc/rfi_flush", rfi_flush) < 0) {
+ if (write_debugfs_int("powerpc/rfi_flush", rfi_flush) < 0) {
perror("error writing to powerpc/rfi_flush debugfs file");
return 1;
}
@@ -120,13 +120,13 @@ int rfi_flush_test(void)
set_dscr(0);
- if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/rfi_flush", rfi_flush_orig) < 0) {
perror("unable to restore original value of powerpc/rfi_flush debugfs file");
return 1;
}
if (have_entry_flush) {
- if (write_debugfs_file("powerpc/entry_flush", entry_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/entry_flush", entry_flush_orig) < 0) {
perror("unable to restore original value of powerpc/entry_flush "
"debugfs file");
return 1;
diff --git a/tools/testing/selftests/powerpc/security/uaccess_flush.c b/tools/testing/selftests/powerpc/security/uaccess_flush.c
index cf80f960e38a..fcf23ea9b183 100644
--- a/tools/testing/selftests/powerpc/security/uaccess_flush.c
+++ b/tools/testing/selftests/powerpc/security/uaccess_flush.c
@@ -36,30 +36,30 @@ int uaccess_flush_test(void)
// The PMU event we use only works on Power7 or later
SKIP_IF(!have_hwcap(PPC_FEATURE_ARCH_2_06));
- if (read_debugfs_file("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/rfi_flush", &rfi_flush_orig) < 0) {
perror("Unable to read powerpc/rfi_flush debugfs file");
SKIP_IF(1);
}
- if (read_debugfs_file("powerpc/entry_flush", &entry_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/entry_flush", &entry_flush_orig) < 0) {
perror("Unable to read powerpc/entry_flush debugfs file");
SKIP_IF(1);
}
- if (read_debugfs_file("powerpc/uaccess_flush", &uaccess_flush_orig) < 0) {
+ if (read_debugfs_int("powerpc/uaccess_flush", &uaccess_flush_orig) < 0) {
perror("Unable to read powerpc/entry_flush debugfs file");
SKIP_IF(1);
}
if (rfi_flush_orig != 0) {
- if (write_debugfs_file("powerpc/rfi_flush", 0) < 0) {
+ if (write_debugfs_int("powerpc/rfi_flush", 0) < 0) {
perror("error writing to powerpc/rfi_flush debugfs file");
FAIL_IF(1);
}
}
if (entry_flush_orig != 0) {
- if (write_debugfs_file("powerpc/entry_flush", 0) < 0) {
+ if (write_debugfs_int("powerpc/entry_flush", 0) < 0) {
perror("error writing to powerpc/entry_flush debugfs file");
FAIL_IF(1);
}
@@ -119,7 +119,7 @@ int uaccess_flush_test(void)
if (uaccess_flush == uaccess_flush_orig) {
uaccess_flush = !uaccess_flush_orig;
- if (write_debugfs_file("powerpc/uaccess_flush", uaccess_flush) < 0) {
+ if (write_debugfs_int("powerpc/uaccess_flush", uaccess_flush) < 0) {
perror("error writing to powerpc/uaccess_flush debugfs file");
return 1;
}
@@ -134,17 +134,17 @@ int uaccess_flush_test(void)
set_dscr(0);
- if (write_debugfs_file("powerpc/rfi_flush", rfi_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/rfi_flush", rfi_flush_orig) < 0) {
perror("unable to restore original value of powerpc/rfi_flush debugfs file");
return 1;
}
- if (write_debugfs_file("powerpc/entry_flush", entry_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/entry_flush", entry_flush_orig) < 0) {
perror("unable to restore original value of powerpc/entry_flush debugfs file");
return 1;
}
- if (write_debugfs_file("powerpc/uaccess_flush", uaccess_flush_orig) < 0) {
+ if (write_debugfs_int("powerpc/uaccess_flush", uaccess_flush_orig) < 0) {
perror("unable to restore original value of powerpc/uaccess_flush debugfs file");
return 1;
}
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index 22ba13425b2c..495299a79f50 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -105,6 +105,24 @@ int read_auxv(char *buf, ssize_t buf_size)
return 0;
}
+int read_debugfs_file(const char *subpath, char *buf, size_t count)
+{
+ char path[PATH_MAX] = "/sys/kernel/debug/";
+
+ strncat(path, subpath, sizeof(path) - strlen(path) - 1);
+
+ return read_file(path, buf, count, NULL);
+}
+
+int write_debugfs_file(const char *subpath, const char *buf, size_t count)
+{
+ char path[PATH_MAX] = "/sys/kernel/debug/";
+
+ strncat(path, subpath, sizeof(path) - strlen(path) - 1);
+
+ return write_file(path, buf, count);
+}
+
void *find_auxv_entry(int type, char *auxv)
{
ElfW(auxv_t) *p;
@@ -197,16 +215,12 @@ int read_sysfs_file(char *fpath, char *result, size_t result_size)
return read_file(path, result, result_size, NULL);
}
-int read_debugfs_file(char *debugfs_file, int *result)
+int read_debugfs_int(const char *debugfs_file, int *result)
{
int err;
- char path[PATH_MAX];
char value[16] = {0};
- strcpy(path, "/sys/kernel/debug/");
- strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
-
- err = read_file(path, value, sizeof(value) - 1, NULL);
+ err = read_debugfs_file(debugfs_file, value, sizeof(value) - 1);
if (err)
return err;
@@ -215,17 +229,13 @@ int read_debugfs_file(char *debugfs_file, int *result)
return 0;
}
-int write_debugfs_file(char *debugfs_file, int result)
+int write_debugfs_int(const char *debugfs_file, int result)
{
- char path[PATH_MAX];
char value[16];
- strcpy(path, "/sys/kernel/debug/");
- strncat(path, debugfs_file, PATH_MAX - strlen(path) - 1);
-
snprintf(value, 16, "%d", result);
- return write_file(path, value, strlen(value));
+ return write_debugfs_file(debugfs_file, value, strlen(value));
}
static long perf_event_open(struct perf_event_attr *hw_event, pid_t pid,
--
2.39.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 3/5] selftests/powerpc: Parse long/unsigned long value safely
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
2023-02-03 0:39 ` [PATCH 1/5] selftests/powerpc: Add generic read/write file util Benjamin Gray
2023-02-03 0:39 ` [PATCH 2/5] selftests/powerpc: Add read/write debugfs file, int Benjamin Gray
@ 2023-02-03 0:39 ` Benjamin Gray
2023-02-03 0:39 ` [PATCH 4/5] selftests/powerpc: Add {read,write}_{long,ulong} Benjamin Gray
` (2 subsequent siblings)
5 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gray @ 2023-02-03 0:39 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Benjamin Gray
Often a file is expected to hold an integral value. Existing functions
will use a C stdlib function like atoi or strtol to parse the file.
These operations are error prone, with complicated error conditions
(atoi returns 0 if not a number, and is undefined behaviour if not in
range. strtol returns 0 if not a number, and LONG_MIN/MAX if not in
range + sets errno to ERANGE).
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
v4: * Implement as C functions, remove macros
* Declare parsers for intmax_t, uintmax_t
* Stop validating the remaining buffer after a null terminator
* Set errno to match the return code
---
.../testing/selftests/powerpc/include/utils.h | 7 +
tools/testing/selftests/powerpc/pmu/lib.c | 6 +-
tools/testing/selftests/powerpc/utils.c | 126 +++++++++++++++++-
3 files changed, 132 insertions(+), 7 deletions(-)
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index de5e3790f397..7c1fa385824c 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -33,6 +33,13 @@ void *get_auxv_entry(int type);
int pick_online_cpu(void);
+int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base);
+int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base);
+int parse_int(const char *buffer, size_t count, int *result, int base);
+int parse_uint(const char *buffer, size_t count, unsigned int *result, int base);
+int parse_long(const char *buffer, size_t count, long *result, int base);
+int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base);
+
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_debugfs_file(const char *debugfs_file, char *buf, size_t count);
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index 960915304a65..1cfc13a25aee 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -192,7 +192,6 @@ bool require_paranoia_below(int level)
{
int err;
long current;
- char *end;
char buf[16] = {0};
err = read_file(PARANOID_PATH, buf, sizeof(buf) - 1, NULL);
@@ -201,9 +200,8 @@ bool require_paranoia_below(int level)
return false;
}
- current = strtol(buf, &end, 10);
-
- if (end == buf) {
+ err = parse_long(buf, sizeof(buf), ¤t, 10);
+ if (err) {
printf("Couldn't parse " PARANOID_PATH "?\n");
return false;
}
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index 495299a79f50..ddfd871881bf 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -8,6 +8,8 @@
#include <elf.h>
#include <errno.h>
#include <fcntl.h>
+#include <inttypes.h>
+#include <limits.h>
#include <link.h>
#include <sched.h>
#include <stdio.h>
@@ -123,6 +125,126 @@ int write_debugfs_file(const char *subpath, const char *buf, size_t count)
return write_file(path, buf, count);
}
+static int validate_int_parse(const char *buffer, size_t count, char *end)
+{
+ int err = 0;
+
+ /* Require at least one digit */
+ if (end == buffer) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ /* Require all remaining characters be whitespace-ish */
+ for (; end < buffer + count; end++) {
+ if (*end == '\0')
+ break;
+
+ if (*end != ' ' && *end != '\n') {
+ err = -EINVAL;
+ goto out;
+ }
+ }
+
+out:
+ errno = -err;
+ return err;
+}
+
+static int parse_bounded_int(const char *buffer, size_t count, intmax_t *result,
+ int base, intmax_t min, intmax_t max)
+{
+ int err;
+ char *end;
+
+ errno = 0;
+ *result = strtoimax(buffer, &end, base);
+
+ if (errno)
+ return -errno;
+
+ err = validate_int_parse(buffer, count, end);
+ if (err)
+ goto out;
+
+ if (*result < min || *result > max)
+ err = -EOVERFLOW;
+
+out:
+ errno = -err;
+ return err;
+}
+
+static int parse_bounded_uint(const char *buffer, size_t count, uintmax_t *result,
+ int base, uintmax_t max)
+{
+ int err = 0;
+ char *end;
+
+ errno = 0;
+ *result = strtoumax(buffer, &end, base);
+
+ if (errno)
+ return -errno;
+
+ err = validate_int_parse(buffer, count, end);
+ if (err)
+ goto out;
+
+ if (*result > max)
+ err = -EOVERFLOW;
+
+out:
+ errno = -err;
+ return err;
+}
+
+int parse_intmax(const char *buffer, size_t count, intmax_t *result, int base)
+{
+ return parse_bounded_int(buffer, count, result, base, INTMAX_MIN, INTMAX_MAX);
+}
+
+int parse_uintmax(const char *buffer, size_t count, uintmax_t *result, int base)
+{
+ return parse_bounded_uint(buffer, count, result, base, UINTMAX_MAX);
+}
+
+int parse_int(const char *buffer, size_t count, int *result, int base)
+{
+ intmax_t parsed;
+ int err = parse_bounded_int(buffer, count, &parsed, base, INT_MIN, INT_MAX);
+
+ *result = parsed;
+ return err;
+}
+
+int parse_uint(const char *buffer, size_t count, unsigned int *result, int base)
+{
+ uintmax_t parsed;
+ int err = parse_bounded_uint(buffer, count, &parsed, base, UINT_MAX);
+
+ *result = parsed;
+ return err;
+}
+
+int parse_long(const char *buffer, size_t count, long *result, int base)
+{
+ intmax_t parsed;
+ int err = parse_bounded_int(buffer, count, &parsed, base, LONG_MIN, LONG_MAX);
+
+ *result = parsed;
+ return err;
+}
+
+int parse_ulong(const char *buffer, size_t count, unsigned long *result, int base)
+{
+ uintmax_t parsed;
+ int err = parse_bounded_uint(buffer, count, &parsed, base, ULONG_MAX);
+
+ *result = parsed;
+ return err;
+}
+
void *find_auxv_entry(int type, char *auxv)
{
ElfW(auxv_t) *p;
@@ -224,9 +346,7 @@ int read_debugfs_int(const char *debugfs_file, int *result)
if (err)
return err;
- *result = atoi(value);
-
- return 0;
+ return parse_int(value, sizeof(value), result, 10);
}
int write_debugfs_int(const char *debugfs_file, int result)
--
2.39.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 4/5] selftests/powerpc: Add {read,write}_{long,ulong}
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
` (2 preceding siblings ...)
2023-02-03 0:39 ` [PATCH 3/5] selftests/powerpc: Parse long/unsigned long value safely Benjamin Gray
@ 2023-02-03 0:39 ` Benjamin Gray
2023-02-03 0:39 ` [PATCH 5/5] selftests/powerpc: Add automatically allocating read_file Benjamin Gray
2023-02-15 12:40 ` [PATCH 0/5] Expand selftest utils Michael Ellerman
5 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gray @ 2023-02-03 0:39 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Benjamin Gray
Add helper functions to read and write (unsigned) long values directly
from/to files. One of the kernel interfaces uses hex strings, so we need
to allow passing a base too.
Signed-off-by: Benjamin Gray <bgray@linux.ibm.com>
---
v4: * Set errno where it isn't already set
---
tools/testing/selftests/powerpc/dscr/dscr.h | 9 +--
.../selftests/powerpc/dscr/dscr_sysfs_test.c | 14 ++--
.../testing/selftests/powerpc/include/utils.h | 4 +
tools/testing/selftests/powerpc/pmu/lib.c | 9 +--
tools/testing/selftests/powerpc/utils.c | 81 +++++++++++++++++++
5 files changed, 95 insertions(+), 22 deletions(-)
diff --git a/tools/testing/selftests/powerpc/dscr/dscr.h b/tools/testing/selftests/powerpc/dscr/dscr.h
index aaa2b0d89f7e..2c54998d4715 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr.h
+++ b/tools/testing/selftests/powerpc/dscr/dscr.h
@@ -65,26 +65,21 @@ inline void set_dscr_usr(unsigned long val)
unsigned long get_default_dscr(void)
{
int err;
- char buf[16] = {0};
unsigned long val;
- err = read_file(DSCR_DEFAULT, buf, sizeof(buf) - 1, NULL);
+ err = read_ulong(DSCR_DEFAULT, &val, 16);
if (err) {
perror("read() failed");
exit(1);
}
- sscanf(buf, "%lx", &val);
return val;
}
void set_default_dscr(unsigned long val)
{
int err;
- char buf[16];
- sprintf(buf, "%lx\n", val);
-
- err = write_file(DSCR_DEFAULT, buf, strlen(buf));
+ err = write_ulong(DSCR_DEFAULT, val, 16);
if (err) {
perror("write() failed");
exit(1);
diff --git a/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c b/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
index c350f193830a..4f1fef6198fc 100644
--- a/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
+++ b/tools/testing/selftests/powerpc/dscr/dscr_sysfs_test.c
@@ -12,16 +12,16 @@
static int check_cpu_dscr_default(char *file, unsigned long val)
{
- char buf[10] = {0};
- int rc;
+ unsigned long cpu_dscr;
+ int err;
- rc = read_file(file, buf, sizeof(buf) - 1, NULL);
- if (rc)
- return rc;
+ err = read_ulong(file, &cpu_dscr, 16);
+ if (err)
+ return err;
- if (strtol(buf, NULL, 16) != val) {
+ if (cpu_dscr != val) {
printf("DSCR match failed: %ld (system) %ld (cpu)\n",
- val, strtol(buf, NULL, 16));
+ val, cpu_dscr);
return 1;
}
return 0;
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index 7c1fa385824c..311ddc124ebc 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -42,6 +42,10 @@ 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_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);
+int write_ulong(const char *path, unsigned long result, int base);
int read_debugfs_file(const char *debugfs_file, char *buf, size_t count);
int write_debugfs_file(const char *debugfs_file, const char *buf, size_t count);
int read_debugfs_int(const char *debugfs_file, int *result);
diff --git a/tools/testing/selftests/powerpc/pmu/lib.c b/tools/testing/selftests/powerpc/pmu/lib.c
index 1cfc13a25aee..719f94f10d41 100644
--- a/tools/testing/selftests/powerpc/pmu/lib.c
+++ b/tools/testing/selftests/powerpc/pmu/lib.c
@@ -192,15 +192,8 @@ bool require_paranoia_below(int level)
{
int err;
long current;
- char buf[16] = {0};
- err = read_file(PARANOID_PATH, buf, sizeof(buf) - 1, NULL);
- if (err) {
- printf("Couldn't read " PARANOID_PATH "?\n");
- return false;
- }
-
- err = parse_long(buf, sizeof(buf), ¤t, 10);
+ err = read_long(PARANOID_PATH, ¤t, 10);
if (err) {
printf("Couldn't parse " PARANOID_PATH "?\n");
return false;
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index ddfd871881bf..1017f1738619 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -245,6 +245,87 @@ int parse_ulong(const char *buffer, size_t count, unsigned long *result, int bas
return err;
}
+int read_long(const char *path, long *result, int base)
+{
+ int err;
+ char buffer[32] = {0};
+
+ err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
+ if (err)
+ return err;
+
+ return parse_long(buffer, sizeof(buffer), result, base);
+}
+
+int read_ulong(const char *path, unsigned long *result, int base)
+{
+ int err;
+ char buffer[32] = {0};
+
+ err = read_file(path, buffer, sizeof(buffer) - 1, NULL);
+ if (err)
+ return err;
+
+ return parse_ulong(buffer, sizeof(buffer), result, base);
+}
+
+int write_long(const char *path, long result, int base)
+{
+ int err;
+ int len;
+ char buffer[32];
+
+ /* Decimal only for now: no format specifier for signed hex values */
+ if (base != 10) {
+ err = -EINVAL;
+ goto out;
+ }
+
+ len = snprintf(buffer, sizeof(buffer), "%ld", result);
+ if (len < 0 || len >= sizeof(buffer)) {
+ err = -EOVERFLOW;
+ goto out;
+ }
+
+ err = write_file(path, buffer, len);
+
+out:
+ errno = -err;
+ return err;
+}
+
+int write_ulong(const char *path, unsigned long result, int base)
+{
+ int err;
+ int len;
+ char buffer[32];
+ char *fmt;
+
+ switch (base) {
+ case 10:
+ fmt = "%lu";
+ break;
+ case 16:
+ fmt = "%lx";
+ break;
+ default:
+ err = -EINVAL;
+ goto out;
+ }
+
+ len = snprintf(buffer, sizeof(buffer), fmt, result);
+ if (len < 0 || len >= sizeof(buffer)) {
+ err = -errno;
+ goto out;
+ }
+
+ err = write_file(path, buffer, len);
+
+out:
+ errno = -err;
+ return err;
+}
+
void *find_auxv_entry(int type, char *auxv)
{
ElfW(auxv_t) *p;
--
2.39.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* [PATCH 5/5] selftests/powerpc: Add automatically allocating read_file
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
` (3 preceding siblings ...)
2023-02-03 0:39 ` [PATCH 4/5] selftests/powerpc: Add {read,write}_{long,ulong} Benjamin Gray
@ 2023-02-03 0:39 ` Benjamin Gray
2023-02-15 12:40 ` [PATCH 0/5] Expand selftest utils Michael Ellerman
5 siblings, 0 replies; 7+ messages in thread
From: Benjamin Gray @ 2023-02-03 0:39 UTC (permalink / raw)
To: linuxppc-dev; +Cc: Benjamin Gray
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: Benjamin Gray <bgray@linux.ibm.com>
---
v4: * Make allocation more concise using realloc(NULL, length)
without special casing initial malloc(length)
---
.../testing/selftests/powerpc/include/utils.h | 1 +
.../selftests/powerpc/nx-gzip/gzfht_test.c | 38 +--------
.../selftests/powerpc/syscalls/Makefile | 2 +-
.../selftests/powerpc/syscalls/rtas_filter.c | 81 +++----------------
tools/testing/selftests/powerpc/utils.c | 58 +++++++++++++
5 files changed, 71 insertions(+), 109 deletions(-)
diff --git a/tools/testing/selftests/powerpc/include/utils.h b/tools/testing/selftests/powerpc/include/utils.h
index 311ddc124ebc..eed7dd7582b2 100644
--- a/tools/testing/selftests/powerpc/include/utils.h
+++ b/tools/testing/selftests/powerpc/include/utils.h
@@ -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);
diff --git a/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c b/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c
index fbc3d265155b..4de079923ccb 100644
--- a/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c
+++ b/tools/testing/selftests/powerpc/nx-gzip/gzfht_test.c
@@ -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);
diff --git a/tools/testing/selftests/powerpc/syscalls/Makefile b/tools/testing/selftests/powerpc/syscalls/Makefile
index b63f8459c704..54ff5cfffc63 100644
--- a/tools/testing/selftests/powerpc/syscalls/Makefile
+++ b/tools/testing/selftests/powerpc/syscalls/Makefile
@@ -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
diff --git a/tools/testing/selftests/powerpc/syscalls/rtas_filter.c b/tools/testing/selftests/powerpc/syscalls/rtas_filter.c
index 03b487f18d00..9b17780f0b18 100644
--- a/tools/testing/selftests/powerpc/syscalls/rtas_filter.c
+++ b/tools/testing/selftests/powerpc/syscalls/rtas_filter.c
@@ -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;
+ char path[PATH_MAX];
- rc = open_prop_file(prop_path, prop_name, &fd);
- if (rc)
- return rc;
+ int len = snprintf(path, sizeof(path), "%s/%s", prop_path, prop_name);
+ if (len < 0 || len >= sizeof(path))
+ return -ENOMEM;
- rc = read_entire_file(fd, prop_val, prop_len);
- close(fd);
-
- 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);
diff --git a/tools/testing/selftests/powerpc/utils.c b/tools/testing/selftests/powerpc/utils.c
index 1017f1738619..7c8cfedb012a 100644
--- a/tools/testing/selftests/powerpc/utils.c
+++ b/tools/testing/selftests/powerpc/utils.c
@@ -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;
--
2.39.1
^ permalink raw reply related [flat|nested] 7+ messages in thread
* Re: [PATCH 0/5] Expand selftest utils
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
` (4 preceding siblings ...)
2023-02-03 0:39 ` [PATCH 5/5] selftests/powerpc: Add automatically allocating read_file Benjamin Gray
@ 2023-02-15 12:40 ` Michael Ellerman
5 siblings, 0 replies; 7+ messages in thread
From: Michael Ellerman @ 2023-02-15 12:40 UTC (permalink / raw)
To: linuxppc-dev, Benjamin Gray
On Fri, 3 Feb 2023 11:39:42 +1100, Benjamin Gray wrote:
> Started this when writing tests for a feature I'm working on, needing a way to
> read/write numbers to system files. After writing some utils to safely handle
> file IO and parsing, I realised I'd made the ~6th file read/write implementation
> and only(?) number parser that checks all the failure modes when expecting to
> parse a single number from a file.
>
> So these utils ended up becoming this series. I also modified some other test
> utils I came across while doing so. My understanding is selftests are not expected
> to be backported, so I wasn't concerned about only introducing new utils and leaving
> the existing implementations be.
>
> [...]
Applied to powerpc/next.
[1/5] selftests/powerpc: Add generic read/write file util
https://git.kernel.org/powerpc/c/a974f0c131891027fe8490e654a220151b4caa82
[2/5] selftests/powerpc: Add read/write debugfs file, int
https://git.kernel.org/powerpc/c/121d340be9a17ed89d523c56203908c01e09a306
[3/5] selftests/powerpc: Parse long/unsigned long value safely
https://git.kernel.org/powerpc/c/d1bc05b7bf02f8635fe6c445f67d78f85234cbb7
[4/5] selftests/powerpc: Add {read,write}_{long,ulong}
https://git.kernel.org/powerpc/c/5c20de57888f0962e25a0eeec1a59c98056fc42e
[5/5] selftests/powerpc: Add automatically allocating read_file
https://git.kernel.org/powerpc/c/8d7253dc447473dfcf3f09fb0fa2bd6f7d05b43b
cheers
^ permalink raw reply [flat|nested] 7+ messages in thread
end of thread, other threads:[~2023-02-15 12:44 UTC | newest]
Thread overview: 7+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2023-02-03 0:39 [PATCH 0/5] Expand selftest utils Benjamin Gray
2023-02-03 0:39 ` [PATCH 1/5] selftests/powerpc: Add generic read/write file util Benjamin Gray
2023-02-03 0:39 ` [PATCH 2/5] selftests/powerpc: Add read/write debugfs file, int Benjamin Gray
2023-02-03 0:39 ` [PATCH 3/5] selftests/powerpc: Parse long/unsigned long value safely Benjamin Gray
2023-02-03 0:39 ` [PATCH 4/5] selftests/powerpc: Add {read,write}_{long,ulong} Benjamin Gray
2023-02-03 0:39 ` [PATCH 5/5] selftests/powerpc: Add automatically allocating read_file Benjamin Gray
2023-02-15 12:40 ` [PATCH 0/5] Expand selftest utils Michael Ellerman
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.