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 32using namespace std; 33 34 35static 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 42struct module_name_list { 43 set<string> names; 44 set<string>::iterator it; 45}; 46 47 48// ModuleAddOn 49 50class ModuleAddOn { 51public: 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 66private: 67 image_id fAddOn; 68 module_info **fInfos; 69 int32 fReferenceCount; 70 BString fName; 71}; 72 73class Module { 74public: 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 87private: 88 ModuleAddOn *fAddOn; 89 module_info *fInfo; 90 int32 fReferenceCount; 91 bool fInitialized; 92}; 93 94class ModuleList : public BLocker { 95public: 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 106private: 107 BList fModules; 108}; 109 110class ModuleManager { 111public: 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 134private: 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 144private: 145 static ModuleManager sDefaultManager; 146 ModuleList fModules; 147 BObjectList<ModuleAddOn> fAddOns; 148}; 149 150 151// #pragma mark - ModuleAddOn 152 153 154ModuleAddOn::ModuleAddOn() 155 : fAddOn(-1), 156 fInfos(NULL), 157 fReferenceCount(0) 158{ 159} 160 161 162ModuleAddOn::~ModuleAddOn() 163{ 164 Unload(); 165} 166 167// Load 168status_t 169ModuleAddOn::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 211void 212ModuleAddOn::Unload() 213{ 214 if (fAddOn >= 0) 215 unload_add_on(fAddOn); 216 fAddOn = -1; 217 fInfos = NULL; 218 fReferenceCount = 0; 219} 220 221// Get 222status_t 223ModuleAddOn::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 238bool 239ModuleAddOn::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 252module_info * 253ModuleAddOn::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 268Module::Module(ModuleAddOn *addon, module_info *info) 269 : fAddOn(addon), 270 fInfo(info), 271 fReferenceCount(0), 272 fInitialized(false) 273{ 274} 275 276// destructor 277Module::~Module() 278{ 279} 280 281// Init 282status_t 283Module::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 296status_t 297Module::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 309status_t 310Module::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 323bool 324Module::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 337ModuleList::ModuleList() 338{ 339} 340 341 342ModuleList::~ModuleList() 343{ 344} 345 346// CountModules 347int32 348ModuleList::CountModules() const 349{ 350 return fModules.CountItems(); 351} 352 353// ModuleAt 354Module * 355ModuleList::ModuleAt(int32 index) const 356{ 357 return (Module*)fModules.ItemAt(index); 358} 359 360// AddModule 361bool 362ModuleList::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 371bool 372ModuleList::RemoveModule(Module *module) 373{ 374 return (module && fModules.RemoveItem(module)); 375} 376 377// FindModule 378Module * 379ModuleList::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 394ModuleManager::ModuleManager() 395 : fModules() 396{ 397} 398 399// destructor 400ModuleManager::~ModuleManager() 401{ 402 for (int32 i = 0; Module *module = fModules.ModuleAt(i); i++) 403 delete module; 404} 405 406 407status_t 408ModuleManager::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 444status_t 445ModuleManager::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 466status_t 467ModuleManager::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 489module_name_list * 490ModuleManager::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 512status_t 513ModuleManager::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 535status_t 536ModuleManager::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 545status_t 546ModuleManager::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 555status_t 556ModuleManager::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 575void 576ModuleManager::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 592bool 593ModuleManager::_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 608void 609ModuleManager::_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 635void 636ModuleManager::_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 651status_t 652ModuleManager::_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 702void 703ModuleManager::_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 715ModuleManager ModuleManager::sDefaultManager; 716 717 718// #pragma mark - Private emulation functions 719 720 721extern "C" status_t 722_add_builtin_module(module_info *info) 723{ 724 return ModuleManager::Default()->AddBuiltInModule(info); 725} 726 727 728extern "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 747status_t 748get_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 755status_t 756put_module(const char *path) 757{ 758 TRACE(("put_module(`%s')\n", path)); 759 return ModuleManager::Default()->PutModule(path); 760} 761 762 763status_t 764get_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 772void * 773open_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 780void * 781open_module_list(const char *prefix) 782{ 783 TRACE(("open_module_list('%s')\n", prefix)); 784 return (void*)ModuleManager::Default()->OpenModuleList(prefix); 785} 786 787 788status_t 789read_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 797status_t 798close_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