Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit a664a834 authored by Peter Wu's avatar Peter Wu Committed by Daniel Borkmann
Browse files

tools: bpftool: fix reading from /proc/config.gz



/proc/config has never existed as far as I can see, but /proc/config.gz
is present on Arch Linux. Add support for decompressing config.gz using
zlib which is a mandatory dependency of libelf anyway. Replace existing
stdio functions with gzFile operations since the latter transparently
handles uncompressed and gzip-compressed files.

Cc: Quentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: default avatarPeter Wu <peter@lekensteyn.nl>
Reviewed-by: default avatarQuentin Monnet <quentin.monnet@netronome.com>
Signed-off-by: default avatarDaniel Borkmann <daniel@iogearbox.net>
parent 9f30cd56
Loading
Loading
Loading
Loading
+1 −1
Original line number Diff line number Diff line
@@ -52,7 +52,7 @@ ifneq ($(EXTRA_LDFLAGS),)
LDFLAGS += $(EXTRA_LDFLAGS)
endif

LIBS = -lelf $(LIBBPF)
LIBS = -lelf -lz $(LIBBPF)

INSTALL ?= install
RM ?= rm -f
+53 −52
Original line number Diff line number Diff line
@@ -14,6 +14,7 @@

#include <bpf.h>
#include <libbpf.h>
#include <zlib.h>

#include "main.h"

@@ -284,34 +285,32 @@ static void probe_jit_limit(void)
	}
}

static char *get_kernel_config_option(FILE *fd, const char *option)
static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n,
					   char **value)
{
	size_t line_n = 0, optlen = strlen(option);
	char *res, *strval, *line = NULL;
	ssize_t n;
	char *sep;

	rewind(fd);
	while ((n = getline(&line, &line_n, fd)) > 0) {
		if (strncmp(line, option, optlen))
	while (gzgets(file, buf, n)) {
		if (strncmp(buf, "CONFIG_", 7))
			continue;
		/* Check we have at least '=', value, and '\n' */
		if (strlen(line) < optlen + 3)
			continue;
		if (*(line + optlen) != '=')

		sep = strchr(buf, '=');
		if (!sep)
			continue;

		/* Trim ending '\n' */
		line[strlen(line) - 1] = '\0';
		buf[strlen(buf) - 1] = '\0';

		/* Copy and return config option value */
		strval = line + optlen + 1;
		res = strdup(strval);
		free(line);
		return res;
		/* Split on '=' and ensure that a value is present. */
		*sep = '\0';
		if (!sep[1])
			continue;

		*value = sep + 1;
		return true;
	}
	free(line);

	return NULL;
	return false;
}

static void probe_kernel_image_config(void)
@@ -386,59 +385,61 @@ static void probe_kernel_image_config(void)
		/* test_bpf module for BPF tests */
		"CONFIG_TEST_BPF",
	};
	char *value, *buf = NULL;
	char *values[ARRAY_SIZE(options)] = { };
	struct utsname utsn;
	char path[PATH_MAX];
	size_t i, n;
	ssize_t ret;
	FILE *fd;

	if (uname(&utsn))
		goto no_config;
	gzFile file = NULL;
	char buf[4096];
	char *value;
	size_t i;

	if (!uname(&utsn)) {
		snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);

	fd = fopen(path, "r");
	if (!fd && errno == ENOENT) {
		/* Some distributions put the config file at /proc/config, give
		 * it a try.
		 * Sometimes it is also at /proc/config.gz but we do not try
		 * this one for now, it would require linking against libz.
		/* gzopen also accepts uncompressed files. */
		file = gzopen(path, "r");
	}

	if (!file) {
		/* Some distributions build with CONFIG_IKCONFIG=y and put the
		 * config file at /proc/config.gz.
		 */
		fd = fopen("/proc/config", "r");
		file = gzopen("/proc/config.gz", "r");
	}
	if (!fd) {
	if (!file) {
		p_info("skipping kernel config, can't open file: %s",
		       strerror(errno));
		goto no_config;
		goto end_parse;
	}
	/* Sanity checks */
	ret = getline(&buf, &n, fd);
	ret = getline(&buf, &n, fd);
	if (!buf || !ret) {
	if (!gzgets(file, buf, sizeof(buf)) ||
	    !gzgets(file, buf, sizeof(buf))) {
		p_info("skipping kernel config, can't read from file: %s",
		       strerror(errno));
		free(buf);
		goto no_config;
		goto end_parse;
	}
	if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
		p_info("skipping kernel config, can't find correct file");
		free(buf);
		goto no_config;
		goto end_parse;
	}
	free(buf);

	while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
		for (i = 0; i < ARRAY_SIZE(options); i++) {
		value = get_kernel_config_option(fd, options[i]);
		print_kernel_option(options[i], value);
		free(value);
			if (values[i] || strcmp(buf, options[i]))
				continue;

			values[i] = strdup(value);
		}
	fclose(fd);
	return;
	}

end_parse:
	if (file)
		gzclose(file);

no_config:
	for (i = 0; i < ARRAY_SIZE(options); i++)
		print_kernel_option(options[i], NULL);
	for (i = 0; i < ARRAY_SIZE(options); i++) {
		print_kernel_option(options[i], values[i]);
		free(values[i]);
	}
}

static bool probe_bpf_syscall(const char *define_prefix)