644 lines · 11.2 KB · C
RawDownload
// SPDX-License-Identifier: GPL-2.0-only/* * Copyright 2013-2015, Michael Ellerman, IBM Corp. */ #define _GNU_SOURCE	/* For CPU_ZERO etc. */ #include <elf.h>#include <errno.h>#include <fcntl.h>#include <inttypes.h>#include <limits.h>#include <link.h>#include <sched.h>#include <stdio.h>#include <stdlib.h>#include <string.h>#include <sys/ioctl.h>#include <sys/stat.h>#include <sys/sysinfo.h>#include <sys/types.h>#include <sys/utsname.h>#include <unistd.h>#include <asm/unistd.h>#include <linux/limits.h> #include "utils.h" 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 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;	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){	int err; 	err = read_file("/proc/self/auxv", buf, buf_size, NULL);	if (err) {		perror("Error reading /proc/self/auxv");		return err;	} 	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);} 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;} 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; 	p = (ElfW(auxv_t) *)auxv; 	while (p->a_type != AT_NULL) {		if (p->a_type == type)			return p; 		p++;	} 	return NULL;} void *get_auxv_entry(int type){	ElfW(auxv_t) *p; 	if (read_auxv(auxv, sizeof(auxv)))		return NULL; 	p = find_auxv_entry(type, auxv);	if (p)		return (void *)p->a_un.a_val; 	return NULL;} int pick_online_cpu(void){	int ncpus, cpu = -1;	cpu_set_t *mask;	size_t size; 	ncpus = get_nprocs_conf();	size = CPU_ALLOC_SIZE(ncpus);	mask = CPU_ALLOC(ncpus);	if (!mask) {		perror("malloc");		return -1;	} 	CPU_ZERO_S(size, mask); 	if (sched_getaffinity(0, size, mask)) {		perror("sched_getaffinity");		goto done;	} 	/* We prefer a primary thread, but skip 0 */	for (cpu = 8; cpu < ncpus; cpu += 8)		if (CPU_ISSET_S(cpu, size, mask))			goto done; 	/* Search for anything, but in reverse */	for (cpu = ncpus - 1; cpu >= 0; cpu--)		if (CPU_ISSET_S(cpu, size, mask))			goto done; 	printf("No cpus in affinity mask?!\n"); done:	CPU_FREE(mask);	return cpu;} int bind_to_cpu(int cpu){	cpu_set_t mask;	int err; 	if (cpu == BIND_CPU_ANY) {		cpu = pick_online_cpu();		if (cpu < 0)			return cpu;	} 	printf("Binding to cpu %d\n", cpu); 	CPU_ZERO(&mask);	CPU_SET(cpu, &mask); 	err = sched_setaffinity(0, sizeof(mask), &mask);	if (err)		return err; 	return cpu;} bool is_ppc64le(void){	struct utsname uts;	int rc; 	errno = 0;	rc = uname(&uts);	if (rc) {		perror("uname");		return false;	} 	return strcmp(uts.machine, "ppc64le") == 0;} int read_sysfs_file(char *fpath, char *result, size_t result_size){	char path[PATH_MAX] = "/sys/"; 	strncat(path, fpath, PATH_MAX - strlen(path) - 1); 	return read_file(path, result, result_size, NULL);}

Lines 1–500 of 644.