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