brintos

brintos / linux-shallow public Read only

0
0
Text · 6.9 KiB · d6f99eb Raw
353 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2#define _GNU_SOURCE3#include <errno.h>4#include <fcntl.h>5#include <stdlib.h>6#include <string.h>7#include <sys/ioctl.h>8#include <unistd.h>9 10#include <asm/papr-vpd.h>11 12#include "utils.h"13 14#define DEVPATH "/dev/papr-vpd"15 16static int dev_papr_vpd_open_close(void)17{18	const int devfd = open(DEVPATH, O_RDONLY);19 20	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,21		    DEVPATH " not present");22 23	FAIL_IF(devfd < 0);24	FAIL_IF(close(devfd) != 0);25 26	return 0;27}28 29static int dev_papr_vpd_get_handle_all(void)30{31	const int devfd = open(DEVPATH, O_RDONLY);32	struct papr_location_code lc = { .str = "", };33	off_t size;34	int fd;35 36	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,37		    DEVPATH " not present");38 39	FAIL_IF(devfd < 0);40 41	errno = 0;42	fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);43	FAIL_IF(errno != 0);44	FAIL_IF(fd < 0);45 46	FAIL_IF(close(devfd) != 0);47 48	size = lseek(fd, 0, SEEK_END);49	FAIL_IF(size <= 0);50 51	void *buf = malloc((size_t)size);52	FAIL_IF(!buf);53 54	ssize_t consumed = pread(fd, buf, size, 0);55	FAIL_IF(consumed != size);56 57	/* Ensure EOF */58	FAIL_IF(read(fd, buf, size) != 0);59	FAIL_IF(close(fd));60 61	/* Verify that the buffer looks like VPD */62	static const char needle[] = "System VPD";63	FAIL_IF(!memmem(buf, size, needle, strlen(needle)));64 65	return 0;66}67 68static int dev_papr_vpd_get_handle_byte_at_a_time(void)69{70	const int devfd = open(DEVPATH, O_RDONLY);71	struct papr_location_code lc = { .str = "", };72	int fd;73 74	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,75		    DEVPATH " not present");76 77	FAIL_IF(devfd < 0);78 79	errno = 0;80	fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);81	FAIL_IF(errno != 0);82	FAIL_IF(fd < 0);83 84	FAIL_IF(close(devfd) != 0);85 86	size_t consumed = 0;87	while (1) {88		ssize_t res;89		char c;90 91		errno = 0;92		res = read(fd, &c, sizeof(c));93		FAIL_IF(res > sizeof(c));94		FAIL_IF(res < 0);95		FAIL_IF(errno != 0);96		consumed += res;97		if (res == 0)98			break;99	}100 101	FAIL_IF(consumed != lseek(fd, 0, SEEK_END));102 103	FAIL_IF(close(fd));104 105	return 0;106}107 108 109static int dev_papr_vpd_unterm_loc_code(void)110{111	const int devfd = open(DEVPATH, O_RDONLY);112	struct papr_location_code lc = {};113	int fd;114 115	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,116		    DEVPATH " not present");117 118	FAIL_IF(devfd < 0);119 120	/*121	 * Place a non-null byte in every element of loc_code; the122	 * driver should reject this input.123	 */124	memset(lc.str, 'x', ARRAY_SIZE(lc.str));125 126	errno = 0;127	fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);128	FAIL_IF(fd != -1);129	FAIL_IF(errno != EINVAL);130 131	FAIL_IF(close(devfd) != 0);132	return 0;133}134 135static int dev_papr_vpd_null_handle(void)136{137	const int devfd = open(DEVPATH, O_RDONLY);138	int rc;139 140	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,141		    DEVPATH " not present");142 143	FAIL_IF(devfd < 0);144 145	errno = 0;146	rc = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, NULL);147	FAIL_IF(rc != -1);148	FAIL_IF(errno != EFAULT);149 150	FAIL_IF(close(devfd) != 0);151	return 0;152}153 154static int papr_vpd_close_handle_without_reading(void)155{156	const int devfd = open(DEVPATH, O_RDONLY);157	struct papr_location_code lc = { .str = "", };158	int fd;159 160	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,161		    DEVPATH " not present");162 163	FAIL_IF(devfd < 0);164 165	errno = 0;166	fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);167	FAIL_IF(errno != 0);168	FAIL_IF(fd < 0);169 170	/* close the handle without reading it */171	FAIL_IF(close(fd) != 0);172 173	FAIL_IF(close(devfd) != 0);174	return 0;175}176 177static int papr_vpd_reread(void)178{179	const int devfd = open(DEVPATH, O_RDONLY);180	struct papr_location_code lc = { .str = "", };181	int fd;182 183	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,184		    DEVPATH " not present");185 186	FAIL_IF(devfd < 0);187 188	errno = 0;189	fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);190	FAIL_IF(errno != 0);191	FAIL_IF(fd < 0);192 193	FAIL_IF(close(devfd) != 0);194 195	const off_t size = lseek(fd, 0, SEEK_END);196	FAIL_IF(size <= 0);197 198	char *bufs[2];199 200	for (size_t i = 0; i < ARRAY_SIZE(bufs); ++i) {201		bufs[i] = malloc(size);202		FAIL_IF(!bufs[i]);203		ssize_t consumed = pread(fd, bufs[i], size, 0);204		FAIL_IF(consumed != size);205	}206 207	FAIL_IF(memcmp(bufs[0], bufs[1], size));208 209	FAIL_IF(close(fd) != 0);210 211	return 0;212}213 214static int get_system_loc_code(struct papr_location_code *lc)215{216	static const char system_id_path[] = "/sys/firmware/devicetree/base/system-id";217	static const char model_path[] = "/sys/firmware/devicetree/base/model";218	char *system_id;219	char *model;220	int err = -1;221 222	if (read_file_alloc(model_path, &model, NULL))223		return err;224 225	if (read_file_alloc(system_id_path, &system_id, NULL))226		goto free_model;227 228	char *mtm;229	int sscanf_ret = sscanf(model, "IBM,%ms", &mtm);230	if (sscanf_ret != 1)231		goto free_system_id;232 233	char *plant_and_seq;234	if (sscanf(system_id, "IBM,%*c%*c%ms", &plant_and_seq) != 1)235		goto free_mtm;236	/*237	 * Replace - with . to build location code.238	 */239	char *sep = strchr(mtm, '-');240	if (!sep)241		goto free_mtm;242	else243		*sep = '.';244 245	snprintf(lc->str, sizeof(lc->str),246		 "U%s.%s", mtm, plant_and_seq);247	err = 0;248 249	free(plant_and_seq);250free_mtm:251	free(mtm);252free_system_id:253	free(system_id);254free_model:255	free(model);256	return err;257}258 259static int papr_vpd_system_loc_code(void)260{261	struct papr_location_code lc;262	const int devfd = open(DEVPATH, O_RDONLY);263	off_t size;264	int fd;265 266	SKIP_IF_MSG(devfd < 0 && errno == ENOENT,267		    DEVPATH " not present");268	SKIP_IF_MSG(get_system_loc_code(&lc),269		    "Cannot determine system location code");270 271	FAIL_IF(devfd < 0);272 273	errno = 0;274	fd = ioctl(devfd, PAPR_VPD_IOC_CREATE_HANDLE, &lc);275	FAIL_IF(errno != 0);276	FAIL_IF(fd < 0);277 278	FAIL_IF(close(devfd) != 0);279 280	size = lseek(fd, 0, SEEK_END);281	FAIL_IF(size <= 0);282 283	void *buf = malloc((size_t)size);284	FAIL_IF(!buf);285 286	ssize_t consumed = pread(fd, buf, size, 0);287	FAIL_IF(consumed != size);288 289	/* Ensure EOF */290	FAIL_IF(read(fd, buf, size) != 0);291	FAIL_IF(close(fd));292 293	/* Verify that the buffer looks like VPD */294	static const char needle[] = "System VPD";295	FAIL_IF(!memmem(buf, size, needle, strlen(needle)));296 297	return 0;298}299 300struct vpd_test {301	int (*function)(void);302	const char *description;303};304 305static const struct vpd_test vpd_tests[] = {306	{307		.function = dev_papr_vpd_open_close,308		.description = "open/close " DEVPATH,309	},310	{311		.function = dev_papr_vpd_unterm_loc_code,312		.description = "ensure EINVAL on unterminated location code",313	},314	{315		.function = dev_papr_vpd_null_handle,316		.description = "ensure EFAULT on bad handle addr",317	},318	{319		.function = dev_papr_vpd_get_handle_all,320		.description = "get handle for all VPD"321	},322	{323		.function = papr_vpd_close_handle_without_reading,324		.description = "close handle without consuming VPD"325	},326	{327		.function = dev_papr_vpd_get_handle_byte_at_a_time,328		.description = "read all VPD one byte at a time"329	},330	{331		.function = papr_vpd_reread,332		.description = "ensure re-read yields same results"333	},334	{335		.function = papr_vpd_system_loc_code,336		.description = "get handle for system VPD"337	},338};339 340int main(void)341{342	size_t fails = 0;343 344	for (size_t i = 0; i < ARRAY_SIZE(vpd_tests); ++i) {345		const struct vpd_test *t = &vpd_tests[i];346 347		if (test_harness(t->function, t->description))348			++fails;349	}350 351	return fails == 0 ? EXIT_SUCCESS : EXIT_FAILURE;352}353