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