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