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 */
53 extern module_info gDeviceManagerModule;
54 extern module_info gDeviceRootModule;
55 extern module_info gDeviceGenericModule;
56 extern module_info gFrameBufferConsoleModule;
57
58 // file systems
59 extern module_info gRootFileSystem;
60 extern module_info gDeviceFileSystem;
61
62 static module_info* sBuiltInModules[] = {
63 &gDeviceManagerModule,
64 &gDeviceRootModule,
65 &gDeviceGenericModule,
66 &gFrameBufferConsoleModule,
67
68 &gRootFileSystem,
69 &gDeviceFileSystem,
70 NULL
71 };
72
73 enum module_state {
74 MODULE_QUERIED = 0,
75 MODULE_LOADED,
76 MODULE_INIT,
77 MODULE_READY,
78 MODULE_UNINIT,
79 MODULE_ERROR
80 };
81
82
83 /* Each loaded module image (which can export several modules) is put
84 * in a hash (gModuleImagesHash) to be easily found when you search
85 * for a specific file name.
86 * TODO: Could use only the inode number for hashing. Would probably be
87 * a little bit slower, but would lower the memory foot print quite a lot.
88 */
89
90 struct module_image {
91 struct module_image* next;
92 module_info** info; // the module_info we use
93 module_dependency* dependencies;
94 char* path; // the full path for the module
95 image_id image;
96 int32 ref_count; // how many ref's to this file
97 };
98
99 /* Each known module will have this structure which is put in the
100 * gModulesHash, and looked up by name.
101 */
102
103 struct module {
104 struct module* next;
105 ::module_image* module_image;
106 char* name;
107 int32 ref_count;
108 module_info* info; // will only be valid if ref_count > 0
109 int32 offset; // this is the offset in the headers
110 module_state state;
111 uint32 flags;
112 };
113
114 #define B_BUILT_IN_MODULE 2
115
116 typedef struct module_path {
117 const char* name;
118 uint32 base_length;
119 } module_path;
120
121 typedef struct module_iterator {
122 module_path* stack;
123 int32 stack_size;
124 int32 stack_current;
125
126 char* prefix;
127 size_t prefix_length;
128 const char* suffix;
129 size_t suffix_length;
130 DIR* current_dir;
131 status_t status;
132 int32 module_offset;
133 // This is used to keep track of which module_info
134 // within a module we're addressing.
135 ::module_image* module_image;
136 module_info** current_header;
137 const char* current_path;
138 uint32 path_base_length;
139 const char* current_module_path;
140 bool builtin_modules;
141 bool loaded_modules;
142 } module_iterator;
143
144 namespace Module {
145
146 struct entry {
147 dev_t device;
148 ino_t node;
149 };
150
151 struct hash_entry : entry {
~hash_entryModule::hash_entry152 ~hash_entry()
153 {
154 free((char*)path);
155 }
156
157 hash_entry* hash_link;
158 const char* path;
159 };
160
161 struct NodeHashDefinition {
162 typedef entry* KeyType;
163 typedef hash_entry ValueType;
164
HashModule::NodeHashDefinition165 size_t Hash(ValueType* entry) const
166 { return HashKey(entry); }
GetLinkModule::NodeHashDefinition167 ValueType*& GetLink(ValueType* entry) const
168 { return entry->hash_link; }
169
HashKeyModule::NodeHashDefinition170 size_t HashKey(KeyType key) const
171 {
172 return ((uint32)(key->node >> 32) + (uint32)key->node) ^ key->device;
173 }
174
CompareModule::NodeHashDefinition175 bool Compare(KeyType key, ValueType* entry) const
176 {
177 return key->device == entry->device
178 && key->node == entry->node;
179 }
180 };
181
182 typedef BOpenHashTable<NodeHashDefinition> NodeHash;
183
184 struct module_listener : DoublyLinkedListLinkImpl<module_listener> {
~module_listenerModule::module_listener185 ~module_listener()
186 {
187 free((char*)prefix);
188 }
189
190 NotificationListener* listener;
191 const char* prefix;
192 };
193
194 typedef DoublyLinkedList<module_listener> ModuleListenerList;
195
196 struct module_notification : DoublyLinkedListLinkImpl<module_notification> {
~module_notificationModule::module_notification197 ~module_notification()
198 {
199 free((char*)name);
200 }
201
202 int32 opcode;
203 dev_t device;
204 ino_t directory;
205 ino_t node;
206 const char* name;
207 };
208
209 typedef DoublyLinkedList<module_notification> NotificationList;
210
211 class DirectoryWatcher : public NotificationListener {
212 public:
213 DirectoryWatcher();
214 virtual ~DirectoryWatcher();
215
216 virtual void EventOccurred(NotificationService& service,
217 const KMessage* event);
218 };
219
220 class ModuleWatcher : public NotificationListener {
221 public:
222 ModuleWatcher();
223 virtual ~ModuleWatcher();
224
225 virtual void EventOccurred(NotificationService& service,
226 const KMessage* event);
227 };
228
229 class ModuleNotificationService : public NotificationService {
230 public:
231 ModuleNotificationService();
232 virtual ~ModuleNotificationService();
233
234 status_t InitCheck();
235
236 status_t AddListener(const KMessage* eventSpecifier,
237 NotificationListener& listener);
238 status_t UpdateListener(const KMessage* eventSpecifier,
239 NotificationListener& listener);
240 status_t RemoveListener(const KMessage* eventSpecifier,
241 NotificationListener& listener);
242
243 bool HasNode(dev_t device, ino_t node);
244
245 void Notify(int32 opcode, dev_t device, ino_t directory,
246 ino_t node, const char* name);
247
Name()248 virtual const char* Name() { return "modules"; }
249
250 static void HandleNotifications(void *data, int iteration);
251
252 private:
253 status_t _RemoveNode(dev_t device, ino_t node);
254 status_t _AddNode(dev_t device, ino_t node, const char* path,
255 uint32 flags, NotificationListener& listener);
256 status_t _AddDirectoryNode(dev_t device, ino_t node);
257 status_t _AddModuleNode(dev_t device, ino_t node, int fd,
258 const char* name);
259
260 status_t _AddDirectory(const char* prefix);
261 status_t _ScanDirectory(char* directoryPath, const char* prefix,
262 size_t& prefixPosition);
263 status_t _ScanDirectory(Stack<DIR*>& stack, DIR* dir,
264 const char* prefix, size_t prefixPosition);
265
266 void _Notify(int32 opcode, dev_t device, ino_t directory,
267 ino_t node, const char* name);
268 void _HandleNotifications();
269
270 recursive_lock fLock;
271 ModuleListenerList fListeners;
272 NodeHash fNodes;
273 DirectoryWatcher fDirectoryWatcher;
274 ModuleWatcher fModuleWatcher;
275 NotificationList fNotifications;
276 };
277
278
279 struct ModuleHash {
280 typedef const char* KeyType;
281 typedef module ValueType;
282
HashModule::ModuleHash283 size_t Hash(ValueType* module) const
284 { return HashKey(module->name); }
GetLinkModule::ModuleHash285 ValueType*& GetLink(ValueType* entry) const
286 { return entry->next; }
287
HashKeyModule::ModuleHash288 size_t HashKey(KeyType key) const
289 {
290 return hash_hash_string(key);
291 }
292
CompareModule::ModuleHash293 bool Compare(KeyType key, ValueType* module) const
294 {
295 if (key == NULL)
296 return false;
297 return strcmp(module->name, key) == 0;
298 }
299 };
300
301 typedef BOpenHashTable<ModuleHash> ModuleTable;
302
303
304 struct ImageHash {
305 typedef const char* KeyType;
306 typedef module_image ValueType;
307
HashModule::ImageHash308 size_t Hash(ValueType* image) const
309 { return HashKey(image->path); }
GetLinkModule::ImageHash310 ValueType*& GetLink(ValueType* entry) const
311 { return entry->next; }
312
HashKeyModule::ImageHash313 size_t HashKey(KeyType key) const
314 {
315 return hash_hash_string(key);
316 }
317
CompareModule::ImageHash318 bool Compare(KeyType key, ValueType* image) const
319 {
320 if (key == NULL)
321 return false;
322 return strcmp(image->path, key) == 0;
323 }
324 };
325
326 typedef BOpenHashTable<ImageHash> ImageTable;
327
328 } // namespace Module
329
330 using namespace Module;
331
332 /* These are the standard base paths where we start to look for modules
333 * to load. Order is important, the last entry here will be searched
334 * first.
335 */
336 static const directory_which kModulePaths[] = {
337 B_SYSTEM_ADDONS_DIRECTORY,
338 B_SYSTEM_NONPACKAGED_ADDONS_DIRECTORY,
339 B_USER_ADDONS_DIRECTORY,
340 B_USER_NONPACKAGED_ADDONS_DIRECTORY,
341 };
342
343 static const uint32 kNumModulePaths = sizeof(kModulePaths)
344 / sizeof(kModulePaths[0]);
345 static const uint32 kFirstNonSystemModulePath = 1;
346
347
348 static ModuleNotificationService sModuleNotificationService;
349 static bool sDisableUserAddOns = false;
350
351 /* Locking scheme: There is a global lock only; having several locks
352 makes trouble if dependent modules get loaded concurrently ->
353 they have to wait for each other, i.e. we need one lock per module;
354 also we must detect circular references during init and not dead-lock.
355
356 Reference counting: get_module() increments the ref count of a module,
357 put_module() decrements it. When a B_KEEP_LOADED module is initialized
358 the ref count is incremented once more, so it never gets
359 uninitialized/unloaded. A referenced module, unless it's built-in, has a
360 non-null module_image and owns a reference to the image. When the last
361 module reference is put, the image's reference is released and module_image
362 zeroed (as long as the boot volume has not been mounted, it is not zeroed).
363 An unreferenced module image is unloaded (when the boot volume is mounted).
364 */
365 static recursive_lock sModulesLock;
366
367
368 /* We store the loaded modules by directory path, and all known modules
369 * by module name in a hash table for quick access
370 */
371 static ImageTable* sModuleImagesHash;
372 static ModuleTable* sModulesHash;
373
374
375
376
377 /*! Try to load the module image at the specified \a path.
378 If it could be loaded, it returns \c B_OK, and stores a pointer
379 to the module_image object in \a _moduleImage.
380 Needs to be called with the sModulesLock held.
381 */
382 static status_t
load_module_image(const char * path,module_image ** _moduleImage)383 load_module_image(const char* path, module_image** _moduleImage)
384 {
385 module_image* moduleImage;
386 status_t status;
387 image_id image;
388
389 TRACE(("load_module_image(path = \"%s\", _image = %p)\n", path,
390 _moduleImage));
391 ASSERT_LOCKED_RECURSIVE(&sModulesLock);
392 ASSERT(_moduleImage != NULL);
393
394 image = load_kernel_add_on(path);
395 if (image < 0) {
396 dprintf("load_module_image(%s) failed: %s\n", path, strerror(image));
397 return image;
398 }
399
400 moduleImage = (module_image*)malloc(sizeof(module_image));
401 if (moduleImage == NULL) {
402 status = B_NO_MEMORY;
403 goto err;
404 }
405
406 if (get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
407 (void**)&moduleImage->info) != B_OK) {
408 TRACE(("load_module_image: Failed to load \"%s\" due to lack of "
409 "'modules' symbol\n", path));
410 status = B_BAD_TYPE;
411 goto err1;
412 }
413
414 moduleImage->dependencies = NULL;
415 get_image_symbol(image, "module_dependencies", B_SYMBOL_TYPE_DATA,
416 (void**)&moduleImage->dependencies);
417 // this is allowed to be NULL
418
419 moduleImage->path = strdup(path);
420 if (!moduleImage->path) {
421 status = B_NO_MEMORY;
422 goto err1;
423 }
424
425 moduleImage->image = image;
426 moduleImage->ref_count = 0;
427
428 sModuleImagesHash->Insert(moduleImage);
429
430 TRACE(("load_module_image(\"%s\"): image loaded: %p\n", path, moduleImage));
431
432 *_moduleImage = moduleImage;
433 return B_OK;
434
435 err1:
436 free(moduleImage);
437 err:
438 unload_kernel_add_on(image);
439
440 return status;
441 }
442
443
444 /*! Unloads the module's kernel add-on. The \a image will be freed.
445 Needs to be called with the sModulesLock held.
446 */
447 static status_t
unload_module_image(module_image * moduleImage,bool remove)448 unload_module_image(module_image* moduleImage, bool remove)
449 {
450 TRACE(("unload_module_image(image %p, remove %d)\n", moduleImage, remove));
451 ASSERT_LOCKED_RECURSIVE(&sModulesLock);
452
453 if (moduleImage->ref_count != 0) {
454 FATAL(("Can't unload %s due to ref_cnt = %" B_PRId32 "\n",
455 moduleImage->path, moduleImage->ref_count));
456 return B_ERROR;
457 }
458
459 if (remove)
460 sModuleImagesHash->Remove(moduleImage);
461
462 unload_kernel_add_on(moduleImage->image);
463 free(moduleImage->path);
464 free(moduleImage);
465
466 return B_OK;
467 }
468
469
470 static void
put_module_image(module_image * image)471 put_module_image(module_image* image)
472 {
473 RecursiveLocker locker(sModulesLock);
474
475 int32 refCount = atomic_add(&image->ref_count, -1);
476 ASSERT(refCount > 0);
477
478 // Don't unload anything when there is no boot device yet
479 // (because chances are that we will never be able to access it again)
480
481 if (refCount == 1 && gBootDevice > 0)
482 unload_module_image(image, true);
483 }
484
485
486 static status_t
get_module_image(const char * path,module_image ** _image)487 get_module_image(const char* path, module_image** _image)
488 {
489 struct module_image* image;
490
491 TRACE(("get_module_image(path = \"%s\")\n", path));
492
493 RecursiveLocker _(sModulesLock);
494
495 image = sModuleImagesHash->Lookup(path);
496 if (image == NULL) {
497 status_t status = load_module_image(path, &image);
498 if (status < B_OK)
499 return status;
500 }
501
502 atomic_add(&image->ref_count, 1);
503 *_image = image;
504
505 return B_OK;
506 }
507
508
509 /*! Extract the information from the module_info structure pointed at
510 by "info" and create the entries required for access to it's details.
511 */
512 static status_t
create_module(module_info * info,int offset,module ** _module)513 create_module(module_info* info, int offset, module** _module)
514 {
515 module* module;
516
517 TRACE(("create_module(info = %p, offset = %d, _module = %p)\n",
518 info, offset, _module));
519
520 if (!info->name)
521 return B_BAD_VALUE;
522
523 module = sModulesHash->Lookup(info->name);
524 if (module) {
525 FATAL(("Duplicate module name (%s) detected... ignoring new one\n",
526 info->name));
527 return B_FILE_EXISTS;
528 }
529
530 if ((module = (struct module*)malloc(sizeof(struct module))) == NULL)
531 return B_NO_MEMORY;
532
533 TRACE(("create_module: name = \"%s\"\n", info->name));
534
535 module->module_image = NULL;
536 module->name = strdup(info->name);
537 if (module->name == NULL) {
538 free(module);
539 return B_NO_MEMORY;
540 }
541
542 module->state = MODULE_QUERIED;
543 module->info = info;
544 module->offset = offset;
545 // record where the module_info can be found in the module_info array
546 module->ref_count = 0;
547 module->flags = info->flags;
548
549 recursive_lock_lock(&sModulesLock);
550 sModulesHash->Insert(module);
551 recursive_lock_unlock(&sModulesLock);
552
553 if (_module)
554 *_module = module;
555
556 return B_OK;
557 }
558
559
560 /*! Loads the file at \a path and scans all modules contained therein.
561 Returns \c B_OK if \a searchedName could be found under those modules,
562 and will return the referenced image in \a _moduleImage.
563 Returns \c B_ENTRY_NOT_FOUND if the module could not be found.
564
565 Must only be called for files that haven't been scanned yet.
566 \a searchedName is allowed to be \c NULL (if all modules should be scanned)
567 */
568 static status_t
check_module_image(const char * path,const char * searchedName,module_image ** _moduleImage)569 check_module_image(const char* path, const char* searchedName,
570 module_image** _moduleImage)
571 {
572 status_t status = B_ENTRY_NOT_FOUND;
573 module_image* image;
574 module_info** info;
575 int index = 0;
576
577 TRACE(("check_module_image(path = \"%s\", searchedName = \"%s\")\n", path,
578 searchedName));
579
580 if (get_module_image(path, &image) < B_OK)
581 return B_ENTRY_NOT_FOUND;
582
583 for (info = image->info; *info; info++) {
584 // try to create a module for every module_info, check if the
585 // name matches if it was a new entry
586 bool freshModule = false;
587 struct module* module = sModulesHash->Lookup((*info)->name);
588 if (module != NULL) {
589 // Module does already exist
590 if (module->module_image == NULL && module->ref_count == 0) {
591 module->info = *info;
592 module->offset = index;
593 module->flags = (*info)->flags;
594 module->state = MODULE_QUERIED;
595 freshModule = true;
596 }
597 } else if (create_module(*info, index, NULL) == B_OK)
598 freshModule = true;
599
600 if (freshModule && searchedName != NULL
601 && strcmp((*info)->name, searchedName) == 0) {
602 status = B_OK;
603 }
604
605 index++;
606 }
607
608 if (status != B_OK) {
609 // decrement the ref we got in get_module_image
610 put_module_image(image);
611 return status;
612 }
613
614 *_moduleImage = image;
615 return B_OK;
616 }
617
618
619 static module*
search_module(const char * name,module_image ** _moduleImage)620 search_module(const char* name, module_image** _moduleImage)
621 {
622 status_t status = B_ENTRY_NOT_FOUND;
623 uint32 i;
624
625 TRACE(("search_module(%s)\n", name));
626
627 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
664 static status_t
put_dependent_modules(struct module * module)665 put_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
685 static status_t
get_dependent_modules(struct module * module)686 get_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 */
713 static inline status_t
init_module(module * module)714 init_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 */
776 static inline int
uninit_module(module * module)777 uninit_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
830 static const char*
iterator_pop_path_from_stack(module_iterator * iterator,uint32 * _baseLength)831 iterator_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
843 static status_t
iterator_push_path_on_stack(module_iterator * iterator,const char * path,uint32 baseLength)844 iterator_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
864 static bool
match_iterator_suffix(module_iterator * iterator,const char * name)865 match_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
879 static status_t
iterator_get_next_module(module_iterator * iterator,char * buffer,size_t * _bufferSize)880 iterator_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
927 nextPath:
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
949 nextModuleImage:
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
1069 static void
register_builtin_modules(struct module_info ** info)1070 register_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
1085 static status_t
register_preloaded_module_image(struct preloaded_image * image)1086 register_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
1142 error:
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
1154 static int
dump_modules(int argc,char ** argv)1155 dump_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
DirectoryWatcher()1187 DirectoryWatcher::DirectoryWatcher()
1188 {
1189 }
1190
1191
~DirectoryWatcher()1192 DirectoryWatcher::~DirectoryWatcher()
1193 {
1194 }
1195
1196
1197 void
EventOccurred(NotificationService & service,const KMessage * event)1198 DirectoryWatcher::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
ModuleWatcher()1227 ModuleWatcher::ModuleWatcher()
1228 {
1229 }
1230
1231
~ModuleWatcher()1232 ModuleWatcher::~ModuleWatcher()
1233 {
1234 }
1235
1236
1237 void
EventOccurred(NotificationService & service,const KMessage * event)1238 ModuleWatcher::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
ModuleNotificationService()1254 ModuleNotificationService::ModuleNotificationService()
1255 {
1256 recursive_lock_init(&fLock, "module notifications");
1257 }
1258
1259
~ModuleNotificationService()1260 ModuleNotificationService::~ModuleNotificationService()
1261 {
1262 recursive_lock_destroy(&fLock);
1263 }
1264
1265
1266 status_t
AddListener(const KMessage * eventSpecifier,NotificationListener & listener)1267 ModuleNotificationService::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
1297 status_t
UpdateListener(const KMessage * eventSpecifier,NotificationListener & listener)1298 ModuleNotificationService::UpdateListener(const KMessage* eventSpecifier,
1299 NotificationListener& listener)
1300 {
1301 return B_ERROR;
1302 }
1303
1304
1305 status_t
RemoveListener(const KMessage * eventSpecifier,NotificationListener & listener)1306 ModuleNotificationService::RemoveListener(const KMessage* eventSpecifier,
1307 NotificationListener& listener)
1308 {
1309 return B_ERROR;
1310 }
1311
1312
1313 bool
HasNode(dev_t device,ino_t node)1314 ModuleNotificationService::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
1323 status_t
_RemoveNode(dev_t device,ino_t node)1324 ModuleNotificationService::_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
1344 status_t
_AddNode(dev_t device,ino_t node,const char * path,uint32 flags,NotificationListener & listener)1345 ModuleNotificationService::_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
1383 status_t
_AddDirectoryNode(dev_t device,ino_t node)1384 ModuleNotificationService::_AddDirectoryNode(dev_t device, ino_t node)
1385 {
1386 return _AddNode(device, node, NULL, B_WATCH_DIRECTORY, fDirectoryWatcher);
1387 }
1388
1389
1390 status_t
_AddModuleNode(dev_t device,ino_t node,int fd,const char * name)1391 ModuleNotificationService::_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
1417 status_t
_AddDirectory(const char * prefix)1418 ModuleNotificationService::_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
1450 status_t
_ScanDirectory(char * directoryPath,const char * prefix,size_t & prefixPosition)1451 ModuleNotificationService::_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
1487 status_t
_ScanDirectory(Stack<DIR * > & stack,DIR * dir,const char * prefix,size_t prefixPosition)1488 ModuleNotificationService::_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
1564 void
_Notify(int32 opcode,dev_t device,ino_t directory,ino_t node,const char * name)1565 ModuleNotificationService::_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
1648 void
_HandleNotifications()1649 ModuleNotificationService::_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
1666 void
Notify(int32 opcode,dev_t device,ino_t directory,ino_t node,const char * name)1667 ModuleNotificationService::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
HandleNotifications(void *,int)1694 ModuleNotificationService::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 */
1707 status_t
unload_module(const char * path)1708 unload_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 */
1732 status_t
load_module(const char * path,module_info *** _modules)1733 load_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
1745 status_t
module_get_path(const char * moduleName,char ** filePath)1746 module_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
1767 status_t
start_watching_modules(const char * prefix,NotificationListener & listener)1768 start_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
1779 status_t
stop_watching_modules(const char * prefix,NotificationListener & listener)1780 stop_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 */
1794 status_t
module_init(kernel_args * args)1795 module_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
1837 status_t
module_init_post_threads(void)1838 module_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
1848 status_t
module_init_post_boot_device(bool bootingFromBootLoaderVolume)1849 module_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 */
1979 void*
open_module_list_etc(const char * prefix,const char * suffix)1980 open_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
2066 void*
open_module_list(const char * prefix)2067 open_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() */
2074 status_t
close_module_list(void * cookie)2075 close_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 */
2112 status_t
read_next_module_name(void * cookie,char * buffer,size_t * _bufferSize)2113 read_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 */
2145 status_t
get_next_loaded_module_name(uint32 * _cookie,char * buffer,size_t * _bufferSize)2146 get_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
2179 status_t
get_module(const char * path,module_info ** _info)2180 get_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
2241 status_t
put_module(const char * path)2242 put_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