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 32static 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 39struct module_name_list { 40 set<string> names; 41 set<string>::iterator it; 42}; 43 44 45// ModuleAddOn 46 47class ModuleAddOn { 48public: 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 63private: 64 image_id fAddOn; 65 module_info **fInfos; 66 int32 fReferenceCount; 67 BString fName; 68}; 69 70class Module { 71public: 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 84private: 85 ModuleAddOn *fAddOn; 86 module_info *fInfo; 87 int32 fReferenceCount; 88 bool fInitialized; 89}; 90 91class ModuleList : public BLocker { 92public: 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 103private: 104 BList fModules; 105}; 106 107class ModuleManager { 108public: 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 131private: 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 141private: 142 static ModuleManager sDefaultManager; 143 ModuleList fModules; 144 BObjectList<ModuleAddOn> fAddOns; 145}; 146 147 148// #pragma mark - ModuleAddOn 149 150 151ModuleAddOn::ModuleAddOn() 152 : fAddOn(-1), 153 fInfos(NULL), 154 fReferenceCount(0) 155{ 156} 157 158 159ModuleAddOn::~ModuleAddOn() 160{ 161 Unload(); 162} 163 164// Load 165status_t 166ModuleAddOn::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 208void 209ModuleAddOn::Unload() 210{ 211 if (fAddOn >= 0) 212 unload_add_on(fAddOn); 213 fAddOn = -1; 214 fInfos = NULL; 215 fReferenceCount = 0; 216} 217 218// Get 219status_t 220ModuleAddOn::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 235bool 236ModuleAddOn::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 249module_info * 250ModuleAddOn::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 265Module::Module(ModuleAddOn *addon, module_info *info) 266 : fAddOn(addon), 267 fInfo(info), 268 fReferenceCount(0), 269 fInitialized(false) 270{ 271} 272 273// destructor 274Module::~Module() 275{ 276} 277 278// Init 279status_t 280Module::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 293status_t 294Module::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 306status_t 307Module::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 320bool 321Module::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 334ModuleList::ModuleList() 335{ 336} 337 338 339ModuleList::~ModuleList() 340{ 341} 342 343// CountModules 344int32 345ModuleList::CountModules() const 346{ 347 return fModules.CountItems(); 348} 349 350// ModuleAt 351Module * 352ModuleList::ModuleAt(int32 index) const 353{ 354 return (Module*)fModules.ItemAt(index); 355} 356 357// AddModule 358bool 359ModuleList::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 368bool 369ModuleList::RemoveModule(Module *module) 370{ 371 return (module && fModules.RemoveItem(module)); 372} 373 374// FindModule 375Module * 376ModuleList::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 391ModuleManager::ModuleManager() 392 : fModules() 393{ 394} 395 396// destructor 397ModuleManager::~ModuleManager() 398{ 399 for (int32 i = 0; Module *module = fModules.ModuleAt(i); i++) 400 delete module; 401} 402 403 404status_t 405ModuleManager::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 441status_t 442ModuleManager::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 463status_t 464ModuleManager::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 486module_name_list * 487ModuleManager::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 509status_t 510ModuleManager::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 532status_t 533ModuleManager::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 542status_t 543ModuleManager::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 552status_t 553ModuleManager::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 572void 573ModuleManager::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 589bool 590ModuleManager::_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 605void 606ModuleManager::_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 632void 633ModuleManager::_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 648status_t 649ModuleManager::_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 699void 700ModuleManager::_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 712ModuleManager ModuleManager::sDefaultManager; 713 714 715// #pragma mark - Private emulation functions 716 717 718extern "C" status_t 719_add_builtin_module(module_info *info) 720{ 721 return ModuleManager::Default()->AddBuiltInModule(info); 722} 723 724 725extern "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 744status_t 745get_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 752status_t 753put_module(const char *path) 754{ 755 TRACE(("put_module(`%s')\n", path)); 756 return ModuleManager::Default()->PutModule(path); 757} 758 759 760status_t 761get_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 769void * 770open_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 777void * 778open_module_list(const char *prefix) 779{ 780 TRACE(("open_module_list('%s')\n", prefix)); 781 return (void*)ModuleManager::Default()->OpenModuleList(prefix); 782} 783 784 785status_t 786read_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 794status_t 795close_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