|
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