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