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