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

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
...@@ -52,7 +52,7 @@ ifneq ($(EXTRA_LDFLAGS),) ...@@ -52,7 +52,7 @@ ifneq ($(EXTRA_LDFLAGS),)
LDFLAGS += $(EXTRA_LDFLAGS) LDFLAGS += $(EXTRA_LDFLAGS)
endif endif
LIBS = -lelf $(LIBBPF) LIBS = -lelf -lz $(LIBBPF)
INSTALL ?= install INSTALL ?= install
RM ?= rm -f RM ?= rm -f
......
...@@ -14,6 +14,7 @@ ...@@ -14,6 +14,7 @@
#include <bpf.h> #include <bpf.h>
#include <libbpf.h> #include <libbpf.h>
#include <zlib.h>
#include "main.h" #include "main.h"
...@@ -284,34 +285,32 @@ static void probe_jit_limit(void) ...@@ -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 *sep;
char *res, *strval, *line = NULL;
ssize_t n;
rewind(fd); while (gzgets(file, buf, n)) {
while ((n = getline(&line, &line_n, fd)) > 0) { if (strncmp(buf, "CONFIG_", 7))
if (strncmp(line, option, optlen))
continue; continue;
/* Check we have at least '=', value, and '\n' */
if (strlen(line) < optlen + 3) sep = strchr(buf, '=');
continue; if (!sep)
if (*(line + optlen) != '=')
continue; continue;
/* Trim ending '\n' */ /* Trim ending '\n' */
line[strlen(line) - 1] = '\0'; buf[strlen(buf) - 1] = '\0';
/* Split on '=' and ensure that a value is present. */
*sep = '\0';
if (!sep[1])
continue;
/* Copy and return config option value */ *value = sep + 1;
strval = line + optlen + 1; return true;
res = strdup(strval);
free(line);
return res;
} }
free(line);
return NULL; return false;
} }
static void probe_kernel_image_config(void) static void probe_kernel_image_config(void)
...@@ -386,59 +385,61 @@ static void probe_kernel_image_config(void) ...@@ -386,59 +385,61 @@ static void probe_kernel_image_config(void)
/* test_bpf module for BPF tests */ /* test_bpf module for BPF tests */
"CONFIG_TEST_BPF", "CONFIG_TEST_BPF",
}; };
char *value, *buf = NULL; char *values[ARRAY_SIZE(options)] = { };
struct utsname utsn; struct utsname utsn;
char path[PATH_MAX]; char path[PATH_MAX];
size_t i, n; gzFile file = NULL;
ssize_t ret; char buf[4096];
FILE *fd; char *value;
size_t i;
if (uname(&utsn)) if (!uname(&utsn)) {
goto no_config; snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); /* gzopen also accepts uncompressed files. */
file = gzopen(path, "r");
}
fd = fopen(path, "r"); if (!file) {
if (!fd && errno == ENOENT) { /* Some distributions build with CONFIG_IKCONFIG=y and put the
/* Some distributions put the config file at /proc/config, give * config file at /proc/config.gz.
* 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.
*/ */
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", p_info("skipping kernel config, can't open file: %s",
strerror(errno)); strerror(errno));
goto no_config; goto end_parse;
} }
/* Sanity checks */ /* Sanity checks */
ret = getline(&buf, &n, fd); if (!gzgets(file, buf, sizeof(buf)) ||
ret = getline(&buf, &n, fd); !gzgets(file, buf, sizeof(buf))) {
if (!buf || !ret) {
p_info("skipping kernel config, can't read from file: %s", p_info("skipping kernel config, can't read from file: %s",
strerror(errno)); strerror(errno));
free(buf); goto end_parse;
goto no_config;
} }
if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
p_info("skipping kernel config, can't find correct file"); p_info("skipping kernel config, can't find correct file");
free(buf); goto end_parse;
goto no_config;
} }
free(buf);
for (i = 0; i < ARRAY_SIZE(options); i++) { while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
value = get_kernel_config_option(fd, options[i]); for (i = 0; i < ARRAY_SIZE(options); i++) {
print_kernel_option(options[i], value); if (values[i] || strcmp(buf, options[i]))
free(value); continue;
values[i] = strdup(value);
}
} }
fclose(fd);
return;
no_config: end_parse:
for (i = 0; i < ARRAY_SIZE(options); i++) if (file)
print_kernel_option(options[i], NULL); gzclose(file);
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) static bool probe_bpf_syscall(const char *define_prefix)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment