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