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