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 <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:%Ld (%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 start_watching_modules(const char* prefix, NotificationListener& listener) 1747 { 1748 KMessage specifier; 1749 status_t status = specifier.AddString("prefix", prefix); 1750 if (status != B_OK) 1751 return status; 1752 1753 return sModuleNotificationService.AddListener(&specifier, listener); 1754 } 1755 1756 1757 status_t 1758 stop_watching_modules(const char* prefix, NotificationListener& listener) 1759 { 1760 KMessage specifier; 1761 status_t status = specifier.AddString("prefix", prefix); 1762 if (status != B_OK) 1763 return status; 1764 1765 return sModuleNotificationService.RemoveListener(&specifier, listener); 1766 } 1767 1768 1769 /*! Setup the module structures and data for use - must be called 1770 before any other module call. 1771 */ 1772 status_t 1773 module_init(kernel_args* args) 1774 { 1775 struct preloaded_image* image; 1776 1777 recursive_lock_init(&sModulesLock, "modules rlock"); 1778 1779 sModulesHash = new(std::nothrow) ModuleTable(); 1780 if (sModulesHash == NULL 1781 || sModulesHash->Init(MODULE_HASH_SIZE) != B_OK) 1782 return B_NO_MEMORY; 1783 1784 sModuleImagesHash = new(std::nothrow) ImageTable(); 1785 if (sModuleImagesHash == NULL 1786 || sModuleImagesHash->Init(MODULE_HASH_SIZE) != B_OK) 1787 return B_NO_MEMORY; 1788 1789 // register built-in modules 1790 1791 register_builtin_modules(sBuiltInModules); 1792 1793 // register preloaded images 1794 1795 for (image = args->preloaded_images; image != NULL; image = image->next) { 1796 status_t status = register_preloaded_module_image(image); 1797 if (status != B_OK && image->is_module) { 1798 dprintf("Could not register image \"%s\": %s\n", (char *)image->name, 1799 strerror(status)); 1800 } 1801 } 1802 1803 new(&sModuleNotificationService) ModuleNotificationService(); 1804 1805 sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS, 1806 false); 1807 1808 add_debugger_command("modules", &dump_modules, 1809 "list all known & loaded modules"); 1810 1811 return B_OK; 1812 } 1813 1814 1815 status_t 1816 module_init_post_threads(void) 1817 { 1818 return register_kernel_daemon( 1819 &ModuleNotificationService::HandleNotifications, NULL, 10); 1820 // once every second 1821 1822 return B_OK; 1823 } 1824 1825 1826 status_t 1827 module_init_post_boot_device(bool bootingFromBootLoaderVolume) 1828 { 1829 // Remove all unused pre-loaded module images. Now that the boot device is 1830 // available, we can load an image when we need it. 1831 // When the boot volume is also where the boot loader pre-loaded the images 1832 // from, we get the actual paths for those images. 1833 TRACE(("module_init_post_boot_device(%d)\n", bootingFromBootLoaderVolume)); 1834 1835 RecursiveLocker _(sModulesLock); 1836 1837 // First of all, clear all pre-loaded module's module_image, if the module 1838 // isn't in use. 1839 ModuleTable::Iterator iterator(sModulesHash); 1840 struct module* module; 1841 while (iterator.HasNext()) { 1842 module = iterator.Next(); 1843 if (module->ref_count == 0 1844 && (module->flags & B_BUILT_IN_MODULE) == 0) { 1845 TRACE((" module %p, \"%s\" unused, clearing image\n", module, 1846 module->name)); 1847 module->module_image = NULL; 1848 } 1849 } 1850 1851 // Now iterate through the images and drop them respectively normalize their 1852 // paths. 1853 ImageTable::Iterator imageIterator(sModuleImagesHash); 1854 1855 module_image* imagesToReinsert = NULL; 1856 // When renamed, an image is added to this list to be re-entered in the 1857 // hash at the end. We can't do that during the iteration. 1858 1859 while (imageIterator.HasNext()) { 1860 struct module_image* image = imageIterator.Next(); 1861 1862 if (image->ref_count == 0) { 1863 // not in use -- unload it 1864 TRACE((" module image %p, \"%s\" unused, removing\n", image, 1865 image->path)); 1866 // Using RemoveUnchecked to avoid invalidating the iterator 1867 sModuleImagesHash->RemoveUnchecked(image); 1868 unload_module_image(image, false); 1869 } else if (bootingFromBootLoaderVolume) { 1870 bool pathNormalized = false; 1871 KPath pathBuffer; 1872 if (image->path[0] != '/') { 1873 // relative path 1874 for (uint32 i = kNumModulePaths; i-- > 0;) { 1875 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 1876 continue; 1877 1878 if (__find_directory(kModulePaths[i], gBootDevice, true, 1879 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) 1880 != B_OK) { 1881 pathBuffer.UnlockBuffer(); 1882 continue; 1883 } 1884 1885 pathBuffer.UnlockBuffer(); 1886 1887 // Append the relative boot module directory and the 1888 // relative image path, normalize the path, and check 1889 // whether it exists. 1890 struct stat st; 1891 if (pathBuffer.Append("kernel/boot") != B_OK 1892 || pathBuffer.Append(image->path) != B_OK 1893 || pathBuffer.Normalize(true) != B_OK 1894 || lstat(pathBuffer.Path(), &st) != 0) { 1895 continue; 1896 } 1897 1898 pathNormalized = true; 1899 break; 1900 } 1901 } else { 1902 // absolute path -- try to normalize it anyway 1903 struct stat st; 1904 if (pathBuffer.SetPath(image->path) == B_OK 1905 && pathBuffer.Normalize(true) == B_OK 1906 && lstat(pathBuffer.Path(), &st) == 0) { 1907 pathNormalized = true; 1908 } 1909 } 1910 1911 if (pathNormalized) { 1912 TRACE((" normalized path of module image %p, \"%s\" -> " 1913 "\"%s\"\n", image, image->path, pathBuffer.Path())); 1914 1915 // remove the image -- its hash value has probably changed, 1916 // so we need to re-insert it later 1917 sModuleImagesHash->RemoveUnchecked(image); 1918 1919 // set the new path 1920 free(image->path); 1921 size_t pathLen = pathBuffer.Length(); 1922 image->path = (char*)realloc(pathBuffer.DetachBuffer(), 1923 pathLen + 1); 1924 1925 image->next = imagesToReinsert; 1926 imagesToReinsert = image; 1927 } else { 1928 dprintf("module_init_post_boot_device() failed to normalize " 1929 "path of module image %p, \"%s\"\n", image, image->path); 1930 } 1931 } 1932 } 1933 1934 // re-insert the images that have got a new path 1935 while (module_image* image = imagesToReinsert) { 1936 imagesToReinsert = image->next; 1937 sModuleImagesHash->Insert(image); 1938 } 1939 1940 TRACE(("module_init_post_boot_device() done\n")); 1941 1942 return B_OK; 1943 } 1944 1945 1946 // #pragma mark - Exported Kernel API (public part) 1947 1948 1949 /*! This returns a pointer to a structure that can be used to 1950 iterate through a list of all modules available under 1951 a given prefix that adhere to the specified suffix. 1952 All paths will be searched and the returned list will 1953 contain all modules available under the prefix. 1954 The structure is then used by read_next_module_name(), and 1955 must be freed by calling close_module_list(). 1956 */ 1957 void* 1958 open_module_list_etc(const char* prefix, const char* suffix) 1959 { 1960 TRACE(("open_module_list(prefix = %s)\n", prefix)); 1961 1962 if (sModulesHash == NULL) { 1963 dprintf("open_module_list() called too early!\n"); 1964 return NULL; 1965 } 1966 1967 module_iterator* iterator = (module_iterator*)malloc( 1968 sizeof(module_iterator)); 1969 if (iterator == NULL) 1970 return NULL; 1971 1972 memset(iterator, 0, sizeof(module_iterator)); 1973 1974 iterator->prefix = strdup(prefix != NULL ? prefix : ""); 1975 if (iterator->prefix == NULL) { 1976 free(iterator); 1977 return NULL; 1978 } 1979 iterator->prefix_length = strlen(iterator->prefix); 1980 1981 iterator->suffix = suffix; 1982 if (suffix != NULL) 1983 iterator->suffix_length = strlen(iterator->suffix); 1984 1985 if (gBootDevice > 0) { 1986 // We do have a boot device to scan 1987 1988 // first, we'll traverse over the built-in modules 1989 iterator->builtin_modules = true; 1990 iterator->loaded_modules = false; 1991 1992 // put all search paths on the stack 1993 for (uint32 i = 0; i < kNumModulePaths; i++) { 1994 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 1995 break; 1996 1997 KPath pathBuffer; 1998 if (__find_directory(kModulePaths[i], gBootDevice, true, 1999 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 2000 continue; 2001 2002 pathBuffer.UnlockBuffer(); 2003 pathBuffer.Append("kernel"); 2004 2005 // Copy base path onto the iterator stack 2006 char* path = strdup(pathBuffer.Path()); 2007 if (path == NULL) 2008 continue; 2009 2010 size_t length = strlen(path); 2011 2012 // TODO: it would currently be nicer to use the commented 2013 // version below, but the iterator won't work if the prefix 2014 // is inside a module then. 2015 // It works this way, but should be done better. 2016 #if 0 2017 // Build path component: base path + '/' + prefix 2018 size_t length = strlen(sModulePaths[i]); 2019 char* path = (char*)malloc(length + iterator->prefix_length + 2); 2020 if (path == NULL) { 2021 // ToDo: should we abort the whole operation here? 2022 // if we do, don't forget to empty the stack 2023 continue; 2024 } 2025 2026 memcpy(path, sModulePaths[i], length); 2027 path[length] = '/'; 2028 memcpy(path + length + 1, iterator->prefix, 2029 iterator->prefix_length + 1); 2030 #endif 2031 2032 iterator_push_path_on_stack(iterator, path, length + 1); 2033 } 2034 } else { 2035 // include loaded modules in case there is no boot device yet 2036 iterator->builtin_modules = false; 2037 iterator->loaded_modules = true; 2038 } 2039 2040 return (void*)iterator; 2041 } 2042 2043 2044 void* 2045 open_module_list(const char* prefix) 2046 { 2047 return open_module_list_etc(prefix, NULL); 2048 } 2049 2050 2051 /*! Frees the cookie allocated by open_module_list() */ 2052 status_t 2053 close_module_list(void* cookie) 2054 { 2055 module_iterator* iterator = (module_iterator*)cookie; 2056 const char* path; 2057 2058 TRACE(("close_module_list()\n")); 2059 2060 if (iterator == NULL) 2061 return B_BAD_VALUE; 2062 2063 // free stack 2064 while ((path = iterator_pop_path_from_stack(iterator, NULL)) != NULL) 2065 free((char*)path); 2066 2067 // close what have been left open 2068 if (iterator->module_image != NULL) 2069 put_module_image(iterator->module_image); 2070 2071 if (iterator->current_dir != NULL) 2072 closedir(iterator->current_dir); 2073 2074 free(iterator->stack); 2075 free((char*)iterator->current_path); 2076 free((char*)iterator->current_module_path); 2077 2078 free(iterator->prefix); 2079 free(iterator); 2080 2081 return B_OK; 2082 } 2083 2084 2085 /*! Return the next module name from the available list, using 2086 a structure previously created by a call to open_module_list(). 2087 Returns B_OK as long as it found another module, B_ENTRY_NOT_FOUND 2088 when done. 2089 */ 2090 status_t 2091 read_next_module_name(void* cookie, char* buffer, size_t* _bufferSize) 2092 { 2093 module_iterator* iterator = (module_iterator*)cookie; 2094 status_t status; 2095 2096 TRACE(("read_next_module_name: looking for next module\n")); 2097 2098 if (iterator == NULL || buffer == NULL || _bufferSize == NULL) 2099 return B_BAD_VALUE; 2100 2101 if (iterator->status < B_OK) 2102 return iterator->status; 2103 2104 status = iterator->status; 2105 recursive_lock_lock(&sModulesLock); 2106 2107 status = iterator_get_next_module(iterator, buffer, _bufferSize); 2108 2109 iterator->status = status; 2110 recursive_lock_unlock(&sModulesLock); 2111 2112 TRACE(("read_next_module_name: finished with status %s\n", 2113 strerror(status))); 2114 return status; 2115 } 2116 2117 2118 /*! Iterates through all loaded modules, and stores its path in "buffer". 2119 TODO: check if the function in BeOS really does that (could also mean: 2120 iterate through all modules that are currently loaded; have a valid 2121 module_image pointer) 2122 */ 2123 status_t 2124 get_next_loaded_module_name(uint32* _cookie, char* buffer, size_t* _bufferSize) 2125 { 2126 if (sModulesHash == NULL) { 2127 dprintf("get_next_loaded_module_name() called too early!\n"); 2128 return B_ERROR; 2129 } 2130 2131 //TRACE(("get_next_loaded_module_name(\"%s\")\n", buffer)); 2132 2133 if (_cookie == NULL || buffer == NULL || _bufferSize == NULL) 2134 return B_BAD_VALUE; 2135 2136 status_t status = B_ENTRY_NOT_FOUND; 2137 uint32 offset = *_cookie; 2138 2139 RecursiveLocker _(sModulesLock); 2140 2141 ModuleTable::Iterator iterator(sModulesHash); 2142 2143 for (uint32 i = 0; iterator.HasNext(); i++) { 2144 struct module* module = iterator.Next(); 2145 if (i >= offset) { 2146 *_bufferSize = strlcpy(buffer, module->name, *_bufferSize); 2147 *_cookie = i + 1; 2148 status = B_OK; 2149 break; 2150 } 2151 } 2152 2153 return status; 2154 } 2155 2156 2157 status_t 2158 get_module(const char* path, module_info** _info) 2159 { 2160 module_image* moduleImage = NULL; 2161 module* module; 2162 status_t status; 2163 2164 TRACE(("get_module(%s)\n", path)); 2165 2166 if (path == NULL) 2167 return B_BAD_VALUE; 2168 2169 RecursiveLocker _(sModulesLock); 2170 2171 module = sModulesHash->Lookup(path); 2172 2173 // if we don't have it cached yet, search for it 2174 if (module == NULL || ((module->flags & B_BUILT_IN_MODULE) == 0 2175 && module->module_image == NULL)) { 2176 module = search_module(path, &moduleImage); 2177 if (module == NULL) { 2178 FATAL(("module: Search for %s failed.\n", path)); 2179 return B_ENTRY_NOT_FOUND; 2180 } 2181 2182 module->info = moduleImage->info[module->offset]; 2183 module->module_image = moduleImage; 2184 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 && gBootDevice < 0 2185 && module->ref_count == 0) { 2186 // The boot volume isn't available yet. I.e. instead of searching the 2187 // right module image, we already know it and just increment the ref 2188 // count. 2189 atomic_add(&module->module_image->ref_count, 1); 2190 } 2191 2192 // The state will be adjusted by the call to init_module 2193 // if we have just loaded the file 2194 if (module->ref_count == 0) { 2195 status = init_module(module); 2196 // For "keep loaded" modules we increment the ref count here. That will 2197 // cause them never to get unloaded. 2198 if (status == B_OK && (module->flags & B_KEEP_LOADED) != 0) 2199 module->ref_count++; 2200 } else 2201 status = B_OK; 2202 2203 if (status == B_OK) { 2204 ASSERT(module->ref_count >= 0); 2205 module->ref_count++; 2206 *_info = module->info; 2207 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 2208 && module->ref_count == 0) { 2209 // initialization failed -- release the image reference 2210 put_module_image(module->module_image); 2211 if (gBootDevice >= 0) 2212 module->module_image = NULL; 2213 } 2214 2215 return status; 2216 } 2217 2218 2219 status_t 2220 put_module(const char* path) 2221 { 2222 module* module; 2223 2224 TRACE(("put_module(path = %s)\n", path)); 2225 2226 RecursiveLocker _(sModulesLock); 2227 2228 module = sModulesHash->Lookup(path); 2229 if (module == NULL) { 2230 FATAL(("module: We don't seem to have a reference to module %s\n", 2231 path)); 2232 return B_BAD_VALUE; 2233 } 2234 2235 if (module->ref_count == 0) { 2236 panic("module %s has no references.\n", path); 2237 return B_BAD_VALUE; 2238 } 2239 2240 if (--module->ref_count == 0) { 2241 if ((module->flags & B_KEEP_LOADED) != 0) { 2242 panic("ref count of B_KEEP_LOADED module %s dropped to 0!", 2243 module->name); 2244 module->ref_count++; 2245 return B_BAD_VALUE; 2246 } 2247 2248 uninit_module(module); 2249 2250 if ((module->flags & B_BUILT_IN_MODULE) == 0 2251 && module->ref_count == 0) { 2252 // uninit_module() increments the ref count on failure 2253 put_module_image(module->module_image); 2254 // Unless we don't have a boot device yet, we clear the module's 2255 // image pointer if the ref count dropped to 0. get_module() will 2256 // have to reload the image. 2257 if (gBootDevice >= 0) 2258 module->module_image = NULL; 2259 } 2260 } 2261 2262 return B_OK; 2263 } 2264