1 /* 2 * Copyright 2002-2009, Haiku Inc. All Rights Reserved. 3 * Distributed under the terms of the MIT license. 4 * 5 * Authors: 6 * Ingo Weinhold, bonefish@cs.tu-berlin.de. 7 * Axel Dörfler, axeld@pinc-software.de. 8 */ 9 10 #include <set> 11 #include <stdio.h> 12 #include <string> 13 14 #include <Autolock.h> 15 #include <Directory.h> 16 #include <Entry.h> 17 #include <KernelExport.h> 18 #include <module.h> 19 #include <List.h> 20 #include <Locker.h> 21 #include <ObjectList.h> 22 #include <Path.h> 23 #include <String.h> 24 25 #ifdef TRACE 26 # undef TRACE 27 #endif 28 #define TRACE(x) 29 //#define TRACE(x) printf x 30 31 32 static const char *gModuleDirs[] = { 33 "generated/objects/haiku/x86/release/add-ons/userland", 34 "generated/objects/haiku/x86/release/tests/add-ons/kernel", 35 NULL 36 }; 37 38 39 struct module_name_list { 40 set<string> names; 41 set<string>::iterator it; 42 }; 43 44 45 // ModuleAddOn 46 47 class ModuleAddOn { 48 public: 49 ModuleAddOn(); 50 ~ModuleAddOn(); 51 52 status_t Load(const char *path, const char *dirPath); 53 void Unload(); 54 55 const char *Name() { return fName.String(); } 56 57 status_t Get(); 58 bool Put(); 59 60 module_info **ModuleInfos() const { return fInfos; } 61 module_info *FindModuleInfo(const char *name) const; 62 63 private: 64 image_id fAddOn; 65 module_info **fInfos; 66 int32 fReferenceCount; 67 BString fName; 68 }; 69 70 class Module { 71 public: 72 Module(ModuleAddOn *addon, module_info *info); 73 ~Module(); 74 75 status_t Init(); 76 status_t Uninit(); 77 78 status_t Get(); 79 bool Put(); 80 81 ModuleAddOn *AddOn() const { return fAddOn; } 82 module_info *Info() const { return fInfo; } 83 84 private: 85 ModuleAddOn *fAddOn; 86 module_info *fInfo; 87 int32 fReferenceCount; 88 bool fInitialized; 89 }; 90 91 class ModuleList : public BLocker { 92 public: 93 ModuleList(); 94 ~ModuleList(); 95 96 int32 CountModules() const; 97 Module *ModuleAt(int32 index) const; 98 99 bool AddModule(Module *module); 100 bool RemoveModule(Module *module); 101 Module *FindModule(const char *path); 102 103 private: 104 BList fModules; 105 }; 106 107 class ModuleManager { 108 public: 109 ModuleManager(); 110 ~ModuleManager(); 111 112 static ModuleManager *Default() { return &sDefaultManager; } 113 114 status_t GetModule(const char *path, module_info **infop); 115 status_t PutModule(const char *path); 116 117 status_t GetNextLoadedModuleName(uint32 *cookie, char *buffer, 118 size_t *bufferSize); 119 120 module_name_list *OpenModuleList(const char *prefix, 121 const char *suffix = NULL); 122 status_t ReadNextModuleName(module_name_list *list, char *buffer, 123 size_t *bufferSize); 124 status_t CloseModuleList(module_name_list *list); 125 126 status_t AddBuiltInModule(module_info *info); 127 128 status_t GetDependencies(image_id image); 129 void PutDependencies(image_id image); 130 131 private: 132 bool _MatchSuffix(const char *name, const char *suffix); 133 void _FindModules(BDirectory &dir, const char *moduleDir, 134 const char *suffix, module_name_list *list); 135 void _FindBuiltInModules(const char *prefix, const char *suffix, 136 module_name_list *list); 137 138 status_t _GetAddOn(const char *path, ModuleAddOn **addon); 139 void _PutAddOn(ModuleAddOn *addon); 140 141 private: 142 static ModuleManager sDefaultManager; 143 ModuleList fModules; 144 BObjectList<ModuleAddOn> fAddOns; 145 }; 146 147 148 // #pragma mark - ModuleAddOn 149 150 151 ModuleAddOn::ModuleAddOn() 152 : fAddOn(-1), 153 fInfos(NULL), 154 fReferenceCount(0) 155 { 156 } 157 158 159 ModuleAddOn::~ModuleAddOn() 160 { 161 Unload(); 162 } 163 164 // Load 165 status_t 166 ModuleAddOn::Load(const char *path, const char *dirPath) 167 { 168 TRACE(("ModuleAddOn::Load(): searching module `%s'...\n", path)); 169 Unload(); 170 status_t error = (path && dirPath ? B_OK : B_BAD_VALUE); 171 if (error == B_OK) { 172 // get the module dir relative path 173 BPath absPath; 174 BPath absDirPath; 175 if (absPath.SetTo(path, NULL, true) != B_OK 176 || absDirPath.SetTo(dirPath, NULL, true) != B_OK 177 || strlen(absPath.Path()) <= strlen(absDirPath.Path())) { 178 return B_ENTRY_NOT_FOUND; 179 } 180 int32 dirPathLen = strlen(absDirPath.Path()); 181 if (strncmp(absPath.Path(), absDirPath.Path(), dirPathLen) 182 || absPath.Path()[dirPathLen] != '/') { 183 return B_ENTRY_NOT_FOUND; 184 } 185 const char *name = absPath.Path() + dirPathLen + 1; 186 // load the file 187 error = B_ENTRY_NOT_FOUND; 188 BEntry entry; 189 if (entry.SetTo(path) == B_OK && entry.Exists()) { 190 image_id image = load_add_on(path); 191 module_info **infos = NULL; 192 if (image >= 0 193 && get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA, 194 (void**)&infos) == B_OK 195 && infos != NULL) { 196 fAddOn = image; 197 fInfos = infos; 198 fName = name; 199 fReferenceCount = 0; 200 error = B_OK; 201 } 202 } 203 } 204 return error; 205 } 206 207 // Unload 208 void 209 ModuleAddOn::Unload() 210 { 211 if (fAddOn >= 0) 212 unload_add_on(fAddOn); 213 fAddOn = -1; 214 fInfos = NULL; 215 fReferenceCount = 0; 216 } 217 218 // Get 219 status_t 220 ModuleAddOn::Get() 221 { 222 if (fAddOn >= 0) { 223 if (fReferenceCount == 0) { 224 status_t status = ModuleManager::Default()->GetDependencies(fAddOn); 225 if (status < B_OK) 226 return status; 227 } 228 fReferenceCount++; 229 } 230 231 return B_OK; 232 } 233 234 // Put 235 bool 236 ModuleAddOn::Put() 237 { 238 if (fAddOn >= 0) 239 fReferenceCount--; 240 241 if (fReferenceCount == 0) { 242 ModuleManager::Default()->PutDependencies(fAddOn); 243 return true; 244 } 245 return false; 246 } 247 248 // FindModuleInfo 249 module_info * 250 ModuleAddOn::FindModuleInfo(const char *name) const 251 { 252 if (fInfos && name) { 253 for (int32 i = 0; module_info *info = fInfos[i]; i++) { 254 if (!strcmp(info->name, name)) 255 return info; 256 } 257 } 258 return NULL; 259 } 260 261 262 // #pragma mark - Module 263 264 265 Module::Module(ModuleAddOn *addon, module_info *info) 266 : fAddOn(addon), 267 fInfo(info), 268 fReferenceCount(0), 269 fInitialized(false) 270 { 271 } 272 273 // destructor 274 Module::~Module() 275 { 276 } 277 278 // Init 279 status_t 280 Module::Init() 281 { 282 status_t error = (fInfo ? B_OK : B_NO_INIT); 283 if (error == B_OK && !fInitialized) { 284 if (fInfo->std_ops != NULL) 285 error = fInfo->std_ops(B_MODULE_INIT); 286 if (error == B_OK) 287 fInitialized = true; 288 } 289 return error; 290 } 291 292 // Uninit 293 status_t 294 Module::Uninit() 295 { 296 status_t error = (fInfo ? B_OK : B_NO_INIT); 297 if (error == B_OK && fInitialized) { 298 if (fInfo->std_ops != NULL) 299 error = fInfo->std_ops(B_MODULE_UNINIT); 300 fInitialized = false; 301 } 302 return error; 303 } 304 305 306 status_t 307 Module::Get() 308 { 309 if (fReferenceCount == 0) { 310 status_t status = Init(); 311 if (status < B_OK) 312 return status; 313 } 314 315 fReferenceCount++; 316 return B_OK; 317 } 318 319 320 bool 321 Module::Put() 322 { 323 if (--fReferenceCount > 0) 324 return false; 325 326 Uninit(); 327 return fAddOn && !(fInfo->flags & B_KEEP_LOADED); 328 } 329 330 331 // #pragma mark - ModuleList 332 333 334 ModuleList::ModuleList() 335 { 336 } 337 338 339 ModuleList::~ModuleList() 340 { 341 } 342 343 // CountModules 344 int32 345 ModuleList::CountModules() const 346 { 347 return fModules.CountItems(); 348 } 349 350 // ModuleAt 351 Module * 352 ModuleList::ModuleAt(int32 index) const 353 { 354 return (Module*)fModules.ItemAt(index); 355 } 356 357 // AddModule 358 bool 359 ModuleList::AddModule(Module *module) 360 { 361 bool result = false; 362 if (module && !FindModule(module->Info()->name)) 363 result = fModules.AddItem(module); 364 return module; 365 } 366 367 // RemoveModule 368 bool 369 ModuleList::RemoveModule(Module *module) 370 { 371 return (module && fModules.RemoveItem(module)); 372 } 373 374 // FindModule 375 Module * 376 ModuleList::FindModule(const char *path) 377 { 378 if (path) { 379 for (int32 i = 0; Module *module = ModuleAt(i); i++) { 380 if (!strcmp(path, module->Info()->name)) 381 return module; 382 } 383 } 384 return NULL; 385 } 386 387 388 // #pragma mark - ModuleManager 389 390 391 ModuleManager::ModuleManager() 392 : fModules() 393 { 394 } 395 396 // destructor 397 ModuleManager::~ModuleManager() 398 { 399 for (int32 i = 0; Module *module = fModules.ModuleAt(i); i++) 400 delete module; 401 } 402 403 404 status_t 405 ModuleManager::GetModule(const char *path, module_info **_info) 406 { 407 if (path == NULL || _info == NULL) 408 return B_BAD_VALUE; 409 410 BAutolock _lock(fModules); 411 status_t error = B_OK; 412 413 Module *module = fModules.FindModule(path); 414 if (module == NULL) { 415 // module not yet loaded, try to get it 416 // get the responsible add-on 417 ModuleAddOn *addon = NULL; 418 error = _GetAddOn(path, &addon); 419 if (error == B_OK) { 420 // add-on found, get the module 421 if (module_info *info = addon->FindModuleInfo(path)) { 422 module = new Module(addon, info); 423 fModules.AddModule(module); 424 } else { 425 _PutAddOn(addon); 426 error = B_ENTRY_NOT_FOUND; 427 } 428 } 429 } 430 431 // "get" the module 432 if (error == B_OK) 433 error = module->Get(); 434 if (error == B_OK) 435 *_info = module->Info(); 436 437 return error; 438 } 439 440 // PutModule 441 status_t 442 ModuleManager::PutModule(const char *path) 443 { 444 if (path == NULL) 445 return B_BAD_VALUE; 446 447 BAutolock _lock(fModules); 448 449 if (Module *module = fModules.FindModule(path)) { 450 if (module->Put()) { 451 ModuleAddOn *addon = module->AddOn(); 452 fModules.RemoveModule(module); 453 delete module; 454 _PutAddOn(addon); 455 } 456 } else 457 return B_BAD_VALUE; 458 459 return B_OK; 460 } 461 462 // GetNextLoadedModuleName 463 status_t 464 ModuleManager::GetNextLoadedModuleName(uint32 *cookie, char *buffer, 465 size_t *bufferSize) 466 { 467 status_t error = (cookie && buffer && bufferSize ? B_OK : B_BAD_VALUE); 468 if (error == B_OK) { 469 BAutolock _lock(fModules); 470 if (Module *module = fModules.ModuleAt(*cookie)) { 471 module_info *info = module->Info(); 472 size_t nameLen = strlen(info->name); 473 if (nameLen < *bufferSize) { 474 strcpy(buffer, info->name); 475 *bufferSize = nameLen; 476 (*cookie)++; 477 } else 478 error = B_BAD_VALUE; 479 } else 480 error = B_ENTRY_NOT_FOUND; 481 } 482 return error; 483 } 484 485 // OpenModuleList 486 module_name_list * 487 ModuleManager::OpenModuleList(const char *prefix, const char *suffix) 488 { 489 module_name_list *list = NULL; 490 if (prefix) { 491 list = new module_name_list; 492 _FindBuiltInModules(prefix, suffix, list); 493 494 for (int32 i = 0; gModuleDirs[i]; i++) { 495 BPath path; 496 BDirectory dir; 497 if (path.SetTo(gModuleDirs[i], prefix) == B_OK 498 && dir.SetTo(path.Path()) == B_OK) { 499 _FindModules(dir, gModuleDirs[i], suffix, list); 500 } 501 } 502 503 list->it = list->names.begin(); 504 } 505 return list; 506 } 507 508 // ReadNextModuleName 509 status_t 510 ModuleManager::ReadNextModuleName(module_name_list *list, char *buffer, 511 size_t *bufferSize) 512 { 513 status_t error = (list && buffer && bufferSize ? B_OK : B_BAD_VALUE); 514 if (error == B_OK) { 515 if (list->it != list->names.end()) { 516 const string &name = *list->it; 517 size_t nameLen = name.length(); 518 if (nameLen < *bufferSize) { 519 strcpy(buffer, name.c_str()); 520 *bufferSize = nameLen; 521 list->it++; 522 } else 523 error = B_BAD_VALUE; 524 } else 525 error = B_ENTRY_NOT_FOUND; 526 } 527 return error; 528 } 529 530 531 // CloseModuleList 532 status_t 533 ModuleManager::CloseModuleList(module_name_list *list) 534 { 535 status_t error = (list ? B_OK : B_BAD_VALUE); 536 if (error == B_OK) 537 delete list; 538 return error; 539 } 540 541 542 status_t 543 ModuleManager::AddBuiltInModule(module_info *info) 544 { 545 BAutolock _lock(fModules); 546 547 TRACE(("add module %p, \"%s\"\n", info, info->name)); 548 return fModules.AddModule(new Module(NULL, info)) ? B_OK : B_ERROR; 549 } 550 551 552 status_t 553 ModuleManager::GetDependencies(image_id image) 554 { 555 module_dependency *dependencies; 556 status_t status = get_image_symbol(image, "module_dependencies", 557 B_SYMBOL_TYPE_DATA, (void**)&dependencies); 558 if (status < B_OK) { 559 // no dependencies means we don't have to do anything 560 return B_OK; 561 } 562 563 for (uint32 i = 0; dependencies[i].name != NULL; i++) { 564 status = GetModule(dependencies[i].name, dependencies[i].info); 565 if (status < B_OK) 566 return status; 567 } 568 return B_OK; 569 } 570 571 572 void 573 ModuleManager::PutDependencies(image_id image) 574 { 575 module_dependency *dependencies; 576 status_t status = get_image_symbol(image, "module_dependencies", 577 B_SYMBOL_TYPE_DATA, (void**)&dependencies); 578 if (status < B_OK) { 579 // no dependencies means we don't have to do anything 580 return; 581 } 582 583 for (uint32 i = 0; dependencies[i].name != NULL; i++) { 584 PutModule(dependencies[i].name); 585 } 586 } 587 588 589 bool 590 ModuleManager::_MatchSuffix(const char *name, const char *suffix) 591 { 592 if (suffix == NULL || suffix[0] == '\0') 593 return true; 594 595 size_t suffixLength = strlen(suffix); 596 size_t length = strlen(name); 597 if (length <= suffixLength) 598 return false; 599 600 return name[length - suffixLength - 1] == '/' 601 && !strcmp(name + length - suffixLength, suffix); 602 } 603 604 605 void 606 ModuleManager::_FindModules(BDirectory &dir, const char *moduleDir, 607 const char *suffix, module_name_list *list) 608 { 609 BEntry entry; 610 while (dir.GetNextEntry(&entry) == B_OK) { 611 if (entry.IsFile()) { 612 ModuleAddOn addon; 613 BPath path; 614 if (entry.GetPath(&path) == B_OK 615 && addon.Load(path.Path(), moduleDir) == B_OK) { 616 module_info **infos = addon.ModuleInfos(); 617 for (int32 i = 0; infos[i]; i++) { 618 if (infos[i]->name 619 && _MatchSuffix(infos[i]->name, suffix)) 620 list->names.insert(infos[i]->name); 621 } 622 } 623 } else if (entry.IsDirectory()) { 624 BDirectory subdir; 625 if (subdir.SetTo(&entry) == B_OK) 626 _FindModules(subdir, moduleDir, suffix, list); 627 } 628 } 629 } 630 631 632 void 633 ModuleManager::_FindBuiltInModules(const char *prefix, const char *suffix, 634 module_name_list *list) 635 { 636 uint32 count = fModules.CountModules(); 637 uint32 prefixLength = strlen(prefix); 638 639 for (uint32 i = 0; i < count; i++) { 640 Module *module = fModules.ModuleAt(i); 641 if (!strncmp(module->Info()->name, prefix, prefixLength) 642 && _MatchSuffix(module->Info()->name, suffix)) 643 list->names.insert(module->Info()->name); 644 } 645 } 646 647 648 status_t 649 ModuleManager::_GetAddOn(const char *name, ModuleAddOn **_addon) 650 { 651 // search list first 652 for (int32 i = 0; ModuleAddOn *addon = fAddOns.ItemAt(i); i++) { 653 BString addonName(addon->Name()); 654 addonName << "/"; 655 if (!strcmp(name, addon->Name()) 656 || !strncmp(addonName.String(), name, addonName.Length())) { 657 addon->Get(); 658 *_addon = addon; 659 return B_OK; 660 } 661 } 662 // not in list yet, load from disk 663 // iterate through module dirs 664 for (int32 i = 0; gModuleDirs[i]; i++) { 665 BPath path; 666 if (path.SetTo(gModuleDirs[i]) == B_OK 667 && path.SetTo(path.Path(), name) == B_OK) { 668 BEntry entry; 669 for (;;) { 670 if (entry.SetTo(path.Path()) == B_OK && entry.Exists()) { 671 // found an entry: if it is a file, try to load it 672 if (entry.IsFile()) { 673 ModuleAddOn *addon = new ModuleAddOn; 674 if (addon->Load(path.Path(), gModuleDirs[i]) == B_OK) { 675 status_t status = addon->Get(); 676 if (status < B_OK) { 677 delete addon; 678 return status; 679 } 680 681 fAddOns.AddItem(addon); 682 *_addon = addon; 683 return B_OK; 684 } 685 delete addon; 686 } 687 break; 688 } 689 // chop off last path component 690 if (path.GetParent(&path) != B_OK) 691 break; 692 } 693 } 694 } 695 return B_ENTRY_NOT_FOUND; 696 } 697 698 // _PutAddOn 699 void 700 ModuleManager::_PutAddOn(ModuleAddOn *addon) 701 { 702 if (addon) { 703 if (addon->Put()) { 704 fAddOns.RemoveItem(addon); 705 delete addon; 706 } 707 } 708 } 709 710 711 // singleton instance 712 ModuleManager ModuleManager::sDefaultManager; 713 714 715 // #pragma mark - Private emulation functions 716 717 718 extern "C" status_t 719 _add_builtin_module(module_info *info) 720 { 721 return ModuleManager::Default()->AddBuiltInModule(info); 722 } 723 724 725 extern "C" status_t 726 _get_builtin_dependencies(void) 727 { 728 image_info info; 729 int32 cookie = 0; 730 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) { 731 if (info.type != B_APP_IMAGE) 732 continue; 733 734 return ModuleManager::Default()->GetDependencies(info.id); 735 } 736 737 return B_OK; 738 } 739 740 741 // #pragma mark - Emulated kernel functions 742 743 744 status_t 745 get_module(const char *path, module_info **_info) 746 { 747 TRACE(("get_module(`%s')\n", path)); 748 return ModuleManager::Default()->GetModule(path, _info); 749 } 750 751 752 status_t 753 put_module(const char *path) 754 { 755 TRACE(("put_module(`%s')\n", path)); 756 return ModuleManager::Default()->PutModule(path); 757 } 758 759 760 status_t 761 get_next_loaded_module_name(uint32 *cookie, char *name, size_t *nameLength) 762 { 763 TRACE(("get_next_loaded_module_name(%lu)\n", *cookie)); 764 return ModuleManager::Default()->GetNextLoadedModuleName(cookie, name, 765 nameLength); 766 } 767 768 769 void * 770 open_module_list_etc(const char *prefix, const char *suffix) 771 { 772 TRACE(("open_module_list_etc('%s', '%s')\n", prefix, suffix)); 773 return (void*)ModuleManager::Default()->OpenModuleList(prefix, suffix); 774 } 775 776 777 void * 778 open_module_list(const char *prefix) 779 { 780 TRACE(("open_module_list('%s')\n", prefix)); 781 return (void*)ModuleManager::Default()->OpenModuleList(prefix); 782 } 783 784 785 status_t 786 read_next_module_name(void *cookie, char *buf, size_t *bufsize) 787 { 788 TRACE(("read_next_module_name(%p, %p, %lu)\n", cookie, buf, *bufsize)); 789 return ModuleManager::Default()->ReadNextModuleName( 790 (module_name_list*)cookie, buf, bufsize); 791 } 792 793 794 status_t 795 close_module_list(void *cookie) 796 { 797 TRACE(("close_module_list(%p)\n", cookie)); 798 return ModuleManager::Default()->CloseModuleList( 799 (module_name_list*)cookie); 800 } 801