xref: /haiku/src/system/kernel/module.cpp (revision 1e60bdeab63fa7a57bc9a55b032052e95a18bd2c)
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 		recursive_lock_lock(&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 					recursive_lock_unlock(&sModulesLock);
914 					return B_OK;
915 				}
916 			}
917 		}
918 
919 		recursive_lock_unlock(&sModulesLock);
920 
921 		// prevent from falling into modules hash iteration again
922 		iterator->loaded_modules = false;
923 	}
924 
925 nextPath:
926 	if (iterator->current_dir == NULL) {
927 		// get next directory path from the stack
928 		const char* path = iterator_pop_path_from_stack(iterator,
929 			&iterator->path_base_length);
930 		if (path == NULL) {
931 			// we are finished, there are no more entries on the stack
932 			return B_ENTRY_NOT_FOUND;
933 		}
934 
935 		free((char*)iterator->current_path);
936 		iterator->current_path = path;
937 		iterator->current_dir = opendir(path);
938 		TRACE(("open directory at %s -> %p\n", path, iterator->current_dir));
939 
940 		if (iterator->current_dir == NULL) {
941 			// we don't throw an error here, but silently go to
942 			// the next directory on the stack
943 			goto nextPath;
944 		}
945 	}
946 
947 nextModuleImage:
948 	// TODO: remember which directories were already scanned, and don't search
949 	// through them again, unless they change (use DirectoryWatcher)
950 
951 	if (iterator->current_header == NULL) {
952 		// get next entry from the current directory
953 
954 		errno = 0;
955 
956 		struct dirent* dirent;
957 		if ((dirent = readdir(iterator->current_dir)) == NULL) {
958 			closedir(iterator->current_dir);
959 			iterator->current_dir = NULL;
960 
961 			if (errno < B_OK)
962 				return errno;
963 
964 			goto nextPath;
965 		}
966 
967 		// check if the prefix matches
968 		int32 passedOffset, commonLength;
969 		passedOffset = strlen(iterator->current_path) + 1;
970 		commonLength = iterator->path_base_length + iterator->prefix_length
971 			- passedOffset;
972 
973 		if (commonLength > 0) {
974 			// the prefix still reaches into the new path part
975 			int32 length = strlen(dirent->d_name);
976 			if (commonLength > length)
977 				commonLength = length;
978 
979 			if (strncmp(dirent->d_name, iterator->prefix + passedOffset
980 					- iterator->path_base_length, commonLength))
981 				goto nextModuleImage;
982 		}
983 
984 		// we're not interested in traversing these (again)
985 		if (!strcmp(dirent->d_name, ".")
986 			|| !strcmp(dirent->d_name, "..")
987 			// TODO: this is a bit unclean, as we actually only want to prevent
988 			// drivers/bin and drivers/dev to be scanned
989 			|| !strcmp(dirent->d_name, "bin")
990 			|| !strcmp(dirent->d_name, "dev"))
991 			goto nextModuleImage;
992 
993 		// build absolute path to current file
994 		KPath path(iterator->current_path);
995 		if (path.InitCheck() != B_OK)
996 			return B_NO_MEMORY;
997 
998 		if (path.Append(dirent->d_name) != B_OK)
999 			return B_BUFFER_OVERFLOW;
1000 
1001 		// find out if it's a directory or a file
1002 		struct stat stat;
1003 		if (::stat(path.Path(), &stat) < 0)
1004 			return errno;
1005 
1006 		iterator->current_module_path = strdup(path.Path());
1007 		if (iterator->current_module_path == NULL)
1008 			return B_NO_MEMORY;
1009 
1010 		if (S_ISDIR(stat.st_mode)) {
1011 			status = iterator_push_path_on_stack(iterator,
1012 				iterator->current_module_path, iterator->path_base_length);
1013 			if (status != B_OK)
1014 				return status;
1015 
1016 			iterator->current_module_path = NULL;
1017 			goto nextModuleImage;
1018 		}
1019 
1020 		if (!S_ISREG(stat.st_mode))
1021 			return B_BAD_TYPE;
1022 
1023 		TRACE(("open module at %s\n", path.Path()));
1024 
1025 		status = get_module_image(path.Path(), &iterator->module_image);
1026 		if (status < B_OK) {
1027 			free((char*)iterator->current_module_path);
1028 			iterator->current_module_path = NULL;
1029 			goto nextModuleImage;
1030 		}
1031 
1032 		iterator->current_header = iterator->module_image->info;
1033 		iterator->module_offset = 0;
1034 	}
1035 
1036 	// search the current module image until we've got a match
1037 	while (*iterator->current_header != NULL) {
1038 		module_info* info = *iterator->current_header;
1039 
1040 		// TODO: we might want to create a module here and cache it in the
1041 		// hash table
1042 
1043 		iterator->current_header++;
1044 		iterator->module_offset++;
1045 
1046 		if (strncmp(info->name, iterator->prefix, iterator->prefix_length)
1047 			|| !match_iterator_suffix(iterator, info->name))
1048 			continue;
1049 
1050 		*_bufferSize = strlcpy(buffer, info->name, *_bufferSize);
1051 		return B_OK;
1052 	}
1053 
1054 	// leave this module and get the next one
1055 
1056 	iterator->current_header = NULL;
1057 	free((char*)iterator->current_module_path);
1058 	iterator->current_module_path = NULL;
1059 
1060 	put_module_image(iterator->module_image);
1061 	iterator->module_image = NULL;
1062 
1063 	goto nextModuleImage;
1064 }
1065 
1066 
1067 static void
1068 register_builtin_modules(struct module_info** info)
1069 {
1070 	for (; *info; info++) {
1071 		(*info)->flags |= B_BUILT_IN_MODULE;
1072 			// this is an internal flag, it doesn't have to be set by modules
1073 			// itself
1074 
1075 		if (create_module(*info, -1, NULL) != B_OK) {
1076 			dprintf("creation of built-in module \"%s\" failed!\n",
1077 				(*info)->name);
1078 		}
1079 	}
1080 }
1081 
1082 
1083 static status_t
1084 register_preloaded_module_image(struct preloaded_image* image)
1085 {
1086 	module_image* moduleImage;
1087 	struct module_info** info;
1088 	status_t status;
1089 	int32 index = 0;
1090 
1091 	TRACE(("register_preloaded_module_image(image = %p, name = \"%s\")\n",
1092 		image, image->name.Pointer()));
1093 
1094 	image->is_module = false;
1095 
1096 	if (image->id < 0)
1097 		return B_BAD_VALUE;
1098 
1099 	moduleImage = (module_image*)malloc(sizeof(module_image));
1100 	if (moduleImage == NULL)
1101 		return B_NO_MEMORY;
1102 
1103 	if (get_image_symbol(image->id, "modules", B_SYMBOL_TYPE_DATA,
1104 			(void**)&moduleImage->info) != B_OK) {
1105 		status = B_BAD_TYPE;
1106 		goto error;
1107 	}
1108 
1109 	image->is_module = true;
1110 
1111 	if (moduleImage->info[0] == NULL) {
1112 		status = B_BAD_DATA;
1113 		goto error;
1114 	}
1115 
1116 	moduleImage->dependencies = NULL;
1117 	get_image_symbol(image->id, "module_dependencies", B_SYMBOL_TYPE_DATA,
1118 		(void**)&moduleImage->dependencies);
1119 		// this is allowed to be NULL
1120 
1121 	moduleImage->path = strdup(image->name);
1122 	if (moduleImage->path == NULL) {
1123 		status = B_NO_MEMORY;
1124 		goto error;
1125 	}
1126 
1127 	moduleImage->image = image->id;
1128 	moduleImage->ref_count = 0;
1129 
1130 	sModuleImagesHash->Insert(moduleImage);
1131 
1132 	for (info = moduleImage->info; *info; info++) {
1133 		struct module* module = NULL;
1134 		if (create_module(*info, index++, &module) == B_OK)
1135 			module->module_image = moduleImage;
1136 	}
1137 
1138 	return B_OK;
1139 
1140 error:
1141 	free(moduleImage);
1142 
1143 	// We don't need this image anymore. We keep it, if it doesn't look like
1144 	// a module at all. It might be an old-style driver.
1145 	if (image->is_module)
1146 		unload_kernel_add_on(image->id);
1147 
1148 	return status;
1149 }
1150 
1151 
1152 static int
1153 dump_modules(int argc, char** argv)
1154 {
1155 	struct module_image* image;
1156 
1157 	ModuleTable::Iterator iterator(sModulesHash);
1158 	kprintf("-- known modules:\n");
1159 
1160 	while (iterator.HasNext()) {
1161 		struct module* module = iterator.Next();
1162 		kprintf("%p: \"%s\", \"%s\" (%" B_PRId32 "), refcount = %" B_PRId32 ", "
1163 			"state = %d, mimage = %p\n", module, module->name,
1164 			module->module_image ? module->module_image->path : "",
1165 			module->offset, module->ref_count, module->state,
1166 			module->module_image);
1167 	}
1168 
1169 	ImageTable::Iterator imageIterator(sModuleImagesHash);
1170 	kprintf("\n-- loaded module images:\n");
1171 
1172 	while (imageIterator.HasNext()) {
1173 		image = imageIterator.Next();
1174 		kprintf("%p: \"%s\" (image_id = %" B_PRId32 "), info = %p, refcount = "
1175 			"%" B_PRId32 "\n", image, image->path, image->image, image->info,
1176 			image->ref_count);
1177 	}
1178 	return 0;
1179 }
1180 
1181 
1182 //	#pragma mark - DirectoryWatcher
1183 
1184 
1185 DirectoryWatcher::DirectoryWatcher()
1186 {
1187 }
1188 
1189 
1190 DirectoryWatcher::~DirectoryWatcher()
1191 {
1192 }
1193 
1194 
1195 void
1196 DirectoryWatcher::EventOccurred(NotificationService& service,
1197 	const KMessage* event)
1198 {
1199 	int32 opcode = event->GetInt32("opcode", -1);
1200 	dev_t device = event->GetInt32("device", -1);
1201 	ino_t directory = event->GetInt64("directory", -1);
1202 	ino_t node = event->GetInt64("node", -1);
1203 	const char *name = event->GetString("name", NULL);
1204 
1205 	if (opcode == B_ENTRY_MOVED) {
1206 		// Determine whether it's a move within, out of, or into one
1207 		// of our watched directories.
1208 		directory = event->GetInt64("to directory", -1);
1209 		if (!sModuleNotificationService.HasNode(device, directory)) {
1210 			directory = event->GetInt64("from directory", -1);
1211 			opcode = B_ENTRY_REMOVED;
1212 		} else {
1213 			// Move within, doesn't sound like a good idea for modules
1214 			opcode = B_ENTRY_CREATED;
1215 		}
1216 	}
1217 
1218 	sModuleNotificationService.Notify(opcode, device, directory, node, name);
1219 }
1220 
1221 
1222 //	#pragma mark - ModuleWatcher
1223 
1224 
1225 ModuleWatcher::ModuleWatcher()
1226 {
1227 }
1228 
1229 
1230 ModuleWatcher::~ModuleWatcher()
1231 {
1232 }
1233 
1234 
1235 void
1236 ModuleWatcher::EventOccurred(NotificationService& service, const KMessage* event)
1237 {
1238 	if (event->GetInt32("opcode", -1) != B_STAT_CHANGED
1239 		|| (event->GetInt32("fields", 0) & B_STAT_MODIFICATION_TIME) == 0)
1240 		return;
1241 
1242 	dev_t device = event->GetInt32("device", -1);
1243 	ino_t node = event->GetInt64("node", -1);
1244 
1245 	sModuleNotificationService.Notify(B_STAT_CHANGED, device, -1, node, NULL);
1246 }
1247 
1248 
1249 //	#pragma mark - ModuleNotificationService
1250 
1251 
1252 ModuleNotificationService::ModuleNotificationService()
1253 {
1254 	recursive_lock_init(&fLock, "module notifications");
1255 }
1256 
1257 
1258 ModuleNotificationService::~ModuleNotificationService()
1259 {
1260 	recursive_lock_destroy(&fLock);
1261 }
1262 
1263 
1264 status_t
1265 ModuleNotificationService::AddListener(const KMessage* eventSpecifier,
1266 	NotificationListener& listener)
1267 {
1268 	const char* prefix = eventSpecifier->GetString("prefix", NULL);
1269 	if (prefix == NULL)
1270 		return B_BAD_VALUE;
1271 
1272 	module_listener* moduleListener = new(std::nothrow) module_listener;
1273 	if (moduleListener == NULL)
1274 		return B_NO_MEMORY;
1275 
1276 	moduleListener->prefix = strdup(prefix);
1277 	if (moduleListener->prefix == NULL) {
1278 		delete moduleListener;
1279 		return B_NO_MEMORY;
1280 	}
1281 
1282 	status_t status = _AddDirectory(prefix);
1283 	if (status != B_OK) {
1284 		delete moduleListener;
1285 		return status;
1286 	}
1287 
1288 	moduleListener->listener = &listener;
1289 	fListeners.Add(moduleListener);
1290 
1291 	return B_OK;
1292 }
1293 
1294 
1295 status_t
1296 ModuleNotificationService::UpdateListener(const KMessage* eventSpecifier,
1297 	NotificationListener& listener)
1298 {
1299 	return B_ERROR;
1300 }
1301 
1302 
1303 status_t
1304 ModuleNotificationService::RemoveListener(const KMessage* eventSpecifier,
1305 	NotificationListener& listener)
1306 {
1307 	return B_ERROR;
1308 }
1309 
1310 
1311 bool
1312 ModuleNotificationService::HasNode(dev_t device, ino_t node)
1313 {
1314 	RecursiveLocker _(fLock);
1315 
1316 	struct entry entry = {device, node};
1317 	return fNodes.Lookup(&entry) != NULL;
1318 }
1319 
1320 
1321 status_t
1322 ModuleNotificationService::_RemoveNode(dev_t device, ino_t node)
1323 {
1324 	RecursiveLocker _(fLock);
1325 
1326 	struct entry key = {device, node};
1327 	hash_entry* entry = fNodes.Lookup(&key);
1328 	if (entry == NULL)
1329 		return B_ENTRY_NOT_FOUND;
1330 
1331 	remove_node_listener(device, node, entry->path != NULL
1332 		? (NotificationListener&)fModuleWatcher
1333 		: (NotificationListener&)fDirectoryWatcher);
1334 
1335 	fNodes.Remove(entry);
1336 	delete entry;
1337 
1338 	return B_OK;
1339 }
1340 
1341 
1342 status_t
1343 ModuleNotificationService::_AddNode(dev_t device, ino_t node, const char* path,
1344 	uint32 flags, NotificationListener& listener)
1345 {
1346 	RecursiveLocker locker(fLock);
1347 
1348 	if (HasNode(device, node))
1349 		return B_OK;
1350 
1351 	struct hash_entry* entry = new(std::nothrow) hash_entry;
1352 	if (entry == NULL)
1353 		return B_NO_MEMORY;
1354 
1355 	if (path != NULL) {
1356 		entry->path = strdup(path);
1357 		if (entry->path == NULL) {
1358 			delete entry;
1359 			return B_NO_MEMORY;
1360 		}
1361 	} else
1362 		entry->path = NULL;
1363 
1364 	status_t status = add_node_listener(device, node, flags, listener);
1365 	if (status != B_OK) {
1366 		delete entry;
1367 		return status;
1368 	}
1369 
1370 	//dprintf("  add %s %ld:%Ld (%s)\n", flags == B_WATCH_DIRECTORY
1371 	//	? "dir" : "file", device, node, path);
1372 
1373 	entry->device = device;
1374 	entry->node = node;
1375 	fNodes.Insert(entry);
1376 
1377 	return B_OK;
1378 }
1379 
1380 
1381 status_t
1382 ModuleNotificationService::_AddDirectoryNode(dev_t device, ino_t node)
1383 {
1384 	return _AddNode(device, node, NULL, B_WATCH_DIRECTORY, fDirectoryWatcher);
1385 }
1386 
1387 
1388 status_t
1389 ModuleNotificationService::_AddModuleNode(dev_t device, ino_t node, int fd,
1390 	const char* name)
1391 {
1392 	struct vnode* vnode;
1393 	status_t status = vfs_get_vnode_from_fd(fd, true, &vnode);
1394 	if (status != B_OK)
1395 		return status;
1396 
1397 	ino_t directory;
1398 	vfs_vnode_to_node_ref(vnode, &device, &directory);
1399 
1400 	KPath path;
1401 	status = path.InitCheck();
1402 	if (status == B_OK) {
1403 		status = vfs_entry_ref_to_path(device, directory, name, true,
1404 			path.LockBuffer(), path.BufferSize());
1405 	}
1406 	if (status != B_OK)
1407 		return status;
1408 
1409 	path.UnlockBuffer();
1410 
1411 	return _AddNode(device, node, path.Path(), B_WATCH_STAT, fModuleWatcher);
1412 }
1413 
1414 
1415 status_t
1416 ModuleNotificationService::_AddDirectory(const char* prefix)
1417 {
1418 	status_t status = B_ERROR;
1419 
1420 	for (uint32 i = 0; i < kNumModulePaths; i++) {
1421 		if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
1422 			break;
1423 
1424 		KPath pathBuffer;
1425 		if (__find_directory(kModulePaths[i], gBootDevice, true,
1426 				pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
1427 			continue;
1428 
1429 		pathBuffer.UnlockBuffer();
1430 		pathBuffer.Append("kernel");
1431 		pathBuffer.Append(prefix);
1432 
1433 		size_t prefixPosition = strlen(prefix);
1434 		status_t scanStatus = _ScanDirectory(pathBuffer.LockBuffer(), prefix,
1435 			prefixPosition);
1436 
1437 		pathBuffer.UnlockBuffer();
1438 
1439 		// It's enough if we succeed for one directory
1440 		if (status != B_OK)
1441 			status = scanStatus;
1442 	}
1443 
1444 	return status;
1445 }
1446 
1447 
1448 status_t
1449 ModuleNotificationService::_ScanDirectory(char* directoryPath,
1450 	const char* prefix, size_t& prefixPosition)
1451 {
1452 	DIR* dir = NULL;
1453 	while (true) {
1454 		dir = opendir(directoryPath);
1455 		if (dir != NULL || prefixPosition == 0)
1456 			break;
1457 
1458 		// the full prefix is not accessible, remove path components
1459 		const char* parentPrefix = prefix + prefixPosition - 1;
1460 		while (parentPrefix != prefix && parentPrefix[0] != '/')
1461 			parentPrefix--;
1462 
1463 		size_t cutPosition = parentPrefix - prefix;
1464 		size_t length = strlen(directoryPath);
1465 		directoryPath[length - prefixPosition + cutPosition] = '\0';
1466 		prefixPosition = cutPosition;
1467 	}
1468 
1469 	if (dir == NULL)
1470 		return B_ERROR;
1471 
1472 	Stack<DIR*> stack;
1473 	stack.Push(dir);
1474 
1475 	while (stack.Pop(&dir)) {
1476 		status_t status = _ScanDirectory(stack, dir, prefix, prefixPosition);
1477 		if (status != B_OK)
1478 			return status;
1479 	}
1480 
1481 	return B_OK;
1482 }
1483 
1484 
1485 status_t
1486 ModuleNotificationService::_ScanDirectory(Stack<DIR*>& stack, DIR* dir,
1487 	const char* prefix, size_t prefixPosition)
1488 {
1489 	bool directMatchAdded = false;
1490 	struct dirent* dirent;
1491 
1492 	while ((dirent = readdir(dir)) != NULL) {
1493 		if (dirent->d_name[0] == '.')
1494 			continue;
1495 
1496 		bool directMatch = false;
1497 
1498 		if (prefix[prefixPosition] != '\0') {
1499 			// the start must match
1500 			const char* startPrefix = prefix + prefixPosition;
1501 			if (startPrefix[0] == '/')
1502 				startPrefix++;
1503 
1504 			const char* endPrefix = strchr(startPrefix, '/');
1505 			size_t length;
1506 
1507 			if (endPrefix != NULL)
1508 				length = endPrefix - startPrefix;
1509 			else
1510 				length = strlen(startPrefix);
1511 
1512 			if (strncmp(dirent->d_name, startPrefix, length))
1513 				continue;
1514 
1515 			if (dirent->d_name[length] == '\0')
1516 				directMatch = true;
1517 		}
1518 
1519 		struct stat stat;
1520 		status_t status = vfs_read_stat(dirfd(dir), dirent->d_name, true, &stat,
1521 			true);
1522 		if (status != B_OK)
1523 			continue;
1524 
1525 		if (S_ISDIR(stat.st_mode)) {
1526 			int fd = _kern_open_dir(dirfd(dir), dirent->d_name);
1527 			if (fd < 0)
1528 				continue;
1529 
1530 			DIR* subDir = fdopendir(fd);
1531 			if (subDir == NULL) {
1532 				close(fd);
1533 				continue;
1534 			}
1535 
1536 			stack.Push(subDir);
1537 
1538 			if (_AddDirectoryNode(stat.st_dev, stat.st_ino) == B_OK
1539 				&& directMatch)
1540 				directMatchAdded = true;
1541 		} else if (S_ISREG(stat.st_mode)) {
1542 			if (_AddModuleNode(stat.st_dev, stat.st_ino, dirfd(dir),
1543 					dirent->d_name) == B_OK && directMatch)
1544 				directMatchAdded = true;
1545 		}
1546 	}
1547 
1548 	if (!directMatchAdded) {
1549 		// We need to monitor this directory to see if a matching file
1550 		// is added.
1551 		struct stat stat;
1552 		status_t status = vfs_read_stat(dirfd(dir), NULL, true, &stat, true);
1553 		if (status == B_OK)
1554 			_AddDirectoryNode(stat.st_dev, stat.st_ino);
1555 	}
1556 
1557 	closedir(dir);
1558 	return B_OK;
1559 }
1560 
1561 
1562 void
1563 ModuleNotificationService::_Notify(int32 opcode, dev_t device, ino_t directory,
1564 	ino_t node, const char* name)
1565 {
1566 	// construct path
1567 
1568 	KPath pathBuffer;
1569 	const char* path;
1570 
1571 	if (name != NULL) {
1572 		// we have an entry ref
1573 		if (pathBuffer.InitCheck() != B_OK
1574 			|| vfs_entry_ref_to_path(device, directory, name, true,
1575 				pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
1576 			return;
1577 
1578 		pathBuffer.UnlockBuffer();
1579 		path = pathBuffer.Path();
1580 	} else {
1581 		// we only have a node ref
1582 		RecursiveLocker _(fLock);
1583 
1584 		struct entry key = {device, node};
1585 		hash_entry* entry = fNodes.Lookup(&key);
1586 		if (entry == NULL || entry->path == NULL)
1587 			return;
1588 
1589 		path = entry->path;
1590 	}
1591 
1592 	// remove kModulePaths from path
1593 
1594 	for (uint32 i = 0; i < kNumModulePaths; i++) {
1595 		KPath modulePath;
1596 		if (__find_directory(kModulePaths[i], gBootDevice, true,
1597 				modulePath.LockBuffer(), modulePath.BufferSize()) != B_OK)
1598 			continue;
1599 
1600 		modulePath.UnlockBuffer();
1601 		modulePath.Append("kernel");
1602 
1603 		if (strncmp(path, modulePath.Path(), modulePath.Length()))
1604 			continue;
1605 
1606 		path += modulePath.Length();
1607 		if (path[i] == '/')
1608 			path++;
1609 
1610 		break;
1611 	}
1612 
1613 	KMessage event;
1614 
1615 	// find listeners by prefix/path
1616 
1617 	ModuleListenerList::Iterator iterator = fListeners.GetIterator();
1618 	while (iterator.HasNext()) {
1619 		module_listener* listener = iterator.Next();
1620 
1621 		if (strncmp(path, listener->prefix, strlen(listener->prefix)))
1622 			continue;
1623 
1624 		if (event.IsEmpty()) {
1625 			// construct message only when needed
1626 			event.AddInt32("opcode", opcode);
1627 			event.AddString("path", path);
1628 		}
1629 
1630 		// notify them!
1631 		listener->listener->EventOccurred(*this, &event);
1632 
1633 		// we might need to watch new files now
1634 		if (opcode == B_ENTRY_CREATED)
1635 			_AddDirectory(listener->prefix);
1636 
1637 	}
1638 
1639 	// remove notification listeners, if needed
1640 
1641 	if (opcode == B_ENTRY_REMOVED)
1642 		_RemoveNode(device, node);
1643 }
1644 
1645 
1646 void
1647 ModuleNotificationService::_HandleNotifications()
1648 {
1649 	RecursiveLocker _(fLock);
1650 
1651 	NotificationList::Iterator iterator = fNotifications.GetIterator();
1652 	while (iterator.HasNext()) {
1653 		module_notification* notification = iterator.Next();
1654 
1655 		_Notify(notification->opcode, notification->device,
1656 			notification->directory, notification->node, notification->name);
1657 
1658 		iterator.Remove();
1659 		delete notification;
1660 	}
1661 }
1662 
1663 
1664 void
1665 ModuleNotificationService::Notify(int32 opcode, dev_t device, ino_t directory,
1666 	ino_t node, const char* name)
1667 {
1668 	module_notification* notification = new(std::nothrow) module_notification;
1669 	if (notification == NULL)
1670 		return;
1671 
1672 	if (name != NULL) {
1673 		notification->name = strdup(name);
1674 		if (notification->name == NULL) {
1675 			delete notification;
1676 			return;
1677 		}
1678 	} else
1679 		notification->name = NULL;
1680 
1681 	notification->opcode = opcode;
1682 	notification->device = device;
1683 	notification->directory = directory;
1684 	notification->node = node;
1685 
1686 	RecursiveLocker _(fLock);
1687 	fNotifications.Add(notification);
1688 }
1689 
1690 
1691 /*static*/ void
1692 ModuleNotificationService::HandleNotifications(void * /*data*/,
1693 	int /*iteration*/)
1694 {
1695 	sModuleNotificationService._HandleNotifications();
1696 }
1697 
1698 
1699 //	#pragma mark - Exported Kernel API (private part)
1700 
1701 
1702 /*!	Unloads a module in case it's not in use. This is the counterpart
1703 	to load_module().
1704 */
1705 status_t
1706 unload_module(const char* path)
1707 {
1708 	struct module_image* moduleImage;
1709 
1710 	recursive_lock_lock(&sModulesLock);
1711 	moduleImage = sModuleImagesHash->Lookup(path);
1712 	recursive_lock_unlock(&sModulesLock);
1713 
1714 	if (moduleImage == NULL)
1715 		return B_ENTRY_NOT_FOUND;
1716 
1717 	put_module_image(moduleImage);
1718 	return B_OK;
1719 }
1720 
1721 
1722 /*!	Unlike get_module(), this function lets you specify the add-on to
1723 	be loaded by path.
1724 	However, you must not use the exported modules without having called
1725 	get_module() on them. When you're done with the NULL terminated
1726 	\a modules array, you have to call unload_module(), no matter if
1727 	you're actually using any of the modules or not - of course, the
1728 	add-on won't be unloaded until the last put_module().
1729 */
1730 status_t
1731 load_module(const char* path, module_info*** _modules)
1732 {
1733 	module_image* moduleImage;
1734 	status_t status = get_module_image(path, &moduleImage);
1735 	if (status != B_OK)
1736 		return status;
1737 
1738 	*_modules = moduleImage->info;
1739 	return B_OK;
1740 }
1741 
1742 
1743 status_t
1744 start_watching_modules(const char* prefix, NotificationListener& listener)
1745 {
1746 	KMessage specifier;
1747 	status_t status = specifier.AddString("prefix", prefix);
1748 	if (status != B_OK)
1749 		return status;
1750 
1751 	return sModuleNotificationService.AddListener(&specifier, listener);
1752 }
1753 
1754 
1755 status_t
1756 stop_watching_modules(const char* prefix, NotificationListener& listener)
1757 {
1758 	KMessage specifier;
1759 	status_t status = specifier.AddString("prefix", prefix);
1760 	if (status != B_OK)
1761 		return status;
1762 
1763 	return sModuleNotificationService.RemoveListener(&specifier, listener);
1764 }
1765 
1766 
1767 /*! Setup the module structures and data for use - must be called
1768 	before any other module call.
1769 */
1770 status_t
1771 module_init(kernel_args* args)
1772 {
1773 	struct preloaded_image* image;
1774 
1775 	recursive_lock_init(&sModulesLock, "modules rlock");
1776 
1777 	sModulesHash = new(std::nothrow) ModuleTable();
1778 	if (sModulesHash == NULL
1779 			|| sModulesHash->Init(MODULE_HASH_SIZE) != B_OK)
1780 		return B_NO_MEMORY;
1781 
1782 	sModuleImagesHash = new(std::nothrow) ImageTable();
1783 	if (sModuleImagesHash == NULL
1784 			|| sModuleImagesHash->Init(MODULE_HASH_SIZE) != B_OK)
1785 		return B_NO_MEMORY;
1786 
1787 	// register built-in modules
1788 
1789 	register_builtin_modules(sBuiltInModules);
1790 
1791 	// register preloaded images
1792 
1793 	for (image = args->preloaded_images; image != NULL; image = image->next) {
1794 		status_t status = register_preloaded_module_image(image);
1795 		if (status != B_OK && image->is_module) {
1796 			dprintf("Could not register image \"%s\": %s\n", (char *)image->name,
1797 				strerror(status));
1798 		}
1799 	}
1800 
1801 	new(&sModuleNotificationService) ModuleNotificationService();
1802 
1803 	sDisableUserAddOns = get_safemode_boolean(B_SAFEMODE_DISABLE_USER_ADD_ONS,
1804 		false);
1805 
1806 	add_debugger_command("modules", &dump_modules,
1807 		"list all known & loaded modules");
1808 
1809 	return B_OK;
1810 }
1811 
1812 
1813 status_t
1814 module_init_post_threads(void)
1815 {
1816 	return register_kernel_daemon(
1817 		&ModuleNotificationService::HandleNotifications, NULL, 10);
1818 		// once every second
1819 
1820 	return B_OK;
1821 }
1822 
1823 
1824 status_t
1825 module_init_post_boot_device(bool bootingFromBootLoaderVolume)
1826 {
1827 	// Remove all unused pre-loaded module images. Now that the boot device is
1828 	// available, we can load an image when we need it.
1829 	// When the boot volume is also where the boot loader pre-loaded the images
1830 	// from, we get the actual paths for those images.
1831 	TRACE(("module_init_post_boot_device(%d)\n", bootingFromBootLoaderVolume));
1832 
1833 	RecursiveLocker _(sModulesLock);
1834 
1835 	// First of all, clear all pre-loaded module's module_image, if the module
1836 	// isn't in use.
1837 	ModuleTable::Iterator iterator(sModulesHash);
1838 	struct module* module;
1839 	while (iterator.HasNext()) {
1840 		module = iterator.Next();
1841 		if (module->ref_count == 0
1842 			&& (module->flags & B_BUILT_IN_MODULE) == 0) {
1843 			TRACE(("  module %p, \"%s\" unused, clearing image\n", module,
1844 				module->name));
1845 			module->module_image = NULL;
1846 		}
1847 	}
1848 
1849 	// Now iterate through the images and drop them respectively normalize their
1850 	// paths.
1851 	ImageTable::Iterator imageIterator(sModuleImagesHash);
1852 
1853 	module_image* imagesToReinsert = NULL;
1854 		// When renamed, an image is added to this list to be re-entered in the
1855 		// hash at the end. We can't do that during the iteration.
1856 
1857 	while (imageIterator.HasNext()) {
1858 		struct module_image* image = imageIterator.Next();
1859 
1860 		if (image->ref_count == 0) {
1861 			// not in use -- unload it
1862 			TRACE(("  module image %p, \"%s\" unused, removing\n", image,
1863 				image->path));
1864 			// Using RemoveUnchecked to avoid invalidating the iterator
1865 			sModuleImagesHash->RemoveUnchecked(image);
1866 			unload_module_image(image, false);
1867 		} else if (bootingFromBootLoaderVolume) {
1868 			bool pathNormalized = false;
1869 			KPath pathBuffer;
1870 			if (image->path[0] != '/') {
1871 				// relative path
1872 				for (uint32 i = kNumModulePaths; i-- > 0;) {
1873 					if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
1874 						continue;
1875 
1876 					if (__find_directory(kModulePaths[i], gBootDevice, true,
1877 							pathBuffer.LockBuffer(), pathBuffer.BufferSize())
1878 								!= B_OK) {
1879 						pathBuffer.UnlockBuffer();
1880 						continue;
1881 					}
1882 
1883 					pathBuffer.UnlockBuffer();
1884 
1885 					// Append the relative boot module directory and the
1886 					// relative image path, normalize the path, and check
1887 					// whether it exists.
1888 					struct stat st;
1889 					if (pathBuffer.Append("kernel/boot") != B_OK
1890 						|| pathBuffer.Append(image->path) != B_OK
1891 						|| pathBuffer.Normalize(true) != B_OK
1892 						|| lstat(pathBuffer.Path(), &st) != 0) {
1893 						continue;
1894 					}
1895 
1896 					pathNormalized = true;
1897 					break;
1898 				}
1899 			} else {
1900 				// absolute path -- try to normalize it anyway
1901 				struct stat st;
1902 				if (pathBuffer.SetPath(image->path) == B_OK
1903 					&& pathBuffer.Normalize(true) == B_OK
1904 					&& lstat(pathBuffer.Path(), &st) == 0) {
1905 					pathNormalized = true;
1906 				}
1907 			}
1908 
1909 			if (pathNormalized) {
1910 				TRACE(("  normalized path of module image %p, \"%s\" -> "
1911 					"\"%s\"\n", image, image->path, pathBuffer.Path()));
1912 
1913 				// remove the image -- its hash value has probably changed,
1914 				// so we need to re-insert it later
1915 				sModuleImagesHash->RemoveUnchecked(image);
1916 
1917 				// set the new path
1918 				free(image->path);
1919 				size_t pathLen = pathBuffer.Length();
1920 				image->path = (char*)realloc(pathBuffer.DetachBuffer(),
1921 					pathLen + 1);
1922 
1923 				image->next = imagesToReinsert;
1924 				imagesToReinsert = image;
1925 			} else {
1926 				dprintf("module_init_post_boot_device() failed to normalize "
1927 					"path of module image %p, \"%s\"\n", image, image->path);
1928 			}
1929 		}
1930 	}
1931 
1932 	// re-insert the images that have got a new path
1933 	while (module_image* image = imagesToReinsert) {
1934 		imagesToReinsert = image->next;
1935 		sModuleImagesHash->Insert(image);
1936 	}
1937 
1938 	TRACE(("module_init_post_boot_device() done\n"));
1939 
1940 	return B_OK;
1941 }
1942 
1943 
1944 //	#pragma mark - Exported Kernel API (public part)
1945 
1946 
1947 /*! This returns a pointer to a structure that can be used to
1948 	iterate through a list of all modules available under
1949 	a given prefix that adhere to the specified suffix.
1950 	All paths will be searched and the returned list will
1951 	contain all modules available under the prefix.
1952 	The structure is then used by read_next_module_name(), and
1953 	must be freed by calling close_module_list().
1954 */
1955 void*
1956 open_module_list_etc(const char* prefix, const char* suffix)
1957 {
1958 	TRACE(("open_module_list(prefix = %s)\n", prefix));
1959 
1960 	if (sModulesHash == NULL) {
1961 		dprintf("open_module_list() called too early!\n");
1962 		return NULL;
1963 	}
1964 
1965 	module_iterator* iterator = (module_iterator*)malloc(
1966 		sizeof(module_iterator));
1967 	if (iterator == NULL)
1968 		return NULL;
1969 
1970 	memset(iterator, 0, sizeof(module_iterator));
1971 
1972 	iterator->prefix = strdup(prefix != NULL ? prefix : "");
1973 	if (iterator->prefix == NULL) {
1974 		free(iterator);
1975 		return NULL;
1976 	}
1977 	iterator->prefix_length = strlen(iterator->prefix);
1978 
1979 	iterator->suffix = suffix;
1980 	if (suffix != NULL)
1981 		iterator->suffix_length = strlen(iterator->suffix);
1982 
1983 	if (gBootDevice > 0) {
1984 		// We do have a boot device to scan
1985 
1986 		// first, we'll traverse over the built-in modules
1987 		iterator->builtin_modules = true;
1988 		iterator->loaded_modules = false;
1989 
1990 		// put all search paths on the stack
1991 		for (uint32 i = 0; i < kNumModulePaths; i++) {
1992 			if (sDisableUserAddOns && i >= kFirstNonSystemModulePath)
1993 				break;
1994 
1995 			KPath pathBuffer;
1996 			if (__find_directory(kModulePaths[i], gBootDevice, true,
1997 					pathBuffer.LockBuffer(), pathBuffer.BufferSize()) != B_OK)
1998 				continue;
1999 
2000 			pathBuffer.UnlockBuffer();
2001 			pathBuffer.Append("kernel");
2002 
2003 			// Copy base path onto the iterator stack
2004 			char* path = strdup(pathBuffer.Path());
2005 			if (path == NULL)
2006 				continue;
2007 
2008 			size_t length = strlen(path);
2009 
2010 			// TODO: it would currently be nicer to use the commented
2011 			// version below, but the iterator won't work if the prefix
2012 			// is inside a module then.
2013 			// It works this way, but should be done better.
2014 #if 0
2015 			// Build path component: base path + '/' + prefix
2016 			size_t length = strlen(sModulePaths[i]);
2017 			char* path = (char*)malloc(length + iterator->prefix_length + 2);
2018 			if (path == NULL) {
2019 				// ToDo: should we abort the whole operation here?
2020 				//	if we do, don't forget to empty the stack
2021 				continue;
2022 			}
2023 
2024 			memcpy(path, sModulePaths[i], length);
2025 			path[length] = '/';
2026 			memcpy(path + length + 1, iterator->prefix,
2027 				iterator->prefix_length + 1);
2028 #endif
2029 
2030 			iterator_push_path_on_stack(iterator, path, length + 1);
2031 		}
2032 	} else {
2033 		// include loaded modules in case there is no boot device yet
2034 		iterator->builtin_modules = false;
2035 		iterator->loaded_modules = true;
2036 	}
2037 
2038 	return (void*)iterator;
2039 }
2040 
2041 
2042 void*
2043 open_module_list(const char* prefix)
2044 {
2045 	return open_module_list_etc(prefix, NULL);
2046 }
2047 
2048 
2049 /*!	Frees the cookie allocated by open_module_list() */
2050 status_t
2051 close_module_list(void* cookie)
2052 {
2053 	module_iterator* iterator = (module_iterator*)cookie;
2054 	const char* path;
2055 
2056 	TRACE(("close_module_list()\n"));
2057 
2058 	if (iterator == NULL)
2059 		return B_BAD_VALUE;
2060 
2061 	// free stack
2062 	while ((path = iterator_pop_path_from_stack(iterator, NULL)) != NULL)
2063 		free((char*)path);
2064 
2065 	// close what have been left open
2066 	if (iterator->module_image != NULL)
2067 		put_module_image(iterator->module_image);
2068 
2069 	if (iterator->current_dir != NULL)
2070 		closedir(iterator->current_dir);
2071 
2072 	free(iterator->stack);
2073 	free((char*)iterator->current_path);
2074 	free((char*)iterator->current_module_path);
2075 
2076 	free(iterator->prefix);
2077 	free(iterator);
2078 
2079 	return B_OK;
2080 }
2081 
2082 
2083 /*!	Return the next module name from the available list, using
2084 	a structure previously created by a call to open_module_list().
2085 	Returns B_OK as long as it found another module, B_ENTRY_NOT_FOUND
2086 	when done.
2087 */
2088 status_t
2089 read_next_module_name(void* cookie, char* buffer, size_t* _bufferSize)
2090 {
2091 	module_iterator* iterator = (module_iterator*)cookie;
2092 	status_t status;
2093 
2094 	TRACE(("read_next_module_name: looking for next module\n"));
2095 
2096 	if (iterator == NULL || buffer == NULL || _bufferSize == NULL)
2097 		return B_BAD_VALUE;
2098 
2099 	if (iterator->status < B_OK)
2100 		return iterator->status;
2101 
2102 	status = iterator->status;
2103 	recursive_lock_lock(&sModulesLock);
2104 
2105 	status = iterator_get_next_module(iterator, buffer, _bufferSize);
2106 
2107 	iterator->status = status;
2108 	recursive_lock_unlock(&sModulesLock);
2109 
2110 	TRACE(("read_next_module_name: finished with status %s\n",
2111 		strerror(status)));
2112 	return status;
2113 }
2114 
2115 
2116 /*!	Iterates through all loaded modules, and stores its path in "buffer".
2117 	TODO: check if the function in BeOS really does that (could also mean:
2118 		iterate through all modules that are currently loaded; have a valid
2119 		module_image pointer)
2120 */
2121 status_t
2122 get_next_loaded_module_name(uint32* _cookie, char* buffer, size_t* _bufferSize)
2123 {
2124 	if (sModulesHash == NULL) {
2125 		dprintf("get_next_loaded_module_name() called too early!\n");
2126 		return B_ERROR;
2127 	}
2128 
2129 	//TRACE(("get_next_loaded_module_name(\"%s\")\n", buffer));
2130 
2131 	if (_cookie == NULL || buffer == NULL || _bufferSize == NULL)
2132 		return B_BAD_VALUE;
2133 
2134 	status_t status = B_ENTRY_NOT_FOUND;
2135 	uint32 offset = *_cookie;
2136 
2137 	RecursiveLocker _(sModulesLock);
2138 
2139 	ModuleTable::Iterator iterator(sModulesHash);
2140 
2141 	for (uint32 i = 0; iterator.HasNext(); i++) {
2142 		struct module* module = iterator.Next();
2143 		if (i >= offset) {
2144 			*_bufferSize = strlcpy(buffer, module->name, *_bufferSize);
2145 			*_cookie = i + 1;
2146 			status = B_OK;
2147 			break;
2148 		}
2149 	}
2150 
2151 	return status;
2152 }
2153 
2154 
2155 status_t
2156 get_module(const char* path, module_info** _info)
2157 {
2158 	module_image* moduleImage = NULL;
2159 	module* module;
2160 	status_t status;
2161 
2162 	TRACE(("get_module(%s)\n", path));
2163 
2164 	if (path == NULL)
2165 		return B_BAD_VALUE;
2166 
2167 	RecursiveLocker _(sModulesLock);
2168 
2169 	module = sModulesHash->Lookup(path);
2170 
2171 	// if we don't have it cached yet, search for it
2172 	if (module == NULL || ((module->flags & B_BUILT_IN_MODULE) == 0
2173 			&& module->module_image == NULL)) {
2174 		module = search_module(path, &moduleImage);
2175 		if (module == NULL) {
2176 			FATAL(("module: Search for %s failed.\n", path));
2177 			return B_ENTRY_NOT_FOUND;
2178 		}
2179 
2180 		module->info = moduleImage->info[module->offset];
2181 		module->module_image = moduleImage;
2182 	} else if ((module->flags & B_BUILT_IN_MODULE) == 0 && gBootDevice < 0
2183 		&& module->ref_count == 0) {
2184 		// The boot volume isn't available yet. I.e. instead of searching the
2185 		// right module image, we already know it and just increment the ref
2186 		// count.
2187 		atomic_add(&module->module_image->ref_count, 1);
2188 	}
2189 
2190 	// The state will be adjusted by the call to init_module
2191 	// if we have just loaded the file
2192 	if (module->ref_count == 0) {
2193 		status = init_module(module);
2194 		// For "keep loaded" modules we increment the ref count here. That will
2195 		// cause them never to get unloaded.
2196 		if (status == B_OK && (module->flags & B_KEEP_LOADED) != 0)
2197 			module->ref_count++;
2198 	} else
2199 		status = B_OK;
2200 
2201 	if (status == B_OK) {
2202 		ASSERT(module->ref_count >= 0);
2203 		module->ref_count++;
2204 		*_info = module->info;
2205 	} else if ((module->flags & B_BUILT_IN_MODULE) == 0
2206 		&& module->ref_count == 0) {
2207 		// initialization failed -- release the image reference
2208 		put_module_image(module->module_image);
2209 		if (gBootDevice >= 0)
2210 			module->module_image = NULL;
2211 	}
2212 
2213 	return status;
2214 }
2215 
2216 
2217 status_t
2218 put_module(const char* path)
2219 {
2220 	module* module;
2221 
2222 	TRACE(("put_module(path = %s)\n", path));
2223 
2224 	RecursiveLocker _(sModulesLock);
2225 
2226 	module = sModulesHash->Lookup(path);
2227 	if (module == NULL) {
2228 		FATAL(("module: We don't seem to have a reference to module %s\n",
2229 			path));
2230 		return B_BAD_VALUE;
2231 	}
2232 
2233 	if (module->ref_count == 0) {
2234 		panic("module %s has no references.\n", path);
2235 		return B_BAD_VALUE;
2236 	}
2237 
2238 	if (--module->ref_count == 0) {
2239 		if ((module->flags & B_KEEP_LOADED) != 0) {
2240 			panic("ref count of B_KEEP_LOADED module %s dropped to 0!",
2241 				module->name);
2242 			module->ref_count++;
2243 			return B_BAD_VALUE;
2244 		}
2245 
2246 		uninit_module(module);
2247 
2248 		if ((module->flags & B_BUILT_IN_MODULE) == 0
2249 			&& module->ref_count == 0) {
2250 				// uninit_module() increments the ref count on failure
2251 			put_module_image(module->module_image);
2252 			// Unless we don't have a boot device yet, we clear the module's
2253 			// image pointer if the ref count dropped to 0. get_module() will
2254 			// have to reload the image.
2255 			if (gBootDevice >= 0)
2256 				module->module_image = NULL;
2257 		}
2258 	}
2259 
2260 	return B_OK;
2261 }
2262