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