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