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 = %" B_PRId32 "\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.Pointer())); 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\" (%" B_PRId32 "), refcount = %" B_PRId32 ", " 1176 "state = %d, 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 = %" B_PRId32 "), info = %p, refcount = " 1188 "%" B_PRId32 "\n", image, image->path, image->image, image->info, 1189 image->ref_count); 1190 } 1191 return 0; 1192 } 1193 1194 1195 // #pragma mark - DirectoryWatcher 1196 1197 1198 DirectoryWatcher::DirectoryWatcher() 1199 { 1200 } 1201 1202 1203 DirectoryWatcher::~DirectoryWatcher() 1204 { 1205 } 1206 1207 1208 void 1209 DirectoryWatcher::EventOccurred(NotificationService& service, 1210 const KMessage* event) 1211 { 1212 int32 opcode = event->GetInt32("opcode", -1); 1213 dev_t device = event->GetInt32("device", -1); 1214 ino_t directory = event->GetInt64("directory", -1); 1215 ino_t node = event->GetInt64("node", -1); 1216 const char *name = event->GetString("name", NULL); 1217 1218 if (opcode == B_ENTRY_MOVED) { 1219 // Determine whether it's a move within, out of, or into one 1220 // of our watched directories. 1221 directory = event->GetInt64("to directory", -1); 1222 if (!sModuleNotificationService.HasNode(device, directory)) { 1223 directory = event->GetInt64("from directory", -1); 1224 opcode = B_ENTRY_REMOVED; 1225 } else { 1226 // Move within, doesn't sound like a good idea for modules 1227 opcode = B_ENTRY_CREATED; 1228 } 1229 } 1230 1231 sModuleNotificationService.Notify(opcode, device, directory, node, name); 1232 } 1233 1234 1235 // #pragma mark - ModuleWatcher 1236 1237 1238 ModuleWatcher::ModuleWatcher() 1239 { 1240 } 1241 1242 1243 ModuleWatcher::~ModuleWatcher() 1244 { 1245 } 1246 1247 1248 void 1249 ModuleWatcher::EventOccurred(NotificationService& service, const KMessage* event) 1250 { 1251 if (event->GetInt32("opcode", -1) != B_STAT_CHANGED 1252 || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0) 1253 return; 1254 1255 dev_t device = event->GetInt32("device", -1); 1256 ino_t node = event->GetInt64("node", -1); 1257 1258 sModuleNotificationService.Notify(B_STAT_CHANGED, device, -1, node, NULL); 1259 } 1260 1261 1262 // #pragma mark - ModuleNotificationService 1263 1264 1265 ModuleNotificationService::ModuleNotificationService() 1266 { 1267 recursive_lock_init(&fLock, "module notifications"); 1268 } 1269 1270 1271 ModuleNotificationService::~ModuleNotificationService() 1272 { 1273 recursive_lock_destroy(&fLock); 1274 } 1275 1276 1277 status_t 1278 ModuleNotificationService::AddListener(const KMessage* eventSpecifier, 1279 NotificationListener& listener) 1280 { 1281 const char* prefix = eventSpecifier->GetString("prefix", NULL); 1282 if (prefix == NULL) 1283 return B_BAD_VALUE; 1284 1285 module_listener* moduleListener = new(std::nothrow) module_listener; 1286 if (moduleListener == NULL) 1287 return B_NO_MEMORY; 1288 1289 moduleListener->prefix = strdup(prefix); 1290 if (moduleListener->prefix == NULL) { 1291 delete moduleListener; 1292 return B_NO_MEMORY; 1293 } 1294 1295 status_t status = _AddDirectory(prefix); 1296 if (status != B_OK) { 1297 delete moduleListener; 1298 return status; 1299 } 1300 1301 moduleListener->listener = &listener; 1302 fListeners.Add(moduleListener); 1303 1304 return B_OK; 1305 } 1306 1307 1308 status_t 1309 ModuleNotificationService::UpdateListener(const KMessage* eventSpecifier, 1310 NotificationListener& listener) 1311 { 1312 return B_ERROR; 1313 } 1314 1315 1316 status_t 1317 ModuleNotificationService::RemoveListener(const KMessage* eventSpecifier, 1318 NotificationListener& listener) 1319 { 1320 return B_ERROR; 1321 } 1322 1323 1324 bool 1325 ModuleNotificationService::HasNode(dev_t device, ino_t node) 1326 { 1327 RecursiveLocker _(fLock); 1328 1329 struct entry entry = {device, node}; 1330 return fNodes.Lookup(&entry) != NULL; 1331 } 1332 1333 1334 status_t 1335 ModuleNotificationService::_RemoveNode(dev_t device, ino_t node) 1336 { 1337 RecursiveLocker _(fLock); 1338 1339 struct entry key = {device, node}; 1340 hash_entry* entry = fNodes.Lookup(&key); 1341 if (entry == NULL) 1342 return B_ENTRY_NOT_FOUND; 1343 1344 remove_node_listener(device, node, entry->path != NULL 1345 ? (NotificationListener&)fModuleWatcher 1346 : (NotificationListener&)fDirectoryWatcher); 1347 1348 fNodes.Remove(entry); 1349 delete entry; 1350 1351 return B_OK; 1352 } 1353 1354 1355 status_t 1356 ModuleNotificationService::_AddNode(dev_t device, ino_t node, const char* path, 1357 uint32 flags, NotificationListener& listener) 1358 { 1359 RecursiveLocker locker(fLock); 1360 1361 if (HasNode(device, node)) 1362 return B_OK; 1363 1364 struct hash_entry* entry = new(std::nothrow) hash_entry; 1365 if (entry == NULL) 1366 return B_NO_MEMORY; 1367 1368 if (path != NULL) { 1369 entry->path = strdup(path); 1370 if (entry->path == NULL) { 1371 delete entry; 1372 return B_NO_MEMORY; 1373 } 1374 } else 1375 entry->path = NULL; 1376 1377 status_t status = add_node_listener(device, node, flags, listener); 1378 if (status != B_OK) { 1379 delete entry; 1380 return status; 1381 } 1382 1383 //dprintf(" add %s %ld:%Ld (%s)\n", flags == B_WATCH_DIRECTORY 1384 // ? "dir" : "file", device, node, path); 1385 1386 entry->device = device; 1387 entry->node = node; 1388 fNodes.Insert(entry); 1389 1390 return B_OK; 1391 } 1392 1393 1394 status_t 1395 ModuleNotificationService::_AddDirectoryNode(dev_t device, ino_t node) 1396 { 1397 return _AddNode(device, node, NULL, B_WATCH_DIRECTORY, fDirectoryWatcher); 1398 } 1399 1400 1401 status_t 1402 ModuleNotificationService::_AddModuleNode(dev_t device, ino_t node, int fd, 1403 const char* name) 1404 { 1405 struct vnode* vnode; 1406 status_t status = vfs_get_vnode_from_fd(fd, true, &vnode); 1407 if (status != B_OK) 1408 return status; 1409 1410 ino_t directory; 1411 vfs_vnode_to_node_ref(vnode, &device, &directory); 1412 1413 KPath path; 1414 status = path.InitCheck(); 1415 if (status == B_OK) { 1416 status = vfs_entry_ref_to_path(device, directory, name, true, 1417 path.LockBuffer(), path.BufferSize()); 1418 } 1419 if (status != B_OK) 1420 return status; 1421 1422 path.UnlockBuffer(); 1423 1424 return _AddNode(device, node, path.Path(), B_WATCH_STAT, fModuleWatcher); 1425 } 1426 1427 1428 status_t 1429 ModuleNotificationService::_AddDirectory(const char* prefix) 1430 { 1431 status_t status = B_ERROR; 1432 1433 for (uint32 i = 0; i < kNumModulePaths; i++) { 1434 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 1435 break; 1436 1437 KPath pathBuffer; 1438 if (find_directory(kModulePaths[i], gBootDevice, true, 1439 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 1440 continue; 1441 1442 pathBuffer.UnlockBuffer(); 1443 pathBuffer.Append("kernel"); 1444 pathBuffer.Append(prefix); 1445 1446 size_t prefixPosition = strlen(prefix); 1447 status_t scanStatus = _ScanDirectory(pathBuffer.LockBuffer(), prefix, 1448 prefixPosition); 1449 1450 pathBuffer.UnlockBuffer(); 1451 1452 // It's enough if we succeed for one directory 1453 if (status != B_OK) 1454 status = scanStatus; 1455 } 1456 1457 return status; 1458 } 1459 1460 1461 status_t 1462 ModuleNotificationService::_ScanDirectory(char* directoryPath, 1463 const char* prefix, size_t& prefixPosition) 1464 { 1465 DIR* dir = NULL; 1466 while (true) { 1467 dir = opendir(directoryPath); 1468 if (dir != NULL || prefixPosition == 0) 1469 break; 1470 1471 // the full prefix is not accessible, remove path components 1472 const char* parentPrefix = prefix + prefixPosition - 1; 1473 while (parentPrefix != prefix && parentPrefix[0] != '/') 1474 parentPrefix--; 1475 1476 size_t cutPosition = parentPrefix - prefix; 1477 size_t length = strlen(directoryPath); 1478 directoryPath[length - prefixPosition + cutPosition] = '\0'; 1479 prefixPosition = cutPosition; 1480 } 1481 1482 if (dir == NULL) 1483 return B_ERROR; 1484 1485 Stack<DIR*> stack; 1486 stack.Push(dir); 1487 1488 while (stack.Pop(&dir)) { 1489 status_t status = _ScanDirectory(stack, dir, prefix, prefixPosition); 1490 if (status != B_OK) 1491 return status; 1492 } 1493 1494 return B_OK; 1495 } 1496 1497 1498 status_t 1499 ModuleNotificationService::_ScanDirectory(Stack<DIR*>& stack, DIR* dir, 1500 const char* prefix, size_t prefixPosition) 1501 { 1502 bool directMatchAdded = false; 1503 struct dirent* dirent; 1504 1505 while ((dirent = readdir(dir)) != NULL) { 1506 if (dirent->d_name[0] == '.') 1507 continue; 1508 1509 bool directMatch = false; 1510 1511 if (prefix[prefixPosition] != '\0') { 1512 // the start must match 1513 const char* startPrefix = prefix + prefixPosition; 1514 if (startPrefix[0] == '/') 1515 startPrefix++; 1516 1517 const char* endPrefix = strchr(startPrefix, '/'); 1518 size_t length; 1519 1520 if (endPrefix != NULL) 1521 length = endPrefix - startPrefix; 1522 else 1523 length = strlen(startPrefix); 1524 1525 if (strncmp(dirent->d_name, startPrefix, length)) 1526 continue; 1527 1528 if (dirent->d_name[length] == '\0') 1529 directMatch = true; 1530 } 1531 1532 struct stat stat; 1533 status_t status = vfs_read_stat(dirfd(dir), dirent->d_name, true, &stat, 1534 true); 1535 if (status != B_OK) 1536 continue; 1537 1538 if (S_ISDIR(stat.st_mode)) { 1539 int fd = _kern_open_dir(dirfd(dir), dirent->d_name); 1540 if (fd < 0) 1541 continue; 1542 1543 DIR* subDir = fdopendir(fd); 1544 if (subDir == NULL) { 1545 close(fd); 1546 continue; 1547 } 1548 1549 stack.Push(subDir); 1550 1551 if (_AddDirectoryNode(stat.st_dev, stat.st_ino) == B_OK 1552 && directMatch) 1553 directMatchAdded = true; 1554 } else if (S_ISREG(stat.st_mode)) { 1555 if (_AddModuleNode(stat.st_dev, stat.st_ino, dirfd(dir), 1556 dirent->d_name) == B_OK && directMatch) 1557 directMatchAdded = true; 1558 } 1559 } 1560 1561 if (!directMatchAdded) { 1562 // We need to monitor this directory to see if a matching file 1563 // is added. 1564 struct stat stat; 1565 status_t status = vfs_read_stat(dirfd(dir), NULL, true, &stat, true); 1566 if (status == B_OK) 1567 _AddDirectoryNode(stat.st_dev, stat.st_ino); 1568 } 1569 1570 closedir(dir); 1571 return B_OK; 1572 } 1573 1574 1575 void 1576 ModuleNotificationService::_Notify(int32 opcode, dev_t device, ino_t directory, 1577 ino_t node, const char* name) 1578 { 1579 // construct path 1580 1581 KPath pathBuffer; 1582 const char* path; 1583 1584 if (name != NULL) { 1585 // we have an entry ref 1586 if (pathBuffer.InitCheck() != B_OK 1587 || vfs_entry_ref_to_path(device, directory, name, true, 1588 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 1589 return; 1590 1591 pathBuffer.UnlockBuffer(); 1592 path = pathBuffer.Path(); 1593 } else { 1594 // we only have a node ref 1595 RecursiveLocker _(fLock); 1596 1597 struct entry key = {device, node}; 1598 hash_entry* entry = fNodes.Lookup(&key); 1599 if (entry == NULL || entry->path == NULL) 1600 return; 1601 1602 path = entry->path; 1603 } 1604 1605 // remove kModulePaths from path 1606 1607 for (uint32 i = 0; i < kNumModulePaths; i++) { 1608 KPath modulePath; 1609 if (find_directory(kModulePaths[i], gBootDevice, true, 1610 modulePath.LockBuffer(), modulePath.BufferSize()) != B_OK) 1611 continue; 1612 1613 modulePath.UnlockBuffer(); 1614 modulePath.Append("kernel"); 1615 1616 if (strncmp(path, modulePath.Path(), modulePath.Length())) 1617 continue; 1618 1619 path += modulePath.Length(); 1620 if (path[i] == '/') 1621 path++; 1622 1623 break; 1624 } 1625 1626 KMessage event; 1627 1628 // find listeners by prefix/path 1629 1630 ModuleListenerList::Iterator iterator = fListeners.GetIterator(); 1631 while (iterator.HasNext()) { 1632 module_listener* listener = iterator.Next(); 1633 1634 if (strncmp(path, listener->prefix, strlen(listener->prefix))) 1635 continue; 1636 1637 if (event.IsEmpty()) { 1638 // construct message only when needed 1639 event.AddInt32("opcode", opcode); 1640 event.AddString("path", path); 1641 } 1642 1643 // notify them! 1644 listener->listener->EventOccurred(*this, &event); 1645 1646 // we might need to watch new files now 1647 if (opcode == B_ENTRY_CREATED) 1648 _AddDirectory(listener->prefix); 1649 1650 } 1651 1652 // remove notification listeners, if needed 1653 1654 if (opcode == B_ENTRY_REMOVED) 1655 _RemoveNode(device, node); 1656 } 1657 1658 1659 void 1660 ModuleNotificationService::_HandleNotifications() 1661 { 1662 RecursiveLocker _(fLock); 1663 1664 NotificationList::Iterator iterator = fNotifications.GetIterator(); 1665 while (iterator.HasNext()) { 1666 module_notification* notification = iterator.Next(); 1667 1668 _Notify(notification->opcode, notification->device, 1669 notification->directory, notification->node, notification->name); 1670 1671 iterator.Remove(); 1672 delete notification; 1673 } 1674 } 1675 1676 1677 void 1678 ModuleNotificationService::Notify(int32 opcode, dev_t device, ino_t directory, 1679 ino_t node, const char* name) 1680 { 1681 module_notification* notification = new(std::nothrow) module_notification; 1682 if (notification == NULL) 1683 return; 1684 1685 if (name != NULL) { 1686 notification->name = strdup(name); 1687 if (notification->name == NULL) { 1688 delete notification; 1689 return; 1690 } 1691 } else 1692 notification->name = NULL; 1693 1694 notification->opcode = opcode; 1695 notification->device = device; 1696 notification->directory = directory; 1697 notification->node = node; 1698 1699 RecursiveLocker _(fLock); 1700 fNotifications.Add(notification); 1701 } 1702 1703 1704 /*static*/ void 1705 ModuleNotificationService::HandleNotifications(void */*data*/, 1706 int /*iteration*/) 1707 { 1708 sModuleNotificationService._HandleNotifications(); 1709 } 1710 1711 1712 // #pragma mark - Exported Kernel API (private part) 1713 1714 1715 /*! Unloads a module in case it's not in use. This is the counterpart 1716 to load_module(). 1717 */ 1718 status_t 1719 unload_module(const char* path) 1720 { 1721 struct module_image* moduleImage; 1722 1723 recursive_lock_lock(&sModulesLock); 1724 moduleImage = (module_image*)hash_lookup(sModuleImagesHash, path); 1725 recursive_lock_unlock(&sModulesLock); 1726 1727 if (moduleImage == NULL) 1728 return B_ENTRY_NOT_FOUND; 1729 1730 put_module_image(moduleImage); 1731 return B_OK; 1732 } 1733 1734 1735 /*! Unlike get_module(), this function lets you specify the add-on to 1736 be loaded by path. 1737 However, you must not use the exported modules without having called 1738 get_module() on them. When you're done with the NULL terminated 1739 \a modules array, you have to call unload_module(), no matter if 1740 you're actually using any of the modules or not - of course, the 1741 add-on won't be unloaded until the last put_module(). 1742 */ 1743 status_t 1744 load_module(const char* path, module_info*** _modules) 1745 { 1746 module_image* moduleImage; 1747 status_t status = get_module_image(path, &moduleImage); 1748 if (status != B_OK) 1749 return status; 1750 1751 *_modules = moduleImage->info; 1752 return B_OK; 1753 } 1754 1755 1756 status_t 1757 start_watching_modules(const char* prefix, NotificationListener& listener) 1758 { 1759 KMessage specifier; 1760 status_t status = specifier.AddString("prefix", prefix); 1761 if (status != B_OK) 1762 return status; 1763 1764 return sModuleNotificationService.AddListener(&specifier, listener); 1765 } 1766 1767 1768 status_t 1769 stop_watching_modules(const char* prefix, NotificationListener& listener) 1770 { 1771 KMessage specifier; 1772 status_t status = specifier.AddString("prefix", prefix); 1773 if (status != B_OK) 1774 return status; 1775 1776 return sModuleNotificationService.RemoveListener(&specifier, listener); 1777 } 1778 1779 1780 /*! Setup the module structures and data for use - must be called 1781 before any other module call. 1782 */ 1783 status_t 1784 module_init(kernel_args* args) 1785 { 1786 struct preloaded_image* image; 1787 1788 recursive_lock_init(&sModulesLock, "modules rlock"); 1789 1790 sModulesHash = hash_init(MODULE_HASH_SIZE, 0, module_compare, module_hash); 1791 if (sModulesHash == NULL) 1792 return B_NO_MEMORY; 1793 1794 sModuleImagesHash = hash_init(MODULE_HASH_SIZE, 0, module_image_compare, 1795 module_image_hash); 1796 if (sModuleImagesHash == NULL) 1797 return B_NO_MEMORY; 1798 1799 // register built-in modules 1800 1801 register_builtin_modules(sBuiltInModules); 1802 1803 // register preloaded images 1804 1805 for (image = args->preloaded_images; image != NULL; image = image->next) { 1806 status_t status = register_preloaded_module_image(image); 1807 if (status != B_OK && image->is_module) { 1808 dprintf("Could not register image \"%s\": %s\n", (char *)image->name, 1809 strerror(status)); 1810 } 1811 } 1812 1813 new(&sModuleNotificationService) ModuleNotificationService(); 1814 1815 sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS, 1816 false); 1817 1818 add_debugger_command("modules", &dump_modules, 1819 "list all known & loaded modules"); 1820 1821 return B_OK; 1822 } 1823 1824 1825 status_t 1826 module_init_post_threads(void) 1827 { 1828 return register_kernel_daemon( 1829 &ModuleNotificationService::HandleNotifications, NULL, 10); 1830 // once every second 1831 1832 return B_OK; 1833 } 1834 1835 1836 status_t 1837 module_init_post_boot_device(bool bootingFromBootLoaderVolume) 1838 { 1839 // Remove all unused pre-loaded module images. Now that the boot device is 1840 // available, we can load an image when we need it. 1841 // When the boot volume is also where the boot loader pre-loaded the images 1842 // from, we get the actual paths for those images. 1843 TRACE(("module_init_post_boot_device(%d)\n", bootingFromBootLoaderVolume)); 1844 1845 RecursiveLocker _(sModulesLock); 1846 1847 // First of all, clear all pre-loaded module's module_image, if the module 1848 // isn't in use. 1849 hash_iterator iterator; 1850 hash_open(sModulesHash, &iterator); 1851 struct module* module; 1852 while ((module = (struct module*)hash_next(sModulesHash, &iterator)) 1853 != NULL) { 1854 if (module->ref_count == 0 1855 && (module->flags & B_BUILT_IN_MODULE) == 0) { 1856 TRACE((" module %p, \"%s\" unused, clearing image\n", module, 1857 module->name)); 1858 module->module_image = NULL; 1859 } 1860 } 1861 1862 // Now iterate through the images and drop them respectively normalize their 1863 // paths. 1864 hash_open(sModuleImagesHash, &iterator); 1865 1866 module_image* imagesToReinsert = NULL; 1867 // When renamed, an image is added to this list to be re-entered in the 1868 // hash at the end. We can't do that during the iteration. 1869 1870 while (true) { 1871 struct module_image* image 1872 = (struct module_image*)hash_next(sModuleImagesHash, &iterator); 1873 if (image == NULL) 1874 break; 1875 1876 if (image->ref_count == 0) { 1877 // not in use -- unload it 1878 TRACE((" module image %p, \"%s\" unused, removing\n", image, 1879 image->path)); 1880 hash_remove_current(sModuleImagesHash, &iterator); 1881 unload_module_image(image, false); 1882 } else if (bootingFromBootLoaderVolume) { 1883 bool pathNormalized = false; 1884 KPath pathBuffer; 1885 if (image->path[0] != '/') { 1886 // relative path 1887 for (uint32 i = kNumModulePaths; i-- > 0;) { 1888 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 1889 continue; 1890 1891 if (find_directory(kModulePaths[i], gBootDevice, true, 1892 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) 1893 != B_OK) { 1894 pathBuffer.UnlockBuffer(); 1895 continue; 1896 } 1897 1898 pathBuffer.UnlockBuffer(); 1899 1900 // Append the relative boot module directory and the 1901 // relative image path, normalize the path, and check 1902 // whether it exists. 1903 struct stat st; 1904 if (pathBuffer.Append("kernel/boot") != B_OK 1905 || pathBuffer.Append(image->path) != B_OK 1906 || pathBuffer.Normalize(true) != B_OK 1907 || lstat(pathBuffer.Path(), &st) != 0) { 1908 continue; 1909 } 1910 1911 pathNormalized = true; 1912 break; 1913 } 1914 } else { 1915 // absolute path -- try to normalize it anyway 1916 struct stat st; 1917 if (pathBuffer.SetPath(image->path) == B_OK 1918 && pathBuffer.Normalize(true) == B_OK 1919 && lstat(pathBuffer.Path(), &st) == 0) { 1920 pathNormalized = true; 1921 } 1922 } 1923 1924 if (pathNormalized) { 1925 TRACE((" normalized path of module image %p, \"%s\" -> " 1926 "\"%s\"\n", image, image->path, pathBuffer.Path())); 1927 1928 // set the new path 1929 free(image->path); 1930 size_t pathLen = pathBuffer.Length(); 1931 image->path = (char*)realloc(pathBuffer.DetachBuffer(), 1932 pathLen + 1); 1933 1934 // remove the image -- its hash value has probably changed, 1935 // so we need to re-insert it later 1936 hash_remove_current(sModuleImagesHash, &iterator); 1937 image->next = imagesToReinsert; 1938 imagesToReinsert = image; 1939 } else { 1940 dprintf("module_init_post_boot_device() failed to normalize " 1941 "path of module image %p, \"%s\"\n", image, image->path); 1942 } 1943 } 1944 } 1945 1946 // re-insert the images that have got a new path 1947 while (module_image* image = imagesToReinsert) { 1948 imagesToReinsert = image->next; 1949 hash_insert(sModuleImagesHash, image); 1950 } 1951 1952 TRACE(("module_init_post_boot_device() done\n")); 1953 1954 return B_OK; 1955 } 1956 1957 1958 // #pragma mark - Exported Kernel API (public part) 1959 1960 1961 /*! This returns a pointer to a structure that can be used to 1962 iterate through a list of all modules available under 1963 a given prefix that adhere to the specified suffix. 1964 All paths will be searched and the returned list will 1965 contain all modules available under the prefix. 1966 The structure is then used by read_next_module_name(), and 1967 must be freed by calling close_module_list(). 1968 */ 1969 void* 1970 open_module_list_etc(const char* prefix, const char* suffix) 1971 { 1972 TRACE(("open_module_list(prefix = %s)\n", prefix)); 1973 1974 if (sModulesHash == NULL) { 1975 dprintf("open_module_list() called too early!\n"); 1976 return NULL; 1977 } 1978 1979 module_iterator* iterator = (module_iterator*)malloc( 1980 sizeof(module_iterator)); 1981 if (iterator == NULL) 1982 return NULL; 1983 1984 memset(iterator, 0, sizeof(module_iterator)); 1985 1986 iterator->prefix = strdup(prefix != NULL ? prefix : ""); 1987 if (iterator->prefix == NULL) { 1988 free(iterator); 1989 return NULL; 1990 } 1991 iterator->prefix_length = strlen(iterator->prefix); 1992 1993 iterator->suffix = suffix; 1994 if (suffix != NULL) 1995 iterator->suffix_length = strlen(iterator->suffix); 1996 1997 if (gBootDevice > 0) { 1998 // We do have a boot device to scan 1999 2000 // first, we'll traverse over the built-in modules 2001 iterator->builtin_modules = true; 2002 iterator->loaded_modules = false; 2003 2004 // put all search paths on the stack 2005 for (uint32 i = 0; i < kNumModulePaths; i++) { 2006 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath) 2007 break; 2008 2009 KPath pathBuffer; 2010 if (find_directory(kModulePaths[i], gBootDevice, true, 2011 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK) 2012 continue; 2013 2014 pathBuffer.UnlockBuffer(); 2015 pathBuffer.Append("kernel"); 2016 2017 // Copy base path onto the iterator stack 2018 char* path = strdup(pathBuffer.Path()); 2019 if (path == NULL) 2020 continue; 2021 2022 size_t length = strlen(path); 2023 2024 // TODO: it would currently be nicer to use the commented 2025 // version below, but the iterator won't work if the prefix 2026 // is inside a module then. 2027 // It works this way, but should be done better. 2028 #if 0 2029 // Build path component: base path + '/' + prefix 2030 size_t length = strlen(sModulePaths[i]); 2031 char* path = (char*)malloc(length + iterator->prefix_length + 2); 2032 if (path == NULL) { 2033 // ToDo: should we abort the whole operation here? 2034 // if we do, don't forget to empty the stack 2035 continue; 2036 } 2037 2038 memcpy(path, sModulePaths[i], length); 2039 path[length] = '/'; 2040 memcpy(path + length + 1, iterator->prefix, 2041 iterator->prefix_length + 1); 2042 #endif 2043 2044 iterator_push_path_on_stack(iterator, path, length + 1); 2045 } 2046 } else { 2047 // include loaded modules in case there is no boot device yet 2048 iterator->builtin_modules = false; 2049 iterator->loaded_modules = true; 2050 } 2051 2052 return (void*)iterator; 2053 } 2054 2055 2056 void* 2057 open_module_list(const char* prefix) 2058 { 2059 return open_module_list_etc(prefix, NULL); 2060 } 2061 2062 2063 /*! Frees the cookie allocated by open_module_list() */ 2064 status_t 2065 close_module_list(void* cookie) 2066 { 2067 module_iterator* iterator = (module_iterator*)cookie; 2068 const char* path; 2069 2070 TRACE(("close_module_list()\n")); 2071 2072 if (iterator == NULL) 2073 return B_BAD_VALUE; 2074 2075 // free stack 2076 while ((path = iterator_pop_path_from_stack(iterator, NULL)) != NULL) 2077 free((char*)path); 2078 2079 // close what have been left open 2080 if (iterator->module_image != NULL) 2081 put_module_image(iterator->module_image); 2082 2083 if (iterator->current_dir != NULL) 2084 closedir(iterator->current_dir); 2085 2086 free(iterator->stack); 2087 free((char*)iterator->current_path); 2088 free((char*)iterator->current_module_path); 2089 2090 free(iterator->prefix); 2091 free(iterator); 2092 2093 return B_OK; 2094 } 2095 2096 2097 /*! Return the next module name from the available list, using 2098 a structure previously created by a call to open_module_list(). 2099 Returns B_OK as long as it found another module, B_ENTRY_NOT_FOUND 2100 when done. 2101 */ 2102 status_t 2103 read_next_module_name(void* cookie, char* buffer, size_t* _bufferSize) 2104 { 2105 module_iterator* iterator = (module_iterator*)cookie; 2106 status_t status; 2107 2108 TRACE(("read_next_module_name: looking for next module\n")); 2109 2110 if (iterator == NULL || buffer == NULL || _bufferSize == NULL) 2111 return B_BAD_VALUE; 2112 2113 if (iterator->status < B_OK) 2114 return iterator->status; 2115 2116 status = iterator->status; 2117 recursive_lock_lock(&sModulesLock); 2118 2119 status = iterator_get_next_module(iterator, buffer, _bufferSize); 2120 2121 iterator->status = status; 2122 recursive_lock_unlock(&sModulesLock); 2123 2124 TRACE(("read_next_module_name: finished with status %s\n", 2125 strerror(status))); 2126 return status; 2127 } 2128 2129 2130 /*! Iterates through all loaded modules, and stores its path in "buffer". 2131 TODO: check if the function in BeOS really does that (could also mean: 2132 iterate through all modules that are currently loaded; have a valid 2133 module_image pointer) 2134 */ 2135 status_t 2136 get_next_loaded_module_name(uint32* _cookie, char* buffer, size_t* _bufferSize) 2137 { 2138 if (sModulesHash == NULL) { 2139 dprintf("get_next_loaded_module_name() called too early!\n"); 2140 return B_ERROR; 2141 } 2142 2143 //TRACE(("get_next_loaded_module_name(\"%s\")\n", buffer)); 2144 2145 if (_cookie == NULL || buffer == NULL || _bufferSize == NULL) 2146 return B_BAD_VALUE; 2147 2148 status_t status = B_ENTRY_NOT_FOUND; 2149 uint32 offset = *_cookie; 2150 2151 RecursiveLocker _(sModulesLock); 2152 2153 hash_iterator iterator; 2154 hash_open(sModulesHash, &iterator); 2155 struct module* module = (struct module*)hash_next(sModulesHash, &iterator); 2156 2157 for (uint32 i = 0; module != NULL; i++) { 2158 if (i >= offset) { 2159 *_bufferSize = strlcpy(buffer, module->name, *_bufferSize); 2160 *_cookie = i + 1; 2161 status = B_OK; 2162 break; 2163 } 2164 module = (struct module*)hash_next(sModulesHash, &iterator); 2165 } 2166 2167 hash_close(sModulesHash, &iterator, false); 2168 2169 return status; 2170 } 2171 2172 2173 status_t 2174 get_module(const char* path, module_info** _info) 2175 { 2176 module_image* moduleImage = NULL; 2177 module* module; 2178 status_t status; 2179 2180 TRACE(("get_module(%s)\n", path)); 2181 2182 if (path == NULL) 2183 return B_BAD_VALUE; 2184 2185 RecursiveLocker _(sModulesLock); 2186 2187 module = (struct module*)hash_lookup(sModulesHash, path); 2188 2189 // if we don't have it cached yet, search for it 2190 if (module == NULL || ((module->flags & B_BUILT_IN_MODULE) == 0 2191 && module->module_image == NULL)) { 2192 module = search_module(path, &moduleImage); 2193 if (module == NULL) { 2194 FATAL(("module: Search for %s failed.\n", path)); 2195 return B_ENTRY_NOT_FOUND; 2196 } 2197 2198 module->info = moduleImage->info[module->offset]; 2199 module->module_image = moduleImage; 2200 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 && gBootDevice < 0 2201 && module->ref_count == 0) { 2202 // The boot volume isn't available yet. I.e. instead of searching the 2203 // right module image, we already know it and just increment the ref 2204 // count. 2205 atomic_add(&module->module_image->ref_count, 1); 2206 } 2207 2208 // The state will be adjusted by the call to init_module 2209 // if we have just loaded the file 2210 if (module->ref_count == 0) { 2211 status = init_module(module); 2212 // For "keep loaded" modules we increment the ref count here. That will 2213 // cause them never to get unloaded. 2214 if (status == B_OK && (module->flags & B_KEEP_LOADED) != 0) 2215 module->ref_count++; 2216 } else 2217 status = B_OK; 2218 2219 if (status == B_OK) { 2220 ASSERT(module->ref_count >= 0); 2221 module->ref_count++; 2222 *_info = module->info; 2223 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 2224 && module->ref_count == 0) { 2225 // initialization failed -- release the image reference 2226 put_module_image(module->module_image); 2227 if (gBootDevice >= 0) 2228 module->module_image = NULL; 2229 } 2230 2231 return status; 2232 } 2233 2234 2235 status_t 2236 put_module(const char* path) 2237 { 2238 module* module; 2239 2240 TRACE(("put_module(path = %s)\n", path)); 2241 2242 RecursiveLocker _(sModulesLock); 2243 2244 module = (struct module*)hash_lookup(sModulesHash, path); 2245 if (module == NULL) { 2246 FATAL(("module: We don't seem to have a reference to module %s\n", 2247 path)); 2248 return B_BAD_VALUE; 2249 } 2250 2251 if (module->ref_count == 0) { 2252 panic("module %s has no references.\n", path); 2253 return B_BAD_VALUE; 2254 } 2255 2256 if (--module->ref_count == 0) { 2257 if ((module->flags & B_KEEP_LOADED) != 0) { 2258 panic("ref count of B_KEEP_LOADED module %s dropped to 0!", 2259 module->name); 2260 module->ref_count++; 2261 return B_BAD_VALUE; 2262 } 2263 2264 uninit_module(module); 2265 2266 if ((module->flags & B_BUILT_IN_MODULE) == 0 2267 && module->ref_count == 0) { 2268 // uninit_module() increments the ref count on failure 2269 put_module_image(module->module_image); 2270 // Unless we don't have a boot device yet, we clear the module's 2271 // image pointer if the ref count dropped to 0. get_module() will 2272 // have to reload the image. 2273 if (gBootDevice >= 0) 2274 module->module_image = NULL; 2275 } 2276 } 2277 2278 return B_OK; 2279 } 2280