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