|
14 | 14 |
|
15 | 15 | #include <bpf.h> |
16 | 16 | #include <libbpf.h> |
| 17 | +#include <zlib.h> |
17 | 18 |
|
18 | 19 | #include "main.h" |
19 | 20 |
|
@@ -284,34 +285,32 @@ static void probe_jit_limit(void) |
284 | 285 | } |
285 | 286 | } |
286 | 287 |
|
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) |
288 | 290 | { |
289 | | - size_t line_n = 0, optlen = strlen(option); |
290 | | - char *res, *strval, *line = NULL; |
291 | | - ssize_t n; |
| 291 | + char *sep; |
292 | 292 |
|
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)) |
296 | 295 | 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) |
301 | 299 | continue; |
302 | 300 |
|
303 | 301 | /* 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; |
305 | 308 |
|
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; |
311 | 311 | } |
312 | | - free(line); |
313 | 312 |
|
314 | | - return NULL; |
| 313 | + return false; |
315 | 314 | } |
316 | 315 |
|
317 | 316 | static void probe_kernel_image_config(void) |
@@ -386,59 +385,61 @@ static void probe_kernel_image_config(void) |
386 | 385 | /* test_bpf module for BPF tests */ |
387 | 386 | "CONFIG_TEST_BPF", |
388 | 387 | }; |
389 | | - char *value, *buf = NULL; |
| 388 | + char *values[ARRAY_SIZE(options)] = { }; |
390 | 389 | struct utsname utsn; |
391 | 390 | 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; |
395 | 395 |
|
396 | | - if (uname(&utsn)) |
397 | | - goto no_config; |
| 396 | + if (!uname(&utsn)) { |
| 397 | + snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); |
398 | 398 |
|
399 | | - snprintf(path, sizeof(path), "/boot/config-%s", utsn.release); |
| 399 | + /* gzopen also accepts uncompressed files. */ |
| 400 | + file = gzopen(path, "r"); |
| 401 | + } |
400 | 402 |
|
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. |
407 | 406 | */ |
408 | | - fd = fopen("/proc/config", "r"); |
| 407 | + file = gzopen("/proc/config.gz", "r"); |
409 | 408 | } |
410 | | - if (!fd) { |
| 409 | + if (!file) { |
411 | 410 | p_info("skipping kernel config, can't open file: %s", |
412 | 411 | strerror(errno)); |
413 | | - goto no_config; |
| 412 | + goto end_parse; |
414 | 413 | } |
415 | 414 | /* 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))) { |
419 | 417 | p_info("skipping kernel config, can't read from file: %s", |
420 | 418 | strerror(errno)); |
421 | | - free(buf); |
422 | | - goto no_config; |
| 419 | + goto end_parse; |
423 | 420 | } |
424 | 421 | if (strcmp(buf, "# Automatically generated file; DO NOT EDIT.\n")) { |
425 | 422 | p_info("skipping kernel config, can't find correct file"); |
426 | | - free(buf); |
427 | | - goto no_config; |
| 423 | + goto end_parse; |
428 | 424 | } |
429 | | - free(buf); |
430 | 425 |
|
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 | + } |
435 | 433 | } |
436 | | - fclose(fd); |
437 | | - return; |
438 | 434 |
|
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 | + } |
442 | 443 | } |
443 | 444 |
|
444 | 445 | static bool probe_bpf_syscall(const char *define_prefix) |
|
0 commit comments