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