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