module.c revision 300117
1/*- 2 * Copyright (c) 1998 Michael Smith <msmith@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/sys/boot/common/module.c 300117 2016-05-18 05:59:05Z imp $"); 29 30/* 31 * file/module function dispatcher, support, etc. 32 */ 33 34#include <stand.h> 35#include <string.h> 36#include <sys/param.h> 37#include <sys/linker.h> 38#include <sys/module.h> 39#include <sys/queue.h> 40#include <sys/stdint.h> 41 42#include "bootstrap.h" 43 44#define MDIR_REMOVED 0x0001 45#define MDIR_NOHINTS 0x0002 46 47struct moduledir { 48 char *d_path; /* path of modules directory */ 49 u_char *d_hints; /* content of linker.hints file */ 50 int d_hintsz; /* size of hints data */ 51 int d_flags; 52 STAILQ_ENTRY(moduledir) d_link; 53}; 54 55static int file_load(char *filename, vm_offset_t dest, struct preloaded_file **result); 56static int file_load_dependencies(struct preloaded_file *base_mod); 57static char * file_search(const char *name, char **extlist); 58static struct kernel_module * file_findmodule(struct preloaded_file *fp, char *modname, struct mod_depend *verinfo); 59static int file_havepath(const char *name); 60static char *mod_searchmodule(char *name, struct mod_depend *verinfo); 61static void file_insert_tail(struct preloaded_file *mp); 62struct file_metadata* metadata_next(struct file_metadata *base_mp, int type); 63static void moduledir_readhints(struct moduledir *mdp); 64static void moduledir_rebuild(void); 65 66/* load address should be tweaked by first module loaded (kernel) */ 67static vm_offset_t loadaddr = 0; 68 69#if defined(LOADER_FDT_SUPPORT) 70static const char *default_searchpath = 71 "/boot/kernel;/boot/modules;/boot/dtb"; 72#else 73static const char *default_searchpath ="/boot/kernel;/boot/modules"; 74#endif 75 76static STAILQ_HEAD(, moduledir) moduledir_list = STAILQ_HEAD_INITIALIZER(moduledir_list); 77 78struct preloaded_file *preloaded_files = NULL; 79 80static char *kld_ext_list[] = { 81 ".ko", 82 "", 83 ".debug", 84 NULL 85}; 86 87 88/* 89 * load an object, either a disk file or code module. 90 * 91 * To load a file, the syntax is: 92 * 93 * load -t <type> <path> 94 * 95 * code modules are loaded as: 96 * 97 * load <path> <options> 98 */ 99 100COMMAND_SET(load, "load", "load a kernel or module", command_load); 101 102static int 103command_load(int argc, char *argv[]) 104{ 105 struct preloaded_file *fp; 106 char *typestr; 107 int dofile, dokld, ch, error; 108 109 dokld = dofile = 0; 110 optind = 1; 111 optreset = 1; 112 typestr = NULL; 113 if (argc == 1) { 114 command_errmsg = "no filename specified"; 115 return (CMD_CRIT); 116 } 117 while ((ch = getopt(argc, argv, "kt:")) != -1) { 118 switch(ch) { 119 case 'k': 120 dokld = 1; 121 break; 122 case 't': 123 typestr = optarg; 124 dofile = 1; 125 break; 126 case '?': 127 default: 128 /* getopt has already reported an error */ 129 return (CMD_OK); 130 } 131 } 132 argv += (optind - 1); 133 argc -= (optind - 1); 134 135 /* 136 * Request to load a raw file? 137 */ 138 if (dofile) { 139 if ((argc != 2) || (typestr == NULL) || (*typestr == 0)) { 140 command_errmsg = "invalid load type"; 141 return (CMD_CRIT); 142 } 143 144 fp = file_findfile(argv[1], typestr); 145 if (fp) { 146 sprintf(command_errbuf, "warning: file '%s' already loaded", argv[1]); 147 return (CMD_WARN); 148 } 149 150 if (file_loadraw(argv[1], typestr, 1) != NULL) 151 return (CMD_OK); 152 153 /* Failing to load mfs_root is never going to end well! */ 154 if (strcmp("mfs_root", typestr) == 0) 155 return (CMD_FATAL); 156 157 return (CMD_ERROR); 158 } 159 /* 160 * Do we have explicit KLD load ? 161 */ 162 if (dokld || file_havepath(argv[1])) { 163 error = mod_loadkld(argv[1], argc - 2, argv + 2); 164 if (error == EEXIST) { 165 sprintf(command_errbuf, "warning: KLD '%s' already loaded", argv[1]); 166 return (CMD_WARN); 167 } 168 169 return (error == 0 ? CMD_OK : CMD_CRIT); 170 } 171 /* 172 * Looks like a request for a module. 173 */ 174 error = mod_load(argv[1], NULL, argc - 2, argv + 2); 175 if (error == EEXIST) { 176 sprintf(command_errbuf, "warning: module '%s' already loaded", argv[1]); 177 return (CMD_WARN); 178 } 179 180 return (error == 0 ? CMD_OK : CMD_CRIT); 181} 182 183COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli); 184 185static int 186command_load_geli(int argc, char *argv[]) 187{ 188 char typestr[80]; 189 char *cp; 190 int ch, num; 191 192 if (argc < 3) { 193 command_errmsg = "usage is [-n key#] <prov> <file>"; 194 return(CMD_ERROR); 195 } 196 197 num = 0; 198 optind = 1; 199 optreset = 1; 200 while ((ch = getopt(argc, argv, "n:")) != -1) { 201 switch(ch) { 202 case 'n': 203 num = strtol(optarg, &cp, 0); 204 if (cp == optarg) { 205 sprintf(command_errbuf, "bad key index '%s'", optarg); 206 return(CMD_ERROR); 207 } 208 break; 209 case '?': 210 default: 211 /* getopt has already reported an error */ 212 return(CMD_OK); 213 } 214 } 215 argv += (optind - 1); 216 argc -= (optind - 1); 217 sprintf(typestr, "%s:geli_keyfile%d", argv[1], num); 218 return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR); 219} 220 221void 222unload(void) 223{ 224 struct preloaded_file *fp; 225 226 while (preloaded_files != NULL) { 227 fp = preloaded_files; 228 preloaded_files = preloaded_files->f_next; 229 file_discard(fp); 230 } 231 loadaddr = 0; 232 unsetenv("kernelname"); 233} 234 235COMMAND_SET(unload, "unload", "unload all modules", command_unload); 236 237static int 238command_unload(int argc, char *argv[]) 239{ 240 unload(); 241 return(CMD_OK); 242} 243 244COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod); 245 246static int 247command_lsmod(int argc, char *argv[]) 248{ 249 struct preloaded_file *fp; 250 struct kernel_module *mp; 251 struct file_metadata *md; 252 char lbuf[80]; 253 int ch, verbose; 254 255 verbose = 0; 256 optind = 1; 257 optreset = 1; 258 while ((ch = getopt(argc, argv, "v")) != -1) { 259 switch(ch) { 260 case 'v': 261 verbose = 1; 262 break; 263 case '?': 264 default: 265 /* getopt has already reported an error */ 266 return(CMD_OK); 267 } 268 } 269 270 pager_open(); 271 for (fp = preloaded_files; fp; fp = fp->f_next) { 272 sprintf(lbuf, " %p: ", (void *) fp->f_addr); 273 pager_output(lbuf); 274 pager_output(fp->f_name); 275 sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size); 276 pager_output(lbuf); 277 if (fp->f_args != NULL) { 278 pager_output(" args: "); 279 pager_output(fp->f_args); 280 if (pager_output("\n")) 281 break; 282 } 283 if (fp->f_modules) { 284 pager_output(" modules: "); 285 for (mp = fp->f_modules; mp; mp = mp->m_next) { 286 sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version); 287 pager_output(lbuf); 288 } 289 if (pager_output("\n")) 290 break; 291 } 292 if (verbose) { 293 /* XXX could add some formatting smarts here to display some better */ 294 for (md = fp->f_metadata; md != NULL; md = md->md_next) { 295 sprintf(lbuf, " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size); 296 if (pager_output(lbuf)) 297 break; 298 } 299 } 300 } 301 pager_close(); 302 return(CMD_OK); 303} 304 305/* 306 * File level interface, functions file_* 307 */ 308int 309file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) 310{ 311 static int last_file_format = 0; 312 struct preloaded_file *fp; 313 int error; 314 int i; 315 316 if (archsw.arch_loadaddr != NULL) 317 dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); 318 319 error = EFTYPE; 320 for (i = last_file_format, fp = NULL; 321 file_formats[i] && fp == NULL; i++) { 322 error = (file_formats[i]->l_load)(filename, dest, &fp); 323 if (error == 0) { 324 fp->f_loader = last_file_format = i; /* remember the loader */ 325 *result = fp; 326 break; 327 } else if (last_file_format == i && i != 0) { 328 /* Restart from the beginning */ 329 i = -1; 330 last_file_format = 0; 331 fp = NULL; 332 continue; 333 } 334 if (error == EFTYPE) 335 continue; /* Unknown to this handler? */ 336 if (error) { 337 sprintf(command_errbuf, "can't load file '%s': %s", 338 filename, strerror(error)); 339 break; 340 } 341 } 342 return (error); 343} 344 345static int 346file_load_dependencies(struct preloaded_file *base_file) 347{ 348 struct file_metadata *md; 349 struct preloaded_file *fp; 350 struct mod_depend *verinfo; 351 struct kernel_module *mp; 352 char *dmodname; 353 int error; 354 355 md = file_findmetadata(base_file, MODINFOMD_DEPLIST); 356 if (md == NULL) 357 return (0); 358 error = 0; 359 do { 360 verinfo = (struct mod_depend*)md->md_data; 361 dmodname = (char *)(verinfo + 1); 362 if (file_findmodule(NULL, dmodname, verinfo) == NULL) { 363 printf("loading required module '%s'\n", dmodname); 364 error = mod_load(dmodname, verinfo, 0, NULL); 365 if (error) 366 break; 367 /* 368 * If module loaded via kld name which isn't listed 369 * in the linker.hints file, we should check if it have 370 * required version. 371 */ 372 mp = file_findmodule(NULL, dmodname, verinfo); 373 if (mp == NULL) { 374 sprintf(command_errbuf, "module '%s' exists but with wrong version", 375 dmodname); 376 error = ENOENT; 377 break; 378 } 379 } 380 md = metadata_next(md, MODINFOMD_DEPLIST); 381 } while (md); 382 if (!error) 383 return (0); 384 /* Load failed; discard everything */ 385 while (base_file != NULL) { 386 fp = base_file; 387 base_file = base_file->f_next; 388 file_discard(fp); 389 } 390 return (error); 391} 392 393/* 394 * We've been asked to load (fname) as (type), so just suck it in, 395 * no arguments or anything. 396 */ 397struct preloaded_file * 398file_loadraw(const char *fname, char *type, int insert) 399{ 400 struct preloaded_file *fp; 401 char *name; 402 int fd, got; 403 vm_offset_t laddr; 404 405 /* We can't load first */ 406 if ((file_findfile(NULL, NULL)) == NULL) { 407 command_errmsg = "can't load file before kernel"; 408 return(NULL); 409 } 410 411 /* locate the file on the load path */ 412 name = file_search(fname, NULL); 413 if (name == NULL) { 414 sprintf(command_errbuf, "can't find '%s'", fname); 415 return(NULL); 416 } 417 418 if ((fd = open(name, O_RDONLY)) < 0) { 419 sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno)); 420 free(name); 421 return(NULL); 422 } 423 424 if (archsw.arch_loadaddr != NULL) 425 loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); 426 427 printf("%s ", name); 428 429 laddr = loadaddr; 430 for (;;) { 431 /* read in 4k chunks; size is not really important */ 432 got = archsw.arch_readin(fd, laddr, 4096); 433 if (got == 0) /* end of file */ 434 break; 435 if (got < 0) { /* error */ 436 sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno)); 437 free(name); 438 close(fd); 439 return(NULL); 440 } 441 laddr += got; 442 } 443 444 printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr)); 445 446 /* Looks OK so far; create & populate control structure */ 447 fp = file_alloc(); 448 fp->f_name = strdup(name); 449 fp->f_type = strdup(type); 450 fp->f_args = NULL; 451 fp->f_metadata = NULL; 452 fp->f_loader = -1; 453 fp->f_addr = loadaddr; 454 fp->f_size = laddr - loadaddr; 455 456 /* recognise space consumption */ 457 loadaddr = laddr; 458 459 /* Add to the list of loaded files */ 460 if (insert != 0) 461 file_insert_tail(fp); 462 close(fd); 463 return(fp); 464} 465 466/* 467 * Load the module (name), pass it (argc),(argv), add container file 468 * to the list of loaded files. 469 * If module is already loaded just assign new argc/argv. 470 */ 471int 472mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[]) 473{ 474 struct kernel_module *mp; 475 int err; 476 char *filename; 477 478 if (file_havepath(modname)) { 479 printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname); 480 return (mod_loadkld(modname, argc, argv)); 481 } 482 /* see if module is already loaded */ 483 mp = file_findmodule(NULL, modname, verinfo); 484 if (mp) { 485#ifdef moduleargs 486 if (mp->m_args) 487 free(mp->m_args); 488 mp->m_args = unargv(argc, argv); 489#endif 490 sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name); 491 return (0); 492 } 493 /* locate file with the module on the search path */ 494 filename = mod_searchmodule(modname, verinfo); 495 if (filename == NULL) { 496 sprintf(command_errbuf, "can't find '%s'", modname); 497 return (ENOENT); 498 } 499 err = mod_loadkld(filename, argc, argv); 500 return (err); 501} 502 503/* 504 * Load specified KLD. If path is omitted, then try to locate it via 505 * search path. 506 */ 507int 508mod_loadkld(const char *kldname, int argc, char *argv[]) 509{ 510 struct preloaded_file *fp, *last_file; 511 int err; 512 char *filename; 513 514 /* 515 * Get fully qualified KLD name 516 */ 517 filename = file_search(kldname, kld_ext_list); 518 if (filename == NULL) { 519 sprintf(command_errbuf, "can't find '%s'", kldname); 520 return (ENOENT); 521 } 522 /* 523 * Check if KLD already loaded 524 */ 525 fp = file_findfile(filename, NULL); 526 if (fp) { 527 sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename); 528 free(filename); 529 return (0); 530 } 531 for (last_file = preloaded_files; 532 last_file != NULL && last_file->f_next != NULL; 533 last_file = last_file->f_next) 534 ; 535 536 do { 537 err = file_load(filename, loadaddr, &fp); 538 if (err) 539 break; 540 fp->f_args = unargv(argc, argv); 541 loadaddr = fp->f_addr + fp->f_size; 542 file_insert_tail(fp); /* Add to the list of loaded files */ 543 if (file_load_dependencies(fp) != 0) { 544 err = ENOENT; 545 last_file->f_next = NULL; 546 loadaddr = last_file->f_addr + last_file->f_size; 547 fp = NULL; 548 break; 549 } 550 } while(0); 551 if (err == EFTYPE) 552 sprintf(command_errbuf, "don't know how to load module '%s'", filename); 553 if (err && fp) 554 file_discard(fp); 555 free(filename); 556 return (err); 557} 558 559/* 560 * Find a file matching (name) and (type). 561 * NULL may be passed as a wildcard to either. 562 */ 563struct preloaded_file * 564file_findfile(const char *name, const char *type) 565{ 566 struct preloaded_file *fp; 567 568 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) { 569 if (((name == NULL) || !strcmp(name, fp->f_name)) && 570 ((type == NULL) || !strcmp(type, fp->f_type))) 571 break; 572 } 573 return (fp); 574} 575 576/* 577 * Find a module matching (name) inside of given file. 578 * NULL may be passed as a wildcard. 579 */ 580struct kernel_module * 581file_findmodule(struct preloaded_file *fp, char *modname, 582 struct mod_depend *verinfo) 583{ 584 struct kernel_module *mp, *best; 585 int bestver, mver; 586 587 if (fp == NULL) { 588 for (fp = preloaded_files; fp; fp = fp->f_next) { 589 mp = file_findmodule(fp, modname, verinfo); 590 if (mp) 591 return (mp); 592 } 593 return (NULL); 594 } 595 best = NULL; 596 bestver = 0; 597 for (mp = fp->f_modules; mp; mp = mp->m_next) { 598 if (strcmp(modname, mp->m_name) == 0) { 599 if (verinfo == NULL) 600 return (mp); 601 mver = mp->m_version; 602 if (mver == verinfo->md_ver_preferred) 603 return (mp); 604 if (mver >= verinfo->md_ver_minimum && 605 mver <= verinfo->md_ver_maximum && 606 mver > bestver) { 607 best = mp; 608 bestver = mver; 609 } 610 } 611 } 612 return (best); 613} 614/* 615 * Make a copy of (size) bytes of data from (p), and associate them as 616 * metadata of (type) to the module (mp). 617 */ 618void 619file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p) 620{ 621 struct file_metadata *md; 622 623 md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size); 624 md->md_size = size; 625 md->md_type = type; 626 bcopy(p, md->md_data, size); 627 md->md_next = fp->f_metadata; 628 fp->f_metadata = md; 629} 630 631/* 632 * Find a metadata object of (type) associated with the file (fp) 633 */ 634struct file_metadata * 635file_findmetadata(struct preloaded_file *fp, int type) 636{ 637 struct file_metadata *md; 638 639 for (md = fp->f_metadata; md != NULL; md = md->md_next) 640 if (md->md_type == type) 641 break; 642 return(md); 643} 644 645struct file_metadata * 646metadata_next(struct file_metadata *md, int type) 647{ 648 if (md == NULL) 649 return (NULL); 650 while((md = md->md_next) != NULL) 651 if (md->md_type == type) 652 break; 653 return (md); 654} 655 656static char *emptyextlist[] = { "", NULL }; 657 658/* 659 * Check if the given file is in place and return full path to it. 660 */ 661static char * 662file_lookup(const char *path, const char *name, int namelen, char **extlist) 663{ 664 struct stat st; 665 char *result, *cp, **cpp; 666 int pathlen, extlen, len; 667 668 pathlen = strlen(path); 669 extlen = 0; 670 if (extlist == NULL) 671 extlist = emptyextlist; 672 for (cpp = extlist; *cpp; cpp++) { 673 len = strlen(*cpp); 674 if (len > extlen) 675 extlen = len; 676 } 677 result = malloc(pathlen + namelen + extlen + 2); 678 if (result == NULL) 679 return (NULL); 680 bcopy(path, result, pathlen); 681 if (pathlen > 0 && result[pathlen - 1] != '/') 682 result[pathlen++] = '/'; 683 cp = result + pathlen; 684 bcopy(name, cp, namelen); 685 cp += namelen; 686 for (cpp = extlist; *cpp; cpp++) { 687 strcpy(cp, *cpp); 688 if (stat(result, &st) == 0 && S_ISREG(st.st_mode)) 689 return result; 690 } 691 free(result); 692 return NULL; 693} 694 695/* 696 * Check if file name have any qualifiers 697 */ 698static int 699file_havepath(const char *name) 700{ 701 const char *cp; 702 703 archsw.arch_getdev(NULL, name, &cp); 704 return (cp != name || strchr(name, '/') != NULL); 705} 706 707/* 708 * Attempt to find the file (name) on the module searchpath. 709 * If (name) is qualified in any way, we simply check it and 710 * return it or NULL. If it is not qualified, then we attempt 711 * to construct a path using entries in the environment variable 712 * module_path. 713 * 714 * The path we return a pointer to need never be freed, as we manage 715 * it internally. 716 */ 717static char * 718file_search(const char *name, char **extlist) 719{ 720 struct moduledir *mdp; 721 struct stat sb; 722 char *result; 723 int namelen; 724 725 /* Don't look for nothing */ 726 if (name == NULL) 727 return(NULL); 728 729 if (*name == 0) 730 return(strdup(name)); 731 732 if (file_havepath(name)) { 733 /* Qualified, so just see if it exists */ 734 if (stat(name, &sb) == 0) 735 return(strdup(name)); 736 return(NULL); 737 } 738 moduledir_rebuild(); 739 result = NULL; 740 namelen = strlen(name); 741 STAILQ_FOREACH(mdp, &moduledir_list, d_link) { 742 result = file_lookup(mdp->d_path, name, namelen, extlist); 743 if (result) 744 break; 745 } 746 return(result); 747} 748 749#define INT_ALIGN(base, ptr) ptr = \ 750 (base) + roundup2((ptr) - (base), sizeof(int)) 751 752static char * 753mod_search_hints(struct moduledir *mdp, const char *modname, 754 struct mod_depend *verinfo) 755{ 756 u_char *cp, *recptr, *bufend, *best; 757 char *result; 758 int *intp, bestver, blen, clen, found, ival, modnamelen, reclen; 759 760 moduledir_readhints(mdp); 761 modnamelen = strlen(modname); 762 found = 0; 763 result = NULL; 764 bestver = 0; 765 if (mdp->d_hints == NULL) 766 goto bad; 767 recptr = mdp->d_hints; 768 bufend = recptr + mdp->d_hintsz; 769 clen = blen = 0; 770 best = cp = NULL; 771 while (recptr < bufend && !found) { 772 intp = (int*)recptr; 773 reclen = *intp++; 774 ival = *intp++; 775 cp = (u_char*)intp; 776 switch (ival) { 777 case MDT_VERSION: 778 clen = *cp++; 779 if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 780 break; 781 cp += clen; 782 INT_ALIGN(mdp->d_hints, cp); 783 ival = *(int*)cp; 784 cp += sizeof(int); 785 clen = *cp++; 786 if (verinfo == NULL || ival == verinfo->md_ver_preferred) { 787 found = 1; 788 break; 789 } 790 if (ival >= verinfo->md_ver_minimum && 791 ival <= verinfo->md_ver_maximum && 792 ival > bestver) { 793 bestver = ival; 794 best = cp; 795 blen = clen; 796 } 797 break; 798 default: 799 break; 800 } 801 recptr += reclen + sizeof(int); 802 } 803 /* 804 * Finally check if KLD is in the place 805 */ 806 if (found) 807 result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL); 808 else if (best) 809 result = file_lookup(mdp->d_path, (const char *)best, blen, NULL); 810bad: 811 /* 812 * If nothing found or hints is absent - fallback to the old way 813 * by using "kldname[.ko]" as module name. 814 */ 815 if (!found && !bestver && result == NULL) 816 result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list); 817 return result; 818} 819 820/* 821 * Attempt to locate the file containing the module (name) 822 */ 823static char * 824mod_searchmodule(char *name, struct mod_depend *verinfo) 825{ 826 struct moduledir *mdp; 827 char *result; 828 829 moduledir_rebuild(); 830 /* 831 * Now we ready to lookup module in the given directories 832 */ 833 result = NULL; 834 STAILQ_FOREACH(mdp, &moduledir_list, d_link) { 835 result = mod_search_hints(mdp, name, verinfo); 836 if (result) 837 break; 838 } 839 840 return(result); 841} 842 843int 844file_addmodule(struct preloaded_file *fp, char *modname, int version, 845 struct kernel_module **newmp) 846{ 847 struct kernel_module *mp; 848 struct mod_depend mdepend; 849 850 bzero(&mdepend, sizeof(mdepend)); 851 mdepend.md_ver_preferred = version; 852 mp = file_findmodule(fp, modname, &mdepend); 853 if (mp) 854 return (EEXIST); 855 mp = malloc(sizeof(struct kernel_module)); 856 if (mp == NULL) 857 return (ENOMEM); 858 bzero(mp, sizeof(struct kernel_module)); 859 mp->m_name = strdup(modname); 860 mp->m_version = version; 861 mp->m_fp = fp; 862 mp->m_next = fp->f_modules; 863 fp->f_modules = mp; 864 if (newmp) 865 *newmp = mp; 866 return (0); 867} 868 869/* 870 * Throw a file away 871 */ 872void 873file_discard(struct preloaded_file *fp) 874{ 875 struct file_metadata *md, *md1; 876 struct kernel_module *mp, *mp1; 877 if (fp == NULL) 878 return; 879 md = fp->f_metadata; 880 while (md) { 881 md1 = md; 882 md = md->md_next; 883 free(md1); 884 } 885 mp = fp->f_modules; 886 while (mp) { 887 if (mp->m_name) 888 free(mp->m_name); 889 mp1 = mp; 890 mp = mp->m_next; 891 free(mp1); 892 } 893 if (fp->f_name != NULL) 894 free(fp->f_name); 895 if (fp->f_type != NULL) 896 free(fp->f_type); 897 if (fp->f_args != NULL) 898 free(fp->f_args); 899 free(fp); 900} 901 902/* 903 * Allocate a new file; must be used instead of malloc() 904 * to ensure safe initialisation. 905 */ 906struct preloaded_file * 907file_alloc(void) 908{ 909 struct preloaded_file *fp; 910 911 if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) { 912 bzero(fp, sizeof(struct preloaded_file)); 913 } 914 return (fp); 915} 916 917/* 918 * Add a module to the chain 919 */ 920static void 921file_insert_tail(struct preloaded_file *fp) 922{ 923 struct preloaded_file *cm; 924 925 /* Append to list of loaded file */ 926 fp->f_next = NULL; 927 if (preloaded_files == NULL) { 928 preloaded_files = fp; 929 } else { 930 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) 931 ; 932 cm->f_next = fp; 933 } 934} 935 936static char * 937moduledir_fullpath(struct moduledir *mdp, const char *fname) 938{ 939 char *cp; 940 941 cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2); 942 if (cp == NULL) 943 return NULL; 944 strcpy(cp, mdp->d_path); 945 strcat(cp, "/"); 946 strcat(cp, fname); 947 return (cp); 948} 949 950/* 951 * Read linker.hints file into memory performing some sanity checks. 952 */ 953static void 954moduledir_readhints(struct moduledir *mdp) 955{ 956 struct stat st; 957 char *path; 958 int fd, size, version; 959 960 if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS)) 961 return; 962 path = moduledir_fullpath(mdp, "linker.hints"); 963 if (stat(path, &st) != 0 || 964 st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) || 965 st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) { 966 free(path); 967 mdp->d_flags |= MDIR_NOHINTS; 968 return; 969 } 970 free(path); 971 size = read(fd, &version, sizeof(version)); 972 if (size != sizeof(version) || version != LINKER_HINTS_VERSION) 973 goto bad; 974 size = st.st_size - size; 975 mdp->d_hints = malloc(size); 976 if (mdp->d_hints == NULL) 977 goto bad; 978 if (read(fd, mdp->d_hints, size) != size) 979 goto bad; 980 mdp->d_hintsz = size; 981 close(fd); 982 return; 983bad: 984 close(fd); 985 if (mdp->d_hints) { 986 free(mdp->d_hints); 987 mdp->d_hints = NULL; 988 } 989 mdp->d_flags |= MDIR_NOHINTS; 990 return; 991} 992 993/* 994 * Extract directories from the ';' separated list, remove duplicates. 995 */ 996static void 997moduledir_rebuild(void) 998{ 999 struct moduledir *mdp, *mtmp; 1000 const char *path, *cp, *ep; 1001 size_t cplen; 1002 1003 path = getenv("module_path"); 1004 if (path == NULL) 1005 path = default_searchpath; 1006 /* 1007 * Rebuild list of module directories if it changed 1008 */ 1009 STAILQ_FOREACH(mdp, &moduledir_list, d_link) 1010 mdp->d_flags |= MDIR_REMOVED; 1011 1012 for (ep = path; *ep != 0; ep++) { 1013 cp = ep; 1014 for (; *ep != 0 && *ep != ';'; ep++) 1015 ; 1016 /* 1017 * Ignore trailing slashes 1018 */ 1019 for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--) 1020 ; 1021 STAILQ_FOREACH(mdp, &moduledir_list, d_link) { 1022 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0) 1023 continue; 1024 mdp->d_flags &= ~MDIR_REMOVED; 1025 break; 1026 } 1027 if (mdp == NULL) { 1028 mdp = malloc(sizeof(*mdp) + cplen + 1); 1029 if (mdp == NULL) 1030 return; 1031 mdp->d_path = (char*)(mdp + 1); 1032 bcopy(cp, mdp->d_path, cplen); 1033 mdp->d_path[cplen] = 0; 1034 mdp->d_hints = NULL; 1035 mdp->d_flags = 0; 1036 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link); 1037 } 1038 if (*ep == 0) 1039 break; 1040 } 1041 /* 1042 * Delete unused directories if any 1043 */ 1044 mdp = STAILQ_FIRST(&moduledir_list); 1045 while (mdp) { 1046 if ((mdp->d_flags & MDIR_REMOVED) == 0) { 1047 mdp = STAILQ_NEXT(mdp, d_link); 1048 } else { 1049 if (mdp->d_hints) 1050 free(mdp->d_hints); 1051 mtmp = mdp; 1052 mdp = STAILQ_NEXT(mdp, d_link); 1053 STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link); 1054 free(mtmp); 1055 } 1056 } 1057 return; 1058} 1059