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