module.c revision 321232
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: stable/11/sys/boot/common/module.c 321232 2017-07-19 19:06:19Z ngie $"); 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 183#ifdef LOADER_GELI_SUPPORT 184COMMAND_SET(load_geli, "load_geli", "load a geli key", command_load_geli); 185 186static int 187command_load_geli(int argc, char *argv[]) 188{ 189 char typestr[80]; 190 char *cp; 191 int ch, num; 192 193 if (argc < 3) { 194 command_errmsg = "usage is [-n key#] <prov> <file>"; 195 return(CMD_ERROR); 196 } 197 198 num = 0; 199 optind = 1; 200 optreset = 1; 201 while ((ch = getopt(argc, argv, "n:")) != -1) { 202 switch(ch) { 203 case 'n': 204 num = strtol(optarg, &cp, 0); 205 if (cp == optarg) { 206 sprintf(command_errbuf, "bad key index '%s'", optarg); 207 return(CMD_ERROR); 208 } 209 break; 210 case '?': 211 default: 212 /* getopt has already reported an error */ 213 return(CMD_OK); 214 } 215 } 216 argv += (optind - 1); 217 argc -= (optind - 1); 218 sprintf(typestr, "%s:geli_keyfile%d", argv[1], num); 219 return (file_loadraw(argv[2], typestr, 1) ? CMD_OK : CMD_ERROR); 220} 221#endif 222 223void 224unload(void) 225{ 226 struct preloaded_file *fp; 227 228 while (preloaded_files != NULL) { 229 fp = preloaded_files; 230 preloaded_files = preloaded_files->f_next; 231 file_discard(fp); 232 } 233 loadaddr = 0; 234 unsetenv("kernelname"); 235} 236 237COMMAND_SET(unload, "unload", "unload all modules", command_unload); 238 239static int 240command_unload(int argc, char *argv[]) 241{ 242 unload(); 243 return(CMD_OK); 244} 245 246COMMAND_SET(lsmod, "lsmod", "list loaded modules", command_lsmod); 247 248static int 249command_lsmod(int argc, char *argv[]) 250{ 251 struct preloaded_file *fp; 252 struct kernel_module *mp; 253 struct file_metadata *md; 254 char lbuf[80]; 255 int ch, verbose; 256 257 verbose = 0; 258 optind = 1; 259 optreset = 1; 260 while ((ch = getopt(argc, argv, "v")) != -1) { 261 switch(ch) { 262 case 'v': 263 verbose = 1; 264 break; 265 case '?': 266 default: 267 /* getopt has already reported an error */ 268 return(CMD_OK); 269 } 270 } 271 272 pager_open(); 273 for (fp = preloaded_files; fp; fp = fp->f_next) { 274 sprintf(lbuf, " %p: ", (void *) fp->f_addr); 275 pager_output(lbuf); 276 pager_output(fp->f_name); 277 sprintf(lbuf, " (%s, 0x%lx)\n", fp->f_type, (long)fp->f_size); 278 pager_output(lbuf); 279 if (fp->f_args != NULL) { 280 pager_output(" args: "); 281 pager_output(fp->f_args); 282 if (pager_output("\n")) 283 break; 284 } 285 if (fp->f_modules) { 286 pager_output(" modules: "); 287 for (mp = fp->f_modules; mp; mp = mp->m_next) { 288 sprintf(lbuf, "%s.%d ", mp->m_name, mp->m_version); 289 pager_output(lbuf); 290 } 291 if (pager_output("\n")) 292 break; 293 } 294 if (verbose) { 295 /* XXX could add some formatting smarts here to display some better */ 296 for (md = fp->f_metadata; md != NULL; md = md->md_next) { 297 sprintf(lbuf, " 0x%04x, 0x%lx\n", md->md_type, (long) md->md_size); 298 if (pager_output(lbuf)) 299 break; 300 } 301 } 302 } 303 pager_close(); 304 return(CMD_OK); 305} 306 307/* 308 * File level interface, functions file_* 309 */ 310int 311file_load(char *filename, vm_offset_t dest, struct preloaded_file **result) 312{ 313 static int last_file_format = 0; 314 struct preloaded_file *fp; 315 int error; 316 int i; 317 318 if (archsw.arch_loadaddr != NULL) 319 dest = archsw.arch_loadaddr(LOAD_RAW, filename, dest); 320 321 error = EFTYPE; 322 for (i = last_file_format, fp = NULL; 323 file_formats[i] && fp == NULL; i++) { 324 error = (file_formats[i]->l_load)(filename, dest, &fp); 325 if (error == 0) { 326 fp->f_loader = last_file_format = i; /* remember the loader */ 327 *result = fp; 328 break; 329 } else if (last_file_format == i && i != 0) { 330 /* Restart from the beginning */ 331 i = -1; 332 last_file_format = 0; 333 fp = NULL; 334 continue; 335 } 336 if (error == EFTYPE) 337 continue; /* Unknown to this handler? */ 338 if (error) { 339 sprintf(command_errbuf, "can't load file '%s': %s", 340 filename, strerror(error)); 341 break; 342 } 343 } 344 return (error); 345} 346 347static int 348file_load_dependencies(struct preloaded_file *base_file) 349{ 350 struct file_metadata *md; 351 struct preloaded_file *fp; 352 struct mod_depend *verinfo; 353 struct kernel_module *mp; 354 char *dmodname; 355 int error; 356 357 md = file_findmetadata(base_file, MODINFOMD_DEPLIST); 358 if (md == NULL) 359 return (0); 360 error = 0; 361 do { 362 verinfo = (struct mod_depend*)md->md_data; 363 dmodname = (char *)(verinfo + 1); 364 if (file_findmodule(NULL, dmodname, verinfo) == NULL) { 365 printf("loading required module '%s'\n", dmodname); 366 error = mod_load(dmodname, verinfo, 0, NULL); 367 if (error) 368 break; 369 /* 370 * If module loaded via kld name which isn't listed 371 * in the linker.hints file, we should check if it have 372 * required version. 373 */ 374 mp = file_findmodule(NULL, dmodname, verinfo); 375 if (mp == NULL) { 376 sprintf(command_errbuf, "module '%s' exists but with wrong version", 377 dmodname); 378 error = ENOENT; 379 break; 380 } 381 } 382 md = metadata_next(md, MODINFOMD_DEPLIST); 383 } while (md); 384 if (!error) 385 return (0); 386 /* Load failed; discard everything */ 387 while (base_file != NULL) { 388 fp = base_file; 389 base_file = base_file->f_next; 390 file_discard(fp); 391 } 392 return (error); 393} 394 395/* 396 * We've been asked to load (fname) as (type), so just suck it in, 397 * no arguments or anything. 398 */ 399struct preloaded_file * 400file_loadraw(const char *fname, char *type, int insert) 401{ 402 struct preloaded_file *fp; 403 char *name; 404 int fd, got; 405 vm_offset_t laddr; 406 407 /* We can't load first */ 408 if ((file_findfile(NULL, NULL)) == NULL) { 409 command_errmsg = "can't load file before kernel"; 410 return(NULL); 411 } 412 413 /* locate the file on the load path */ 414 name = file_search(fname, NULL); 415 if (name == NULL) { 416 sprintf(command_errbuf, "can't find '%s'", fname); 417 return(NULL); 418 } 419 420 if ((fd = open(name, O_RDONLY)) < 0) { 421 sprintf(command_errbuf, "can't open '%s': %s", name, strerror(errno)); 422 free(name); 423 return(NULL); 424 } 425 426 if (archsw.arch_loadaddr != NULL) 427 loadaddr = archsw.arch_loadaddr(LOAD_RAW, name, loadaddr); 428 429 printf("%s ", name); 430 431 laddr = loadaddr; 432 for (;;) { 433 /* read in 4k chunks; size is not really important */ 434 got = archsw.arch_readin(fd, laddr, 4096); 435 if (got == 0) /* end of file */ 436 break; 437 if (got < 0) { /* error */ 438 sprintf(command_errbuf, "error reading '%s': %s", name, strerror(errno)); 439 free(name); 440 close(fd); 441 return(NULL); 442 } 443 laddr += got; 444 } 445 446 printf("size=%#jx\n", (uintmax_t)(laddr - loadaddr)); 447 448 /* Looks OK so far; create & populate control structure */ 449 fp = file_alloc(); 450 fp->f_name = strdup(name); 451 fp->f_type = strdup(type); 452 fp->f_args = NULL; 453 fp->f_metadata = NULL; 454 fp->f_loader = -1; 455 fp->f_addr = loadaddr; 456 fp->f_size = laddr - loadaddr; 457 458 /* recognise space consumption */ 459 loadaddr = laddr; 460 461 /* Add to the list of loaded files */ 462 if (insert != 0) 463 file_insert_tail(fp); 464 close(fd); 465 return(fp); 466} 467 468/* 469 * Load the module (name), pass it (argc),(argv), add container file 470 * to the list of loaded files. 471 * If module is already loaded just assign new argc/argv. 472 */ 473int 474mod_load(char *modname, struct mod_depend *verinfo, int argc, char *argv[]) 475{ 476 struct kernel_module *mp; 477 int err; 478 char *filename; 479 480 if (file_havepath(modname)) { 481 printf("Warning: mod_load() called instead of mod_loadkld() for module '%s'\n", modname); 482 return (mod_loadkld(modname, argc, argv)); 483 } 484 /* see if module is already loaded */ 485 mp = file_findmodule(NULL, modname, verinfo); 486 if (mp) { 487#ifdef moduleargs 488 if (mp->m_args) 489 free(mp->m_args); 490 mp->m_args = unargv(argc, argv); 491#endif 492 sprintf(command_errbuf, "warning: module '%s' already loaded", mp->m_name); 493 return (0); 494 } 495 /* locate file with the module on the search path */ 496 filename = mod_searchmodule(modname, verinfo); 497 if (filename == NULL) { 498 sprintf(command_errbuf, "can't find '%s'", modname); 499 return (ENOENT); 500 } 501 err = mod_loadkld(filename, argc, argv); 502 return (err); 503} 504 505/* 506 * Load specified KLD. If path is omitted, then try to locate it via 507 * search path. 508 */ 509int 510mod_loadkld(const char *kldname, int argc, char *argv[]) 511{ 512 struct preloaded_file *fp, *last_file; 513 int err; 514 char *filename; 515 516 /* 517 * Get fully qualified KLD name 518 */ 519 filename = file_search(kldname, kld_ext_list); 520 if (filename == NULL) { 521 sprintf(command_errbuf, "can't find '%s'", kldname); 522 return (ENOENT); 523 } 524 /* 525 * Check if KLD already loaded 526 */ 527 fp = file_findfile(filename, NULL); 528 if (fp) { 529 sprintf(command_errbuf, "warning: KLD '%s' already loaded", filename); 530 free(filename); 531 return (0); 532 } 533 for (last_file = preloaded_files; 534 last_file != NULL && last_file->f_next != NULL; 535 last_file = last_file->f_next) 536 ; 537 538 do { 539 err = file_load(filename, loadaddr, &fp); 540 if (err) 541 break; 542 fp->f_args = unargv(argc, argv); 543 loadaddr = fp->f_addr + fp->f_size; 544 file_insert_tail(fp); /* Add to the list of loaded files */ 545 if (file_load_dependencies(fp) != 0) { 546 err = ENOENT; 547 last_file->f_next = NULL; 548 loadaddr = last_file->f_addr + last_file->f_size; 549 fp = NULL; 550 break; 551 } 552 } while(0); 553 if (err == EFTYPE) 554 sprintf(command_errbuf, "don't know how to load module '%s'", filename); 555 if (err && fp) 556 file_discard(fp); 557 free(filename); 558 return (err); 559} 560 561/* 562 * Find a file matching (name) and (type). 563 * NULL may be passed as a wildcard to either. 564 */ 565struct preloaded_file * 566file_findfile(const char *name, const char *type) 567{ 568 struct preloaded_file *fp; 569 570 for (fp = preloaded_files; fp != NULL; fp = fp->f_next) { 571 if (((name == NULL) || !strcmp(name, fp->f_name)) && 572 ((type == NULL) || !strcmp(type, fp->f_type))) 573 break; 574 } 575 return (fp); 576} 577 578/* 579 * Find a module matching (name) inside of given file. 580 * NULL may be passed as a wildcard. 581 */ 582struct kernel_module * 583file_findmodule(struct preloaded_file *fp, char *modname, 584 struct mod_depend *verinfo) 585{ 586 struct kernel_module *mp, *best; 587 int bestver, mver; 588 589 if (fp == NULL) { 590 for (fp = preloaded_files; fp; fp = fp->f_next) { 591 mp = file_findmodule(fp, modname, verinfo); 592 if (mp) 593 return (mp); 594 } 595 return (NULL); 596 } 597 best = NULL; 598 bestver = 0; 599 for (mp = fp->f_modules; mp; mp = mp->m_next) { 600 if (strcmp(modname, mp->m_name) == 0) { 601 if (verinfo == NULL) 602 return (mp); 603 mver = mp->m_version; 604 if (mver == verinfo->md_ver_preferred) 605 return (mp); 606 if (mver >= verinfo->md_ver_minimum && 607 mver <= verinfo->md_ver_maximum && 608 mver > bestver) { 609 best = mp; 610 bestver = mver; 611 } 612 } 613 } 614 return (best); 615} 616/* 617 * Make a copy of (size) bytes of data from (p), and associate them as 618 * metadata of (type) to the module (mp). 619 */ 620void 621file_addmetadata(struct preloaded_file *fp, int type, size_t size, void *p) 622{ 623 struct file_metadata *md; 624 625 md = malloc(sizeof(struct file_metadata) - sizeof(md->md_data) + size); 626 md->md_size = size; 627 md->md_type = type; 628 bcopy(p, md->md_data, size); 629 md->md_next = fp->f_metadata; 630 fp->f_metadata = md; 631} 632 633/* 634 * Find a metadata object of (type) associated with the file (fp) 635 */ 636struct file_metadata * 637file_findmetadata(struct preloaded_file *fp, int type) 638{ 639 struct file_metadata *md; 640 641 for (md = fp->f_metadata; md != NULL; md = md->md_next) 642 if (md->md_type == type) 643 break; 644 return(md); 645} 646 647/* 648 * Remove all metadata from the file. 649 */ 650void 651file_removemetadata(struct preloaded_file *fp) 652{ 653 struct file_metadata *md, *next; 654 655 for (md = fp->f_metadata; md != NULL; md = next) 656 { 657 next = md->md_next; 658 free(md); 659 } 660 fp->f_metadata = NULL; 661} 662 663struct file_metadata * 664metadata_next(struct file_metadata *md, int type) 665{ 666 if (md == NULL) 667 return (NULL); 668 while((md = md->md_next) != NULL) 669 if (md->md_type == type) 670 break; 671 return (md); 672} 673 674static char *emptyextlist[] = { "", NULL }; 675 676/* 677 * Check if the given file is in place and return full path to it. 678 */ 679static char * 680file_lookup(const char *path, const char *name, int namelen, char **extlist) 681{ 682 struct stat st; 683 char *result, *cp, **cpp; 684 int pathlen, extlen, len; 685 686 pathlen = strlen(path); 687 extlen = 0; 688 if (extlist == NULL) 689 extlist = emptyextlist; 690 for (cpp = extlist; *cpp; cpp++) { 691 len = strlen(*cpp); 692 if (len > extlen) 693 extlen = len; 694 } 695 result = malloc(pathlen + namelen + extlen + 2); 696 if (result == NULL) 697 return (NULL); 698 bcopy(path, result, pathlen); 699 if (pathlen > 0 && result[pathlen - 1] != '/') 700 result[pathlen++] = '/'; 701 cp = result + pathlen; 702 bcopy(name, cp, namelen); 703 cp += namelen; 704 for (cpp = extlist; *cpp; cpp++) { 705 strcpy(cp, *cpp); 706 if (stat(result, &st) == 0 && S_ISREG(st.st_mode)) 707 return result; 708 } 709 free(result); 710 return NULL; 711} 712 713/* 714 * Check if file name have any qualifiers 715 */ 716static int 717file_havepath(const char *name) 718{ 719 const char *cp; 720 721 archsw.arch_getdev(NULL, name, &cp); 722 return (cp != name || strchr(name, '/') != NULL); 723} 724 725/* 726 * Attempt to find the file (name) on the module searchpath. 727 * If (name) is qualified in any way, we simply check it and 728 * return it or NULL. If it is not qualified, then we attempt 729 * to construct a path using entries in the environment variable 730 * module_path. 731 * 732 * The path we return a pointer to need never be freed, as we manage 733 * it internally. 734 */ 735static char * 736file_search(const char *name, char **extlist) 737{ 738 struct moduledir *mdp; 739 struct stat sb; 740 char *result; 741 int namelen; 742 743 /* Don't look for nothing */ 744 if (name == NULL) 745 return(NULL); 746 747 if (*name == 0) 748 return(strdup(name)); 749 750 if (file_havepath(name)) { 751 /* Qualified, so just see if it exists */ 752 if (stat(name, &sb) == 0) 753 return(strdup(name)); 754 return(NULL); 755 } 756 moduledir_rebuild(); 757 result = NULL; 758 namelen = strlen(name); 759 STAILQ_FOREACH(mdp, &moduledir_list, d_link) { 760 result = file_lookup(mdp->d_path, name, namelen, extlist); 761 if (result) 762 break; 763 } 764 return(result); 765} 766 767#define INT_ALIGN(base, ptr) ptr = \ 768 (base) + roundup2((ptr) - (base), sizeof(int)) 769 770static char * 771mod_search_hints(struct moduledir *mdp, const char *modname, 772 struct mod_depend *verinfo) 773{ 774 u_char *cp, *recptr, *bufend, *best; 775 char *result; 776 int *intp, bestver, blen, clen, found, ival, modnamelen, reclen; 777 778 moduledir_readhints(mdp); 779 modnamelen = strlen(modname); 780 found = 0; 781 result = NULL; 782 bestver = 0; 783 if (mdp->d_hints == NULL) 784 goto bad; 785 recptr = mdp->d_hints; 786 bufend = recptr + mdp->d_hintsz; 787 clen = blen = 0; 788 best = cp = NULL; 789 while (recptr < bufend && !found) { 790 intp = (int*)recptr; 791 reclen = *intp++; 792 ival = *intp++; 793 cp = (u_char*)intp; 794 switch (ival) { 795 case MDT_VERSION: 796 clen = *cp++; 797 if (clen != modnamelen || bcmp(cp, modname, clen) != 0) 798 break; 799 cp += clen; 800 INT_ALIGN(mdp->d_hints, cp); 801 ival = *(int*)cp; 802 cp += sizeof(int); 803 clen = *cp++; 804 if (verinfo == NULL || ival == verinfo->md_ver_preferred) { 805 found = 1; 806 break; 807 } 808 if (ival >= verinfo->md_ver_minimum && 809 ival <= verinfo->md_ver_maximum && 810 ival > bestver) { 811 bestver = ival; 812 best = cp; 813 blen = clen; 814 } 815 break; 816 default: 817 break; 818 } 819 recptr += reclen + sizeof(int); 820 } 821 /* 822 * Finally check if KLD is in the place 823 */ 824 if (found) 825 result = file_lookup(mdp->d_path, (const char *)cp, clen, NULL); 826 else if (best) 827 result = file_lookup(mdp->d_path, (const char *)best, blen, NULL); 828bad: 829 /* 830 * If nothing found or hints is absent - fallback to the old way 831 * by using "kldname[.ko]" as module name. 832 */ 833 if (!found && !bestver && result == NULL) 834 result = file_lookup(mdp->d_path, modname, modnamelen, kld_ext_list); 835 return result; 836} 837 838/* 839 * Attempt to locate the file containing the module (name) 840 */ 841static char * 842mod_searchmodule(char *name, struct mod_depend *verinfo) 843{ 844 struct moduledir *mdp; 845 char *result; 846 847 moduledir_rebuild(); 848 /* 849 * Now we ready to lookup module in the given directories 850 */ 851 result = NULL; 852 STAILQ_FOREACH(mdp, &moduledir_list, d_link) { 853 result = mod_search_hints(mdp, name, verinfo); 854 if (result) 855 break; 856 } 857 858 return(result); 859} 860 861int 862file_addmodule(struct preloaded_file *fp, char *modname, int version, 863 struct kernel_module **newmp) 864{ 865 struct kernel_module *mp; 866 struct mod_depend mdepend; 867 868 bzero(&mdepend, sizeof(mdepend)); 869 mdepend.md_ver_preferred = version; 870 mp = file_findmodule(fp, modname, &mdepend); 871 if (mp) 872 return (EEXIST); 873 mp = malloc(sizeof(struct kernel_module)); 874 if (mp == NULL) 875 return (ENOMEM); 876 bzero(mp, sizeof(struct kernel_module)); 877 mp->m_name = strdup(modname); 878 mp->m_version = version; 879 mp->m_fp = fp; 880 mp->m_next = fp->f_modules; 881 fp->f_modules = mp; 882 if (newmp) 883 *newmp = mp; 884 return (0); 885} 886 887/* 888 * Throw a file away 889 */ 890void 891file_discard(struct preloaded_file *fp) 892{ 893 struct file_metadata *md, *md1; 894 struct kernel_module *mp, *mp1; 895 if (fp == NULL) 896 return; 897 md = fp->f_metadata; 898 while (md) { 899 md1 = md; 900 md = md->md_next; 901 free(md1); 902 } 903 mp = fp->f_modules; 904 while (mp) { 905 if (mp->m_name) 906 free(mp->m_name); 907 mp1 = mp; 908 mp = mp->m_next; 909 free(mp1); 910 } 911 if (fp->f_name != NULL) 912 free(fp->f_name); 913 if (fp->f_type != NULL) 914 free(fp->f_type); 915 if (fp->f_args != NULL) 916 free(fp->f_args); 917 free(fp); 918} 919 920/* 921 * Allocate a new file; must be used instead of malloc() 922 * to ensure safe initialisation. 923 */ 924struct preloaded_file * 925file_alloc(void) 926{ 927 struct preloaded_file *fp; 928 929 if ((fp = malloc(sizeof(struct preloaded_file))) != NULL) { 930 bzero(fp, sizeof(struct preloaded_file)); 931 } 932 return (fp); 933} 934 935/* 936 * Add a module to the chain 937 */ 938static void 939file_insert_tail(struct preloaded_file *fp) 940{ 941 struct preloaded_file *cm; 942 943 /* Append to list of loaded file */ 944 fp->f_next = NULL; 945 if (preloaded_files == NULL) { 946 preloaded_files = fp; 947 } else { 948 for (cm = preloaded_files; cm->f_next != NULL; cm = cm->f_next) 949 ; 950 cm->f_next = fp; 951 } 952} 953 954static char * 955moduledir_fullpath(struct moduledir *mdp, const char *fname) 956{ 957 char *cp; 958 959 cp = malloc(strlen(mdp->d_path) + strlen(fname) + 2); 960 if (cp == NULL) 961 return NULL; 962 strcpy(cp, mdp->d_path); 963 strcat(cp, "/"); 964 strcat(cp, fname); 965 return (cp); 966} 967 968/* 969 * Read linker.hints file into memory performing some sanity checks. 970 */ 971static void 972moduledir_readhints(struct moduledir *mdp) 973{ 974 struct stat st; 975 char *path; 976 int fd, size, version; 977 978 if (mdp->d_hints != NULL || (mdp->d_flags & MDIR_NOHINTS)) 979 return; 980 path = moduledir_fullpath(mdp, "linker.hints"); 981 if (stat(path, &st) != 0 || 982 st.st_size < (ssize_t)(sizeof(version) + sizeof(int)) || 983 st.st_size > LINKER_HINTS_MAX || (fd = open(path, O_RDONLY)) < 0) { 984 free(path); 985 mdp->d_flags |= MDIR_NOHINTS; 986 return; 987 } 988 free(path); 989 size = read(fd, &version, sizeof(version)); 990 if (size != sizeof(version) || version != LINKER_HINTS_VERSION) 991 goto bad; 992 size = st.st_size - size; 993 mdp->d_hints = malloc(size); 994 if (mdp->d_hints == NULL) 995 goto bad; 996 if (read(fd, mdp->d_hints, size) != size) 997 goto bad; 998 mdp->d_hintsz = size; 999 close(fd); 1000 return; 1001bad: 1002 close(fd); 1003 if (mdp->d_hints) { 1004 free(mdp->d_hints); 1005 mdp->d_hints = NULL; 1006 } 1007 mdp->d_flags |= MDIR_NOHINTS; 1008 return; 1009} 1010 1011/* 1012 * Extract directories from the ';' separated list, remove duplicates. 1013 */ 1014static void 1015moduledir_rebuild(void) 1016{ 1017 struct moduledir *mdp, *mtmp; 1018 const char *path, *cp, *ep; 1019 size_t cplen; 1020 1021 path = getenv("module_path"); 1022 if (path == NULL) 1023 path = default_searchpath; 1024 /* 1025 * Rebuild list of module directories if it changed 1026 */ 1027 STAILQ_FOREACH(mdp, &moduledir_list, d_link) 1028 mdp->d_flags |= MDIR_REMOVED; 1029 1030 for (ep = path; *ep != 0; ep++) { 1031 cp = ep; 1032 for (; *ep != 0 && *ep != ';'; ep++) 1033 ; 1034 /* 1035 * Ignore trailing slashes 1036 */ 1037 for (cplen = ep - cp; cplen > 1 && cp[cplen - 1] == '/'; cplen--) 1038 ; 1039 STAILQ_FOREACH(mdp, &moduledir_list, d_link) { 1040 if (strlen(mdp->d_path) != cplen || bcmp(cp, mdp->d_path, cplen) != 0) 1041 continue; 1042 mdp->d_flags &= ~MDIR_REMOVED; 1043 break; 1044 } 1045 if (mdp == NULL) { 1046 mdp = malloc(sizeof(*mdp) + cplen + 1); 1047 if (mdp == NULL) 1048 return; 1049 mdp->d_path = (char*)(mdp + 1); 1050 bcopy(cp, mdp->d_path, cplen); 1051 mdp->d_path[cplen] = 0; 1052 mdp->d_hints = NULL; 1053 mdp->d_flags = 0; 1054 STAILQ_INSERT_TAIL(&moduledir_list, mdp, d_link); 1055 } 1056 if (*ep == 0) 1057 break; 1058 } 1059 /* 1060 * Delete unused directories if any 1061 */ 1062 mdp = STAILQ_FIRST(&moduledir_list); 1063 while (mdp) { 1064 if ((mdp->d_flags & MDIR_REMOVED) == 0) { 1065 mdp = STAILQ_NEXT(mdp, d_link); 1066 } else { 1067 if (mdp->d_hints) 1068 free(mdp->d_hints); 1069 mtmp = mdp; 1070 mdp = STAILQ_NEXT(mdp, d_link); 1071 STAILQ_REMOVE(&moduledir_list, mtmp, moduledir, d_link); 1072 free(mtmp); 1073 } 1074 } 1075 return; 1076} 1077