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