1 /* 2 * Copyright 2002-2008, Haiku Inc. All rights reserved. 3 * Distributed under the terms of the MIT License. 4 * 5 * Copyright 2001, Thomas Kurschel. All rights reserved. 6 * Distributed under the terms of the NewOS License. 7 */ 8 9 /*! Manages kernel add-ons and their exported modules. */ 10 11 12 #include <kmodule.h> 13 14 #include <errno.h> 15 #include <stdlib.h> 16 #include <string.h> 17 #include <sys/stat.h> 18 19 #include <FindDirectory.h> 20 #include <NodeMonitor.h> 21 22 #include <dirent_private.h> 23 24 #include <boot_device.h> 25 #include <boot/elf.h> 26 #include <elf.h> 27 #include <fs/KPath.h> 28 #include <fs/node_monitor.h> 29 #include <lock.h> 30 #include <Notifications.h> 31 #include <safemode.h> 32 #include <syscalls.h> 33 #include <util/AutoLock.h> 34 #include <util/khash.h> 35 #include <util/Stack.h> 36 #include <vfs.h> 37 38 39 //#define TRACE_MODULE 40 #ifdef TRACE_MODULE 41 # define TRACE(x) dprintf x 42 #else 43 # define TRACE(x) ; 44 #endif 45 #define FATAL(x) dprintf x 46 47 48 #define MODULE_HASH_SIZE 16 49 50 /*! The modules referenced by this structure are built-in 51 modules that can't be loaded from disk. 52 */ 53 extern module_info gDeviceManagerModule; 54 extern module_info gDeviceRootModule; 55 extern module_info gDeviceGenericModule; 56 extern module_info gFrameBufferConsoleModule; 57 58 // file systems 59 extern module_info gRootFileSystem; 60 extern module_info gDeviceFileSystem; 61 62 static module_info* sBuiltInModules[] = { 63 &gDeviceManagerModule, 64 &gDeviceRootModule, 65 &gDeviceGenericModule, 66 &gFrameBufferConsoleModule, 67 68 &gRootFileSystem, 69 &gDeviceFileSystem, 70 NULL 71 }; 72 73 enum module_state { 74 MODULE_QUERIED = 0, 75 MODULE_LOADED, 76 MODULE_INIT, 77 MODULE_READY, 78 MODULE_UNINIT, 79 MODULE_ERROR 80 }; 81 82 83 /* Each loaded module image (which can export several modules) is put 84 * in a hash (gModuleImagesHash) to be easily found when you search 85 * for a specific file name. 86 * TODO: Could use only the inode number for hashing. Would probably be 87 * a little bit slower, but would lower the memory foot print quite a lot. 88 */ 89 90 struct module_image { 91 struct module_image* next; 92 module_info** info; // the module_info we use 93 module_dependency* dependencies; 94 char* path; // the full path for the module 95 image_id image; 96 int32 ref_count; // how many ref's to this file 97 }; 98 99 /* Each known module will have this structure which is put in the 100 * gModulesHash, and looked up by name. 101 */ 102 103 struct module { 104 struct module* next; 105 ::module_image* module_image; 106 char* name; 107 int32 ref_count; 108 module_info* info; // will only be valid if ref_count > 0 109 int32 offset; // this is the offset in the headers 110 module_state state; 111 uint32 flags; 112 }; 113 114 #define B_BUILT_IN_MODULE 2 115 116 typedef struct module_path { 117 const char* name; 118 uint32 base_length; 119 } module_path; 120 121 typedef struct module_iterator { 122 module_path* stack; 123 int32 stack_size; 124 int32 stack_current; 125 126 char* prefix; 127 size_t prefix_length; 128 const char* suffix; 129 size_t suffix_length; 130 DIR* current_dir; 131 status_t status; 132 int32 module_offset; 133 // This is used to keep track of which module_info 134 // within a module we're addressing. 135 ::module_image* module_image; 136 module_info** current_header; 137 const char* current_path; 138 uint32 path_base_length; 139 const char* current_module_path; 140 bool builtin_modules; 141 bool loaded_modules; 142 } module_iterator; 143 144 namespace Module { 145 146 struct entry { 147 dev_t device; 148 ino_t node; 149 }; 150 151 struct hash_entry : entry { 152 ~hash_entry() 153 { 154 free((char*)path); 155 } 156 157 hash_entry* hash_link; 158 const char* path; 159 }; 160 161 struct NodeHashDefinition { 162 typedef entry* KeyType; 163 typedef hash_entry ValueType; 164 165 size_t Hash(ValueType* entry) const 166 { return HashKey(entry); } 167 ValueType*& GetLink(ValueType* entry) const 168 { return entry->hash_link; } 169 170 size_t HashKey(KeyType key) const 171 { 172 return ((uint32)(key->node >> 32) + (uint32)key->node) ^ key->device; 173 } 174 175 bool Compare(KeyType key, ValueType* entry) const 176 { 177 return key->device == entry->device 178 && key->node == entry->node; 179 } 180 }; 181 182 typedef BOpenHashTable<NodeHashDefinition> NodeHash; 183 184 struct module_listener : DoublyLinkedListLinkImpl<module_listener> { 185 ~module_listener() 186 { 187 free((char*)prefix); 188 } 189 190 NotificationListener* listener; 191 const char* prefix; 192 }; 193 194 typedef DoublyLinkedList<module_listener> ModuleListenerList; 195 196 struct module_notification : DoublyLinkedListLinkImpl<module_notification> { 197 ~module_notification() 198 { 199 free((char*)name); 200 } 201 202 int32 opcode; 203 dev_t device; 204 ino_t directory; 205 ino_t node; 206 const char* name; 207 }; 208 209 typedef DoublyLinkedList<module_notification> NotificationList; 210 211 class DirectoryWatcher : public NotificationListener { 212 public: 213 DirectoryWatcher(); 214 virtual ~DirectoryWatcher(); 215 216 virtual void EventOccured(NotificationService& service, 217 const KMessage* event); 218 }; 219 220 class ModuleWatcher : public NotificationListener { 221 public: 222 ModuleWatcher(); 223 virtual ~ModuleWatcher(); 224 225 virtual void EventOccured(NotificationService& service, 226 const KMessage* event); 227 }; 228 229 class ModuleNotificationService : public NotificationService { 230 public: 231 ModuleNotificationService(); 232 virtual ~ModuleNotificationService(); 233 234 status_t InitCheck(); 235 236 status_t AddListener(const KMessage* eventSpecifier, 237 NotificationListener& listener); 238 status_t UpdateListener(const KMessage* eventSpecifier, 239 NotificationListener& listener); 240 status_t RemoveListener(const KMessage* eventSpecifier, 241 NotificationListener& listener); 242 243 bool HasNode(dev_t device, ino_t node); 244 245 void Notify(int32 opcode, dev_t device, ino_t directory, 246 ino_t node, const char* name); 247 248 virtual const char* Name() { return "modules"; } 249 250 static void HandleNotifications(void *data, int iteration); 251 252 private: 253 status_t _RemoveNode(dev_t device, ino_t node); 254 status_t _AddNode(dev_t device, ino_t node, const char* path, 255 uint32 flags, NotificationListener& listener); 256 status_t _AddDirectoryNode(dev_t device, ino_t node); 257 status_t _AddModuleNode(dev_t device, ino_t node, int fd, 258 const char* name); 259 260 status_t _AddDirectory(const char* prefix); 261 status_t _ScanDirectory(char* directoryPath, const char* prefix, 262 size_t& prefixPosition); 263 status_t _ScanDirectory(Stack<DIR*>& stack, DIR* dir, 264 const char* prefix, size_t prefixPosition); 265 266 void _Notify(int32 opcode, dev_t device, ino_t directory, 267 ino_t node, const char* name); 268 void _HandleNotifications(); 269 270 recursive_lock fLock; 271 ModuleListenerList fListeners; 272 NodeHash fNodes; 273 DirectoryWatcher fDirectoryWatcher; 274 ModuleWatcher fModuleWatcher; 275 NotificationList fNotifications; 276 }; 277 278 } // namespace Module 279 280 using namespace Module; 281 282 /* These are the standard base paths where we start to look for modules 283 * to load. Order is important, the last entry here will be searched 284 * first. 285 */ 286 static const directory_which kModulePaths[] = { 287 B_BEOS_ADDONS_DIRECTORY, 288 B_COMMON_ADDONS_DIRECTORY, 289 B_USER_ADDONS_DIRECTORY, 290 }; 291 292 static const uint32 kNumModulePaths = sizeof(kModulePaths) 293 / sizeof(kModulePaths[0]); 294 static const uint32 kFirstNonSystemModulePath = 1; 295 296 297 static ModuleNotificationService sModuleNotificationService; 298 static bool sDisableUserAddOns = false; 299 300 /* Locking scheme: There is a global lock only; having several locks 301 makes trouble if dependent modules get loaded concurrently -> 302 they have to wait for each other, i.e. we need one lock per module; 303 also we must detect circular references during init and not dead-lock. 304 305 Reference counting: get_module() increments the ref count of a module, 306 put_module() decrements it. When a B_KEEP_LOADED module is initialized 307 the ref count is incremented once more, so it never gets 308 uninitialized/unloaded. A referenced module, unless it's built-in, has a 309 non-null module_image and owns a reference to the image. When the last 310 module reference is put, the image's reference is released and module_image 311 zeroed (as long as the boot volume has not been mounted, it is not zeroed). 312 An unreferenced module image is unloaded (when the boot volume is mounted). 313 */ 314 static recursive_lock sModulesLock; 315 316 /* We store the loaded modules by directory path, and all known modules 317 * by module name in a hash table for quick access 318 */ 319 static hash_table* sModuleImagesHash; 320 static hash_table* sModulesHash; 321 322 323 /*! Calculates hash for a module using its name */ 324 static uint32 325 module_hash(void* _module, const void* _key, uint32 range) 326 { 327 module* module = (struct module*)_module; 328 const char* name = (const char*)_key; 329 330 if (module != NULL) 331 return hash_hash_string(module->name) % range; 332 333 if (name != NULL) 334 return hash_hash_string(name) % range; 335 336 return 0; 337 } 338 339 340 /*! Compares a module to a given name */ 341 static int 342 module_compare(void* _module, const void* _key) 343 { 344 module* module = (struct module*)_module; 345 const char* name = (const char*)_key; 346 if (name == NULL) 347 return -1; 348 349 return strcmp(module->name, name); 350 } 351 352 353 /*! Calculates the hash of a module image using its path */ 354 static uint32 355 module_image_hash(void* _module, const void* _key, uint32 range) 356 { 357 module_image* image = (module_image*)_module; 358 const char* path = (const char*)_key; 359 360 if (image != NULL) 361 return hash_hash_string(image->path) % range; 362 363 if (path != NULL) 364 return hash_hash_string(path) % range; 365 366 return 0; 367 } 368 369 370 /*! Compares a module image to a path */ 371 static int 372 module_image_compare(void* _module, const void* _key) 373 { 374 module_image* image = (module_image*)_module; 375 const char* path = (const char*)_key; 376 if (path == NULL) 377 return -1; 378 379 return strcmp(image->path, path); 380 } 381 382 383 /*! Try to load the module image at the specified \a path. 384 If it could be loaded, it returns \c B_OK, and stores a pointer 385 to the module_image object in \a _moduleImage. 386 Needs to be called with the sModulesLock held. 387 */ 388 static status_t 389 load_module_image(const char* path, module_image** _moduleImage) 390 { 391 module_image* moduleImage; 392 status_t status; 393 image_id image; 394 395 TRACE(("load_module_image(path = \"%s\", _image = %p)\n", path, 396 _moduleImage)); 397 ASSERT_LOCKED_RECURSIVE(&sModulesLock); 398 ASSERT(_moduleImage != NULL); 399 400 image = load_kernel_add_on(path); 401 if (image < 0) { 402 dprintf("load_module_image(%s) failed: %s\n", path, strerror(image)); 403 return image; 404 } 405 406 moduleImage = (module_image*)malloc(sizeof(module_image)); 407 if (moduleImage == NULL) { 408 status = B_NO_MEMORY; 409 goto err; 410 } 411 412 if (get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA, 413 (void**)&moduleImage->info) != B_OK) { 414 TRACE(("load_module_image: Failed to load \"%s\" due to lack of " 415 "'modules' symbol\n", path)); 416 status = B_BAD_TYPE; 417 goto err1; 418 } 419 420 moduleImage->dependencies = NULL; 421 get_image_symbol(image, "module_dependencies", B_SYMBOL_TYPE_DATA, 422 (void**)&moduleImage->dependencies); 423 // this is allowed to be NULL 424 425 moduleImage->path = strdup(path); 426 if (!moduleImage->path) { 427 status = B_NO_MEMORY; 428 goto err1; 429 } 430 431 moduleImage->image = image; 432 moduleImage->ref_count = 0; 433 434 hash_insert(sModuleImagesHash, moduleImage); 435 436 TRACE(("load_module_image(\"%s\"): image loaded: %p\n", path, moduleImage)); 437 438 *_moduleImage = moduleImage; 439 return B_OK; 440 441 err1: 442 free(moduleImage); 443 err: 444 unload_kernel_add_on(image); 445 446 return status; 447 } 448 449 450 /*! Unloads the module's kernel add-on. The \a image will be freed. 451 Needs to be called with the sModulesLock held. 452 */ 453 static status_t 454 unload_module_image(module_image* moduleImage, bool remove) 455 { 456 TRACE(("unload_module_image(image %p, remove %d)\n", moduleImage, remove)); 457 ASSERT_LOCKED_RECURSIVE(&sModulesLock); 458 459 if (moduleImage->ref_count != 0) { 460 FATAL(("Can't unload %s due to ref_cnt = %ld\n", moduleImage->path, 461 moduleImage->ref_count)); 462 return B_ERROR; 463 } 464 465 if (remove) 466 hash_remove(sModuleImagesHash, moduleImage); 467 468 unload_kernel_add_on(moduleImage->image); 469 free(moduleImage->path); 470 free(moduleImage); 471 472 return B_OK; 473 } 474 475 476 static void 477 put_module_image(module_image* image) 478 { 479 RecursiveLocker locker(sModulesLock); 480 481 int32 refCount = atomic_add(&image->ref_count, -1); 482 ASSERT(refCount > 0); 483 484 // Don't unload anything when there is no boot device yet 485 // (because chances are that we will never be able to access it again) 486 487 if (refCount == 1 && gBootDevice > 0) 488 unload_module_image(image, true); 489 } 490 491 492 static status_t 493 get_module_image(const char* path, module_image** _image) 494 { 495 struct module_image* image; 496 497 TRACE(("get_module_image(path = \"%s\")\n", path)); 498 499 RecursiveLocker _(sModulesLock); 500 501 image = (module_image*)hash_lookup(sModuleImagesHash, path); 502 if (image == NULL) { 503 status_t status = load_module_image(path, &image); 504 if (status < B_OK) 505 return status; 506 } 507 508 atomic_add(&image->ref_count, 1); 509 *_image = image; 510 511 return B_OK; 512 } 513 514 515 /*! Extract the information from the module_info structure pointed at 516 by "info" and create the entries required for access to it's details. 517 */ 518 static status_t 519 create_module(module_info* info, int offset, module** _module) 520 { 521 module* module; 522 523 TRACE(("create_module(info = %p, offset = %d, _module = %p)\n", 524 info, offset, _module)); 525 526 if (!info->name) 527 return B_BAD_VALUE; 528 529 module = (struct module*)hash_lookup(sModulesHash, info->name); 530 if (module) { 531 FATAL(("Duplicate module name (%s) detected... ignoring new one\n", 532 info->name)); 533 return B_FILE_EXISTS; 534 } 535 536 if ((module = (struct module*)malloc(sizeof(struct module))) == NULL) 537 return B_NO_MEMORY; 538 539 TRACE(("create_module: name = \"%s\"\n", info->name)); 540 541 module->module_image = NULL; 542 module->name = strdup(info->name); 543 if (module->name == NULL) { 544 free(module); 545 return B_NO_MEMORY; 546 } 547 548 module->state = MODULE_QUERIED; 549 module->info = info; 550 module->offset = offset; 551 // record where the module_info can be found in the module_info array 552 module->ref_count = 0; 553 module->flags = info->flags; 554 555 recursive_lock_lock(&sModulesLock); 556 hash_insert(sModulesHash, module); 557 recursive_lock_unlock(&sModulesLock); 558 559 if (_module) 560 *_module = module; 561 562 return B_OK; 563 } 564 565 566 /*! Loads the file at \a path and scans all modules contained therein. 567 Returns \c B_OK if \a searchedName could be found under those modules, 568 and will return the referenced image in \a _moduleImage. 569 Returns \c B_ENTRY_NOT_FOUND if the module could not be found. 570 571 Must only be called for files that haven't been scanned yet. 572 \a searchedName is allowed to be \c NULL (if all modules should be scanned) 573 */ 574 static status_t 575 check_module_image(const char* path, const char* searchedName, 576 module_image** _moduleImage) 577 { 578 status_t status = B_ENTRY_NOT_FOUND; 579 module_image* image; 580 module_info** info; 581 int index = 0; 582 583 TRACE(("check_module_image(path = \"%s\", searchedName = \"%s\")\n", path, 584 searchedName)); 585 586 if (get_module_image(path, &image) < B_OK) 587 return B_ENTRY_NOT_FOUND; 588 589 for (info = image->info; *info; info++) { 590 // try to create a module for every module_info, check if the 591 // name matches if it was a new entry 592 bool freshModule = false; 593 struct module* module = (struct module*)hash_lookup(sModulesHash, 594 (*info)->name); 595 if (module != NULL) { 596 // Module does already exist 597 if (module->module_image == NULL && module->ref_count == 0) { 598 module->info = *info; 599 module->offset = index; 600 module->flags = (*info)->flags; 601 module->state = MODULE_QUERIED; 602 freshModule = true; 603 } 604 } else if (create_module(*info, index, NULL) == B_OK) 605 freshModule = true; 606 607 if (freshModule && searchedName != NULL 608 && strcmp((*info)->name, searchedName) == 0) { 609 status = B_OK; 610 } 611 612 index++; 613 } 614 615 if (status != B_OK) { 616 // decrement the ref we got in get_module_image 617 put_module_image(image); 618 return status; 619 } 620 621 *_moduleImage = image; 622 return B_OK; 623 } 624 625 626 static module* 627 search_module(const char* name, module_image** _moduleImage) 628 { 629 status_t status = B_ENTRY_NOT_FOUND; 630 uint32 i; 631 632 TRACE(("search_module(%s)\n", name)); 633 634 for (i = kNumModulePaths; i-- > 0;) { 635 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 636 continue; 637 638 // let the VFS find that module for us 639 640 KPath basePath; 641 if (find_directory(kModulePaths[i], gBootDevice, true, 642 basePath.LockBuffer(), basePath.BufferSize()) != B_OK) 643 continue; 644 645 basePath.UnlockBuffer(); 646 basePath.Append("kernel"); 647 648 KPath path; 649 status = vfs_get_module_path(basePath.Path(), name, path.LockBuffer(), 650 path.BufferSize()); 651 if (status == B_OK) { 652 path.UnlockBuffer(); 653 status = check_module_image(path.Path(), name, _moduleImage); 654 if (status == B_OK) 655 break; 656 } 657 } 658 659 if (status != B_OK) 660 return NULL; 661 662 return (module*)hash_lookup(sModulesHash, name); 663 } 664 665 666 static status_t 667 put_dependent_modules(struct module* module) 668 { 669 module_image* image = module->module_image; 670 module_dependency* dependencies; 671 672 // built-in modules don't have a module_image structure 673 if (image == NULL 674 || (dependencies = image->dependencies) == NULL) 675 return B_OK; 676 677 for (int32 i = 0; dependencies[i].name != NULL; i++) { 678 status_t status = put_module(dependencies[i].name); 679 if (status < B_OK) 680 return status; 681 } 682 683 return B_OK; 684 } 685 686 687 static status_t 688 get_dependent_modules(struct module* module) 689 { 690 module_image* image = module->module_image; 691 module_dependency* dependencies; 692 693 // built-in modules don't have a module_image structure 694 if (image == NULL 695 || (dependencies = image->dependencies) == NULL) 696 return B_OK; 697 698 TRACE(("resolving module dependencies...\n")); 699 700 for (int32 i = 0; dependencies[i].name != NULL; i++) { 701 status_t status = get_module(dependencies[i].name, 702 dependencies[i].info); 703 if (status < B_OK) { 704 dprintf("loading dependent module %s of %s failed!\n", 705 dependencies[i].name, module->name); 706 return status; 707 } 708 } 709 710 return B_OK; 711 } 712 713 714 /*! Initializes a loaded module depending on its state */ 715 static inline status_t 716 init_module(module* module) 717 { 718 switch (module->state) { 719 case MODULE_QUERIED: 720 case MODULE_LOADED: 721 { 722 status_t status; 723 module->state = MODULE_INIT; 724 725 // resolve dependencies 726 727 status = get_dependent_modules(module); 728 if (status < B_OK) { 729 module->state = MODULE_LOADED; 730 return status; 731 } 732 733 // init module 734 735 TRACE(("initializing module %s (at %p)... \n", module->name, 736 module->info->std_ops)); 737 738 if (module->info->std_ops != NULL) 739 status = module->info->std_ops(B_MODULE_INIT); 740 741 TRACE(("...done (%s)\n", strerror(status))); 742 743 if (status >= B_OK) 744 module->state = MODULE_READY; 745 else { 746 put_dependent_modules(module); 747 module->state = MODULE_LOADED; 748 } 749 750 return status; 751 } 752 753 case MODULE_READY: 754 return B_OK; 755 756 case MODULE_INIT: 757 FATAL(("circular reference to %s\n", module->name)); 758 return B_ERROR; 759 760 case MODULE_UNINIT: 761 FATAL(("tried to load module %s which is currently unloading\n", 762 module->name)); 763 return B_ERROR; 764 765 case MODULE_ERROR: 766 FATAL(("cannot load module %s because its earlier unloading " 767 "failed\n", module->name)); 768 return B_ERROR; 769 770 default: 771 return B_ERROR; 772 } 773 // never trespasses here 774 } 775 776 777 /*! Uninitializes a module depeding on its state */ 778 static inline int 779 uninit_module(module* module) 780 { 781 TRACE(("uninit_module(%s)\n", module->name)); 782 783 switch (module->state) { 784 case MODULE_QUERIED: 785 case MODULE_LOADED: 786 return B_NO_ERROR; 787 788 case MODULE_INIT: 789 panic("Trying to unload module %s which is initializing\n", 790 module->name); 791 return B_ERROR; 792 793 case MODULE_UNINIT: 794 panic("Trying to unload module %s which is un-initializing\n", 795 module->name); 796 return B_ERROR; 797 798 case MODULE_READY: 799 { 800 status_t status = B_OK; 801 module->state = MODULE_UNINIT; 802 803 TRACE(("uninitializing module %s...\n", module->name)); 804 805 if (module->info->std_ops != NULL) 806 status = module->info->std_ops(B_MODULE_UNINIT); 807 808 TRACE(("...done (%s)\n", strerror(status))); 809 810 if (status == B_OK) { 811 module->state = MODULE_LOADED; 812 put_dependent_modules(module); 813 return B_OK; 814 } 815 816 FATAL(("Error unloading module %s (%s)\n", module->name, 817 strerror(status))); 818 819 module->state = MODULE_ERROR; 820 module->flags |= B_KEEP_LOADED; 821 module->ref_count++; 822 823 return status; 824 } 825 default: 826 return B_ERROR; 827 } 828 // never trespasses here 829 } 830 831 832 static const char* 833 iterator_pop_path_from_stack(module_iterator* iterator, uint32* _baseLength) 834 { 835 if (iterator->stack_current <= 0) 836 return NULL; 837 838 if (_baseLength) 839 *_baseLength = iterator->stack[iterator->stack_current - 1].base_length; 840 841 return iterator->stack[--iterator->stack_current].name; 842 } 843 844 845 static status_t 846 iterator_push_path_on_stack(module_iterator* iterator, const char* path, 847 uint32 baseLength) 848 { 849 if (iterator->stack_current + 1 > iterator->stack_size) { 850 // allocate new space on the stack 851 module_path* stack = (module_path*)realloc(iterator->stack, 852 (iterator->stack_size + 8) * sizeof(module_path)); 853 if (stack == NULL) 854 return B_NO_MEMORY; 855 856 iterator->stack = stack; 857 iterator->stack_size += 8; 858 } 859 860 iterator->stack[iterator->stack_current].name = path; 861 iterator->stack[iterator->stack_current++].base_length = baseLength; 862 return B_OK; 863 } 864 865 866 static bool 867 match_iterator_suffix(module_iterator* iterator, const char* name) 868 { 869 if (iterator->suffix == NULL || iterator->suffix_length == 0) 870 return true; 871 872 size_t length = strlen(name); 873 if (length <= iterator->suffix_length) 874 return false; 875 876 return name[length - iterator->suffix_length - 1] == '/' 877 && !strcmp(name + length - iterator->suffix_length, iterator->suffix); 878 } 879 880 881 static status_t 882 iterator_get_next_module(module_iterator* iterator, char* buffer, 883 size_t* _bufferSize) 884 { 885 status_t status; 886 887 TRACE(("iterator_get_next_module() -- start\n")); 888 889 if (iterator->builtin_modules) { 890 for (int32 i = iterator->module_offset; sBuiltInModules[i] != NULL; 891 i++) { 892 // the module name must fit the prefix 893 if (strncmp(sBuiltInModules[i]->name, iterator->prefix, 894 iterator->prefix_length) 895 || !match_iterator_suffix(iterator, sBuiltInModules[i]->name)) 896 continue; 897 898 *_bufferSize = strlcpy(buffer, sBuiltInModules[i]->name, 899 *_bufferSize); 900 iterator->module_offset = i + 1; 901 return B_OK; 902 } 903 iterator->builtin_modules = false; 904 } 905 906 if (iterator->loaded_modules) { 907 recursive_lock_lock(&sModulesLock); 908 hash_iterator hashIterator; 909 hash_open(sModulesHash, &hashIterator); 910 911 struct module* module = (struct module*)hash_next(sModulesHash, 912 &hashIterator); 913 for (int32 i = 0; module != NULL; i++) { 914 if (i >= iterator->module_offset) { 915 if (!strncmp(module->name, iterator->prefix, 916 iterator->prefix_length) 917 && match_iterator_suffix(iterator, module->name)) { 918 *_bufferSize = strlcpy(buffer, module->name, *_bufferSize); 919 iterator->module_offset = i + 1; 920 921 hash_close(sModulesHash, &hashIterator, false); 922 recursive_lock_unlock(&sModulesLock); 923 return B_OK; 924 } 925 } 926 module = (struct module*)hash_next(sModulesHash, &hashIterator); 927 } 928 929 hash_close(sModulesHash, &hashIterator, false); 930 recursive_lock_unlock(&sModulesLock); 931 932 // prevent from falling into modules hash iteration again 933 iterator->loaded_modules = false; 934 } 935 936 nextPath: 937 if (iterator->current_dir == NULL) { 938 // get next directory path from the stack 939 const char* path = iterator_pop_path_from_stack(iterator, 940 &iterator->path_base_length); 941 if (path == NULL) { 942 // we are finished, there are no more entries on the stack 943 return B_ENTRY_NOT_FOUND; 944 } 945 946 free((char*)iterator->current_path); 947 iterator->current_path = path; 948 iterator->current_dir = opendir(path); 949 TRACE(("open directory at %s -> %p\n", path, iterator->current_dir)); 950 951 if (iterator->current_dir == NULL) { 952 // we don't throw an error here, but silently go to 953 // the next directory on the stack 954 goto nextPath; 955 } 956 } 957 958 nextModuleImage: 959 // TODO: remember which directories were already scanned, and don't search 960 // through them again, unless they change (use DirectoryWatcher) 961 962 if (iterator->current_header == NULL) { 963 // get next entry from the current directory 964 965 errno = 0; 966 967 struct dirent* dirent; 968 if ((dirent = readdir(iterator->current_dir)) == NULL) { 969 closedir(iterator->current_dir); 970 iterator->current_dir = NULL; 971 972 if (errno < B_OK) 973 return errno; 974 975 goto nextPath; 976 } 977 978 // check if the prefix matches 979 int32 passedOffset, commonLength; 980 passedOffset = strlen(iterator->current_path) + 1; 981 commonLength = iterator->path_base_length + iterator->prefix_length 982 - passedOffset; 983 984 if (commonLength > 0) { 985 // the prefix still reaches into the new path part 986 int32 length = strlen(dirent->d_name); 987 if (commonLength > length) 988 commonLength = length; 989 990 if (strncmp(dirent->d_name, iterator->prefix + passedOffset 991 - iterator->path_base_length, commonLength)) 992 goto nextModuleImage; 993 } 994 995 // we're not interested in traversing these (again) 996 if (!strcmp(dirent->d_name, ".") 997 || !strcmp(dirent->d_name, "..") 998 // TODO: this is a bit unclean, as we actually only want to prevent 999 // drivers/bin and drivers/dev to be scanned 1000 || !strcmp(dirent->d_name, "bin") 1001 || !strcmp(dirent->d_name, "dev")) 1002 goto nextModuleImage; 1003 1004 // build absolute path to current file 1005 KPath path(iterator->current_path); 1006 if (path.InitCheck() != B_OK) 1007 return B_NO_MEMORY; 1008 1009 if (path.Append(dirent->d_name) != B_OK) 1010 return B_BUFFER_OVERFLOW; 1011 1012 // find out if it's a directory or a file 1013 struct stat stat; 1014 if (::stat(path.Path(), &stat) < 0) 1015 return errno; 1016 1017 iterator->current_module_path = strdup(path.Path()); 1018 if (iterator->current_module_path == NULL) 1019 return B_NO_MEMORY; 1020 1021 if (S_ISDIR(stat.st_mode)) { 1022 status = iterator_push_path_on_stack(iterator, 1023 iterator->current_module_path, iterator->path_base_length); 1024 if (status != B_OK) 1025 return status; 1026 1027 iterator->current_module_path = NULL; 1028 goto nextModuleImage; 1029 } 1030 1031 if (!S_ISREG(stat.st_mode)) 1032 return B_BAD_TYPE; 1033 1034 TRACE(("open module at %s\n", path.Path())); 1035 1036 status = get_module_image(path.Path(), &iterator->module_image); 1037 if (status < B_OK) { 1038 free((char*)iterator->current_module_path); 1039 iterator->current_module_path = NULL; 1040 goto nextModuleImage; 1041 } 1042 1043 iterator->current_header = iterator->module_image->info; 1044 iterator->module_offset = 0; 1045 } 1046 1047 // search the current module image until we've got a match 1048 while (*iterator->current_header != NULL) { 1049 module_info* info = *iterator->current_header; 1050 1051 // TODO: we might want to create a module here and cache it in the 1052 // hash table 1053 1054 iterator->current_header++; 1055 iterator->module_offset++; 1056 1057 if (strncmp(info->name, iterator->prefix, iterator->prefix_length) 1058 || !match_iterator_suffix(iterator, info->name)) 1059 continue; 1060 1061 *_bufferSize = strlcpy(buffer, info->name, *_bufferSize); 1062 return B_OK; 1063 } 1064 1065 // leave this module and get the next one 1066 1067 iterator->current_header = NULL; 1068 free((char*)iterator->current_module_path); 1069 iterator->current_module_path = NULL; 1070 1071 put_module_image(iterator->module_image); 1072 iterator->module_image = NULL; 1073 1074 goto nextModuleImage; 1075 } 1076 1077 1078 static void 1079 register_builtin_modules(struct module_info** info) 1080 { 1081 for (; *info; info++) { 1082 (*info)->flags |= B_BUILT_IN_MODULE; 1083 // this is an internal flag, it doesn't have to be set by modules 1084 // itself 1085 1086 if (create_module(*info, -1, NULL) != B_OK) { 1087 dprintf("creation of built-in module \"%s\" failed!\n", 1088 (*info)->name); 1089 } 1090 } 1091 } 1092 1093 1094 static status_t 1095 register_preloaded_module_image(struct preloaded_image* image) 1096 { 1097 module_image* moduleImage; 1098 struct module_info** info; 1099 status_t status; 1100 int32 index = 0; 1101 1102 TRACE(("register_preloaded_module_image(image = %p, name = \"%s\")\n", 1103 image, image->name)); 1104 1105 image->is_module = false; 1106 1107 if (image->id < 0) 1108 return B_BAD_VALUE; 1109 1110 moduleImage = (module_image*)malloc(sizeof(module_image)); 1111 if (moduleImage == NULL) 1112 return B_NO_MEMORY; 1113 1114 if (get_image_symbol(image->id, "modules", B_SYMBOL_TYPE_DATA, 1115 (void**)&moduleImage->info) != B_OK) { 1116 status = B_BAD_TYPE; 1117 goto error; 1118 } 1119 1120 image->is_module = true; 1121 1122 if (moduleImage->info[0] == NULL) { 1123 status = B_BAD_DATA; 1124 goto error; 1125 } 1126 1127 moduleImage->dependencies = NULL; 1128 get_image_symbol(image->id, "module_dependencies", B_SYMBOL_TYPE_DATA, 1129 (void**)&moduleImage->dependencies); 1130 // this is allowed to be NULL 1131 1132 moduleImage->path = strdup(image->name); 1133 if (moduleImage->path == NULL) { 1134 status = B_NO_MEMORY; 1135 goto error; 1136 } 1137 1138 moduleImage->image = image->id; 1139 moduleImage->ref_count = 0; 1140 1141 hash_insert(sModuleImagesHash, moduleImage); 1142 1143 for (info = moduleImage->info; *info; info++) { 1144 struct module* module = NULL; 1145 if (create_module(*info, index++, &module) == B_OK) 1146 module->module_image = moduleImage; 1147 } 1148 1149 return B_OK; 1150 1151 error: 1152 free(moduleImage); 1153 1154 // We don't need this image anymore. We keep it, if it doesn't look like 1155 // a module at all. It might be an old-style driver. 1156 if (image->is_module) 1157 unload_kernel_add_on(image->id); 1158 1159 return status; 1160 } 1161 1162 1163 static int 1164 dump_modules(int argc, char** argv) 1165 { 1166 hash_iterator iterator; 1167 struct module_image* image; 1168 struct module* module; 1169 1170 hash_rewind(sModulesHash, &iterator); 1171 kprintf("-- known modules:\n"); 1172 1173 while ((module = (struct module*)hash_next(sModulesHash, &iterator)) 1174 != NULL) { 1175 kprintf("%p: \"%s\", \"%s\" (%ld), refcount = %ld, state = %d, " 1176 "mimage = %p\n", module, module->name, 1177 module->module_image ? module->module_image->path : "", 1178 module->offset, module->ref_count, module->state, 1179 module->module_image); 1180 } 1181 1182 hash_rewind(sModuleImagesHash, &iterator); 1183 kprintf("\n-- loaded module images:\n"); 1184 1185 while ((image = (struct module_image*)hash_next(sModuleImagesHash, 1186 &iterator)) != NULL) { 1187 kprintf("%p: \"%s\" (image_id = %ld), info = %p, refcount = %ld\n", 1188 image, image->path, image->image, image->info, image->ref_count); 1189 } 1190 return 0; 1191 } 1192 1193 1194 // #pragma mark - DirectoryWatcher 1195 1196 1197 DirectoryWatcher::DirectoryWatcher() 1198 { 1199 } 1200 1201 1202 DirectoryWatcher::~DirectoryWatcher() 1203 { 1204 } 1205 1206 1207 void 1208 DirectoryWatcher::EventOccured(NotificationService& service, 1209 const KMessage* event) 1210 { 1211 int32 opcode = event->GetInt32("opcode", -1); 1212 dev_t device = event->GetInt32("device", -1); 1213 ino_t directory = event->GetInt64("directory", -1); 1214 ino_t node = event->GetInt64("node", -1); 1215 const char *name = event->GetString("name", NULL); 1216 1217 if (opcode == B_ENTRY_MOVED) { 1218 // Determine wether it's a move within, out of, or into one 1219 // of our watched directories. 1220 directory = event->GetInt64("to directory", -1); 1221 if (!sModuleNotificationService.HasNode(device, directory)) { 1222 directory = event->GetInt64("from directory", -1); 1223 opcode = B_ENTRY_REMOVED; 1224 } else { 1225 // Move within, doesn't sound like a good idea for modules 1226 opcode = B_ENTRY_CREATED; 1227 } 1228 } 1229 1230 sModuleNotificationService.Notify(opcode, device, directory, node, name); 1231 } 1232 1233 1234 // #pragma mark - ModuleWatcher 1235 1236 1237 ModuleWatcher::ModuleWatcher() 1238 { 1239 } 1240 1241 1242 ModuleWatcher::~ModuleWatcher() 1243 { 1244 } 1245 1246 1247 void 1248 ModuleWatcher::EventOccured(NotificationService& service, const KMessage* event) 1249 { 1250 if (event->GetInt32("opcode", -1) != B_STAT_CHANGED 1251 || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) 1252 return; 1253 1254 dev_t device = event->GetInt32("device", -1); 1255 ino_t node = event->GetInt64("node", -1); 1256 1257 sModuleNotificationService.Notify(B_STAT_CHANGED, device, -1, node, NULL); 1258 } 1259 1260 1261 // #pragma mark - ModuleNotificationService 1262 1263 1264 ModuleNotificationService::ModuleNotificationService() 1265 { 1266 recursive_lock_init(&fLock, "module notifications"); 1267 } 1268 1269 1270 ModuleNotificationService::~ModuleNotificationService() 1271 { 1272 recursive_lock_destroy(&fLock); 1273 } 1274 1275 1276 status_t 1277 ModuleNotificationService::AddListener(const KMessage* eventSpecifier, 1278 NotificationListener& listener) 1279 { 1280 const char* prefix = eventSpecifier->GetString("prefix", NULL); 1281 if (prefix == NULL) 1282 return B_BAD_VALUE; 1283 1284 module_listener* moduleListener = new(std::nothrow) module_listener; 1285 if (moduleListener == NULL) 1286 return B_NO_MEMORY; 1287 1288 moduleListener->prefix = strdup(prefix); 1289 if (moduleListener->prefix == NULL) { 1290 delete moduleListener; 1291 return B_NO_MEMORY; 1292 } 1293 1294 status_t status = _AddDirectory(prefix); 1295 if (status != B_OK) { 1296 delete moduleListener; 1297 return status; 1298 } 1299 1300 moduleListener->listener = &listener; 1301 fListeners.Add(moduleListener); 1302 1303 return B_OK; 1304 } 1305 1306 1307 status_t 1308 ModuleNotificationService::UpdateListener(const KMessage* eventSpecifier, 1309 NotificationListener& listener) 1310 { 1311 return B_ERROR; 1312 } 1313 1314 1315 status_t 1316 ModuleNotificationService::RemoveListener(const KMessage* eventSpecifier, 1317 NotificationListener& listener) 1318 { 1319 return B_ERROR; 1320 } 1321 1322 1323 bool 1324 ModuleNotificationService::HasNode(dev_t device, ino_t node) 1325 { 1326 RecursiveLocker _(fLock); 1327 1328 struct entry entry = {device, node}; 1329 return fNodes.Lookup(&entry) != NULL; 1330 } 1331 1332 1333 status_t 1334 ModuleNotificationService::_RemoveNode(dev_t device, ino_t node) 1335 { 1336 RecursiveLocker _(fLock); 1337 1338 struct entry key = {device, node}; 1339 hash_entry* entry = fNodes.Lookup(&key); 1340 if (entry == NULL) 1341 return B_ENTRY_NOT_FOUND; 1342 1343 remove_node_listener(device, node, entry->path != NULL 1344 ? (NotificationListener&)fModuleWatcher 1345 : (NotificationListener&)fDirectoryWatcher); 1346 1347 fNodes.Remove(entry); 1348 delete entry; 1349 1350 return B_OK; 1351 } 1352 1353 1354 status_t 1355 ModuleNotificationService::_AddNode(dev_t device, ino_t node, const char* path, 1356 uint32 flags, NotificationListener& listener) 1357 { 1358 RecursiveLocker locker(fLock); 1359 1360 if (HasNode(device, node)) 1361 return B_OK; 1362 1363 struct hash_entry* entry = new(std::nothrow) hash_entry; 1364 if (entry == NULL) 1365 return B_NO_MEMORY; 1366 1367 if (path != NULL) { 1368 entry->path = strdup(path); 1369 if (entry->path == NULL) { 1370 delete entry; 1371 return B_NO_MEMORY; 1372 } 1373 } else 1374 entry->path = NULL; 1375 1376 status_t status = add_node_listener(device, node, flags, listener); 1377 if (status != B_OK) { 1378 delete entry; 1379 return status; 1380 } 1381 1382 //dprintf(" add %s %ld:%Ld (%s)\n", flags == B_WATCH_DIRECTORY 1383 // ? "dir" : "file", device, node, path); 1384 1385 entry->device = device; 1386 entry->node = node; 1387 fNodes.Insert(entry); 1388 1389 return B_OK; 1390 } 1391 1392 1393 status_t 1394 ModuleNotificationService::_AddDirectoryNode(dev_t device, ino_t node) 1395 { 1396 return _AddNode(device, node, NULL, B_WATCH_DIRECTORY, fDirectoryWatcher); 1397 } 1398 1399 1400 status_t 1401 ModuleNotificationService::_AddModuleNode(dev_t device, ino_t node, int fd, 1402 const char* name) 1403 { 1404 struct vnode* vnode; 1405 status_t status = vfs_get_vnode_from_fd(fd, true, &vnode); 1406 if (status != B_OK) 1407 return status; 1408 1409 ino_t directory; 1410 vfs_vnode_to_node_ref(vnode, &device, &directory); 1411 1412 KPath path; 1413 status = path.InitCheck(); 1414 if (status == B_OK) { 1415 status = vfs_entry_ref_to_path(device, directory, name, 1416 path.LockBuffer(), path.BufferSize()); 1417 } 1418 if (status != B_OK) 1419 return status; 1420 1421 path.UnlockBuffer(); 1422 1423 return _AddNode(device, node, path.Path(), B_WATCH_STAT, fModuleWatcher); 1424 } 1425 1426 1427 status_t 1428 ModuleNotificationService::_AddDirectory(const char* prefix) 1429 { 1430 status_t status = B_ERROR; 1431 1432 for (uint32 i = 0; i < kNumModulePaths; i++) { 1433 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 1434 break; 1435 1436 KPath pathBuffer; 1437 if (find_directory(kModulePaths[i], gBootDevice, true, 1438 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 1439 continue; 1440 1441 pathBuffer.UnlockBuffer(); 1442 pathBuffer.Append("kernel"); 1443 pathBuffer.Append(prefix); 1444 1445 size_t prefixPosition = strlen(prefix); 1446 status_t scanStatus = _ScanDirectory(pathBuffer.LockBuffer(), prefix, 1447 prefixPosition); 1448 1449 pathBuffer.UnlockBuffer(); 1450 1451 // It's enough if we succeed for one directory 1452 if (status != B_OK) 1453 status = scanStatus; 1454 } 1455 1456 return status; 1457 } 1458 1459 1460 status_t 1461 ModuleNotificationService::_ScanDirectory(char* directoryPath, 1462 const char* prefix, size_t& prefixPosition) 1463 { 1464 DIR* dir = NULL; 1465 while (true) { 1466 dir = opendir(directoryPath); 1467 if (dir != NULL || prefixPosition == 0) 1468 break; 1469 1470 // the full prefix is not accessible, remove path components 1471 const char* parentPrefix = prefix + prefixPosition - 1; 1472 while (parentPrefix != prefix && parentPrefix[0] != '/') 1473 parentPrefix--; 1474 1475 size_t cutPosition = parentPrefix - prefix; 1476 size_t length = strlen(directoryPath); 1477 directoryPath[length - prefixPosition + cutPosition] = '\0'; 1478 prefixPosition = cutPosition; 1479 } 1480 1481 if (dir == NULL) 1482 return B_ERROR; 1483 1484 Stack<DIR*> stack; 1485 stack.Push(dir); 1486 1487 while (stack.Pop(&dir)) { 1488 status_t status = _ScanDirectory(stack, dir, prefix, prefixPosition); 1489 if (status != B_OK) 1490 return status; 1491 } 1492 1493 return B_OK; 1494 } 1495 1496 1497 status_t 1498 ModuleNotificationService::_ScanDirectory(Stack<DIR*>& stack, DIR* dir, 1499 const char* prefix, size_t prefixPosition) 1500 { 1501 bool directMatchAdded = false; 1502 struct dirent* dirent; 1503 1504 while ((dirent = readdir(dir)) != NULL) { 1505 if (dirent->d_name[0] == '.') 1506 continue; 1507 1508 bool directMatch = false; 1509 1510 if (prefix[prefixPosition] != '\0') { 1511 // the start must match 1512 const char* startPrefix = prefix + prefixPosition; 1513 if (startPrefix[0] == '/') 1514 startPrefix++; 1515 1516 const char* endPrefix = strchr(startPrefix, '/'); 1517 size_t length; 1518 1519 if (endPrefix != NULL) 1520 length = endPrefix - startPrefix; 1521 else 1522 length = strlen(startPrefix); 1523 1524 if (strncmp(dirent->d_name, startPrefix, length)) 1525 continue; 1526 1527 if (dirent->d_name[length] == '\0') 1528 directMatch = true; 1529 } 1530 1531 struct stat stat; 1532 status_t status = vfs_read_stat(dir->fd, dirent->d_name, true, &stat, 1533 true); 1534 if (status != B_OK) 1535 continue; 1536 1537 if (S_ISDIR(stat.st_mode)) { 1538 int fd = _kern_open_dir(dir->fd, dirent->d_name); 1539 if (fd < 0) 1540 continue; 1541 1542 DIR* subDir = (DIR*)malloc(DIR_BUFFER_SIZE); 1543 if (subDir == NULL) { 1544 close(fd); 1545 continue; 1546 } 1547 1548 subDir->fd = fd; 1549 subDir->entries_left = 0; 1550 1551 stack.Push(subDir); 1552 1553 if (_AddDirectoryNode(stat.st_dev, stat.st_ino) == B_OK 1554 && directMatch) 1555 directMatchAdded = true; 1556 } else if (S_ISREG(stat.st_mode)) { 1557 if (_AddModuleNode(stat.st_dev, stat.st_ino, dir->fd, 1558 dirent->d_name) == B_OK && directMatch) 1559 directMatchAdded = true; 1560 } 1561 } 1562 1563 if (!directMatchAdded) { 1564 // We need to monitor this directory to see if a matching file 1565 // is added. 1566 struct stat stat; 1567 status_t status = vfs_read_stat(dir->fd, NULL, true, &stat, true); 1568 if (status == B_OK) 1569 _AddDirectoryNode(stat.st_dev, stat.st_ino); 1570 } 1571 1572 closedir(dir); 1573 return B_OK; 1574 } 1575 1576 1577 void 1578 ModuleNotificationService::_Notify(int32 opcode, dev_t device, ino_t directory, 1579 ino_t node, const char* name) 1580 { 1581 // construct path 1582 1583 KPath pathBuffer; 1584 const char* path; 1585 1586 if (name != NULL) { 1587 // we have an entry ref 1588 if (pathBuffer.InitCheck() != B_OK 1589 || vfs_entry_ref_to_path(device, directory, name, 1590 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 1591 return; 1592 1593 pathBuffer.UnlockBuffer(); 1594 path = pathBuffer.Path(); 1595 } else { 1596 // we only have a node ref 1597 RecursiveLocker _(fLock); 1598 1599 struct entry key = {device, node}; 1600 hash_entry* entry = fNodes.Lookup(&key); 1601 if (entry == NULL || entry->path == NULL) 1602 return; 1603 1604 path = entry->path; 1605 } 1606 1607 // remove kModulePaths from path 1608 1609 for (uint32 i = 0; i < kNumModulePaths; i++) { 1610 KPath modulePath; 1611 if (find_directory(kModulePaths[i], gBootDevice, true, 1612 modulePath.LockBuffer(), modulePath.BufferSize()) != B_OK) 1613 continue; 1614 1615 modulePath.UnlockBuffer(); 1616 modulePath.Append("kernel"); 1617 1618 if (strncmp(path, modulePath.Path(), modulePath.Length())) 1619 continue; 1620 1621 path += modulePath.Length(); 1622 if (path[i] == '/') 1623 path++; 1624 1625 break; 1626 } 1627 1628 KMessage event; 1629 1630 // find listeners by prefix/path 1631 1632 ModuleListenerList::Iterator iterator = fListeners.GetIterator(); 1633 while (iterator.HasNext()) { 1634 module_listener* listener = iterator.Next(); 1635 1636 if (strncmp(path, listener->prefix, strlen(listener->prefix))) 1637 continue; 1638 1639 if (event.IsEmpty()) { 1640 // construct message only when needed 1641 event.AddInt32("opcode", opcode); 1642 event.AddString("path", path); 1643 } 1644 1645 // notify them! 1646 listener->listener->EventOccured(*this, &event); 1647 1648 // we might need to watch new files now 1649 if (opcode == B_ENTRY_CREATED) 1650 _AddDirectory(listener->prefix); 1651 1652 } 1653 1654 // remove notification listeners, if needed 1655 1656 if (opcode == B_ENTRY_REMOVED) 1657 _RemoveNode(device, node); 1658 } 1659 1660 1661 void 1662 ModuleNotificationService::_HandleNotifications() 1663 { 1664 RecursiveLocker _(fLock); 1665 1666 NotificationList::Iterator iterator = fNotifications.GetIterator(); 1667 while (iterator.HasNext()) { 1668 module_notification* notification = iterator.Next(); 1669 1670 _Notify(notification->opcode, notification->device, 1671 notification->directory, notification->node, notification->name); 1672 1673 iterator.Remove(); 1674 delete notification; 1675 } 1676 } 1677 1678 1679 void 1680 ModuleNotificationService::Notify(int32 opcode, dev_t device, ino_t directory, 1681 ino_t node, const char* name) 1682 { 1683 module_notification* notification = new(std::nothrow) module_notification; 1684 if (notification == NULL) 1685 return; 1686 1687 if (name != NULL) { 1688 notification->name = strdup(name); 1689 if (notification->name == NULL) { 1690 delete notification; 1691 return; 1692 } 1693 } else 1694 notification->name = NULL; 1695 1696 notification->opcode = opcode; 1697 notification->device = device; 1698 notification->directory = directory; 1699 notification->node = node; 1700 1701 RecursiveLocker _(fLock); 1702 fNotifications.Add(notification); 1703 } 1704 1705 1706 /*static*/ void 1707 ModuleNotificationService::HandleNotifications(void */*data*/, 1708 int /*iteration*/) 1709 { 1710 sModuleNotificationService._HandleNotifications(); 1711 } 1712 1713 1714 // #pragma mark - Exported Kernel API (private part) 1715 1716 1717 /*! Unloads a module in case it's not in use. This is the counterpart 1718 to load_module(). 1719 */ 1720 status_t 1721 unload_module(const char* path) 1722 { 1723 struct module_image* moduleImage; 1724 1725 recursive_lock_lock(&sModulesLock); 1726 moduleImage = (module_image*)hash_lookup(sModuleImagesHash, path); 1727 recursive_lock_unlock(&sModulesLock); 1728 1729 if (moduleImage == NULL) 1730 return B_ENTRY_NOT_FOUND; 1731 1732 put_module_image(moduleImage); 1733 return B_OK; 1734 } 1735 1736 1737 /*! Unlike get_module(), this function lets you specify the add-on to 1738 be loaded by path. 1739 However, you must not use the exported modules without having called 1740 get_module() on them. When you're done with the NULL terminated 1741 \a modules array, you have to call unload_module(), no matter if 1742 you're actually using any of the modules or not - of course, the 1743 add-on won't be unloaded until the last put_module(). 1744 */ 1745 status_t 1746 load_module(const char* path, module_info*** _modules) 1747 { 1748 module_image* moduleImage; 1749 status_t status = get_module_image(path, &moduleImage); 1750 if (status != B_OK) 1751 return status; 1752 1753 *_modules = moduleImage->info; 1754 return B_OK; 1755 } 1756 1757 1758 status_t 1759 start_watching_modules(const char* prefix, NotificationListener& listener) 1760 { 1761 KMessage specifier; 1762 status_t status = specifier.AddString("prefix", prefix); 1763 if (status != B_OK) 1764 return status; 1765 1766 return sModuleNotificationService.AddListener(&specifier, listener); 1767 } 1768 1769 1770 status_t 1771 stop_watching_modules(const char* prefix, NotificationListener& listener) 1772 { 1773 KMessage specifier; 1774 status_t status = specifier.AddString("prefix", prefix); 1775 if (status != B_OK) 1776 return status; 1777 1778 return sModuleNotificationService.RemoveListener(&specifier, listener); 1779 } 1780 1781 1782 /*! Setup the module structures and data for use - must be called 1783 before any other module call. 1784 */ 1785 status_t 1786 module_init(kernel_args* args) 1787 { 1788 struct preloaded_image* image; 1789 1790 recursive_lock_init(&sModulesLock, "modules rlock"); 1791 1792 sModulesHash = hash_init(MODULE_HASH_SIZE, 0, module_compare, module_hash); 1793 if (sModulesHash == NULL) 1794 return B_NO_MEMORY; 1795 1796 sModuleImagesHash = hash_init(MODULE_HASH_SIZE, 0, module_image_compare, 1797 module_image_hash); 1798 if (sModuleImagesHash == NULL) 1799 return B_NO_MEMORY; 1800 1801 // register built-in modules 1802 1803 register_builtin_modules(sBuiltInModules); 1804 1805 // register preloaded images 1806 1807 for (image = args->preloaded_images; image != NULL; image = image->next) { 1808 status_t status = register_preloaded_module_image(image); 1809 if (status != B_OK && image->is_module) { 1810 dprintf("Could not register image \"%s\": %s\n", image->name, 1811 strerror(status)); 1812 } 1813 } 1814 1815 new(&sModuleNotificationService) ModuleNotificationService(); 1816 1817 sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS, 1818 false); 1819 1820 add_debugger_command("modules", &dump_modules, 1821 "list all known & loaded modules"); 1822 1823 return B_OK; 1824 } 1825 1826 1827 status_t 1828 module_init_post_threads(void) 1829 { 1830 return register_kernel_daemon( 1831 &ModuleNotificationService::HandleNotifications, NULL, 10); 1832 // once every second 1833 1834 return B_OK; 1835 } 1836 1837 1838 status_t 1839 module_init_post_boot_device(bool bootingFromBootLoaderVolume) 1840 { 1841 // Remove all unused pre-loaded module images. Now that the boot device is 1842 // available, we can load an image when we need it. 1843 // When the boot volume is also where the boot loader pre-loaded the images 1844 // from, we get the actual paths for those images. 1845 TRACE(("module_init_post_boot_device(%d)\n", bootingFromBootLoaderVolume)); 1846 1847 RecursiveLocker _(sModulesLock); 1848 1849 // First of all, clear all pre-loaded module's module_image, if the module 1850 // isn't in use. 1851 hash_iterator iterator; 1852 hash_open(sModulesHash, &iterator); 1853 struct module* module; 1854 while ((module = (struct module*)hash_next(sModulesHash, &iterator)) 1855 != NULL) { 1856 if (module->ref_count == 0 1857 && (module->flags & B_BUILT_IN_MODULE) == 0) { 1858 TRACE((" module %p, \"%s\" unused, clearing image\n", module, 1859 module->name)); 1860 module->module_image = NULL; 1861 } 1862 } 1863 1864 // Now iterate through the images and drop them respectively normalize their 1865 // paths. 1866 hash_open(sModuleImagesHash, &iterator); 1867 1868 module_image* imagesToReinsert = NULL; 1869 // When renamed, an image is added to this list to be re-entered in the 1870 // hash at the end. We can't do that during the iteration. 1871 1872 while (true) { 1873 struct module_image* image 1874 = (struct module_image*)hash_next(sModuleImagesHash, &iterator); 1875 if (image == NULL) 1876 break; 1877 1878 if (image->ref_count == 0) { 1879 // not in use -- unload it 1880 TRACE((" module image %p, \"%s\" unused, removing\n", image, 1881 image->path)); 1882 hash_remove_current(sModuleImagesHash, &iterator); 1883 unload_module_image(image, false); 1884 } else if (bootingFromBootLoaderVolume) { 1885 bool pathNormalized = false; 1886 KPath pathBuffer; 1887 if (image->path[0] != '/') { 1888 // relative path 1889 for (uint32 i = kNumModulePaths; i-- > 0;) { 1890 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 1891 continue; 1892 1893 if (find_directory(kModulePaths[i], gBootDevice, true, 1894 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) 1895 != B_OK) { 1896 pathBuffer.UnlockBuffer(); 1897 continue; 1898 } 1899 1900 pathBuffer.UnlockBuffer(); 1901 1902 // Append the relative boot module directory and the 1903 // relative image path, normalize the path, and check 1904 // whether it exists. 1905 struct stat st; 1906 if (pathBuffer.Append("kernel/boot") != B_OK 1907 || pathBuffer.Append(image->path) != B_OK 1908 || pathBuffer.Normalize(true) != B_OK 1909 || lstat(pathBuffer.Path(), &st) != 0) { 1910 continue; 1911 } 1912 1913 pathNormalized = true; 1914 break; 1915 } 1916 } else { 1917 // absolute path -- try to normalize it anyway 1918 struct stat st; 1919 if (pathBuffer.SetPath(image->path) == B_OK 1920 && pathBuffer.Normalize(true) == B_OK 1921 && lstat(pathBuffer.Path(), &st) == 0) { 1922 pathNormalized = true; 1923 } 1924 } 1925 1926 if (pathNormalized) { 1927 TRACE((" normalized path of module image %p, \"%s\" -> " 1928 "\"%s\"\n", image, image->path, pathBuffer.Path())); 1929 1930 // set the new path 1931 free(image->path); 1932 size_t pathLen = pathBuffer.Length(); 1933 image->path = (char*)realloc(pathBuffer.DetachBuffer(), 1934 pathLen + 1); 1935 1936 // remove the image -- its hash value has probably changed, 1937 // so we need to re-insert it later 1938 hash_remove_current(sModuleImagesHash, &iterator); 1939 image->next = imagesToReinsert; 1940 imagesToReinsert = image; 1941 } else { 1942 dprintf("module_init_post_boot_device() failed to normalize " 1943 "path of module image %p, \"%s\"\n", image, image->path); 1944 } 1945 } 1946 } 1947 1948 // re-insert the images that have got a new path 1949 while (module_image* image = imagesToReinsert) { 1950 imagesToReinsert = image->next; 1951 hash_insert(sModuleImagesHash, image); 1952 } 1953 1954 TRACE(("module_init_post_boot_device() done\n")); 1955 1956 return B_OK; 1957 } 1958 1959 1960 // #pragma mark - Exported Kernel API (public part) 1961 1962 1963 /*! This returns a pointer to a structure that can be used to 1964 iterate through a list of all modules available under 1965 a given prefix that adhere to the specified suffix. 1966 All paths will be searched and the returned list will 1967 contain all modules available under the prefix. 1968 The structure is then used by read_next_module_name(), and 1969 must be freed by calling close_module_list(). 1970 */ 1971 void* 1972 open_module_list_etc(const char* prefix, const char* suffix) 1973 { 1974 TRACE(("open_module_list(prefix = %s)\n", prefix)); 1975 1976 if (sModulesHash == NULL) { 1977 dprintf("open_module_list() called too early!\n"); 1978 return NULL; 1979 } 1980 1981 module_iterator* iterator = (module_iterator*)malloc( 1982 sizeof(module_iterator)); 1983 if (iterator == NULL) 1984 return NULL; 1985 1986 memset(iterator, 0, sizeof(module_iterator)); 1987 1988 iterator->prefix = strdup(prefix != NULL ? prefix : ""); 1989 if (iterator->prefix == NULL) { 1990 free(iterator); 1991 return NULL; 1992 } 1993 iterator->prefix_length = strlen(iterator->prefix); 1994 1995 iterator->suffix = suffix; 1996 if (suffix != NULL) 1997 iterator->suffix_length = strlen(iterator->suffix); 1998 1999 if (gBootDevice > 0) { 2000 // We do have a boot device to scan 2001 2002 // first, we'll traverse over the built-in modules 2003 iterator->builtin_modules = true; 2004 iterator->loaded_modules = false; 2005 2006 // put all search paths on the stack 2007 for (uint32 i = 0; i < kNumModulePaths; i++) { 2008 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 2009 break; 2010 2011 KPath pathBuffer; 2012 if (find_directory(kModulePaths[i], gBootDevice, true, 2013 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 2014 continue; 2015 2016 pathBuffer.UnlockBuffer(); 2017 pathBuffer.Append("kernel"); 2018 2019 // Copy base path onto the iterator stack 2020 char* path = strdup(pathBuffer.Path()); 2021 if (path == NULL) 2022 continue; 2023 2024 size_t length = strlen(path); 2025 2026 // TODO: it would currently be nicer to use the commented 2027 // version below, but the iterator won't work if the prefix 2028 // is inside a module then. 2029 // It works this way, but should be done better. 2030 #if 0 2031 // Build path component: base path + '/' + prefix 2032 size_t length = strlen(sModulePaths[i]); 2033 char* path = (char*)malloc(length + iterator->prefix_length + 2); 2034 if (path == NULL) { 2035 // ToDo: should we abort the whole operation here? 2036 // if we do, don't forget to empty the stack 2037 continue; 2038 } 2039 2040 memcpy(path, sModulePaths[i], length); 2041 path[length] = '/'; 2042 memcpy(path + length + 1, iterator->prefix, 2043 iterator->prefix_length + 1); 2044 #endif 2045 2046 iterator_push_path_on_stack(iterator, path, length + 1); 2047 } 2048 } else { 2049 // include loaded modules in case there is no boot device yet 2050 iterator->builtin_modules = false; 2051 iterator->loaded_modules = true; 2052 } 2053 2054 return (void*)iterator; 2055 } 2056 2057 2058 void* 2059 open_module_list(const char* prefix) 2060 { 2061 return open_module_list_etc(prefix, NULL); 2062 } 2063 2064 2065 /*! Frees the cookie allocated by open_module_list() */ 2066 status_t 2067 close_module_list(void* cookie) 2068 { 2069 module_iterator* iterator = (module_iterator*)cookie; 2070 const char* path; 2071 2072 TRACE(("close_module_list()\n")); 2073 2074 if (iterator == NULL) 2075 return B_BAD_VALUE; 2076 2077 // free stack 2078 while ((path = iterator_pop_path_from_stack(iterator, NULL)) != NULL) 2079 free((char*)path); 2080 2081 // close what have been left open 2082 if (iterator->module_image != NULL) 2083 put_module_image(iterator->module_image); 2084 2085 if (iterator->current_dir != NULL) 2086 closedir(iterator->current_dir); 2087 2088 free(iterator->stack); 2089 free((char*)iterator->current_path); 2090 free((char*)iterator->current_module_path); 2091 2092 free(iterator->prefix); 2093 free(iterator); 2094 2095 return B_OK; 2096 } 2097 2098 2099 /*! Return the next module name from the available list, using 2100 a structure previously created by a call to open_module_list(). 2101 Returns B_OK as long as it found another module, B_ENTRY_NOT_FOUND 2102 when done. 2103 */ 2104 status_t 2105 read_next_module_name(void* cookie, char* buffer, size_t* _bufferSize) 2106 { 2107 module_iterator* iterator = (module_iterator*)cookie; 2108 status_t status; 2109 2110 TRACE(("read_next_module_name: looking for next module\n")); 2111 2112 if (iterator == NULL || buffer == NULL || _bufferSize == NULL) 2113 return B_BAD_VALUE; 2114 2115 if (iterator->status < B_OK) 2116 return iterator->status; 2117 2118 status = iterator->status; 2119 recursive_lock_lock(&sModulesLock); 2120 2121 status = iterator_get_next_module(iterator, buffer, _bufferSize); 2122 2123 iterator->status = status; 2124 recursive_lock_unlock(&sModulesLock); 2125 2126 TRACE(("read_next_module_name: finished with status %s\n", 2127 strerror(status))); 2128 return status; 2129 } 2130 2131 2132 /*! Iterates through all loaded modules, and stores its path in "buffer". 2133 TODO: check if the function in BeOS really does that (could also mean: 2134 iterate through all modules that are currently loaded; have a valid 2135 module_image pointer) 2136 */ 2137 status_t 2138 get_next_loaded_module_name(uint32* _cookie, char* buffer, size_t* _bufferSize) 2139 { 2140 if (sModulesHash == NULL) { 2141 dprintf("get_next_loaded_module_name() called too early!\n"); 2142 return B_ERROR; 2143 } 2144 2145 //TRACE(("get_next_loaded_module_name(\"%s\")\n", buffer)); 2146 2147 if (_cookie == NULL || buffer == NULL || _bufferSize == NULL) 2148 return B_BAD_VALUE; 2149 2150 status_t status = B_ENTRY_NOT_FOUND; 2151 uint32 offset = *_cookie; 2152 2153 RecursiveLocker _(sModulesLock); 2154 2155 hash_iterator iterator; 2156 hash_open(sModulesHash, &iterator); 2157 struct module* module = (struct module*)hash_next(sModulesHash, &iterator); 2158 2159 for (uint32 i = 0; module != NULL; i++) { 2160 if (i >= offset) { 2161 *_bufferSize = strlcpy(buffer, module->name, *_bufferSize); 2162 *_cookie = i + 1; 2163 status = B_OK; 2164 break; 2165 } 2166 module = (struct module*)hash_next(sModulesHash, &iterator); 2167 } 2168 2169 hash_close(sModulesHash, &iterator, false); 2170 2171 return status; 2172 } 2173 2174 2175 status_t 2176 get_module(const char* path, module_info** _info) 2177 { 2178 module_image* moduleImage = NULL; 2179 module* module; 2180 status_t status; 2181 2182 TRACE(("get_module(%s)\n", path)); 2183 2184 if (path == NULL) 2185 return B_BAD_VALUE; 2186 2187 RecursiveLocker _(sModulesLock); 2188 2189 module = (struct module*)hash_lookup(sModulesHash, path); 2190 2191 // if we don't have it cached yet, search for it 2192 if (module == NULL || ((module->flags & B_BUILT_IN_MODULE) == 0 2193 && module->module_image == NULL)) { 2194 module = search_module(path, &moduleImage); 2195 if (module == NULL) { 2196 FATAL(("module: Search for %s failed.\n", path)); 2197 return B_ENTRY_NOT_FOUND; 2198 } 2199 2200 module->info = moduleImage->info[module->offset]; 2201 module->module_image = moduleImage; 2202 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 && gBootDevice < 0 2203 && module->ref_count == 0) { 2204 // The boot volume isn't available yet. I.e. instead of searching the 2205 // right module image, we already know it and just increment the ref 2206 // count. 2207 atomic_add(&module->module_image->ref_count, 1); 2208 } 2209 2210 // The state will be adjusted by the call to init_module 2211 // if we have just loaded the file 2212 if (module->ref_count == 0) { 2213 status = init_module(module); 2214 // For "keep loaded" modules we increment the ref count here. That will 2215 // cause them never to get unloaded. 2216 if (status == B_OK && (module->flags & B_KEEP_LOADED) != 0) 2217 module->ref_count++; 2218 } else 2219 status = B_OK; 2220 2221 if (status == B_OK) { 2222 ASSERT(module->ref_count >= 0); 2223 module->ref_count++; 2224 *_info = module->info; 2225 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 2226 && module->ref_count == 0) { 2227 // initialization failed -- release the image reference 2228 put_module_image(module->module_image); 2229 if (gBootDevice >= 0) 2230 module->module_image = NULL; 2231 } 2232 2233 return status; 2234 } 2235 2236 2237 status_t 2238 put_module(const char* path) 2239 { 2240 module* module; 2241 2242 TRACE(("put_module(path = %s)\n", path)); 2243 2244 RecursiveLocker _(sModulesLock); 2245 2246 module = (struct module*)hash_lookup(sModulesHash, path); 2247 if (module == NULL) { 2248 FATAL(("module: We don't seem to have a reference to module %s\n", 2249 path)); 2250 return B_BAD_VALUE; 2251 } 2252 2253 if (module->ref_count == 0) { 2254 panic("module %s has no references.\n", path); 2255 return B_BAD_VALUE; 2256 } 2257 2258 if (--module->ref_count == 0) { 2259 if ((module->flags & B_KEEP_LOADED) != 0) { 2260 panic("ref count of B_KEEP_LOADED module %s dropped to 0!", 2261 module->name); 2262 module->ref_count++; 2263 return B_BAD_VALUE; 2264 } 2265 2266 uninit_module(module); 2267 2268 if ((module->flags & B_BUILT_IN_MODULE) == 0 2269 && module->ref_count == 0) { 2270 // uninit_module() increments the ref count on failure 2271 put_module_image(module->module_image); 2272 // Unless we don't have a boot device yet, we clear the module's 2273 // image pointer if the ref count dropped to 0. get_module() will 2274 // have to reload the image. 2275 if (gBootDevice >= 0) 2276 module->module_image = NULL; 2277 } 2278 } 2279 2280 return B_OK; 2281 } 2282