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