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