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