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