btrfs: Attempt to fix GCC2 build.
[haiku.git] / src / system / kernel / module.cpp
blob829c2513be74d71bc8cf1985f6d527cee2dedfbe
1 /*
2 * Copyright 2002-2008, Haiku Inc. All rights reserved.
3 * Distributed under the terms of the MIT License.
5 * Copyright 2001, Thomas Kurschel. All rights reserved.
6 * Distributed under the terms of the NewOS License.
7 */
9 /*! Manages kernel add-ons and their exported modules. */
12 #include <kmodule.h>
14 #include <dirent.h>
15 #include <errno.h>
16 #include <stdlib.h>
17 #include <string.h>
18 #include <sys/stat.h>
20 #include <FindDirectory.h>
21 #include <NodeMonitor.h>
23 #include <boot_device.h>
24 #include <boot/elf.h>
25 #include <boot/kernel_args.h>
26 #include <elf.h>
27 #include <find_directory_private.h>
28 #include <fs/KPath.h>
29 #include <fs/node_monitor.h>
30 #include <lock.h>
31 #include <Notifications.h>
32 #include <safemode.h>
33 #include <syscalls.h>
34 #include <util/AutoLock.h>
35 #include <util/Stack.h>
36 #include <vfs.h>
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
48 #define MODULE_HASH_SIZE 16
50 /*! The modules referenced by this structure are built-in
51 modules that can't be loaded from disk.
53 extern module_info gDeviceManagerModule;
54 extern module_info gDeviceRootModule;
55 extern module_info gDeviceGenericModule;
56 extern module_info gFrameBufferConsoleModule;
58 // file systems
59 extern module_info gRootFileSystem;
60 extern module_info gDeviceFileSystem;
62 static module_info* sBuiltInModules[] = {
63 &gDeviceManagerModule,
64 &gDeviceRootModule,
65 &gDeviceGenericModule,
66 &gFrameBufferConsoleModule,
68 &gRootFileSystem,
69 &gDeviceFileSystem,
70 NULL
73 enum module_state {
74 MODULE_QUERIED = 0,
75 MODULE_LOADED,
76 MODULE_INIT,
77 MODULE_READY,
78 MODULE_UNINIT,
79 MODULE_ERROR
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.
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
99 /* Each known module will have this structure which is put in the
100 * gModulesHash, and looked up by name.
103 struct module {
104 struct module* next;
105 ::module_image* module_image;
106 char* name;
107 int32 ref_count;
108 module_info* info; // will only be valid if ref_count > 0
109 int32 offset; // this is the offset in the headers
110 module_state state;
111 uint32 flags;
114 #define B_BUILT_IN_MODULE 2
116 typedef struct module_path {
117 const char* name;
118 uint32 base_length;
119 } module_path;
121 typedef struct module_iterator {
122 module_path* stack;
123 int32 stack_size;
124 int32 stack_current;
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;
144 namespace Module {
146 struct entry {
147 dev_t device;
148 ino_t node;
151 struct hash_entry : entry {
152 ~hash_entry()
154 free((char*)path);
157 hash_entry* hash_link;
158 const char* path;
161 struct NodeHashDefinition {
162 typedef entry* KeyType;
163 typedef hash_entry ValueType;
165 size_t Hash(ValueType* entry) const
166 { return HashKey(entry); }
167 ValueType*& GetLink(ValueType* entry) const
168 { return entry->hash_link; }
170 size_t HashKey(KeyType key) const
172 return ((uint32)(key->node >> 32) + (uint32)key->node) ^ key->device;
175 bool Compare(KeyType key, ValueType* entry) const
177 return key->device == entry->device
178 && key->node == entry->node;
182 typedef BOpenHashTable<NodeHashDefinition> NodeHash;
184 struct module_listener : DoublyLinkedListLinkImpl<module_listener> {
185 ~module_listener()
187 free((char*)prefix);
190 NotificationListener* listener;
191 const char* prefix;
194 typedef DoublyLinkedList<module_listener> ModuleListenerList;
196 struct module_notification : DoublyLinkedListLinkImpl<module_notification> {
197 ~module_notification()
199 free((char*)name);
202 int32 opcode;
203 dev_t device;
204 ino_t directory;
205 ino_t node;
206 const char* name;
209 typedef DoublyLinkedList<module_notification> NotificationList;
211 class DirectoryWatcher : public NotificationListener {
212 public:
213 DirectoryWatcher();
214 virtual ~DirectoryWatcher();
216 virtual void EventOccurred(NotificationService& service,
217 const KMessage* event);
220 class ModuleWatcher : public NotificationListener {
221 public:
222 ModuleWatcher();
223 virtual ~ModuleWatcher();
225 virtual void EventOccurred(NotificationService& service,
226 const KMessage* event);
229 class ModuleNotificationService : public NotificationService {
230 public:
231 ModuleNotificationService();
232 virtual ~ModuleNotificationService();
234 status_t InitCheck();
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);
243 bool HasNode(dev_t device, ino_t node);
245 void Notify(int32 opcode, dev_t device, ino_t directory,
246 ino_t node, const char* name);
248 virtual const char* Name() { return "modules"; }
250 static void HandleNotifications(void *data, int iteration);
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);
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);
266 void _Notify(int32 opcode, dev_t device, ino_t directory,
267 ino_t node, const char* name);
268 void _HandleNotifications();
270 recursive_lock fLock;
271 ModuleListenerList fListeners;
272 NodeHash fNodes;
273 DirectoryWatcher fDirectoryWatcher;
274 ModuleWatcher fModuleWatcher;
275 NotificationList fNotifications;
279 struct ModuleHash {
280 typedef const char* KeyType;
281 typedef module ValueType;
283 size_t Hash(ValueType* module) const
284 { return HashKey(module->name); }
285 ValueType*& GetLink(ValueType* entry) const
286 { return entry->next; }
288 size_t HashKey(KeyType key) const
290 return hash_hash_string(key);
293 bool Compare(KeyType key, ValueType* module) const
295 if (key == NULL)
296 return false;
297 return strcmp(module->name, key) == 0;
301 typedef BOpenHashTable<ModuleHash> ModuleTable;
304 struct ImageHash {
305 typedef const char* KeyType;
306 typedef module_image ValueType;
308 size_t Hash(ValueType* image) const
309 { return HashKey(image->path); }
310 ValueType*& GetLink(ValueType* entry) const
311 { return entry->next; }
313 size_t HashKey(KeyType key) const
315 return hash_hash_string(key);
318 bool Compare(KeyType key, ValueType* image) const
320 if (key == NULL)
321 return false;
322 return strcmp(image->path, key) == 0;
326 typedef BOpenHashTable<ImageHash> ImageTable;
328 } // namespace Module
330 using namespace Module;
332 /* These are the standard base paths where we start to look for modules
333 * to load. Order is important, the last entry here will be searched
334 * first.
336 static const directory_which kModulePaths[] = {
337 B_BEOS_ADDONS_DIRECTORY,
338 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
339 B_USER_ADDONS_DIRECTORY,
340 B_USER_NONPACKAGED_ADDONS_DIRECTORY,
343 static const uint32 kNumModulePaths = sizeof(kModulePaths)
344 / sizeof(kModulePaths[0]);
345 static const uint32 kFirstNonSystemModulePath = 1;
348 static ModuleNotificationService sModuleNotificationService;
349 static bool sDisableUserAddOns = false;
351 /* Locking scheme: There is a global lock only; having several locks
352 makes trouble if dependent modules get loaded concurrently ->
353 they have to wait for each other, i.e. we need one lock per module;
354 also we must detect circular references during init and not dead-lock.
356 Reference counting: get_module() increments the ref count of a module,
357 put_module() decrements it. When a B_KEEP_LOADED module is initialized
358 the ref count is incremented once more, so it never gets
359 uninitialized/unloaded. A referenced module, unless it's built-in, has a
360 non-null module_image and owns a reference to the image. When the last
361 module reference is put, the image's reference is released and module_image
362 zeroed (as long as the boot volume has not been mounted, it is not zeroed).
363 An unreferenced module image is unloaded (when the boot volume is mounted).
365 static recursive_lock sModulesLock;
368 /* We store the loaded modules by directory path, and all known modules
369 * by module name in a hash table for quick access
371 static ImageTable* sModuleImagesHash;
372 static ModuleTable* sModulesHash;
377 /*! Try to load the module image at the specified \a path.
378 If it could be loaded, it returns \c B_OK, and stores a pointer
379 to the module_image object in \a _moduleImage.
380 Needs to be called with the sModulesLock held.
382 static status_t
383 load_module_image(const char* path, module_image** _moduleImage)
385 module_image* moduleImage;
386 status_t status;
387 image_id image;
389 TRACE(("load_module_image(path = \"%s\", _image = %p)\n", path,
390 _moduleImage));
391 ASSERT_LOCKED_RECURSIVE(&sModulesLock);
392 ASSERT(_moduleImage != NULL);
394 image = load_kernel_add_on(path);
395 if (image < 0) {
396 dprintf("load_module_image(%s) failed: %s\n", path, strerror(image));
397 return image;
400 moduleImage = (module_image*)malloc(sizeof(module_image));
401 if (moduleImage == NULL) {
402 status = B_NO_MEMORY;
403 goto err;
406 if (get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
407 (void**)&moduleImage->info) != B_OK) {
408 TRACE(("load_module_image: Failed to load \"%s\" due to lack of "
409 "'modules' symbol\n", path));
410 status = B_BAD_TYPE;
411 goto err1;
414 moduleImage->dependencies = NULL;
415 get_image_symbol(image, "module_dependencies", B_SYMBOL_TYPE_DATA,
416 (void**)&moduleImage->dependencies);
417 // this is allowed to be NULL
419 moduleImage->path = strdup(path);
420 if (!moduleImage->path) {
421 status = B_NO_MEMORY;
422 goto err1;
425 moduleImage->image = image;
426 moduleImage->ref_count = 0;
428 sModuleImagesHash->Insert(moduleImage);
430 TRACE(("load_module_image(\"%s\"): image loaded: %p\n", path, moduleImage));
432 *_moduleImage = moduleImage;
433 return B_OK;
435 err1:
436 free(moduleImage);
437 err:
438 unload_kernel_add_on(image);
440 return status;
444 /*! Unloads the module's kernel add-on. The \a image will be freed.
445 Needs to be called with the sModulesLock held.
447 static status_t
448 unload_module_image(module_image* moduleImage, bool remove)
450 TRACE(("unload_module_image(image %p, remove %d)\n", moduleImage, remove));
451 ASSERT_LOCKED_RECURSIVE(&sModulesLock);
453 if (moduleImage->ref_count != 0) {
454 FATAL(("Can't unload %s due to ref_cnt = %" B_PRId32 "\n",
455 moduleImage->path, moduleImage->ref_count));
456 return B_ERROR;
459 if (remove)
460 sModuleImagesHash->Remove(moduleImage);
462 unload_kernel_add_on(moduleImage->image);
463 free(moduleImage->path);
464 free(moduleImage);
466 return B_OK;
470 static void
471 put_module_image(module_image* image)
473 RecursiveLocker locker(sModulesLock);
475 int32 refCount = atomic_add(&image->ref_count, -1);
476 ASSERT(refCount > 0);
478 // Don't unload anything when there is no boot device yet
479 // (because chances are that we will never be able to access it again)
481 if (refCount == 1 && gBootDevice > 0)
482 unload_module_image(image, true);
486 static status_t
487 get_module_image(const char* path, module_image** _image)
489 struct module_image* image;
491 TRACE(("get_module_image(path = \"%s\")\n", path));
493 RecursiveLocker _(sModulesLock);
495 image = sModuleImagesHash->Lookup(path);
496 if (image == NULL) {
497 status_t status = load_module_image(path, &image);
498 if (status < B_OK)
499 return status;
502 atomic_add(&image->ref_count, 1);
503 *_image = image;
505 return B_OK;
509 /*! Extract the information from the module_info structure pointed at
510 by "info" and create the entries required for access to it's details.
512 static status_t
513 create_module(module_info* info, int offset, module** _module)
515 module* module;
517 TRACE(("create_module(info = %p, offset = %d, _module = %p)\n",
518 info, offset, _module));
520 if (!info->name)
521 return B_BAD_VALUE;
523 module = sModulesHash->Lookup(info->name);
524 if (module) {
525 FATAL(("Duplicate module name (%s) detected... ignoring new one\n",
526 info->name));
527 return B_FILE_EXISTS;
530 if ((module = (struct module*)malloc(sizeof(struct module))) == NULL)
531 return B_NO_MEMORY;
533 TRACE(("create_module: name = \"%s\"\n", info->name));
535 module->module_image = NULL;
536 module->name = strdup(info->name);
537 if (module->name == NULL) {
538 free(module);
539 return B_NO_MEMORY;
542 module->state = MODULE_QUERIED;
543 module->info = info;
544 module->offset = offset;
545 // record where the module_info can be found in the module_info array
546 module->ref_count = 0;
547 module->flags = info->flags;
549 recursive_lock_lock(&sModulesLock);
550 sModulesHash->Insert(module);
551 recursive_lock_unlock(&sModulesLock);
553 if (_module)
554 *_module = module;
556 return B_OK;
560 /*! Loads the file at \a path and scans all modules contained therein.
561 Returns \c B_OK if \a searchedName could be found under those modules,
562 and will return the referenced image in \a _moduleImage.
563 Returns \c B_ENTRY_NOT_FOUND if the module could not be found.
565 Must only be called for files that haven't been scanned yet.
566 \a searchedName is allowed to be \c NULL (if all modules should be scanned)
568 static status_t
569 check_module_image(const char* path, const char* searchedName,
570 module_image** _moduleImage)
572 status_t status = B_ENTRY_NOT_FOUND;
573 module_image* image;
574 module_info** info;
575 int index = 0;
577 TRACE(("check_module_image(path = \"%s\", searchedName = \"%s\")\n", path,
578 searchedName));
580 if (get_module_image(path, &image) < B_OK)
581 return B_ENTRY_NOT_FOUND;
583 for (info = image->info; *info; info++) {
584 // try to create a module for every module_info, check if the
585 // name matches if it was a new entry
586 bool freshModule = false;
587 struct module* module = sModulesHash->Lookup((*info)->name);
588 if (module != NULL) {
589 // Module does already exist
590 if (module->module_image == NULL && module->ref_count == 0) {
591 module->info = *info;
592 module->offset = index;
593 module->flags = (*info)->flags;
594 module->state = MODULE_QUERIED;
595 freshModule = true;
597 } else if (create_module(*info, index, NULL) == B_OK)
598 freshModule = true;
600 if (freshModule && searchedName != NULL
601 && strcmp((*info)->name, searchedName) == 0) {
602 status = B_OK;
605 index++;
608 if (status != B_OK) {
609 // decrement the ref we got in get_module_image
610 put_module_image(image);
611 return status;
614 *_moduleImage = image;
615 return B_OK;
619 static module*
620 search_module(const char* name, module_image** _moduleImage)
622 status_t status = B_ENTRY_NOT_FOUND;
623 uint32 i;
625 TRACE(("search_module(%s)\n", name));
627 for (i = kNumModulePaths; i-- > 0;) {
628 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
629 continue;
631 // let the VFS find that module for us
633 KPath basePath;
634 if (__find_directory(kModulePaths[i], gBootDevice, true,
635 basePath.LockBuffer(), basePath.BufferSize()) != B_OK)
636 continue;
638 basePath.UnlockBuffer();
639 basePath.Append("kernel");
641 KPath path;
642 status = vfs_get_module_path(basePath.Path(), name, path.LockBuffer(),
643 path.BufferSize());
644 if (status == B_OK) {
645 path.UnlockBuffer();
646 status = check_module_image(path.Path(), name, _moduleImage);
647 if (status == B_OK)
648 break;
652 if (status != B_OK)
653 return NULL;
655 return sModulesHash->Lookup(name);
659 static status_t
660 put_dependent_modules(struct module* module)
662 module_image* image = module->module_image;
663 module_dependency* dependencies;
665 // built-in modules don't have a module_image structure
666 if (image == NULL
667 || (dependencies = image->dependencies) == NULL)
668 return B_OK;
670 for (int32 i = 0; dependencies[i].name != NULL; i++) {
671 status_t status = put_module(dependencies[i].name);
672 if (status < B_OK)
673 return status;
676 return B_OK;
680 static status_t
681 get_dependent_modules(struct module* module)
683 module_image* image = module->module_image;
684 module_dependency* dependencies;
686 // built-in modules don't have a module_image structure
687 if (image == NULL
688 || (dependencies = image->dependencies) == NULL)
689 return B_OK;
691 TRACE(("resolving module dependencies...\n"));
693 for (int32 i = 0; dependencies[i].name != NULL; i++) {
694 status_t status = get_module(dependencies[i].name,
695 dependencies[i].info);
696 if (status < B_OK) {
697 dprintf("loading dependent module %s of %s failed!\n",
698 dependencies[i].name, module->name);
699 return status;
703 return B_OK;
707 /*! Initializes a loaded module depending on its state */
708 static inline status_t
709 init_module(module* module)
711 switch (module->state) {
712 case MODULE_QUERIED:
713 case MODULE_LOADED:
715 status_t status;
716 module->state = MODULE_INIT;
718 // resolve dependencies
720 status = get_dependent_modules(module);
721 if (status < B_OK) {
722 module->state = MODULE_LOADED;
723 return status;
726 // init module
728 TRACE(("initializing module %s (at %p)... \n", module->name,
729 module->info->std_ops));
731 if (module->info->std_ops != NULL)
732 status = module->info->std_ops(B_MODULE_INIT);
734 TRACE(("...done (%s)\n", strerror(status)));
736 if (status >= B_OK)
737 module->state = MODULE_READY;
738 else {
739 put_dependent_modules(module);
740 module->state = MODULE_LOADED;
743 return status;
746 case MODULE_READY:
747 return B_OK;
749 case MODULE_INIT:
750 FATAL(("circular reference to %s\n", module->name));
751 return B_ERROR;
753 case MODULE_UNINIT:
754 FATAL(("tried to load module %s which is currently unloading\n",
755 module->name));
756 return B_ERROR;
758 case MODULE_ERROR:
759 FATAL(("cannot load module %s because its earlier unloading "
760 "failed\n", module->name));
761 return B_ERROR;
763 default:
764 return B_ERROR;
766 // never trespasses here
770 /*! Uninitializes a module depeding on its state */
771 static inline int
772 uninit_module(module* module)
774 TRACE(("uninit_module(%s)\n", module->name));
776 switch (module->state) {
777 case MODULE_QUERIED:
778 case MODULE_LOADED:
779 return B_NO_ERROR;
781 case MODULE_INIT:
782 panic("Trying to unload module %s which is initializing\n",
783 module->name);
784 return B_ERROR;
786 case MODULE_UNINIT:
787 panic("Trying to unload module %s which is un-initializing\n",
788 module->name);
789 return B_ERROR;
791 case MODULE_READY:
793 status_t status = B_OK;
794 module->state = MODULE_UNINIT;
796 TRACE(("uninitializing module %s...\n", module->name));
798 if (module->info->std_ops != NULL)
799 status = module->info->std_ops(B_MODULE_UNINIT);
801 TRACE(("...done (%s)\n", strerror(status)));
803 if (status == B_OK) {
804 module->state = MODULE_LOADED;
805 put_dependent_modules(module);
806 return B_OK;
809 FATAL(("Error unloading module %s (%s)\n", module->name,
810 strerror(status)));
812 module->state = MODULE_ERROR;
813 module->flags |= B_KEEP_LOADED;
814 module->ref_count++;
816 return status;
818 default:
819 return B_ERROR;
821 // never trespasses here
825 static const char*
826 iterator_pop_path_from_stack(module_iterator* iterator, uint32* _baseLength)
828 if (iterator->stack_current <= 0)
829 return NULL;
831 if (_baseLength)
832 *_baseLength = iterator->stack[iterator->stack_current - 1].base_length;
834 return iterator->stack[--iterator->stack_current].name;
838 static status_t
839 iterator_push_path_on_stack(module_iterator* iterator, const char* path,
840 uint32 baseLength)
842 if (iterator->stack_current + 1 > iterator->stack_size) {
843 // allocate new space on the stack
844 module_path* stack = (module_path*)realloc(iterator->stack,
845 (iterator->stack_size + 8) * sizeof(module_path));
846 if (stack == NULL)
847 return B_NO_MEMORY;
849 iterator->stack = stack;
850 iterator->stack_size += 8;
853 iterator->stack[iterator->stack_current].name = path;
854 iterator->stack[iterator->stack_current++].base_length = baseLength;
855 return B_OK;
859 static bool
860 match_iterator_suffix(module_iterator* iterator, const char* name)
862 if (iterator->suffix == NULL || iterator->suffix_length == 0)
863 return true;
865 size_t length = strlen(name);
866 if (length <= iterator->suffix_length)
867 return false;
869 return name[length - iterator->suffix_length - 1] == '/'
870 && !strcmp(name + length - iterator->suffix_length, iterator->suffix);
874 static status_t
875 iterator_get_next_module(module_iterator* iterator, char* buffer,
876 size_t* _bufferSize)
878 status_t status;
880 TRACE(("iterator_get_next_module() -- start\n"));
882 if (iterator->builtin_modules) {
883 for (int32 i = iterator->module_offset; sBuiltInModules[i] != NULL;
884 i++) {
885 // the module name must fit the prefix
886 if (strncmp(sBuiltInModules[i]->name, iterator->prefix,
887 iterator->prefix_length)
888 || !match_iterator_suffix(iterator, sBuiltInModules[i]->name))
889 continue;
891 *_bufferSize = strlcpy(buffer, sBuiltInModules[i]->name,
892 *_bufferSize);
893 iterator->module_offset = i + 1;
894 return B_OK;
896 iterator->builtin_modules = false;
899 if (iterator->loaded_modules) {
900 recursive_lock_lock(&sModulesLock);
901 ModuleTable::Iterator hashIterator(sModulesHash);
903 for (int32 i = 0; hashIterator.HasNext(); i++) {
904 struct module* module = hashIterator.Next();
906 if (i >= iterator->module_offset) {
907 if (!strncmp(module->name, iterator->prefix,
908 iterator->prefix_length)
909 && match_iterator_suffix(iterator, module->name)) {
910 *_bufferSize = strlcpy(buffer, module->name, *_bufferSize);
911 iterator->module_offset = i + 1;
913 recursive_lock_unlock(&sModulesLock);
914 return B_OK;
919 recursive_lock_unlock(&sModulesLock);
921 // prevent from falling into modules hash iteration again
922 iterator->loaded_modules = false;
925 nextPath:
926 if (iterator->current_dir == NULL) {
927 // get next directory path from the stack
928 const char* path = iterator_pop_path_from_stack(iterator,
929 &iterator->path_base_length);
930 if (path == NULL) {
931 // we are finished, there are no more entries on the stack
932 return B_ENTRY_NOT_FOUND;
935 free((char*)iterator->current_path);
936 iterator->current_path = path;
937 iterator->current_dir = opendir(path);
938 TRACE(("open directory at %s -> %p\n", path, iterator->current_dir));
940 if (iterator->current_dir == NULL) {
941 // we don't throw an error here, but silently go to
942 // the next directory on the stack
943 goto nextPath;
947 nextModuleImage:
948 // TODO: remember which directories were already scanned, and don't search
949 // through them again, unless they change (use DirectoryWatcher)
951 if (iterator->current_header == NULL) {
952 // get next entry from the current directory
954 errno = 0;
956 struct dirent* dirent;
957 if ((dirent = readdir(iterator->current_dir)) == NULL) {
958 closedir(iterator->current_dir);
959 iterator->current_dir = NULL;
961 if (errno < B_OK)
962 return errno;
964 goto nextPath;
967 // check if the prefix matches
968 int32 passedOffset, commonLength;
969 passedOffset = strlen(iterator->current_path) + 1;
970 commonLength = iterator->path_base_length + iterator->prefix_length
971 - passedOffset;
973 if (commonLength > 0) {
974 // the prefix still reaches into the new path part
975 int32 length = strlen(dirent->d_name);
976 if (commonLength > length)
977 commonLength = length;
979 if (strncmp(dirent->d_name, iterator->prefix + passedOffset
980 - iterator->path_base_length, commonLength))
981 goto nextModuleImage;
984 // we're not interested in traversing these (again)
985 if (!strcmp(dirent->d_name, ".")
986 || !strcmp(dirent->d_name, "..")
987 // TODO: this is a bit unclean, as we actually only want to prevent
988 // drivers/bin and drivers/dev to be scanned
989 || !strcmp(dirent->d_name, "bin")
990 || !strcmp(dirent->d_name, "dev"))
991 goto nextModuleImage;
993 // build absolute path to current file
994 KPath path(iterator->current_path);
995 if (path.InitCheck() != B_OK)
996 return B_NO_MEMORY;
998 if (path.Append(dirent->d_name) != B_OK)
999 return B_BUFFER_OVERFLOW;
1001 // find out if it's a directory or a file
1002 struct stat stat;
1003 if (::stat(path.Path(), &stat) < 0)
1004 return errno;
1006 iterator->current_module_path = strdup(path.Path());
1007 if (iterator->current_module_path == NULL)
1008 return B_NO_MEMORY;
1010 if (S_ISDIR(stat.st_mode)) {
1011 status = iterator_push_path_on_stack(iterator,
1012 iterator->current_module_path, iterator->path_base_length);
1013 if (status != B_OK)
1014 return status;
1016 iterator->current_module_path = NULL;
1017 goto nextModuleImage;
1020 if (!S_ISREG(stat.st_mode))
1021 return B_BAD_TYPE;
1023 TRACE(("open module at %s\n", path.Path()));
1025 status = get_module_image(path.Path(), &iterator->module_image);
1026 if (status < B_OK) {
1027 free((char*)iterator->current_module_path);
1028 iterator->current_module_path = NULL;
1029 goto nextModuleImage;
1032 iterator->current_header = iterator->module_image->info;
1033 iterator->module_offset = 0;
1036 // search the current module image until we've got a match
1037 while (*iterator->current_header != NULL) {
1038 module_info* info = *iterator->current_header;
1040 // TODO: we might want to create a module here and cache it in the
1041 // hash table
1043 iterator->current_header++;
1044 iterator->module_offset++;
1046 if (strncmp(info->name, iterator->prefix, iterator->prefix_length)
1047 || !match_iterator_suffix(iterator, info->name))
1048 continue;
1050 *_bufferSize = strlcpy(buffer, info->name, *_bufferSize);
1051 return B_OK;
1054 // leave this module and get the next one
1056 iterator->current_header = NULL;
1057 free((char*)iterator->current_module_path);
1058 iterator->current_module_path = NULL;
1060 put_module_image(iterator->module_image);
1061 iterator->module_image = NULL;
1063 goto nextModuleImage;
1067 static void
1068 register_builtin_modules(struct module_info** info)
1070 for (; *info; info++) {
1071 (*info)->flags |= B_BUILT_IN_MODULE;
1072 // this is an internal flag, it doesn't have to be set by modules
1073 // itself
1075 if (create_module(*info, -1, NULL) != B_OK) {
1076 dprintf("creation of built-in module \"%s\" failed!\n",
1077 (*info)->name);
1083 static status_t
1084 register_preloaded_module_image(struct preloaded_image* image)
1086 module_image* moduleImage;
1087 struct module_info** info;
1088 status_t status;
1089 int32 index = 0;
1091 TRACE(("register_preloaded_module_image(image = %p, name = \"%s\")\n",
1092 image, image->name.Pointer()));
1094 image->is_module = false;
1096 if (image->id < 0)
1097 return B_BAD_VALUE;
1099 moduleImage = (module_image*)malloc(sizeof(module_image));
1100 if (moduleImage == NULL)
1101 return B_NO_MEMORY;
1103 if (get_image_symbol(image->id, "modules", B_SYMBOL_TYPE_DATA,
1104 (void**)&moduleImage->info) != B_OK) {
1105 status = B_BAD_TYPE;
1106 goto error;
1109 image->is_module = true;
1111 if (moduleImage->info[0] == NULL) {
1112 status = B_BAD_DATA;
1113 goto error;
1116 moduleImage->dependencies = NULL;
1117 get_image_symbol(image->id, "module_dependencies", B_SYMBOL_TYPE_DATA,
1118 (void**)&moduleImage->dependencies);
1119 // this is allowed to be NULL
1121 moduleImage->path = strdup(image->name);
1122 if (moduleImage->path == NULL) {
1123 status = B_NO_MEMORY;
1124 goto error;
1127 moduleImage->image = image->id;
1128 moduleImage->ref_count = 0;
1130 sModuleImagesHash->Insert(moduleImage);
1132 for (info = moduleImage->info; *info; info++) {
1133 struct module* module = NULL;
1134 if (create_module(*info, index++, &module) == B_OK)
1135 module->module_image = moduleImage;
1138 return B_OK;
1140 error:
1141 free(moduleImage);
1143 // We don't need this image anymore. We keep it, if it doesn't look like
1144 // a module at all. It might be an old-style driver.
1145 if (image->is_module)
1146 unload_kernel_add_on(image->id);
1148 return status;
1152 static int
1153 dump_modules(int argc, char** argv)
1155 struct module_image* image;
1157 ModuleTable::Iterator iterator(sModulesHash);
1158 kprintf("-- known modules:\n");
1160 while (iterator.HasNext()) {
1161 struct module* module = iterator.Next();
1162 kprintf("%p: \"%s\", \"%s\" (%" B_PRId32 "), refcount = %" B_PRId32 ", "
1163 "state = %d, mimage = %p\n", module, module->name,
1164 module->module_image ? module->module_image->path : "",
1165 module->offset, module->ref_count, module->state,
1166 module->module_image);
1169 ImageTable::Iterator imageIterator(sModuleImagesHash);
1170 kprintf("\n-- loaded module images:\n");
1172 while (imageIterator.HasNext()) {
1173 image = imageIterator.Next();
1174 kprintf("%p: \"%s\" (image_id = %" B_PRId32 "), info = %p, refcount = "
1175 "%" B_PRId32 "\n", image, image->path, image->image, image->info,
1176 image->ref_count);
1178 return 0;
1182 // #pragma mark - DirectoryWatcher
1185 DirectoryWatcher::DirectoryWatcher()
1190 DirectoryWatcher::~DirectoryWatcher()
1195 void
1196 DirectoryWatcher::EventOccurred(NotificationService& service,
1197 const KMessage* event)
1199 int32 opcode = event->GetInt32("opcode", -1);
1200 dev_t device = event->GetInt32("device", -1);
1201 ino_t directory = event->GetInt64("directory", -1);
1202 ino_t node = event->GetInt64("node", -1);
1203 const char *name = event->GetString("name", NULL);
1205 if (opcode == B_ENTRY_MOVED) {
1206 // Determine whether it's a move within, out of, or into one
1207 // of our watched directories.
1208 directory = event->GetInt64("to directory", -1);
1209 if (!sModuleNotificationService.HasNode(device, directory)) {
1210 directory = event->GetInt64("from directory", -1);
1211 opcode = B_ENTRY_REMOVED;
1212 } else {
1213 // Move within, doesn't sound like a good idea for modules
1214 opcode = B_ENTRY_CREATED;
1218 sModuleNotificationService.Notify(opcode, device, directory, node, name);
1222 // #pragma mark - ModuleWatcher
1225 ModuleWatcher::ModuleWatcher()
1230 ModuleWatcher::~ModuleWatcher()
1235 void
1236 ModuleWatcher::EventOccurred(NotificationService& service, const KMessage* event)
1238 if (event->GetInt32("opcode", -1) != B_STAT_CHANGED
1239 || (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0)
1240 return;
1242 dev_t device = event->GetInt32("device", -1);
1243 ino_t node = event->GetInt64("node", -1);
1245 sModuleNotificationService.Notify(B_STAT_CHANGED, device, -1, node, NULL);
1249 // #pragma mark - ModuleNotificationService
1252 ModuleNotificationService::ModuleNotificationService()
1254 recursive_lock_init(&fLock, "module notifications");
1258 ModuleNotificationService::~ModuleNotificationService()
1260 recursive_lock_destroy(&fLock);
1264 status_t
1265 ModuleNotificationService::AddListener(const KMessage* eventSpecifier,
1266 NotificationListener& listener)
1268 const char* prefix = eventSpecifier->GetString("prefix", NULL);
1269 if (prefix == NULL)
1270 return B_BAD_VALUE;
1272 module_listener* moduleListener = new(std::nothrow) module_listener;
1273 if (moduleListener == NULL)
1274 return B_NO_MEMORY;
1276 moduleListener->prefix = strdup(prefix);
1277 if (moduleListener->prefix == NULL) {
1278 delete moduleListener;
1279 return B_NO_MEMORY;
1282 status_t status = _AddDirectory(prefix);
1283 if (status != B_OK) {
1284 delete moduleListener;
1285 return status;
1288 moduleListener->listener = &listener;
1289 fListeners.Add(moduleListener);
1291 return B_OK;
1295 status_t
1296 ModuleNotificationService::UpdateListener(const KMessage* eventSpecifier,
1297 NotificationListener& listener)
1299 return B_ERROR;
1303 status_t
1304 ModuleNotificationService::RemoveListener(const KMessage* eventSpecifier,
1305 NotificationListener& listener)
1307 return B_ERROR;
1311 bool
1312 ModuleNotificationService::HasNode(dev_t device, ino_t node)
1314 RecursiveLocker _(fLock);
1316 struct entry entry = {device, node};
1317 return fNodes.Lookup(&entry) != NULL;
1321 status_t
1322 ModuleNotificationService::_RemoveNode(dev_t device, ino_t node)
1324 RecursiveLocker _(fLock);
1326 struct entry key = {device, node};
1327 hash_entry* entry = fNodes.Lookup(&key);
1328 if (entry == NULL)
1329 return B_ENTRY_NOT_FOUND;
1331 remove_node_listener(device, node, entry->path != NULL
1332 ? (NotificationListener&)fModuleWatcher
1333 : (NotificationListener&)fDirectoryWatcher);
1335 fNodes.Remove(entry);
1336 delete entry;
1338 return B_OK;
1342 status_t
1343 ModuleNotificationService::_AddNode(dev_t device, ino_t node, const char* path,
1344 uint32 flags, NotificationListener& listener)
1346 RecursiveLocker locker(fLock);
1348 if (HasNode(device, node))
1349 return B_OK;
1351 struct hash_entry* entry = new(std::nothrow) hash_entry;
1352 if (entry == NULL)
1353 return B_NO_MEMORY;
1355 if (path != NULL) {
1356 entry->path = strdup(path);
1357 if (entry->path == NULL) {
1358 delete entry;
1359 return B_NO_MEMORY;
1361 } else
1362 entry->path = NULL;
1364 status_t status = add_node_listener(device, node, flags, listener);
1365 if (status != B_OK) {
1366 delete entry;
1367 return status;
1370 //dprintf(" add %s %ld:%Ld (%s)\n", flags == B_WATCH_DIRECTORY
1371 // ? "dir" : "file", device, node, path);
1373 entry->device = device;
1374 entry->node = node;
1375 fNodes.Insert(entry);
1377 return B_OK;
1381 status_t
1382 ModuleNotificationService::_AddDirectoryNode(dev_t device, ino_t node)
1384 return _AddNode(device, node, NULL, B_WATCH_DIRECTORY, fDirectoryWatcher);
1388 status_t
1389 ModuleNotificationService::_AddModuleNode(dev_t device, ino_t node, int fd,
1390 const char* name)
1392 struct vnode* vnode;
1393 status_t status = vfs_get_vnode_from_fd(fd, true, &vnode);
1394 if (status != B_OK)
1395 return status;
1397 ino_t directory;
1398 vfs_vnode_to_node_ref(vnode, &device, &directory);
1400 KPath path;
1401 status = path.InitCheck();
1402 if (status == B_OK) {
1403 status = vfs_entry_ref_to_path(device, directory, name, true,
1404 path.LockBuffer(), path.BufferSize());
1406 if (status != B_OK)
1407 return status;
1409 path.UnlockBuffer();
1411 return _AddNode(device, node, path.Path(), B_WATCH_STAT, fModuleWatcher);
1415 status_t
1416 ModuleNotificationService::_AddDirectory(const char* prefix)
1418 status_t status = B_ERROR;
1420 for (uint32 i = 0; i < kNumModulePaths; i++) {
1421 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
1422 break;
1424 KPath pathBuffer;
1425 if (__find_directory(kModulePaths[i], gBootDevice, true,
1426 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
1427 continue;
1429 pathBuffer.UnlockBuffer();
1430 pathBuffer.Append("kernel");
1431 pathBuffer.Append(prefix);
1433 size_t prefixPosition = strlen(prefix);
1434 status_t scanStatus = _ScanDirectory(pathBuffer.LockBuffer(), prefix,
1435 prefixPosition);
1437 pathBuffer.UnlockBuffer();
1439 // It's enough if we succeed for one directory
1440 if (status != B_OK)
1441 status = scanStatus;
1444 return status;
1448 status_t
1449 ModuleNotificationService::_ScanDirectory(char* directoryPath,
1450 const char* prefix, size_t& prefixPosition)
1452 DIR* dir = NULL;
1453 while (true) {
1454 dir = opendir(directoryPath);
1455 if (dir != NULL || prefixPosition == 0)
1456 break;
1458 // the full prefix is not accessible, remove path components
1459 const char* parentPrefix = prefix + prefixPosition - 1;
1460 while (parentPrefix != prefix && parentPrefix[0] != '/')
1461 parentPrefix--;
1463 size_t cutPosition = parentPrefix - prefix;
1464 size_t length = strlen(directoryPath);
1465 directoryPath[length - prefixPosition + cutPosition] = '\0';
1466 prefixPosition = cutPosition;
1469 if (dir == NULL)
1470 return B_ERROR;
1472 Stack<DIR*> stack;
1473 stack.Push(dir);
1475 while (stack.Pop(&dir)) {
1476 status_t status = _ScanDirectory(stack, dir, prefix, prefixPosition);
1477 if (status != B_OK)
1478 return status;
1481 return B_OK;
1485 status_t
1486 ModuleNotificationService::_ScanDirectory(Stack<DIR*>& stack, DIR* dir,
1487 const char* prefix, size_t prefixPosition)
1489 bool directMatchAdded = false;
1490 struct dirent* dirent;
1492 while ((dirent = readdir(dir)) != NULL) {
1493 if (dirent->d_name[0] == '.')
1494 continue;
1496 bool directMatch = false;
1498 if (prefix[prefixPosition] != '\0') {
1499 // the start must match
1500 const char* startPrefix = prefix + prefixPosition;
1501 if (startPrefix[0] == '/')
1502 startPrefix++;
1504 const char* endPrefix = strchr(startPrefix, '/');
1505 size_t length;
1507 if (endPrefix != NULL)
1508 length = endPrefix - startPrefix;
1509 else
1510 length = strlen(startPrefix);
1512 if (strncmp(dirent->d_name, startPrefix, length))
1513 continue;
1515 if (dirent->d_name[length] == '\0')
1516 directMatch = true;
1519 struct stat stat;
1520 status_t status = vfs_read_stat(dirfd(dir), dirent->d_name, true, &stat,
1521 true);
1522 if (status != B_OK)
1523 continue;
1525 if (S_ISDIR(stat.st_mode)) {
1526 int fd = _kern_open_dir(dirfd(dir), dirent->d_name);
1527 if (fd < 0)
1528 continue;
1530 DIR* subDir = fdopendir(fd);
1531 if (subDir == NULL) {
1532 close(fd);
1533 continue;
1536 stack.Push(subDir);
1538 if (_AddDirectoryNode(stat.st_dev, stat.st_ino) == B_OK
1539 && directMatch)
1540 directMatchAdded = true;
1541 } else if (S_ISREG(stat.st_mode)) {
1542 if (_AddModuleNode(stat.st_dev, stat.st_ino, dirfd(dir),
1543 dirent->d_name) == B_OK && directMatch)
1544 directMatchAdded = true;
1548 if (!directMatchAdded) {
1549 // We need to monitor this directory to see if a matching file
1550 // is added.
1551 struct stat stat;
1552 status_t status = vfs_read_stat(dirfd(dir), NULL, true, &stat, true);
1553 if (status == B_OK)
1554 _AddDirectoryNode(stat.st_dev, stat.st_ino);
1557 closedir(dir);
1558 return B_OK;
1562 void
1563 ModuleNotificationService::_Notify(int32 opcode, dev_t device, ino_t directory,
1564 ino_t node, const char* name)
1566 // construct path
1568 KPath pathBuffer;
1569 const char* path;
1571 if (name != NULL) {
1572 // we have an entry ref
1573 if (pathBuffer.InitCheck() != B_OK
1574 || vfs_entry_ref_to_path(device, directory, name, true,
1575 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
1576 return;
1578 pathBuffer.UnlockBuffer();
1579 path = pathBuffer.Path();
1580 } else {
1581 // we only have a node ref
1582 RecursiveLocker _(fLock);
1584 struct entry key = {device, node};
1585 hash_entry* entry = fNodes.Lookup(&key);
1586 if (entry == NULL || entry->path == NULL)
1587 return;
1589 path = entry->path;
1592 // remove kModulePaths from path
1594 for (uint32 i = 0; i < kNumModulePaths; i++) {
1595 KPath modulePath;
1596 if (__find_directory(kModulePaths[i], gBootDevice, true,
1597 modulePath.LockBuffer(), modulePath.BufferSize()) != B_OK)
1598 continue;
1600 modulePath.UnlockBuffer();
1601 modulePath.Append("kernel");
1603 if (strncmp(path, modulePath.Path(), modulePath.Length()))
1604 continue;
1606 path += modulePath.Length();
1607 if (path[i] == '/')
1608 path++;
1610 break;
1613 KMessage event;
1615 // find listeners by prefix/path
1617 ModuleListenerList::Iterator iterator = fListeners.GetIterator();
1618 while (iterator.HasNext()) {
1619 module_listener* listener = iterator.Next();
1621 if (strncmp(path, listener->prefix, strlen(listener->prefix)))
1622 continue;
1624 if (event.IsEmpty()) {
1625 // construct message only when needed
1626 event.AddInt32("opcode", opcode);
1627 event.AddString("path", path);
1630 // notify them!
1631 listener->listener->EventOccurred(*this, &event);
1633 // we might need to watch new files now
1634 if (opcode == B_ENTRY_CREATED)
1635 _AddDirectory(listener->prefix);
1639 // remove notification listeners, if needed
1641 if (opcode == B_ENTRY_REMOVED)
1642 _RemoveNode(device, node);
1646 void
1647 ModuleNotificationService::_HandleNotifications()
1649 RecursiveLocker _(fLock);
1651 NotificationList::Iterator iterator = fNotifications.GetIterator();
1652 while (iterator.HasNext()) {
1653 module_notification* notification = iterator.Next();
1655 _Notify(notification->opcode, notification->device,
1656 notification->directory, notification->node, notification->name);
1658 iterator.Remove();
1659 delete notification;
1664 void
1665 ModuleNotificationService::Notify(int32 opcode, dev_t device, ino_t directory,
1666 ino_t node, const char* name)
1668 module_notification* notification = new(std::nothrow) module_notification;
1669 if (notification == NULL)
1670 return;
1672 if (name != NULL) {
1673 notification->name = strdup(name);
1674 if (notification->name == NULL) {
1675 delete notification;
1676 return;
1678 } else
1679 notification->name = NULL;
1681 notification->opcode = opcode;
1682 notification->device = device;
1683 notification->directory = directory;
1684 notification->node = node;
1686 RecursiveLocker _(fLock);
1687 fNotifications.Add(notification);
1691 /*static*/ void
1692 ModuleNotificationService::HandleNotifications(void * /*data*/,
1693 int /*iteration*/)
1695 sModuleNotificationService._HandleNotifications();
1699 // #pragma mark - Exported Kernel API (private part)
1702 /*! Unloads a module in case it's not in use. This is the counterpart
1703 to load_module().
1705 status_t
1706 unload_module(const char* path)
1708 struct module_image* moduleImage;
1710 recursive_lock_lock(&sModulesLock);
1711 moduleImage = sModuleImagesHash->Lookup(path);
1712 recursive_lock_unlock(&sModulesLock);
1714 if (moduleImage == NULL)
1715 return B_ENTRY_NOT_FOUND;
1717 put_module_image(moduleImage);
1718 return B_OK;
1722 /*! Unlike get_module(), this function lets you specify the add-on to
1723 be loaded by path.
1724 However, you must not use the exported modules without having called
1725 get_module() on them. When you're done with the NULL terminated
1726 \a modules array, you have to call unload_module(), no matter if
1727 you're actually using any of the modules or not - of course, the
1728 add-on won't be unloaded until the last put_module().
1730 status_t
1731 load_module(const char* path, module_info*** _modules)
1733 module_image* moduleImage;
1734 status_t status = get_module_image(path, &moduleImage);
1735 if (status != B_OK)
1736 return status;
1738 *_modules = moduleImage->info;
1739 return B_OK;
1743 status_t
1744 start_watching_modules(const char* prefix, NotificationListener& listener)
1746 KMessage specifier;
1747 status_t status = specifier.AddString("prefix", prefix);
1748 if (status != B_OK)
1749 return status;
1751 return sModuleNotificationService.AddListener(&specifier, listener);
1755 status_t
1756 stop_watching_modules(const char* prefix, NotificationListener& listener)
1758 KMessage specifier;
1759 status_t status = specifier.AddString("prefix", prefix);
1760 if (status != B_OK)
1761 return status;
1763 return sModuleNotificationService.RemoveListener(&specifier, listener);
1767 /*! Setup the module structures and data for use - must be called
1768 before any other module call.
1770 status_t
1771 module_init(kernel_args* args)
1773 struct preloaded_image* image;
1775 recursive_lock_init(&sModulesLock, "modules rlock");
1777 sModulesHash = new(std::nothrow) ModuleTable();
1778 if (sModulesHash == NULL
1779 || sModulesHash->Init(MODULE_HASH_SIZE) != B_OK)
1780 return B_NO_MEMORY;
1782 sModuleImagesHash = new(std::nothrow) ImageTable();
1783 if (sModuleImagesHash == NULL
1784 || sModuleImagesHash->Init(MODULE_HASH_SIZE) != B_OK)
1785 return B_NO_MEMORY;
1787 // register built-in modules
1789 register_builtin_modules(sBuiltInModules);
1791 // register preloaded images
1793 for (image = args->preloaded_images; image != NULL; image = image->next) {
1794 status_t status = register_preloaded_module_image(image);
1795 if (status != B_OK && image->is_module) {
1796 dprintf("Could not register image \"%s\": %s\n", (char *)image->name,
1797 strerror(status));
1801 new(&sModuleNotificationService) ModuleNotificationService();
1803 sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS,
1804 false);
1806 add_debugger_command("modules", &dump_modules,
1807 "list all known & loaded modules");
1809 return B_OK;
1813 status_t
1814 module_init_post_threads(void)
1816 return register_kernel_daemon(
1817 &ModuleNotificationService::HandleNotifications, NULL, 10);
1818 // once every second
1820 return B_OK;
1824 status_t
1825 module_init_post_boot_device(bool bootingFromBootLoaderVolume)
1827 // Remove all unused pre-loaded module images. Now that the boot device is
1828 // available, we can load an image when we need it.
1829 // When the boot volume is also where the boot loader pre-loaded the images
1830 // from, we get the actual paths for those images.
1831 TRACE(("module_init_post_boot_device(%d)\n", bootingFromBootLoaderVolume));
1833 RecursiveLocker _(sModulesLock);
1835 // First of all, clear all pre-loaded module's module_image, if the module
1836 // isn't in use.
1837 ModuleTable::Iterator iterator(sModulesHash);
1838 struct module* module;
1839 while (iterator.HasNext()) {
1840 module = iterator.Next();
1841 if (module->ref_count == 0
1842 && (module->flags & B_BUILT_IN_MODULE) == 0) {
1843 TRACE((" module %p, \"%s\" unused, clearing image\n", module,
1844 module->name));
1845 module->module_image = NULL;
1849 // Now iterate through the images and drop them respectively normalize their
1850 // paths.
1851 ImageTable::Iterator imageIterator(sModuleImagesHash);
1853 module_image* imagesToReinsert = NULL;
1854 // When renamed, an image is added to this list to be re-entered in the
1855 // hash at the end. We can't do that during the iteration.
1857 while (imageIterator.HasNext()) {
1858 struct module_image* image = imageIterator.Next();
1860 if (image->ref_count == 0) {
1861 // not in use -- unload it
1862 TRACE((" module image %p, \"%s\" unused, removing\n", image,
1863 image->path));
1864 // Using RemoveUnchecked to avoid invalidating the iterator
1865 sModuleImagesHash->RemoveUnchecked(image);
1866 unload_module_image(image, false);
1867 } else if (bootingFromBootLoaderVolume) {
1868 bool pathNormalized = false;
1869 KPath pathBuffer;
1870 if (image->path[0] != '/') {
1871 // relative path
1872 for (uint32 i = kNumModulePaths; i-- > 0;) {
1873 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
1874 continue;
1876 if (__find_directory(kModulePaths[i], gBootDevice, true,
1877 pathBuffer.LockBuffer(), pathBuffer.BufferSize())
1878 != B_OK) {
1879 pathBuffer.UnlockBuffer();
1880 continue;
1883 pathBuffer.UnlockBuffer();
1885 // Append the relative boot module directory and the
1886 // relative image path, normalize the path, and check
1887 // whether it exists.
1888 struct stat st;
1889 if (pathBuffer.Append("kernel/boot") != B_OK
1890 || pathBuffer.Append(image->path) != B_OK
1891 || pathBuffer.Normalize(true) != B_OK
1892 || lstat(pathBuffer.Path(), &st) != 0) {
1893 continue;
1896 pathNormalized = true;
1897 break;
1899 } else {
1900 // absolute path -- try to normalize it anyway
1901 struct stat st;
1902 if (pathBuffer.SetPath(image->path) == B_OK
1903 && pathBuffer.Normalize(true) == B_OK
1904 && lstat(pathBuffer.Path(), &st) == 0) {
1905 pathNormalized = true;
1909 if (pathNormalized) {
1910 TRACE((" normalized path of module image %p, \"%s\" -> "
1911 "\"%s\"\n", image, image->path, pathBuffer.Path()));
1913 // remove the image -- its hash value has probably changed,
1914 // so we need to re-insert it later
1915 sModuleImagesHash->RemoveUnchecked(image);
1917 // set the new path
1918 free(image->path);
1919 size_t pathLen = pathBuffer.Length();
1920 image->path = (char*)realloc(pathBuffer.DetachBuffer(),
1921 pathLen + 1);
1923 image->next = imagesToReinsert;
1924 imagesToReinsert = image;
1925 } else {
1926 dprintf("module_init_post_boot_device() failed to normalize "
1927 "path of module image %p, \"%s\"\n", image, image->path);
1932 // re-insert the images that have got a new path
1933 while (module_image* image = imagesToReinsert) {
1934 imagesToReinsert = image->next;
1935 sModuleImagesHash->Insert(image);
1938 TRACE(("module_init_post_boot_device() done\n"));
1940 return B_OK;
1944 // #pragma mark - Exported Kernel API (public part)
1947 /*! This returns a pointer to a structure that can be used to
1948 iterate through a list of all modules available under
1949 a given prefix that adhere to the specified suffix.
1950 All paths will be searched and the returned list will
1951 contain all modules available under the prefix.
1952 The structure is then used by read_next_module_name(), and
1953 must be freed by calling close_module_list().
1955 void*
1956 open_module_list_etc(const char* prefix, const char* suffix)
1958 TRACE(("open_module_list(prefix = %s)\n", prefix));
1960 if (sModulesHash == NULL) {
1961 dprintf("open_module_list() called too early!\n");
1962 return NULL;
1965 module_iterator* iterator = (module_iterator*)malloc(
1966 sizeof(module_iterator));
1967 if (iterator == NULL)
1968 return NULL;
1970 memset(iterator, 0, sizeof(module_iterator));
1972 iterator->prefix = strdup(prefix != NULL ? prefix : "");
1973 if (iterator->prefix == NULL) {
1974 free(iterator);
1975 return NULL;
1977 iterator->prefix_length = strlen(iterator->prefix);
1979 iterator->suffix = suffix;
1980 if (suffix != NULL)
1981 iterator->suffix_length = strlen(iterator->suffix);
1983 if (gBootDevice > 0) {
1984 // We do have a boot device to scan
1986 // first, we'll traverse over the built-in modules
1987 iterator->builtin_modules = true;
1988 iterator->loaded_modules = false;
1990 // put all search paths on the stack
1991 for (uint32 i = 0; i < kNumModulePaths; i++) {
1992 if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
1993 break;
1995 KPath pathBuffer;
1996 if (__find_directory(kModulePaths[i], gBootDevice, true,
1997 pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
1998 continue;
2000 pathBuffer.UnlockBuffer();
2001 pathBuffer.Append("kernel");
2003 // Copy base path onto the iterator stack
2004 char* path = strdup(pathBuffer.Path());
2005 if (path == NULL)
2006 continue;
2008 size_t length = strlen(path);
2010 // TODO: it would currently be nicer to use the commented
2011 // version below, but the iterator won't work if the prefix
2012 // is inside a module then.
2013 // It works this way, but should be done better.
2014 #if 0
2015 // Build path component: base path + '/' + prefix
2016 size_t length = strlen(sModulePaths[i]);
2017 char* path = (char*)malloc(length + iterator->prefix_length + 2);
2018 if (path == NULL) {
2019 // ToDo: should we abort the whole operation here?
2020 // if we do, don't forget to empty the stack
2021 continue;
2024 memcpy(path, sModulePaths[i], length);
2025 path[length] = '/';
2026 memcpy(path + length + 1, iterator->prefix,
2027 iterator->prefix_length + 1);
2028 #endif
2030 iterator_push_path_on_stack(iterator, path, length + 1);
2032 } else {
2033 // include loaded modules in case there is no boot device yet
2034 iterator->builtin_modules = false;
2035 iterator->loaded_modules = true;
2038 return (void*)iterator;
2042 void*
2043 open_module_list(const char* prefix)
2045 return open_module_list_etc(prefix, NULL);
2049 /*! Frees the cookie allocated by open_module_list() */
2050 status_t
2051 close_module_list(void* cookie)
2053 module_iterator* iterator = (module_iterator*)cookie;
2054 const char* path;
2056 TRACE(("close_module_list()\n"));
2058 if (iterator == NULL)
2059 return B_BAD_VALUE;
2061 // free stack
2062 while ((path = iterator_pop_path_from_stack(iterator, NULL)) != NULL)
2063 free((char*)path);
2065 // close what have been left open
2066 if (iterator->module_image != NULL)
2067 put_module_image(iterator->module_image);
2069 if (iterator->current_dir != NULL)
2070 closedir(iterator->current_dir);
2072 free(iterator->stack);
2073 free((char*)iterator->current_path);
2074 free((char*)iterator->current_module_path);
2076 free(iterator->prefix);
2077 free(iterator);
2079 return B_OK;
2083 /*! Return the next module name from the available list, using
2084 a structure previously created by a call to open_module_list().
2085 Returns B_OK as long as it found another module, B_ENTRY_NOT_FOUND
2086 when done.
2088 status_t
2089 read_next_module_name(void* cookie, char* buffer, size_t* _bufferSize)
2091 module_iterator* iterator = (module_iterator*)cookie;
2092 status_t status;
2094 TRACE(("read_next_module_name: looking for next module\n"));
2096 if (iterator == NULL || buffer == NULL || _bufferSize == NULL)
2097 return B_BAD_VALUE;
2099 if (iterator->status < B_OK)
2100 return iterator->status;
2102 status = iterator->status;
2103 recursive_lock_lock(&sModulesLock);
2105 status = iterator_get_next_module(iterator, buffer, _bufferSize);
2107 iterator->status = status;
2108 recursive_lock_unlock(&sModulesLock);
2110 TRACE(("read_next_module_name: finished with status %s\n",
2111 strerror(status)));
2112 return status;
2116 /*! Iterates through all loaded modules, and stores its path in "buffer".
2117 TODO: check if the function in BeOS really does that (could also mean:
2118 iterate through all modules that are currently loaded; have a valid
2119 module_image pointer)
2121 status_t
2122 get_next_loaded_module_name(uint32* _cookie, char* buffer, size_t* _bufferSize)
2124 if (sModulesHash == NULL) {
2125 dprintf("get_next_loaded_module_name() called too early!\n");
2126 return B_ERROR;
2129 //TRACE(("get_next_loaded_module_name(\"%s\")\n", buffer));
2131 if (_cookie == NULL || buffer == NULL || _bufferSize == NULL)
2132 return B_BAD_VALUE;
2134 status_t status = B_ENTRY_NOT_FOUND;
2135 uint32 offset = *_cookie;
2137 RecursiveLocker _(sModulesLock);
2139 ModuleTable::Iterator iterator(sModulesHash);
2141 for (uint32 i = 0; iterator.HasNext(); i++) {
2142 struct module* module = iterator.Next();
2143 if (i >= offset) {
2144 *_bufferSize = strlcpy(buffer, module->name, *_bufferSize);
2145 *_cookie = i + 1;
2146 status = B_OK;
2147 break;
2151 return status;
2155 status_t
2156 get_module(const char* path, module_info** _info)
2158 module_image* moduleImage = NULL;
2159 module* module;
2160 status_t status;
2162 TRACE(("get_module(%s)\n", path));
2164 if (path == NULL)
2165 return B_BAD_VALUE;
2167 RecursiveLocker _(sModulesLock);
2169 module = sModulesHash->Lookup(path);
2171 // if we don't have it cached yet, search for it
2172 if (module == NULL || ((module->flags & B_BUILT_IN_MODULE) == 0
2173 && module->module_image == NULL)) {
2174 module = search_module(path, &moduleImage);
2175 if (module == NULL) {
2176 FATAL(("module: Search for %s failed.\n", path));
2177 return B_ENTRY_NOT_FOUND;
2180 module->info = moduleImage->info[module->offset];
2181 module->module_image = moduleImage;
2182 } else if ((module->flags & B_BUILT_IN_MODULE) == 0 && gBootDevice < 0
2183 && module->ref_count == 0) {
2184 // The boot volume isn't available yet. I.e. instead of searching the
2185 // right module image, we already know it and just increment the ref
2186 // count.
2187 atomic_add(&module->module_image->ref_count, 1);
2190 // The state will be adjusted by the call to init_module
2191 // if we have just loaded the file
2192 if (module->ref_count == 0) {
2193 status = init_module(module);
2194 // For "keep loaded" modules we increment the ref count here. That will
2195 // cause them never to get unloaded.
2196 if (status == B_OK && (module->flags & B_KEEP_LOADED) != 0)
2197 module->ref_count++;
2198 } else
2199 status = B_OK;
2201 if (status == B_OK) {
2202 ASSERT(module->ref_count >= 0);
2203 module->ref_count++;
2204 *_info = module->info;
2205 } else if ((module->flags & B_BUILT_IN_MODULE) == 0
2206 && module->ref_count == 0) {
2207 // initialization failed -- release the image reference
2208 put_module_image(module->module_image);
2209 if (gBootDevice >= 0)
2210 module->module_image = NULL;
2213 return status;
2217 status_t
2218 put_module(const char* path)
2220 module* module;
2222 TRACE(("put_module(path = %s)\n", path));
2224 RecursiveLocker _(sModulesLock);
2226 module = sModulesHash->Lookup(path);
2227 if (module == NULL) {
2228 FATAL(("module: We don't seem to have a reference to module %s\n",
2229 path));
2230 return B_BAD_VALUE;
2233 if (module->ref_count == 0) {
2234 panic("module %s has no references.\n", path);
2235 return B_BAD_VALUE;
2238 if (--module->ref_count == 0) {
2239 if ((module->flags & B_KEEP_LOADED) != 0) {
2240 panic("ref count of B_KEEP_LOADED module %s dropped to 0!",
2241 module->name);
2242 module->ref_count++;
2243 return B_BAD_VALUE;
2246 uninit_module(module);
2248 if ((module->flags & B_BUILT_IN_MODULE) == 0
2249 && module->ref_count == 0) {
2250 // uninit_module() increments the ref count on failure
2251 put_module_image(module->module_image);
2252 // Unless we don't have a boot device yet, we clear the module's
2253 // image pointer if the ref count dropped to 0. get_module() will
2254 // have to reload the image.
2255 if (gBootDevice >= 0)
2256 module->module_image = NULL;
2260 return B_OK;