1 /* 2 * libkmod - interface to kernel module operations 3 * 4 * Copyright (C) 2011-2013 ProFUSION embedded systems 5 * Copyright (C) 2013 Intel Corporation. All rights reserved. 6 * 7 * This library is free software; you can redistribute it and/or 8 * modify it under the terms of the GNU Lesser General Public 9 * License as published by the Free Software Foundation; either 10 * version 2.1 of the License, or (at your option) any later version. 11 * 12 * This library is distributed in the hope that it will be useful, 13 * but WITHOUT ANY WARRANTY; without even the implied warranty of 14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 15 * Lesser General Public License for more details. 16 * 17 * You should have received a copy of the GNU Lesser General Public 18 * License along with this library; if not, see <http://www.gnu.org/licenses/>. 19 */ 20 21 #include <ctype.h> 22 #include <dirent.h> 23 #include <errno.h> 24 #include <stdarg.h> 25 #include <stddef.h> 26 #include <stdio.h> 27 #include <stdlib.h> 28 #include <string.h> 29 #include <unistd.h> 30 #include <sys/stat.h> 31 #include <sys/types.h> 32 33 #include <shared/util.h> 34 35 #include "libkmod.h" 36 #include "libkmod-internal.h" 37 38 struct kmod_alias { 39 char *name; 40 char modname[]; 41 }; 42 43 struct kmod_options { 44 char *options; 45 char modname[]; 46 }; 47 48 struct kmod_command { 49 char *command; 50 char modname[]; 51 }; 52 53 struct kmod_softdep { 54 char *name; 55 const char **pre; 56 const char **post; 57 unsigned int n_pre; 58 unsigned int n_post; 59 }; 60 61 const char *kmod_blacklist_get_modname(const struct kmod_list *l) 62 { 63 return l->data; 64 } 65 66 const char *kmod_alias_get_name(const struct kmod_list *l) { 67 const struct kmod_alias *alias = l->data; 68 return alias->name; 69 } 70 71 const char *kmod_alias_get_modname(const struct kmod_list *l) { 72 const struct kmod_alias *alias = l->data; 73 return alias->modname; 74 } 75 76 const char *kmod_option_get_options(const struct kmod_list *l) { 77 const struct kmod_options *alias = l->data; 78 return alias->options; 79 } 80 81 const char *kmod_option_get_modname(const struct kmod_list *l) { 82 const struct kmod_options *alias = l->data; 83 return alias->modname; 84 } 85 86 const char *kmod_command_get_command(const struct kmod_list *l) { 87 const struct kmod_command *alias = l->data; 88 return alias->command; 89 } 90 91 const char *kmod_command_get_modname(const struct kmod_list *l) { 92 const struct kmod_command *alias = l->data; 93 return alias->modname; 94 } 95 96 const char *kmod_softdep_get_name(const struct kmod_list *l) { 97 const struct kmod_softdep *dep = l->data; 98 return dep->name; 99 } 100 101 const char * const *kmod_softdep_get_pre(const struct kmod_list *l, unsigned int *count) { 102 const struct kmod_softdep *dep = l->data; 103 *count = dep->n_pre; 104 return dep->pre; 105 } 106 107 const char * const *kmod_softdep_get_post(const struct kmod_list *l, unsigned int *count) { 108 const struct kmod_softdep *dep = l->data; 109 *count = dep->n_post; 110 return dep->post; 111 } 112 113 static int kmod_config_add_command(struct kmod_config *config, 114 const char *modname, 115 const char *command, 116 const char *command_name, 117 struct kmod_list **list) 118 { 119 _cleanup_free_ struct kmod_command *cmd; 120 struct kmod_list *l; 121 size_t modnamelen = strlen(modname) + 1; 122 size_t commandlen = strlen(command) + 1; 123 124 DBG(config->ctx, "modname='%s' cmd='%s %s'\n", modname, command_name, 125 command); 126 127 cmd = malloc(sizeof(*cmd) + modnamelen + commandlen); 128 if (!cmd) 129 return -ENOMEM; 130 131 cmd->command = sizeof(*cmd) + modnamelen + (char *)cmd; 132 memcpy(cmd->modname, modname, modnamelen); 133 memcpy(cmd->command, command, commandlen); 134 135 l = kmod_list_append(*list, cmd); 136 if (!l) 137 return -ENOMEM; 138 139 *list = l; 140 cmd = NULL; 141 return 0; 142 } 143 144 static void kmod_config_free_command(struct kmod_config *config, 145 struct kmod_list *l, 146 struct kmod_list **list) 147 { 148 struct kmod_command *cmd = l->data; 149 150 free(cmd); 151 *list = kmod_list_remove(l); 152 } 153 154 static int kmod_config_add_options(struct kmod_config *config, 155 const char *modname, const char *options) 156 { 157 _cleanup_free_ struct kmod_options *opt; 158 struct kmod_list *list; 159 size_t modnamelen = strlen(modname) + 1; 160 size_t optionslen = strlen(options) + 1; 161 162 DBG(config->ctx, "modname='%s' options='%s'\n", modname, options); 163 164 opt = malloc(sizeof(*opt) + modnamelen + optionslen); 165 if (!opt) 166 return -ENOMEM; 167 168 opt->options = sizeof(*opt) + modnamelen + (char *)opt; 169 170 memcpy(opt->modname, modname, modnamelen); 171 memcpy(opt->options, options, optionslen); 172 strchr_replace(opt->options, '\t', ' '); 173 174 list = kmod_list_append(config->options, opt); 175 if (!list) 176 return -ENOMEM; 177 178 opt = NULL; 179 config->options = list; 180 return 0; 181 } 182 183 static void kmod_config_free_options(struct kmod_config *config, 184 struct kmod_list *l) 185 { 186 struct kmod_options *opt = l->data; 187 188 free(opt); 189 190 config->options = kmod_list_remove(l); 191 } 192 193 static int kmod_config_add_alias(struct kmod_config *config, 194 const char *name, const char *modname) 195 { 196 _cleanup_free_ struct kmod_alias *alias; 197 struct kmod_list *list; 198 size_t namelen = strlen(name) + 1, modnamelen = strlen(modname) + 1; 199 200 DBG(config->ctx, "name=%s modname=%s\n", name, modname); 201 202 alias = malloc(sizeof(*alias) + namelen + modnamelen); 203 if (!alias) 204 return -ENOMEM; 205 206 alias->name = sizeof(*alias) + modnamelen + (char *)alias; 207 208 memcpy(alias->modname, modname, modnamelen); 209 memcpy(alias->name, name, namelen); 210 211 list = kmod_list_append(config->aliases, alias); 212 if (!list) 213 return -ENOMEM; 214 215 alias = NULL; 216 config->aliases = list; 217 return 0; 218 } 219 220 static void kmod_config_free_alias(struct kmod_config *config, 221 struct kmod_list *l) 222 { 223 struct kmod_alias *alias = l->data; 224 225 free(alias); 226 227 config->aliases = kmod_list_remove(l); 228 } 229 230 static int kmod_config_add_blacklist(struct kmod_config *config, 231 const char *modname) 232 { 233 _cleanup_free_ char *p; 234 struct kmod_list *list; 235 236 DBG(config->ctx, "modname=%s\n", modname); 237 238 p = strdup(modname); 239 if (!p) 240 return -ENOMEM; 241 242 list = kmod_list_append(config->blacklists, p); 243 if (!list) 244 return -ENOMEM; 245 246 p = NULL; 247 config->blacklists = list; 248 return 0; 249 } 250 251 static void kmod_config_free_blacklist(struct kmod_config *config, 252 struct kmod_list *l) 253 { 254 free(l->data); 255 config->blacklists = kmod_list_remove(l); 256 } 257 258 static int kmod_config_add_softdep(struct kmod_config *config, 259 const char *modname, 260 const char *line) 261 { 262 struct kmod_list *list; 263 struct kmod_softdep *dep; 264 const char *s, *p; 265 char *itr; 266 unsigned int n_pre = 0, n_post = 0; 267 size_t modnamelen = strlen(modname) + 1; 268 size_t buflen = 0; 269 bool was_space = false; 270 enum { S_NONE, S_PRE, S_POST } mode = S_NONE; 271 272 DBG(config->ctx, "modname=%s\n", modname); 273 274 /* analyze and count */ 275 for (p = s = line; ; s++) { 276 size_t plen; 277 278 if (*s != '\0') { 279 if (!isspace(*s)) { 280 was_space = false; 281 continue; 282 } 283 284 if (was_space) { 285 p = s + 1; 286 continue; 287 } 288 was_space = true; 289 290 if (p >= s) 291 continue; 292 } 293 plen = s - p; 294 295 if (plen == sizeof("pre:") - 1 && 296 memcmp(p, "pre:", sizeof("pre:") - 1) == 0) 297 mode = S_PRE; 298 else if (plen == sizeof("post:") - 1 && 299 memcmp(p, "post:", sizeof("post:") - 1) == 0) 300 mode = S_POST; 301 else if (*s != '\0' || (*s == '\0' && !was_space)) { 302 if (mode == S_PRE) { 303 buflen += plen + 1; 304 n_pre++; 305 } else if (mode == S_POST) { 306 buflen += plen + 1; 307 n_post++; 308 } 309 } 310 p = s + 1; 311 if (*s == '\0') 312 break; 313 } 314 315 DBG(config->ctx, "%u pre, %u post\n", n_pre, n_post); 316 317 dep = malloc(sizeof(struct kmod_softdep) + modnamelen + 318 n_pre * sizeof(const char *) + 319 n_post * sizeof(const char *) + 320 buflen); 321 if (dep == NULL) { 322 ERR(config->ctx, "out-of-memory modname=%s\n", modname); 323 return -ENOMEM; 324 } 325 dep->n_pre = n_pre; 326 dep->n_post = n_post; 327 dep->pre = (const char **)((char *)dep + sizeof(struct kmod_softdep)); 328 dep->post = dep->pre + n_pre; 329 dep->name = (char *)(dep->post + n_post); 330 331 memcpy(dep->name, modname, modnamelen); 332 333 /* copy strings */ 334 itr = dep->name + modnamelen; 335 n_pre = 0; 336 n_post = 0; 337 mode = S_NONE; 338 for (p = s = line; ; s++) { 339 size_t plen; 340 341 if (*s != '\0') { 342 if (!isspace(*s)) { 343 was_space = false; 344 continue; 345 } 346 347 if (was_space) { 348 p = s + 1; 349 continue; 350 } 351 was_space = true; 352 353 if (p >= s) 354 continue; 355 } 356 plen = s - p; 357 358 if (plen == sizeof("pre:") - 1 && 359 memcmp(p, "pre:", sizeof("pre:") - 1) == 0) 360 mode = S_PRE; 361 else if (plen == sizeof("post:") - 1 && 362 memcmp(p, "post:", sizeof("post:") - 1) == 0) 363 mode = S_POST; 364 else if (*s != '\0' || (*s == '\0' && !was_space)) { 365 if (mode == S_PRE) { 366 dep->pre[n_pre] = itr; 367 memcpy(itr, p, plen); 368 itr[plen] = '\0'; 369 itr += plen + 1; 370 n_pre++; 371 } else if (mode == S_POST) { 372 dep->post[n_post] = itr; 373 memcpy(itr, p, plen); 374 itr[plen] = '\0'; 375 itr += plen + 1; 376 n_post++; 377 } 378 } 379 p = s + 1; 380 if (*s == '\0') 381 break; 382 } 383 384 list = kmod_list_append(config->softdeps, dep); 385 if (list == NULL) { 386 free(dep); 387 return -ENOMEM; 388 } 389 config->softdeps = list; 390 391 return 0; 392 } 393 394 static char *softdep_to_char(struct kmod_softdep *dep) { 395 const size_t sz_preprefix = sizeof("pre: ") - 1; 396 const size_t sz_postprefix = sizeof("post: ") - 1; 397 size_t sz = 1; /* at least '\0' */ 398 size_t sz_pre, sz_post; 399 const char *start, *end; 400 char *s, *itr; 401 402 /* 403 * Rely on the fact that dep->pre[] and dep->post[] are strv's that 404 * point to a contiguous buffer 405 */ 406 if (dep->n_pre > 0) { 407 start = dep->pre[0]; 408 end = dep->pre[dep->n_pre - 1] 409 + strlen(dep->pre[dep->n_pre - 1]); 410 sz_pre = end - start; 411 sz += sz_pre + sz_preprefix; 412 } else 413 sz_pre = 0; 414 415 if (dep->n_post > 0) { 416 start = dep->post[0]; 417 end = dep->post[dep->n_post - 1] 418 + strlen(dep->post[dep->n_post - 1]); 419 sz_post = end - start; 420 sz += sz_post + sz_postprefix; 421 } else 422 sz_post = 0; 423 424 itr = s = malloc(sz); 425 if (s == NULL) 426 return NULL; 427 428 if (sz_pre) { 429 char *p; 430 431 memcpy(itr, "pre: ", sz_preprefix); 432 itr += sz_preprefix; 433 434 /* include last '\0' */ 435 memcpy(itr, dep->pre[0], sz_pre + 1); 436 for (p = itr; p < itr + sz_pre; p++) { 437 if (*p == '\0') 438 *p = ' '; 439 } 440 itr = p; 441 } 442 443 if (sz_post) { 444 char *p; 445 446 memcpy(itr, "post: ", sz_postprefix); 447 itr += sz_postprefix; 448 449 /* include last '\0' */ 450 memcpy(itr, dep->post[0], sz_post + 1); 451 for (p = itr; p < itr + sz_post; p++) { 452 if (*p == '\0') 453 *p = ' '; 454 } 455 itr = p; 456 } 457 458 *itr = '\0'; 459 460 return s; 461 } 462 463 static void kmod_config_free_softdep(struct kmod_config *config, 464 struct kmod_list *l) 465 { 466 free(l->data); 467 config->softdeps = kmod_list_remove(l); 468 } 469 470 static void kcmdline_parse_result(struct kmod_config *config, char *modname, 471 char *param, char *value) 472 { 473 if (modname == NULL || param == NULL) 474 return; 475 476 DBG(config->ctx, "%s %s\n", modname, param); 477 478 if (streq(modname, "modprobe") && !strncmp(param, "blacklist=", 10)) { 479 for (;;) { 480 char *t = strsep(&value, ","); 481 if (t == NULL) 482 break; 483 484 kmod_config_add_blacklist(config, t); 485 } 486 } else { 487 if (underscores(modname) < 0) { 488 ERR(config->ctx, "Ignoring bad option on kernel command line while parsing module name: '%s'\n", 489 modname); 490 } 491 kmod_config_add_options(config, modname, param); 492 } 493 } 494 495 static int kmod_config_parse_kcmdline(struct kmod_config *config) 496 { 497 char buf[KCMD_LINE_SIZE]; 498 int fd, err; 499 char *p, *modname, *param = NULL, *value = NULL; 500 bool is_quoted = false, is_module = true; 501 502 fd = open("/proc/cmdline", O_RDONLY|O_CLOEXEC); 503 if (fd < 0) { 504 err = -errno; 505 DBG(config->ctx, "could not open '/proc/cmdline' for reading: %m\n"); 506 return err; 507 } 508 509 err = read_str_safe(fd, buf, sizeof(buf)); 510 close(fd); 511 if (err < 0) { 512 ERR(config->ctx, "could not read from '/proc/cmdline': %s\n", 513 strerror(-err)); 514 return err; 515 } 516 517 for (p = buf, modname = buf; *p != '\0' && *p != '\n'; p++) { 518 if (*p == '"') { 519 is_quoted = !is_quoted; 520 521 if (is_quoted) { 522 /* don't consider a module until closing quotes */ 523 is_module = false; 524 } else if (param != NULL && value != NULL) { 525 /* 526 * If we are indeed expecting a value and 527 * closing quotes, then this can be considered 528 * a valid option for a module 529 */ 530 is_module = true; 531 } 532 533 continue; 534 } 535 if (is_quoted) 536 continue; 537 538 switch (*p) { 539 case ' ': 540 *p = '\0'; 541 if (is_module) 542 kcmdline_parse_result(config, modname, param, value); 543 param = value = NULL; 544 modname = p + 1; 545 is_module = true; 546 break; 547 case '.': 548 if (param == NULL) { 549 *p = '\0'; 550 param = p + 1; 551 } 552 break; 553 case '=': 554 if (param != NULL) 555 value = p + 1; 556 else 557 is_module = false; 558 break; 559 } 560 } 561 562 *p = '\0'; 563 if (is_module) 564 kcmdline_parse_result(config, modname, param, value); 565 566 return 0; 567 } 568 569 /* 570 * Take an fd and own it. It will be closed on return. filename is used only 571 * for debug messages 572 */ 573 static int kmod_config_parse(struct kmod_config *config, int fd, 574 const char *filename) 575 { 576 struct kmod_ctx *ctx = config->ctx; 577 char *line; 578 FILE *fp; 579 unsigned int linenum = 0; 580 int err; 581 582 fp = fdopen(fd, "r"); 583 if (fp == NULL) { 584 err = -errno; 585 ERR(config->ctx, "fd %d: %m\n", fd); 586 close(fd); 587 return err; 588 } 589 590 while ((line = freadline_wrapped(fp, &linenum)) != NULL) { 591 char *cmd, *saveptr; 592 593 if (line[0] == '\0' || line[0] == '#') 594 goto done_next; 595 596 cmd = strtok_r(line, "\t ", &saveptr); 597 if (cmd == NULL) 598 goto done_next; 599 600 if (streq(cmd, "alias")) { 601 char *alias = strtok_r(NULL, "\t ", &saveptr); 602 char *modname = strtok_r(NULL, "\t ", &saveptr); 603 604 if (underscores(alias) < 0 || underscores(modname) < 0) 605 goto syntax_error; 606 607 kmod_config_add_alias(config, alias, modname); 608 } else if (streq(cmd, "blacklist")) { 609 char *modname = strtok_r(NULL, "\t ", &saveptr); 610 611 if (underscores(modname) < 0) 612 goto syntax_error; 613 614 kmod_config_add_blacklist(config, modname); 615 } else if (streq(cmd, "options")) { 616 char *modname = strtok_r(NULL, "\t ", &saveptr); 617 char *options = strtok_r(NULL, "\0", &saveptr); 618 619 if (underscores(modname) < 0 || options == NULL) 620 goto syntax_error; 621 622 kmod_config_add_options(config, modname, options); 623 } else if (streq(cmd, "install")) { 624 char *modname = strtok_r(NULL, "\t ", &saveptr); 625 char *installcmd = strtok_r(NULL, "\0", &saveptr); 626 627 if (underscores(modname) < 0 || installcmd == NULL) 628 goto syntax_error; 629 630 kmod_config_add_command(config, modname, installcmd, 631 cmd, &config->install_commands); 632 } else if (streq(cmd, "remove")) { 633 char *modname = strtok_r(NULL, "\t ", &saveptr); 634 char *removecmd = strtok_r(NULL, "\0", &saveptr); 635 636 if (underscores(modname) < 0 || removecmd == NULL) 637 goto syntax_error; 638 639 kmod_config_add_command(config, modname, removecmd, 640 cmd, &config->remove_commands); 641 } else if (streq(cmd, "softdep")) { 642 char *modname = strtok_r(NULL, "\t ", &saveptr); 643 char *softdeps = strtok_r(NULL, "\0", &saveptr); 644 645 if (underscores(modname) < 0 || softdeps == NULL) 646 goto syntax_error; 647 648 kmod_config_add_softdep(config, modname, softdeps); 649 } else if (streq(cmd, "include") 650 || streq(cmd, "config")) { 651 ERR(ctx, "%s: command %s is deprecated and not parsed anymore\n", 652 filename, cmd); 653 } else { 654 syntax_error: 655 ERR(ctx, "%s line %u: ignoring bad line starting with '%s'\n", 656 filename, linenum, cmd); 657 } 658 659 done_next: 660 free(line); 661 } 662 663 fclose(fp); 664 665 return 0; 666 } 667 668 void kmod_config_free(struct kmod_config *config) 669 { 670 while (config->aliases) 671 kmod_config_free_alias(config, config->aliases); 672 673 while (config->blacklists) 674 kmod_config_free_blacklist(config, config->blacklists); 675 676 while (config->options) 677 kmod_config_free_options(config, config->options); 678 679 while (config->install_commands) { 680 kmod_config_free_command(config, config->install_commands, 681 &config->install_commands); 682 } 683 684 while (config->remove_commands) { 685 kmod_config_free_command(config, config->remove_commands, 686 &config->remove_commands); 687 } 688 689 while (config->softdeps) 690 kmod_config_free_softdep(config, config->softdeps); 691 692 for (; config->paths != NULL; 693 config->paths = kmod_list_remove(config->paths)) 694 free(config->paths->data); 695 696 free(config); 697 } 698 699 static bool conf_files_filter_out(struct kmod_ctx *ctx, DIR *d, 700 const char *path, const char *fn) 701 { 702 size_t len = strlen(fn); 703 struct stat st; 704 705 if (fn[0] == '.') 706 return true; 707 708 if (len < 6 || (!streq(&fn[len - 5], ".conf") 709 && !streq(&fn[len - 6], ".alias"))) 710 return true; 711 712 fstatat(dirfd(d), fn, &st, 0); 713 714 if (S_ISDIR(st.st_mode)) { 715 ERR(ctx, "Directories inside directories are not supported: " 716 "%s/%s\n", path, fn); 717 return true; 718 } 719 720 return false; 721 } 722 723 struct conf_file { 724 const char *path; 725 bool is_single; 726 char name[]; 727 }; 728 729 static int conf_files_insert_sorted(struct kmod_ctx *ctx, 730 struct kmod_list **list, 731 const char *path, const char *name) 732 { 733 struct kmod_list *lpos, *tmp; 734 struct conf_file *cf; 735 size_t namelen; 736 int cmp = -1; 737 bool is_single = false; 738 739 if (name == NULL) { 740 name = basename(path); 741 is_single = true; 742 } 743 744 kmod_list_foreach(lpos, *list) { 745 cf = lpos->data; 746 747 if ((cmp = strcmp(name, cf->name)) <= 0) 748 break; 749 } 750 751 if (cmp == 0) { 752 DBG(ctx, "Ignoring duplicate config file: %s/%s\n", path, 753 name); 754 return -EEXIST; 755 } 756 757 namelen = strlen(name); 758 cf = malloc(sizeof(*cf) + namelen + 1); 759 if (cf == NULL) 760 return -ENOMEM; 761 762 memcpy(cf->name, name, namelen + 1); 763 cf->path = path; 764 cf->is_single = is_single; 765 766 if (lpos == NULL) 767 tmp = kmod_list_append(*list, cf); 768 else if (lpos == *list) 769 tmp = kmod_list_prepend(*list, cf); 770 else 771 tmp = kmod_list_insert_before(lpos, cf); 772 773 if (tmp == NULL) { 774 free(cf); 775 return -ENOMEM; 776 } 777 778 if (lpos == NULL || lpos == *list) 779 *list = tmp; 780 781 return 0; 782 } 783 784 /* 785 * Insert configuration files in @list, ignoring duplicates 786 */ 787 static int conf_files_list(struct kmod_ctx *ctx, struct kmod_list **list, 788 const char *path, 789 unsigned long long *path_stamp) 790 { 791 DIR *d; 792 int err; 793 struct stat st; 794 struct dirent *dent; 795 796 if (stat(path, &st) != 0) { 797 err = -errno; 798 DBG(ctx, "could not stat '%s': %m\n", path); 799 return err; 800 } 801 802 *path_stamp = stat_mstamp(&st); 803 804 if (!S_ISDIR(st.st_mode)) { 805 conf_files_insert_sorted(ctx, list, path, NULL); 806 return 0; 807 } 808 809 d = opendir(path); 810 if (d == NULL) { 811 ERR(ctx, "opendir(%s): %m\n", path); 812 return -EINVAL; 813 } 814 815 for (dent = readdir(d); dent != NULL; dent = readdir(d)) { 816 if (conf_files_filter_out(ctx, d, path, dent->d_name)) 817 continue; 818 819 conf_files_insert_sorted(ctx, list, path, dent->d_name); 820 } 821 822 closedir(d); 823 return 0; 824 } 825 826 int kmod_config_new(struct kmod_ctx *ctx, struct kmod_config **p_config, 827 const char * const *config_paths) 828 { 829 struct kmod_config *config; 830 struct kmod_list *list = NULL; 831 struct kmod_list *path_list = NULL; 832 size_t i; 833 834 conf_files_insert_sorted(ctx, &list, kmod_get_dirname(ctx), "modules.softdep"); 835 836 for (i = 0; config_paths[i] != NULL; i++) { 837 const char *path = config_paths[i]; 838 unsigned long long path_stamp = 0; 839 size_t pathlen; 840 struct kmod_list *tmp; 841 struct kmod_config_path *cf; 842 843 if (conf_files_list(ctx, &list, path, &path_stamp) < 0) 844 continue; 845 846 pathlen = strlen(path) + 1; 847 cf = malloc(sizeof(*cf) + pathlen); 848 if (cf == NULL) 849 goto oom; 850 851 cf->stamp = path_stamp; 852 memcpy(cf->path, path, pathlen); 853 854 tmp = kmod_list_append(path_list, cf); 855 if (tmp == NULL) 856 goto oom; 857 path_list = tmp; 858 } 859 860 *p_config = config = calloc(1, sizeof(struct kmod_config)); 861 if (config == NULL) 862 goto oom; 863 864 config->paths = path_list; 865 config->ctx = ctx; 866 867 for (; list != NULL; list = kmod_list_remove(list)) { 868 char buf[PATH_MAX]; 869 const char *fn = buf; 870 struct conf_file *cf = list->data; 871 int fd; 872 873 if (cf->is_single) { 874 fn = cf->path; 875 } else if (snprintf(buf, sizeof(buf), "%s/%s", 876 cf->path, cf->name) >= (int)sizeof(buf)) { 877 ERR(ctx, "Error parsing %s/%s: path too long\n", 878 cf->path, cf->name); 879 free(cf); 880 continue; 881 } 882 883 fd = open(fn, O_RDONLY|O_CLOEXEC); 884 DBG(ctx, "parsing file '%s' fd=%d\n", fn, fd); 885 886 if (fd >= 0) 887 kmod_config_parse(config, fd, fn); 888 889 free(cf); 890 } 891 892 kmod_config_parse_kcmdline(config); 893 894 return 0; 895 896 oom: 897 for (; list != NULL; list = kmod_list_remove(list)) 898 free(list->data); 899 900 for (; path_list != NULL; path_list = kmod_list_remove(path_list)) 901 free(path_list->data); 902 903 return -ENOMEM; 904 } 905 906 /********************************************************************** 907 * struct kmod_config_iter functions 908 **********************************************************************/ 909 910 enum config_type { 911 CONFIG_TYPE_BLACKLIST = 0, 912 CONFIG_TYPE_INSTALL, 913 CONFIG_TYPE_REMOVE, 914 CONFIG_TYPE_ALIAS, 915 CONFIG_TYPE_OPTION, 916 CONFIG_TYPE_SOFTDEP, 917 }; 918 919 struct kmod_config_iter { 920 enum config_type type; 921 bool intermediate; 922 const struct kmod_list *list; 923 const struct kmod_list *curr; 924 void *data; 925 const char *(*get_key)(const struct kmod_list *l); 926 const char *(*get_value)(const struct kmod_list *l); 927 }; 928 929 static const char *softdep_get_plain_softdep(const struct kmod_list *l) 930 { 931 char *s = softdep_to_char(l->data); 932 return s; 933 } 934 935 static struct kmod_config_iter *kmod_config_iter_new(const struct kmod_ctx* ctx, 936 enum config_type type) 937 { 938 struct kmod_config_iter *iter = calloc(1, sizeof(*iter)); 939 const struct kmod_config *config = kmod_get_config(ctx); 940 941 if (iter == NULL) 942 return NULL; 943 944 iter->type = type; 945 946 switch (type) { 947 case CONFIG_TYPE_BLACKLIST: 948 iter->list = config->blacklists; 949 iter->get_key = kmod_blacklist_get_modname; 950 break; 951 case CONFIG_TYPE_INSTALL: 952 iter->list = config->install_commands; 953 iter->get_key = kmod_command_get_modname; 954 iter->get_value = kmod_command_get_command; 955 break; 956 case CONFIG_TYPE_REMOVE: 957 iter->list = config->remove_commands; 958 iter->get_key = kmod_command_get_modname; 959 iter->get_value = kmod_command_get_command; 960 break; 961 case CONFIG_TYPE_ALIAS: 962 iter->list = config->aliases; 963 iter->get_key = kmod_alias_get_name; 964 iter->get_value = kmod_alias_get_modname; 965 break; 966 case CONFIG_TYPE_OPTION: 967 iter->list = config->options; 968 iter->get_key = kmod_option_get_modname; 969 iter->get_value = kmod_option_get_options; 970 break; 971 case CONFIG_TYPE_SOFTDEP: 972 iter->list = config->softdeps; 973 iter->get_key = kmod_softdep_get_name; 974 iter->get_value = softdep_get_plain_softdep; 975 iter->intermediate = true; 976 break; 977 } 978 979 return iter; 980 } 981 982 /** 983 * SECTION:libkmod-config 984 * @short_description: retrieve current libkmod configuration 985 */ 986 987 /** 988 * kmod_config_get_blacklists: 989 * @ctx: kmod library context 990 * 991 * Retrieve an iterator to deal with the blacklist maintained inside the 992 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and 993 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must 994 * be made to initialize the iterator and check if it's valid. 995 * 996 * Returns: a new iterator over the blacklists or NULL on failure. Free it 997 * with kmod_config_iter_free_iter(). 998 */ 999 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_blacklists(const struct kmod_ctx *ctx) 1000 { 1001 if (ctx == NULL) 1002 return NULL;; 1003 1004 return kmod_config_iter_new(ctx, CONFIG_TYPE_BLACKLIST); 1005 } 1006 1007 /** 1008 * kmod_config_get_install_commands: 1009 * @ctx: kmod library context 1010 * 1011 * Retrieve an iterator to deal with the install commands maintained inside the 1012 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and 1013 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must 1014 * be made to initialize the iterator and check if it's valid. 1015 * 1016 * Returns: a new iterator over the install commands or NULL on failure. Free 1017 * it with kmod_config_iter_free_iter(). 1018 */ 1019 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_install_commands(const struct kmod_ctx *ctx) 1020 { 1021 if (ctx == NULL) 1022 return NULL;; 1023 1024 return kmod_config_iter_new(ctx, CONFIG_TYPE_INSTALL); 1025 } 1026 1027 /** 1028 * kmod_config_get_remove_commands: 1029 * @ctx: kmod library context 1030 * 1031 * Retrieve an iterator to deal with the remove commands maintained inside the 1032 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and 1033 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must 1034 * be made to initialize the iterator and check if it's valid. 1035 * 1036 * Returns: a new iterator over the remove commands or NULL on failure. Free 1037 * it with kmod_config_iter_free_iter(). 1038 */ 1039 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_remove_commands(const struct kmod_ctx *ctx) 1040 { 1041 if (ctx == NULL) 1042 return NULL;; 1043 1044 return kmod_config_iter_new(ctx, CONFIG_TYPE_REMOVE); 1045 } 1046 1047 /** 1048 * kmod_config_get_aliases: 1049 * @ctx: kmod library context 1050 * 1051 * Retrieve an iterator to deal with the aliases maintained inside the 1052 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and 1053 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must 1054 * be made to initialize the iterator and check if it's valid. 1055 * 1056 * Returns: a new iterator over the aliases or NULL on failure. Free it with 1057 * kmod_config_iter_free_iter(). 1058 */ 1059 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_aliases(const struct kmod_ctx *ctx) 1060 { 1061 if (ctx == NULL) 1062 return NULL;; 1063 1064 return kmod_config_iter_new(ctx, CONFIG_TYPE_ALIAS); 1065 } 1066 1067 /** 1068 * kmod_config_get_options: 1069 * @ctx: kmod library context 1070 * 1071 * Retrieve an iterator to deal with the options maintained inside the 1072 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and 1073 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must 1074 * be made to initialize the iterator and check if it's valid. 1075 * 1076 * Returns: a new iterator over the options or NULL on failure. Free it with 1077 * kmod_config_iter_free_iter(). 1078 */ 1079 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_options(const struct kmod_ctx *ctx) 1080 { 1081 if (ctx == NULL) 1082 return NULL;; 1083 1084 return kmod_config_iter_new(ctx, CONFIG_TYPE_OPTION); 1085 } 1086 1087 /** 1088 * kmod_config_get_softdeps: 1089 * @ctx: kmod library context 1090 * 1091 * Retrieve an iterator to deal with the softdeps maintained inside the 1092 * library. See kmod_config_iter_get_key(), kmod_config_iter_get_value() and 1093 * kmod_config_iter_next(). At least one call to kmod_config_iter_next() must 1094 * be made to initialize the iterator and check if it's valid. 1095 * 1096 * Returns: a new iterator over the softdeps or NULL on failure. Free it with 1097 * kmod_config_iter_free_iter(). 1098 */ 1099 KMOD_EXPORT struct kmod_config_iter *kmod_config_get_softdeps(const struct kmod_ctx *ctx) 1100 { 1101 if (ctx == NULL) 1102 return NULL;; 1103 1104 return kmod_config_iter_new(ctx, CONFIG_TYPE_SOFTDEP); 1105 } 1106 1107 /** 1108 * kmod_config_iter_get_key: 1109 * @iter: iterator over a certain configuration 1110 * 1111 * When using a new allocated iterator, user must perform a call to 1112 * kmod_config_iter_next() to initialize iterator's position and check if it's 1113 * valid. 1114 * 1115 * Returns: the key of the current configuration pointed by @iter. 1116 */ 1117 KMOD_EXPORT const char *kmod_config_iter_get_key(const struct kmod_config_iter *iter) 1118 { 1119 if (iter == NULL || iter->curr == NULL) 1120 return NULL; 1121 1122 return iter->get_key(iter->curr); 1123 } 1124 1125 /** 1126 * kmod_config_iter_get_value: 1127 * @iter: iterator over a certain configuration 1128 * 1129 * When using a new allocated iterator, user must perform a call to 1130 * kmod_config_iter_next() to initialize iterator's position and check if it's 1131 * valid. 1132 * 1133 * Returns: the value of the current configuration pointed by @iter. 1134 */ 1135 KMOD_EXPORT const char *kmod_config_iter_get_value(const struct kmod_config_iter *iter) 1136 { 1137 const char *s; 1138 1139 if (iter == NULL || iter->curr == NULL) 1140 return NULL; 1141 1142 if (iter->get_value == NULL) 1143 return NULL; 1144 1145 if (iter->intermediate) { 1146 struct kmod_config_iter *i = (struct kmod_config_iter *)iter; 1147 1148 free(i->data); 1149 s = i->data = (void *) iter->get_value(iter->curr); 1150 } else 1151 s = iter->get_value(iter->curr); 1152 1153 return s; 1154 } 1155 1156 /** 1157 * kmod_config_iter_next: 1158 * @iter: iterator over a certain configuration 1159 * 1160 * Make @iter point to the next item of a certain configuration. It's an 1161 * automatically recycling iterator. When it reaches the end, false is 1162 * returned; then if user wants to iterate again, it's sufficient to call this 1163 * function once more. 1164 * 1165 * Returns: true if next position of @iter is valid or false if its end is 1166 * reached. 1167 */ 1168 KMOD_EXPORT bool kmod_config_iter_next(struct kmod_config_iter *iter) 1169 { 1170 if (iter == NULL) 1171 return false; 1172 1173 if (iter->curr == NULL) { 1174 iter->curr = iter->list; 1175 return iter->curr != NULL; 1176 } 1177 1178 iter->curr = kmod_list_next(iter->list, iter->curr); 1179 1180 return iter->curr != NULL; 1181 } 1182 1183 /** 1184 * kmod_config_iter_free_iter: 1185 * @iter: iterator over a certain configuration 1186 * 1187 * Free resources used by the iterator. 1188 */ 1189 KMOD_EXPORT void kmod_config_iter_free_iter(struct kmod_config_iter *iter) 1190 { 1191 free(iter->data); 1192 free(iter); 1193 } 1194