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