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