Skip to content

Commit a664a83

Browse files
Lekensteynborkmann
authored andcommitted
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 <[email protected]> Signed-off-by: Peter Wu <[email protected]> Reviewed-by: Quentin Monnet <[email protected]> Signed-off-by: Daniel Borkmann <[email protected]>
1 parent 9f30cd5 commit a664a83

File tree

2 files changed

+54
-53
lines changed

2 files changed

+54
-53
lines changed

tools/bpf/bpftool/Makefile

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -52,7 +52,7 @@ ifneq ($(EXTRA_LDFLAGS),)
5252
LDFLAGS += $(EXTRA_LDFLAGS)
5353
endif
5454

55-
LIBS = -lelf $(LIBBPF)
55+
LIBS = -lelf -lz $(LIBBPF)
5656

5757
INSTALL ?= install
5858
RM ?= rm -f

tools/bpf/bpftool/feature.c

Lines changed: 53 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include <bpf.h>
1616
#include <libbpf.h>
17+
#include <zlib.h>
1718

1819
#include "main.h"
1920

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

287-
static char *get_kernel_config_option(FILE *fd, const char *option)
288+
static bool read_next_kernel_config_option(gzFile file, char *buf, size_t n,
289+
char **value)
288290
{
289-
size_t line_n = 0, optlen = strlen(option);
290-
char *res, *strval, *line = NULL;
291-
ssize_t n;
291+
char *sep;
292292

293-
rewind(fd);
294-
while ((n = getline(&line, &line_n, fd)) > 0) {
295-
if (strncmp(line, option, optlen))
293+
while (gzgets(file, buf, n)) {
294+
if (strncmp(buf, "CONFIG_", 7))
296295
continue;
297-
/* Check we have at least '=', value, and '\n' */
298-
if (strlen(line) < optlen + 3)
299-
continue;
300-
if (*(line + optlen) != '=')
296+
297+
sep = strchr(buf, '=');
298+
if (!sep)
301299
continue;
302300

303301
/* Trim ending '\n' */
304-
line[strlen(line) - 1] = '\0';
302+
buf[strlen(buf) - 1] = '\0';
303+
304+
/* Split on '=' and ensure that a value is present. */
305+
*sep = '\0';
306+
if (!sep[1])
307+
continue;
305308

306-
/* Copy and return config option value */
307-
strval = line + optlen + 1;
308-
res = strdup(strval);
309-
free(line);
310-
return res;
309+
*value = sep + 1;
310+
return true;
311311
}
312-
free(line);
313312

314-
return NULL;
313+
return false;
315314
}
316315

317316
static void probe_kernel_image_config(void)
@@ -386,59 +385,61 @@ static void probe_kernel_image_config(void)
386385
/* test_bpf module for BPF tests */
387386
"CONFIG_TEST_BPF",
388387
};
389-
char *value, *buf = NULL;
388+
char *values[ARRAY_SIZE(options)] = { };
390389
struct utsname utsn;
391390
char path[PATH_MAX];
392-
size_t i, n;
393-
ssize_t ret;
394-
FILE *fd;
391+
gzFile file = NULL;
392+
char buf[4096];
393+
char *value;
394+
size_t i;
395395

396-
if (uname(&utsn))
397-
goto no_config;
396+
if (!uname(&utsn)) {
397+
snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
398398

399-
snprintf(path, sizeof(path), "/boot/config-%s", utsn.release);
399+
/* gzopen also accepts uncompressed files. */
400+
file = gzopen(path, "r");
401+
}
400402

401-
fd = fopen(path, "r");
402-
if (!fd && errno == ENOENT) {
403-
/* Some distributions put the config file at /proc/config, give
404-
* it a try.
405-
* Sometimes it is also at /proc/config.gz but we do not try
406-
* this one for now, it would require linking against libz.
403+
if (!file) {
404+
/* Some distributions build with CONFIG_IKCONFIG=y and put the
405+
* config file at /proc/config.gz.
407406
*/
408-
fd = fopen("/proc/config", "r");
407+
file = gzopen("/proc/config.gz", "r");
409408
}
410-
if (!fd) {
409+
if (!file) {
411410
p_info("skipping kernel config, can't open file: %s",
412411
strerror(errno));
413-
goto no_config;
412+
goto end_parse;
414413
}
415414
/* Sanity checks */
416-
ret = getline(&buf, &n, fd);
417-
ret = getline(&buf, &n, fd);
418-
if (!buf || !ret) {
415+
if (!gzgets(file, buf, sizeof(buf)) ||
416+
!gzgets(file, buf, sizeof(buf))) {
419417
p_info("skipping kernel config, can't read from file: %s",
420418
strerror(errno));
421-
free(buf);
422-
goto no_config;
419+
goto end_parse;
423420
}
424421
if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) {
425422
p_info("skipping kernel config, can't find correct file");
426-
free(buf);
427-
goto no_config;
423+
goto end_parse;
428424
}
429-
free(buf);
430425

431-
for (i = 0; i < ARRAY_SIZE(options); i++) {
432-
value = get_kernel_config_option(fd, options[i]);
433-
print_kernel_option(options[i], value);
434-
free(value);
426+
while (read_next_kernel_config_option(file, buf, sizeof(buf), &value)) {
427+
for (i = 0; i < ARRAY_SIZE(options); i++) {
428+
if (values[i] || strcmp(buf, options[i]))
429+
continue;
430+
431+
values[i] = strdup(value);
432+
}
435433
}
436-
fclose(fd);
437-
return;
438434

439-
no_config:
440-
for (i = 0; i < ARRAY_SIZE(options); i++)
441-
print_kernel_option(options[i], NULL);
435+
end_parse:
436+
if (file)
437+
gzclose(file);
438+
439+
for (i = 0; i < ARRAY_SIZE(options); i++) {
440+
print_kernel_option(options[i], values[i]);
441+
free(values[i]);
442+
}
442443
}
443444

444445
static bool probe_bpf_syscall(const char *define_prefix)

0 commit comments

Comments
 (0)