kern_linker.c revision 40906
1/*- 2 * Copyright (c) 1997 Doug Rabson 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 * $Id: kern_linker.c,v 1.13 1998/11/03 14:27:05 peter Exp $ 27 */ 28 29#include "opt_ddb.h" 30 31#include <sys/param.h> 32#include <sys/kernel.h> 33#include <sys/systm.h> 34#include <sys/malloc.h> 35#include <sys/sysproto.h> 36#include <sys/sysent.h> 37#include <sys/proc.h> 38#include <sys/lock.h> 39#include <machine/cpu.h> 40#include <machine/bootinfo.h> 41#include <sys/module.h> 42#include <sys/linker.h> 43#include <sys/unistd.h> 44#include <sys/fcntl.h> 45#include <sys/libkern.h> 46#include <sys/namei.h> 47#include <sys/vnode.h> 48#include <sys/sysctl.h> 49 50MALLOC_DEFINE(M_LINKER, "kld", "kernel linker"); 51linker_file_t linker_current_file; 52linker_file_t linker_kernel_file; 53 54static struct lock lock; /* lock for the file list */ 55static linker_class_list_t classes; 56static linker_file_list_t files; 57static int next_file_id = 1; 58 59static void 60linker_init(void* arg) 61{ 62 lockinit(&lock, PVM, "klink", 0, 0); 63 TAILQ_INIT(&classes); 64 TAILQ_INIT(&files); 65} 66 67SYSINIT(linker, SI_SUB_KLD, SI_ORDER_FIRST, linker_init, 0); 68 69int 70linker_add_class(const char* desc, void* priv, 71 struct linker_class_ops* ops) 72{ 73 linker_class_t lc; 74 75 lc = malloc(sizeof(struct linker_class), M_LINKER, M_NOWAIT); 76 if (!lc) 77 return ENOMEM; 78 bzero(lc, sizeof(*lc)); 79 80 lc->desc = desc; 81 lc->priv = priv; 82 lc->ops = ops; 83 TAILQ_INSERT_HEAD(&classes, lc, link); 84 85 return 0; 86} 87 88static void 89linker_file_sysinit(linker_file_t lf) 90{ 91 struct linker_set* sysinits; 92 struct sysinit** sipp; 93 struct sysinit** xipp; 94 struct sysinit* save; 95 moduledata_t *moddata; 96 97 KLD_DPF(FILE, ("linker_file_sysinit: calling SYSINITs for %s\n", 98 lf->filename)); 99 100 sysinits = (struct linker_set*) 101 linker_file_lookup_symbol(lf, "sysinit_set", 0); 102 103 KLD_DPF(FILE, ("linker_file_sysinit: SYSINITs %p\n", sysinits)); 104 if (!sysinits) 105 return; 106 107 /* HACK ALERT! */ 108 for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 109 if ((*sipp)->func == module_register_init) { 110 moddata = (*sipp)->udata; 111 moddata->_file = lf; 112 } 113 } 114 115 /* 116 * Perform a bubble sort of the system initialization objects by 117 * their subsystem (primary key) and order (secondary key). 118 * 119 * Since some things care about execution order, this is the 120 * operation which ensures continued function. 121 */ 122 for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 123 for( xipp = sipp + 1; *xipp; xipp++) { 124 if( (*sipp)->subsystem < (*xipp)->subsystem || 125 ( (*sipp)->subsystem == (*xipp)->subsystem && 126 (*sipp)->order < (*xipp)->order)) 127 continue; /* skip*/ 128 save = *sipp; 129 *sipp = *xipp; 130 *xipp = save; 131 } 132 } 133 134 135 /* 136 * Traverse the (now) ordered list of system initialization tasks. 137 * Perform each task, and continue on to the next task. 138 * 139 * The last item on the list is expected to be the scheduler, 140 * which will not return. 141 */ 142 for( sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 143 if( (*sipp)->subsystem == SI_SUB_DUMMY) 144 continue; /* skip dummy task(s)*/ 145 146 switch( (*sipp)->type) { 147 case SI_TYPE_DEFAULT: 148 /* no special processing*/ 149 (*((*sipp)->func))( (*sipp)->udata); 150 break; 151 152 case SI_TYPE_KTHREAD: 153#if !defined(SMP) 154 /* kernel thread*/ 155 if (fork1(&proc0, RFFDG|RFPROC|RFMEM)) 156 panic("fork kernel thread"); 157 cpu_set_fork_handler(pfind(proc0.p_retval[0]), 158 (*sipp)->func, (*sipp)->udata); 159 break; 160#endif 161 162 case SI_TYPE_KPROCESS: 163 /* kernel thread*/ 164 if (fork1(&proc0, RFFDG|RFPROC)) 165 panic("fork kernel process"); 166 cpu_set_fork_handler(pfind(proc0.p_retval[0]), 167 (*sipp)->func, (*sipp)->udata); 168 break; 169 170 default: 171 panic( "linker_file_sysinit: unrecognized init type"); 172 } 173 } 174} 175 176int 177linker_load_file(const char* filename, linker_file_t* result) 178{ 179 linker_class_t lc; 180 linker_file_t lf; 181 int error = 0; 182 char *koname = NULL; 183 184 lf = linker_find_file_by_name(filename); 185 if (lf) { 186 KLD_DPF(FILE, ("linker_load_file: file %s is already loaded, incrementing refs\n", filename)); 187 *result = lf; 188 lf->refs++; 189 goto out; 190 } 191 192 koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 193 if (koname == NULL) { 194 error = ENOMEM; 195 goto out; 196 } 197 sprintf(koname, "%s.ko", filename); 198 lf = NULL; 199 for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { 200 KLD_DPF(FILE, ("linker_load_file: trying to load %s as %s\n", 201 filename, lc->desc)); 202 error = lc->ops->load_file(koname, &lf); 203 if (lf == NULL && error && error != ENOENT) 204 goto out; 205 if (lf == NULL) 206 error = lc->ops->load_file(filename, &lf); 207 if (lf == NULL && error && error != ENOENT) 208 goto out; 209 if (lf) { 210 linker_file_sysinit(lf); 211 212 *result = lf; 213 error = 0; 214 goto out; 215 } 216 } 217 error = ENOEXEC; /* format not recognised */ 218 219out: 220 if (koname) 221 free(koname, M_LINKER); 222 return error; 223} 224 225linker_file_t 226linker_find_file_by_name(const char* filename) 227{ 228 linker_file_t lf = 0; 229 char *koname; 230 231 koname = malloc(strlen(filename) + 4, M_LINKER, M_WAITOK); 232 if (koname == NULL) 233 goto out; 234 sprintf(koname, "%s.ko", filename); 235 236 lockmgr(&lock, LK_SHARED, 0, curproc); 237 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 238 if (!strcmp(lf->filename, koname)) 239 break; 240 if (!strcmp(lf->filename, filename)) 241 break; 242 } 243 lockmgr(&lock, LK_RELEASE, 0, curproc); 244 245out: 246 if (koname) 247 free(koname, M_LINKER); 248 return lf; 249} 250 251linker_file_t 252linker_find_file_by_id(int fileid) 253{ 254 linker_file_t lf = 0; 255 256 lockmgr(&lock, LK_SHARED, 0, curproc); 257 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) 258 if (lf->id == fileid) 259 break; 260 lockmgr(&lock, LK_RELEASE, 0, curproc); 261 262 return lf; 263} 264 265linker_file_t 266linker_make_file(const char* pathname, void* priv, struct linker_file_ops* ops) 267{ 268 linker_file_t lf = 0; 269 int namelen; 270 const char *filename; 271 272 filename = rindex(pathname, '/'); 273 if (filename && filename[1]) 274 filename++; 275 else 276 filename = pathname; 277 278 KLD_DPF(FILE, ("linker_make_file: new file, filename=%s\n", filename)); 279 lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 280 namelen = strlen(filename) + 1; 281 lf = malloc(sizeof(struct linker_file) + namelen, M_LINKER, M_WAITOK); 282 if (!lf) 283 goto out; 284 bzero(lf, sizeof(*lf)); 285 286 lf->refs = 1; 287 lf->userrefs = 0; 288 lf->filename = (char*) (lf + 1); 289 strcpy(lf->filename, filename); 290 lf->id = next_file_id++; 291 lf->ndeps = 0; 292 lf->deps = NULL; 293 STAILQ_INIT(&lf->common); 294 TAILQ_INIT(&lf->modules); 295 296 lf->priv = priv; 297 lf->ops = ops; 298 TAILQ_INSERT_TAIL(&files, lf, link); 299 300out: 301 lockmgr(&lock, LK_RELEASE, 0, curproc); 302 return lf; 303} 304 305int 306linker_file_unload(linker_file_t file) 307{ 308 module_t mod, next; 309 struct common_symbol* cp; 310 int error = 0; 311 int i; 312 313 KLD_DPF(FILE, ("linker_file_unload: lf->refs=%d\n", file->refs)); 314 lockmgr(&lock, LK_EXCLUSIVE|LK_RETRY, 0, curproc); 315 if (file->refs == 1) { 316 KLD_DPF(FILE, ("linker_file_unload: file is unloading, informing modules\n")); 317 /* 318 * Inform any modules associated with this file. 319 */ 320 for (mod = TAILQ_FIRST(&file->modules); mod; mod = next) { 321 next = module_getfnext(mod); 322 323 /* 324 * Give the module a chance to veto the unload. 325 */ 326 if (error = module_unload(mod)) { 327 KLD_DPF(FILE, ("linker_file_unload: module %x vetoes unload\n", 328 mod)); 329 lockmgr(&lock, LK_RELEASE, 0, curproc); 330 goto out; 331 } 332 333 module_release(mod); 334 } 335 } 336 337 file->refs--; 338 if (file->refs > 0) { 339 lockmgr(&lock, LK_RELEASE, 0, curproc); 340 goto out; 341 } 342 343 TAILQ_REMOVE(&files, file, link); 344 lockmgr(&lock, LK_RELEASE, 0, curproc); 345 346 for (i = 0; i < file->ndeps; i++) 347 linker_file_unload(file->deps[i]); 348 free(file->deps, M_LINKER); 349 350 for (cp = STAILQ_FIRST(&file->common); cp; 351 cp = STAILQ_FIRST(&file->common)) { 352 STAILQ_REMOVE(&file->common, cp, common_symbol, link); 353 free(cp, M_LINKER); 354 } 355 356 file->ops->unload(file); 357 free(file, M_LINKER); 358 359out: 360 return error; 361} 362 363int 364linker_file_add_dependancy(linker_file_t file, linker_file_t dep) 365{ 366 linker_file_t* newdeps; 367 368 newdeps = malloc((file->ndeps + 1) * sizeof(linker_file_t*), 369 M_LINKER, M_WAITOK); 370 if (newdeps == NULL) 371 return ENOMEM; 372 bzero(newdeps, (file->ndeps + 1) * sizeof(linker_file_t*)); 373 374 if (file->deps) { 375 bcopy(file->deps, newdeps, file->ndeps * sizeof(linker_file_t*)); 376 free(file->deps, M_LINKER); 377 } 378 file->deps = newdeps; 379 file->deps[file->ndeps] = dep; 380 file->ndeps++; 381 382 return 0; 383} 384 385caddr_t 386linker_file_lookup_symbol(linker_file_t file, const char* name, int deps) 387{ 388 linker_sym_t sym; 389 linker_symval_t symval; 390 caddr_t address; 391 size_t common_size = 0; 392 int i; 393 394 KLD_DPF(SYM, ("linker_file_lookup_symbol: file=%x, name=%s, deps=%d\n", 395 file, name, deps)); 396 397 if (file->ops->lookup_symbol(file, name, &sym) == 0) { 398 file->ops->symbol_values(file, sym, &symval); 399 if (symval.value == 0) 400 /* 401 * For commons, first look them up in the dependancies and 402 * only allocate space if not found there. 403 */ 404 common_size = symval.size; 405 else { 406 KLD_DPF(SYM, ("linker_file_lookup_symbol: symbol.value=%x\n", symval.value)); 407 return symval.value; 408 } 409 } 410 411 if (deps) 412 for (i = 0; i < file->ndeps; i++) { 413 address = linker_file_lookup_symbol(file->deps[i], name, 0); 414 if (address) { 415 KLD_DPF(SYM, ("linker_file_lookup_symbol: deps value=%x\n", address)); 416 return address; 417 } 418 } 419 420 if (common_size > 0) { 421 /* 422 * This is a common symbol which was not found in the 423 * dependancies. We maintain a simple common symbol table in 424 * the file object. 425 */ 426 struct common_symbol* cp; 427 428 for (cp = STAILQ_FIRST(&file->common); cp; 429 cp = STAILQ_NEXT(cp, link)) 430 if (!strcmp(cp->name, name)) { 431 KLD_DPF(SYM, ("linker_file_lookup_symbol: old common value=%x\n", cp->address)); 432 return cp->address; 433 } 434 435 /* 436 * Round the symbol size up to align. 437 */ 438 common_size = (common_size + sizeof(int) - 1) & -sizeof(int); 439 cp = malloc(sizeof(struct common_symbol) 440 + common_size 441 + strlen(name) + 1, 442 M_LINKER, M_WAITOK); 443 if (!cp) { 444 KLD_DPF(SYM, ("linker_file_lookup_symbol: nomem\n")); 445 return 0; 446 } 447 bzero(cp, sizeof(struct common_symbol) + common_size + strlen(name)+ 1); 448 449 cp->address = (caddr_t) (cp + 1); 450 cp->name = cp->address + common_size; 451 strcpy(cp->name, name); 452 bzero(cp->address, common_size); 453 STAILQ_INSERT_TAIL(&file->common, cp, link); 454 455 KLD_DPF(SYM, ("linker_file_lookup_symbol: new common value=%x\n", cp->address)); 456 return cp->address; 457 } 458 459 KLD_DPF(SYM, ("linker_file_lookup_symbol: fail\n")); 460 return 0; 461} 462 463#ifdef DDB 464/* 465 * DDB Helpers. DDB has to look across multiple files with their own 466 * symbol tables and string tables. 467 * 468 * Note that we do not obey list locking protocols here. We really don't 469 * need DDB to hang because somebody's got the lock held. We'll take the 470 * chance that the files list is inconsistant instead. 471 */ 472 473int 474linker_ddb_lookup(char *symstr, linker_sym_t *sym) 475{ 476 linker_file_t lf; 477 478 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 479 if (lf->ops->lookup_symbol(lf, symstr, sym) == 0) 480 return 0; 481 } 482 return ENOENT; 483} 484 485int 486linker_ddb_search_symbol(caddr_t value, linker_sym_t *sym, long *diffp) 487{ 488 linker_file_t lf; 489 u_long off = (u_long)value; 490 u_long diff, bestdiff; 491 linker_sym_t best; 492 linker_sym_t es; 493 494 best = 0; 495 bestdiff = off; 496 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 497 if (lf->ops->search_symbol(lf, value, &es, &diff) != 0) 498 continue; 499 if (es != 0 && diff < bestdiff) { 500 best = es; 501 bestdiff = diff; 502 } 503 if (bestdiff == 0) 504 break; 505 } 506 if (best) { 507 *sym = best; 508 *diffp = bestdiff; 509 return 0; 510 } else { 511 *sym = 0; 512 *diffp = off; 513 return ENOENT; 514 } 515} 516 517int 518linker_ddb_symbol_values(linker_sym_t sym, linker_symval_t *symval) 519{ 520 linker_file_t lf; 521 522 for (lf = TAILQ_FIRST(&files); lf; lf = TAILQ_NEXT(lf, link)) { 523 if (lf->ops->symbol_values(lf, sym, symval) == 0) 524 return 0; 525 } 526 return ENOENT; 527} 528 529#endif 530 531/* 532 * Syscalls. 533 */ 534 535int 536kldload(struct proc* p, struct kldload_args* uap) 537{ 538 char* filename = NULL; 539 linker_file_t lf; 540 int error = 0; 541 542 p->p_retval[0] = -1; 543 544 if (securelevel > 0) 545 return EPERM; 546 547 if (error = suser(p->p_ucred, &p->p_acflag)) 548 return error; 549 550 filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 551 if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 552 goto out; 553 554 if (error = linker_load_file(filename, &lf)) 555 goto out; 556 557 lf->userrefs++; 558 p->p_retval[0] = lf->id; 559 560out: 561 if (filename) 562 free(filename, M_TEMP); 563 return error; 564} 565 566int 567kldunload(struct proc* p, struct kldunload_args* uap) 568{ 569 linker_file_t lf; 570 int error = 0; 571 572 if (securelevel > 0) 573 return EPERM; 574 575 if (error = suser(p->p_ucred, &p->p_acflag)) 576 return error; 577 578 lf = linker_find_file_by_id(SCARG(uap, fileid)); 579 if (lf) { 580 KLD_DPF(FILE, ("kldunload: lf->userrefs=%d\n", lf->userrefs)); 581 if (lf->userrefs == 0) { 582 printf("linkerunload: attempt to unload file which was not loaded by user\n"); 583 error = EBUSY; 584 goto out; 585 } 586 lf->userrefs--; 587 error = linker_file_unload(lf); 588 } else 589 error = ENOENT; 590 591out: 592 return error; 593} 594 595int 596kldfind(struct proc* p, struct kldfind_args* uap) 597{ 598 char* filename = NULL; 599 linker_file_t lf; 600 int error = 0; 601 602 p->p_retval[0] = -1; 603 604 filename = malloc(MAXPATHLEN, M_TEMP, M_WAITOK); 605 if (error = copyinstr(SCARG(uap, file), filename, MAXPATHLEN, NULL)) 606 goto out; 607 608 lf = linker_find_file_by_name(filename); 609 if (lf) 610 p->p_retval[0] = lf->id; 611 else 612 error = ENOENT; 613 614out: 615 if (filename) 616 free(filename, M_TEMP); 617 return error; 618} 619 620int 621kldnext(struct proc* p, struct kldnext_args* uap) 622{ 623 linker_file_t lf; 624 int error = 0; 625 626 if (SCARG(uap, fileid) == 0) { 627 if (TAILQ_FIRST(&files)) 628 p->p_retval[0] = TAILQ_FIRST(&files)->id; 629 else 630 p->p_retval[0] = 0; 631 return 0; 632 } 633 634 lf = linker_find_file_by_id(SCARG(uap, fileid)); 635 if (lf) { 636 if (TAILQ_NEXT(lf, link)) 637 p->p_retval[0] = TAILQ_NEXT(lf, link)->id; 638 else 639 p->p_retval[0] = 0; 640 } else 641 error = ENOENT; 642 643 return error; 644} 645 646int 647kldstat(struct proc* p, struct kldstat_args* uap) 648{ 649 linker_file_t lf; 650 int error = 0; 651 int version; 652 struct kld_file_stat* stat; 653 int namelen; 654 655 lf = linker_find_file_by_id(SCARG(uap, fileid)); 656 if (!lf) { 657 error = ENOENT; 658 goto out; 659 } 660 661 stat = SCARG(uap, stat); 662 663 /* 664 * Check the version of the user's structure. 665 */ 666 if (error = copyin(&stat->version, &version, sizeof(version))) 667 goto out; 668 if (version != sizeof(struct kld_file_stat)) { 669 error = EINVAL; 670 goto out; 671 } 672 673 namelen = strlen(lf->filename) + 1; 674 if (namelen > MAXPATHLEN) 675 namelen = MAXPATHLEN; 676 if (error = copyout(lf->filename, &stat->name[0], namelen)) 677 goto out; 678 if (error = copyout(&lf->refs, &stat->refs, sizeof(int))) 679 goto out; 680 if (error = copyout(&lf->id, &stat->id, sizeof(int))) 681 goto out; 682 if (error = copyout(&lf->address, &stat->address, sizeof(caddr_t))) 683 goto out; 684 if (error = copyout(&lf->size, &stat->size, sizeof(size_t))) 685 goto out; 686 687 p->p_retval[0] = 0; 688 689out: 690 return error; 691} 692 693int 694kldfirstmod(struct proc* p, struct kldfirstmod_args* uap) 695{ 696 linker_file_t lf; 697 int error = 0; 698 699 lf = linker_find_file_by_id(SCARG(uap, fileid)); 700 if (lf) { 701 if (TAILQ_FIRST(&lf->modules)) 702 p->p_retval[0] = module_getid(TAILQ_FIRST(&lf->modules)); 703 else 704 p->p_retval[0] = 0; 705 } else 706 error = ENOENT; 707 708 return error; 709} 710 711/* 712 * Preloaded module support 713 */ 714 715static void 716linker_preload(void* arg) 717{ 718 caddr_t modptr; 719 char *modname; 720 char *modtype; 721 linker_file_t lf; 722 linker_class_t lc; 723 int error; 724 struct linker_set *sysinits; 725 struct sysinit **sipp; 726 moduledata_t *moddata; 727 728 modptr = NULL; 729 while ((modptr = preload_search_next_name(modptr)) != NULL) { 730 modname = (char *)preload_search_info(modptr, MODINFO_NAME); 731 modtype = (char *)preload_search_info(modptr, MODINFO_TYPE); 732 if (modname == NULL) { 733 printf("Preloaded module at %p does not have a name!\n", modptr); 734 continue; 735 } 736 if (modtype == NULL) { 737 printf("Preloaded module at %p does not have a type!\n", modptr); 738 continue; 739 } 740 printf("Preloaded %s \"%s\" at %p.\n", modtype, modname, modptr); 741 lf = linker_find_file_by_name(modname); 742 if (lf) { 743 lf->userrefs++; 744 continue; 745 } 746 lf = NULL; 747 for (lc = TAILQ_FIRST(&classes); lc; lc = TAILQ_NEXT(lc, link)) { 748 error = lc->ops->load_file(modname, &lf); 749 if (error) { 750 lf = NULL; 751 break; 752 } 753 } 754 if (lf) { 755 lf->userrefs++; 756 757 sysinits = (struct linker_set*) 758 linker_file_lookup_symbol(lf, "sysinit_set", 0); 759 if (sysinits) { 760 /* HACK ALERT! 761 * This is to set the sysinit moduledata so that the module 762 * can attach itself to the correct containing file. 763 * The sysinit could be run at *any* time. 764 */ 765 for (sipp = (struct sysinit **)sysinits->ls_items; *sipp; sipp++) { 766 if ((*sipp)->func == module_register_init) { 767 moddata = (*sipp)->udata; 768 moddata->_file = lf; 769 } 770 } 771 sysinit_add((struct sysinit **)sysinits->ls_items); 772 } 773 } 774 } 775} 776 777SYSINIT(preload, SI_SUB_KLD, SI_ORDER_MIDDLE, linker_preload, 0); 778 779/* 780 * Search for a not-loaded module by name. 781 * 782 * Modules may be found in the following locations: 783 * 784 * - preloaded (result is just the module name) 785 * - on disk (result is full path to module) 786 * 787 * If the module name is qualified in any way (contains path, etc.) 788 * the we simply return a copy of it. 789 * 790 * The search path can be manipulated via sysctl. Note that we use the ';' 791 * character as a separator to be consistent with the bootloader. 792 */ 793 794static char linker_path[MAXPATHLEN + 1] = "/;/boot/;/modules/"; 795 796SYSCTL_STRING(_kern, OID_AUTO, module_path, CTLFLAG_RW, linker_path, 797 sizeof(linker_path), "module load search path"); 798 799static char * 800linker_strdup(const char *str) 801{ 802 char *result; 803 804 if ((result = malloc((strlen(str) + 1), M_LINKER, M_WAITOK)) != NULL) 805 strcpy(result, str); 806 return(result); 807} 808 809char * 810linker_search_path(const char *name) 811{ 812 struct nameidata nd; 813 struct proc *p = curproc; /* XXX */ 814 char *cp, *ep, *result; 815 int error; 816 enum vtype type; 817 818 /* qualified at all? */ 819 if (index(name, '/')) 820 return(linker_strdup(name)); 821 822 /* traverse the linker path */ 823 cp = linker_path; 824 for (;;) { 825 826 /* find the end of this component */ 827 for (ep = cp; (*ep != 0) && (*ep != ';'); ep++) 828 ; 829 result = malloc((strlen(name) + (ep - cp) + 1), M_LINKER, M_WAITOK); 830 if (result == NULL) /* actually ENOMEM */ 831 return(NULL); 832 833 strncpy(result, cp, ep - cp); 834 strcpy(result + (ep - cp), name); 835 836 /* 837 * Attempt to open the file, and return the path if we succeed and it's 838 * a regular file. 839 */ 840 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, result, p); 841 error = vn_open(&nd, FREAD, 0); 842 if (error == 0) { 843 type = nd.ni_vp->v_type; 844 VOP_UNLOCK(nd.ni_vp, 0, p); 845 vn_close(nd.ni_vp, FREAD, p->p_ucred, p); 846 if (type == VREG) 847 return(result); 848 } 849 free(result, M_LINKER); 850 851 if (*ep == 0) 852 break; 853 cp = ep + 1; 854 } 855 return(NULL); 856} 857