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