1 /*
2 * Copyright 2002-2009, Haiku Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT license.
4 *
5 * Authors:
6 * Ingo Weinhold, bonefish@cs.tu-berlin.de.
7 * Axel Dörfler, axeld@pinc-software.de.
8 */
9
10 #include <set>
11 #include <stdio.h>
12 #include <string>
13
14 #include <Autolock.h>
15 #include <Directory.h>
16 #include <Entry.h>
17 #include <KernelExport.h>
18 #include <module.h>
19 #include <kmodule.h>
20 #include <List.h>
21 #include <Locker.h>
22 #include <Notifications.h>
23 #include <ObjectList.h>
24 #include <Path.h>
25 #include <String.h>
26
27 #ifdef TRACE
28 # undef TRACE
29 #endif
30 #define TRACE(x)
31 //#define TRACE(x) printf x
32
33
34 using namespace std;
35
36
37 static const char *gModuleDirs[] = {
38 "generated/objects/haiku/x86/release/add-ons/userland",
39 "generated/objects/haiku/x86/release/tests/add-ons/kernel",
40 NULL
41 };
42
43
44 struct module_name_list {
45 set<string> names;
46 set<string>::iterator it;
47 };
48
49
50 // ModuleAddOn
51
52 class ModuleAddOn {
53 public:
54 ModuleAddOn();
55 ~ModuleAddOn();
56
57 status_t Load(const char *path, const char *dirPath);
58 void Unload();
59
Name()60 const char *Name() { return fName.String(); }
61
62 status_t Get();
63 bool Put();
64
ModuleInfos() const65 module_info **ModuleInfos() const { return fInfos; }
66 module_info *FindModuleInfo(const char *name) const;
67
68 private:
69 image_id fAddOn;
70 module_info **fInfos;
71 int32 fReferenceCount;
72 BString fName;
73 };
74
75 class Module {
76 public:
77 Module(ModuleAddOn *addon, module_info *info);
78 ~Module();
79
80 status_t Init();
81 status_t Uninit();
82
83 status_t Get();
84 bool Put();
85
AddOn() const86 ModuleAddOn *AddOn() const { return fAddOn; }
Info() const87 module_info *Info() const { return fInfo; }
88
89 private:
90 ModuleAddOn *fAddOn;
91 module_info *fInfo;
92 int32 fReferenceCount;
93 bool fInitialized;
94 };
95
96 class ModuleList : public BLocker {
97 public:
98 ModuleList();
99 ~ModuleList();
100
101 int32 CountModules() const;
102 Module *ModuleAt(int32 index) const;
103
104 bool AddModule(Module *module);
105 bool RemoveModule(Module *module);
106 Module *FindModule(const char *path);
107
108 private:
109 BList fModules;
110 };
111
112 class ModuleManager {
113 public:
114 ModuleManager();
115 ~ModuleManager();
116
Default()117 static ModuleManager *Default() { return &sDefaultManager; }
118
119 status_t GetModule(const char *path, module_info **infop);
120 status_t PutModule(const char *path);
121
122 status_t GetNextLoadedModuleName(uint32 *cookie, char *buffer,
123 size_t *bufferSize);
124
125 module_name_list *OpenModuleList(const char *prefix,
126 const char *suffix = NULL);
127 status_t ReadNextModuleName(module_name_list *list, char *buffer,
128 size_t *bufferSize);
129 status_t CloseModuleList(module_name_list *list);
130
131 status_t AddBuiltInModule(module_info *info);
132
133 status_t GetDependencies(image_id image);
134 void PutDependencies(image_id image);
135
136 private:
137 bool _MatchSuffix(const char *name, const char *suffix);
138 void _FindModules(BDirectory &dir, const char *moduleDir,
139 const char *suffix, module_name_list *list);
140 void _FindBuiltInModules(const char *prefix, const char *suffix,
141 module_name_list *list);
142
143 status_t _GetAddOn(const char *path, ModuleAddOn **addon);
144 void _PutAddOn(ModuleAddOn *addon);
145
146 private:
147 static ModuleManager sDefaultManager;
148 ModuleList fModules;
149 BObjectList<ModuleAddOn> fAddOns;
150 };
151
152
153 // #pragma mark - ModuleAddOn
154
155
ModuleAddOn()156 ModuleAddOn::ModuleAddOn()
157 : fAddOn(-1),
158 fInfos(NULL),
159 fReferenceCount(0)
160 {
161 }
162
163
~ModuleAddOn()164 ModuleAddOn::~ModuleAddOn()
165 {
166 Unload();
167 }
168
169 // Load
170 status_t
Load(const char * path,const char * dirPath)171 ModuleAddOn::Load(const char *path, const char *dirPath)
172 {
173 TRACE(("ModuleAddOn::Load(): searching module `%s'...\n", path));
174 Unload();
175 status_t error = (path && dirPath ? B_OK : B_BAD_VALUE);
176 if (error == B_OK) {
177 // get the module dir relative path
178 BPath absPath;
179 BPath absDirPath;
180 if (absPath.SetTo(path, NULL, true) != B_OK
181 || absDirPath.SetTo(dirPath, NULL, true) != B_OK
182 || strlen(absPath.Path()) <= strlen(absDirPath.Path())) {
183 return B_ENTRY_NOT_FOUND;
184 }
185 int32 dirPathLen = strlen(absDirPath.Path());
186 if (strncmp(absPath.Path(), absDirPath.Path(), dirPathLen)
187 || absPath.Path()[dirPathLen] != '/') {
188 return B_ENTRY_NOT_FOUND;
189 }
190 const char *name = absPath.Path() + dirPathLen + 1;
191 // load the file
192 error = B_ENTRY_NOT_FOUND;
193 BEntry entry;
194 if (entry.SetTo(path) == B_OK && entry.Exists()) {
195 image_id image = load_add_on(path);
196 module_info **infos = NULL;
197 if (image >= 0
198 && get_image_symbol(image, "modules", B_SYMBOL_TYPE_DATA,
199 (void**)&infos) == B_OK
200 && infos != NULL) {
201 fAddOn = image;
202 fInfos = infos;
203 fName = name;
204 fReferenceCount = 0;
205 error = B_OK;
206 }
207 }
208 }
209 return error;
210 }
211
212 // Unload
213 void
Unload()214 ModuleAddOn::Unload()
215 {
216 if (fAddOn >= 0)
217 unload_add_on(fAddOn);
218 fAddOn = -1;
219 fInfos = NULL;
220 fReferenceCount = 0;
221 }
222
223 // Get
224 status_t
Get()225 ModuleAddOn::Get()
226 {
227 if (fAddOn >= 0) {
228 if (fReferenceCount == 0) {
229 status_t status = ModuleManager::Default()->GetDependencies(fAddOn);
230 if (status < B_OK)
231 return status;
232 }
233 fReferenceCount++;
234 }
235
236 return B_OK;
237 }
238
239 // Put
240 bool
Put()241 ModuleAddOn::Put()
242 {
243 if (fAddOn >= 0)
244 fReferenceCount--;
245
246 if (fReferenceCount == 0) {
247 ModuleManager::Default()->PutDependencies(fAddOn);
248 return true;
249 }
250 return false;
251 }
252
253 // FindModuleInfo
254 module_info *
FindModuleInfo(const char * name) const255 ModuleAddOn::FindModuleInfo(const char *name) const
256 {
257 if (fInfos && name) {
258 for (int32 i = 0; module_info *info = fInfos[i]; i++) {
259 if (!strcmp(info->name, name))
260 return info;
261 }
262 }
263 return NULL;
264 }
265
266
267 // #pragma mark - Module
268
269
Module(ModuleAddOn * addon,module_info * info)270 Module::Module(ModuleAddOn *addon, module_info *info)
271 : fAddOn(addon),
272 fInfo(info),
273 fReferenceCount(0),
274 fInitialized(false)
275 {
276 }
277
278 // destructor
~Module()279 Module::~Module()
280 {
281 }
282
283 // Init
284 status_t
Init()285 Module::Init()
286 {
287 status_t error = (fInfo ? B_OK : B_NO_INIT);
288 if (error == B_OK && !fInitialized) {
289 if (fInfo->std_ops != NULL)
290 error = fInfo->std_ops(B_MODULE_INIT);
291 if (error == B_OK)
292 fInitialized = true;
293 }
294 return error;
295 }
296
297 // Uninit
298 status_t
Uninit()299 Module::Uninit()
300 {
301 status_t error = (fInfo ? B_OK : B_NO_INIT);
302 if (error == B_OK && fInitialized) {
303 if (fInfo->std_ops != NULL)
304 error = fInfo->std_ops(B_MODULE_UNINIT);
305 fInitialized = false;
306 }
307 return error;
308 }
309
310
311 status_t
Get()312 Module::Get()
313 {
314 if (fReferenceCount == 0) {
315 status_t status = Init();
316 if (status < B_OK)
317 return status;
318 }
319
320 fReferenceCount++;
321 return B_OK;
322 }
323
324
325 bool
Put()326 Module::Put()
327 {
328 if (--fReferenceCount > 0)
329 return false;
330
331 Uninit();
332 return fAddOn && !(fInfo->flags & B_KEEP_LOADED);
333 }
334
335
336 // #pragma mark - ModuleList
337
338
ModuleList()339 ModuleList::ModuleList()
340 {
341 }
342
343
~ModuleList()344 ModuleList::~ModuleList()
345 {
346 }
347
348 // CountModules
349 int32
CountModules() const350 ModuleList::CountModules() const
351 {
352 return fModules.CountItems();
353 }
354
355 // ModuleAt
356 Module *
ModuleAt(int32 index) const357 ModuleList::ModuleAt(int32 index) const
358 {
359 return (Module*)fModules.ItemAt(index);
360 }
361
362 // AddModule
363 bool
AddModule(Module * module)364 ModuleList::AddModule(Module *module)
365 {
366 bool result = false;
367 if (module && !FindModule(module->Info()->name))
368 result = fModules.AddItem(module);
369 return result;
370 }
371
372 // RemoveModule
373 bool
RemoveModule(Module * module)374 ModuleList::RemoveModule(Module *module)
375 {
376 return (module && fModules.RemoveItem(module));
377 }
378
379 // FindModule
380 Module *
FindModule(const char * path)381 ModuleList::FindModule(const char *path)
382 {
383 if (path) {
384 for (int32 i = 0; Module *module = ModuleAt(i); i++) {
385 if (!strcmp(path, module->Info()->name))
386 return module;
387 }
388 }
389 return NULL;
390 }
391
392
393 // #pragma mark - ModuleManager
394
395
ModuleManager()396 ModuleManager::ModuleManager()
397 : fModules()
398 {
399 }
400
401 // destructor
~ModuleManager()402 ModuleManager::~ModuleManager()
403 {
404 for (int32 i = 0; Module *module = fModules.ModuleAt(i); i++)
405 delete module;
406 }
407
408
409 status_t
GetModule(const char * path,module_info ** _info)410 ModuleManager::GetModule(const char *path, module_info **_info)
411 {
412 if (path == NULL || _info == NULL)
413 return B_BAD_VALUE;
414
415 BAutolock _lock(fModules);
416 status_t error = B_OK;
417
418 Module *module = fModules.FindModule(path);
419 if (module == NULL) {
420 // module not yet loaded, try to get it
421 // get the responsible add-on
422 ModuleAddOn *addon = NULL;
423 error = _GetAddOn(path, &addon);
424 if (error == B_OK) {
425 // add-on found, get the module
426 if (module_info *info = addon->FindModuleInfo(path)) {
427 module = new Module(addon, info);
428 fModules.AddModule(module);
429 } else {
430 _PutAddOn(addon);
431 error = B_ENTRY_NOT_FOUND;
432 }
433 }
434 }
435
436 // "get" the module
437 if (error == B_OK)
438 error = module->Get();
439 if (error == B_OK)
440 *_info = module->Info();
441
442 return error;
443 }
444
445 // PutModule
446 status_t
PutModule(const char * path)447 ModuleManager::PutModule(const char *path)
448 {
449 if (path == NULL)
450 return B_BAD_VALUE;
451
452 BAutolock _lock(fModules);
453
454 if (Module *module = fModules.FindModule(path)) {
455 if (module->Put()) {
456 ModuleAddOn *addon = module->AddOn();
457 fModules.RemoveModule(module);
458 delete module;
459 _PutAddOn(addon);
460 }
461 } else
462 return B_BAD_VALUE;
463
464 return B_OK;
465 }
466
467 // GetNextLoadedModuleName
468 status_t
GetNextLoadedModuleName(uint32 * cookie,char * buffer,size_t * bufferSize)469 ModuleManager::GetNextLoadedModuleName(uint32 *cookie, char *buffer,
470 size_t *bufferSize)
471 {
472 status_t error = (cookie && buffer && bufferSize ? B_OK : B_BAD_VALUE);
473 if (error == B_OK) {
474 BAutolock _lock(fModules);
475 if (Module *module = fModules.ModuleAt(*cookie)) {
476 module_info *info = module->Info();
477 size_t nameLen = strlen(info->name);
478 if (nameLen < *bufferSize) {
479 strcpy(buffer, info->name);
480 *bufferSize = nameLen;
481 (*cookie)++;
482 } else
483 error = B_BAD_VALUE;
484 } else
485 error = B_ENTRY_NOT_FOUND;
486 }
487 return error;
488 }
489
490 // OpenModuleList
491 module_name_list *
OpenModuleList(const char * prefix,const char * suffix)492 ModuleManager::OpenModuleList(const char *prefix, const char *suffix)
493 {
494 module_name_list *list = NULL;
495 if (prefix) {
496 list = new module_name_list;
497 _FindBuiltInModules(prefix, suffix, list);
498
499 for (int32 i = 0; gModuleDirs[i]; i++) {
500 BPath path;
501 BDirectory dir;
502 if (path.SetTo(gModuleDirs[i], prefix) == B_OK
503 && dir.SetTo(path.Path()) == B_OK) {
504 _FindModules(dir, gModuleDirs[i], suffix, list);
505 }
506 }
507
508 list->it = list->names.begin();
509 }
510 return list;
511 }
512
513 // ReadNextModuleName
514 status_t
ReadNextModuleName(module_name_list * list,char * buffer,size_t * bufferSize)515 ModuleManager::ReadNextModuleName(module_name_list *list, char *buffer,
516 size_t *bufferSize)
517 {
518 status_t error = (list && buffer && bufferSize ? B_OK : B_BAD_VALUE);
519 if (error == B_OK) {
520 if (list->it != list->names.end()) {
521 const string &name = *list->it;
522 size_t nameLen = name.length();
523 if (nameLen < *bufferSize) {
524 strcpy(buffer, name.c_str());
525 *bufferSize = nameLen;
526 list->it++;
527 } else
528 error = B_BAD_VALUE;
529 } else
530 error = B_ENTRY_NOT_FOUND;
531 }
532 return error;
533 }
534
535
536 // CloseModuleList
537 status_t
CloseModuleList(module_name_list * list)538 ModuleManager::CloseModuleList(module_name_list *list)
539 {
540 status_t error = (list ? B_OK : B_BAD_VALUE);
541 if (error == B_OK)
542 delete list;
543 return error;
544 }
545
546
547 status_t
AddBuiltInModule(module_info * info)548 ModuleManager::AddBuiltInModule(module_info *info)
549 {
550 BAutolock _lock(fModules);
551
552 TRACE(("add module %p, \"%s\"\n", info, info->name));
553 return fModules.AddModule(new Module(NULL, info)) ? B_OK : B_ERROR;
554 }
555
556
557 status_t
GetDependencies(image_id image)558 ModuleManager::GetDependencies(image_id image)
559 {
560 module_dependency *dependencies;
561 status_t status = get_image_symbol(image, "module_dependencies",
562 B_SYMBOL_TYPE_DATA, (void**)&dependencies);
563 if (status < B_OK) {
564 // no dependencies means we don't have to do anything
565 return B_OK;
566 }
567
568 for (uint32 i = 0; dependencies[i].name != NULL; i++) {
569 status = GetModule(dependencies[i].name, dependencies[i].info);
570 if (status < B_OK)
571 return status;
572 }
573 return B_OK;
574 }
575
576
577 void
PutDependencies(image_id image)578 ModuleManager::PutDependencies(image_id image)
579 {
580 module_dependency *dependencies;
581 status_t status = get_image_symbol(image, "module_dependencies",
582 B_SYMBOL_TYPE_DATA, (void**)&dependencies);
583 if (status < B_OK) {
584 // no dependencies means we don't have to do anything
585 return;
586 }
587
588 for (uint32 i = 0; dependencies[i].name != NULL; i++) {
589 PutModule(dependencies[i].name);
590 }
591 }
592
593
594 bool
_MatchSuffix(const char * name,const char * suffix)595 ModuleManager::_MatchSuffix(const char *name, const char *suffix)
596 {
597 if (suffix == NULL || suffix[0] == '\0')
598 return true;
599
600 size_t suffixLength = strlen(suffix);
601 size_t length = strlen(name);
602 if (length <= suffixLength)
603 return false;
604
605 return name[length - suffixLength - 1] == '/'
606 && !strcmp(name + length - suffixLength, suffix);
607 }
608
609
610 void
_FindModules(BDirectory & dir,const char * moduleDir,const char * suffix,module_name_list * list)611 ModuleManager::_FindModules(BDirectory &dir, const char *moduleDir,
612 const char *suffix, module_name_list *list)
613 {
614 BEntry entry;
615 while (dir.GetNextEntry(&entry) == B_OK) {
616 if (entry.IsFile()) {
617 ModuleAddOn addon;
618 BPath path;
619 if (entry.GetPath(&path) == B_OK
620 && addon.Load(path.Path(), moduleDir) == B_OK) {
621 module_info **infos = addon.ModuleInfos();
622 for (int32 i = 0; infos[i]; i++) {
623 if (infos[i]->name
624 && _MatchSuffix(infos[i]->name, suffix))
625 list->names.insert(infos[i]->name);
626 }
627 }
628 } else if (entry.IsDirectory()) {
629 BDirectory subdir;
630 if (subdir.SetTo(&entry) == B_OK)
631 _FindModules(subdir, moduleDir, suffix, list);
632 }
633 }
634 }
635
636
637 void
_FindBuiltInModules(const char * prefix,const char * suffix,module_name_list * list)638 ModuleManager::_FindBuiltInModules(const char *prefix, const char *suffix,
639 module_name_list *list)
640 {
641 uint32 count = fModules.CountModules();
642 uint32 prefixLength = strlen(prefix);
643
644 for (uint32 i = 0; i < count; i++) {
645 Module *module = fModules.ModuleAt(i);
646 if (!strncmp(module->Info()->name, prefix, prefixLength)
647 && _MatchSuffix(module->Info()->name, suffix))
648 list->names.insert(module->Info()->name);
649 }
650 }
651
652
653 status_t
_GetAddOn(const char * name,ModuleAddOn ** _addon)654 ModuleManager::_GetAddOn(const char *name, ModuleAddOn **_addon)
655 {
656 // search list first
657 for (int32 i = 0; ModuleAddOn *addon = fAddOns.ItemAt(i); i++) {
658 BString addonName(addon->Name());
659 addonName << "/";
660 if (!strcmp(name, addon->Name())
661 || !strncmp(addonName.String(), name, addonName.Length())) {
662 addon->Get();
663 *_addon = addon;
664 return B_OK;
665 }
666 }
667 // not in list yet, load from disk
668 // iterate through module dirs
669 for (int32 i = 0; gModuleDirs[i]; i++) {
670 BPath path;
671 if (path.SetTo(gModuleDirs[i]) == B_OK
672 && path.SetTo(path.Path(), name) == B_OK) {
673 BEntry entry;
674 for (;;) {
675 if (entry.SetTo(path.Path()) == B_OK && entry.Exists()) {
676 // found an entry: if it is a file, try to load it
677 if (entry.IsFile()) {
678 ModuleAddOn *addon = new ModuleAddOn;
679 if (addon->Load(path.Path(), gModuleDirs[i]) == B_OK) {
680 status_t status = addon->Get();
681 if (status < B_OK) {
682 delete addon;
683 return status;
684 }
685
686 fAddOns.AddItem(addon);
687 *_addon = addon;
688 return B_OK;
689 }
690 delete addon;
691 }
692 break;
693 }
694 // chop off last path component
695 if (path.GetParent(&path) != B_OK)
696 break;
697 }
698 }
699 }
700 return B_ENTRY_NOT_FOUND;
701 }
702
703 // _PutAddOn
704 void
_PutAddOn(ModuleAddOn * addon)705 ModuleManager::_PutAddOn(ModuleAddOn *addon)
706 {
707 if (addon) {
708 if (addon->Put()) {
709 fAddOns.RemoveItem(addon);
710 delete addon;
711 }
712 }
713 }
714
715
716 // singleton instance
717 ModuleManager ModuleManager::sDefaultManager;
718
719
720 // #pragma mark - Private emulation functions
721
722
723 extern "C" status_t
_add_builtin_module(module_info * info)724 _add_builtin_module(module_info *info)
725 {
726 return ModuleManager::Default()->AddBuiltInModule(info);
727 }
728
729
730 extern "C" status_t
_get_builtin_dependencies(void)731 _get_builtin_dependencies(void)
732 {
733 image_info info;
734 int32 cookie = 0;
735 while (get_next_image_info(B_CURRENT_TEAM, &cookie, &info) == B_OK) {
736 if (info.type != B_APP_IMAGE)
737 continue;
738
739 return ModuleManager::Default()->GetDependencies(info.id);
740 }
741
742 return B_OK;
743 }
744
745
746 // #pragma mark - Emulated kernel functions
747
748
749 status_t
get_module(const char * path,module_info ** _info)750 get_module(const char *path, module_info **_info)
751 {
752 TRACE(("get_module(`%s')\n", path));
753 return ModuleManager::Default()->GetModule(path, _info);
754 }
755
756
757 status_t
put_module(const char * path)758 put_module(const char *path)
759 {
760 TRACE(("put_module(`%s')\n", path));
761 return ModuleManager::Default()->PutModule(path);
762 }
763
764
765 status_t
get_next_loaded_module_name(uint32 * cookie,char * name,size_t * nameLength)766 get_next_loaded_module_name(uint32 *cookie, char *name, size_t *nameLength)
767 {
768 TRACE(("get_next_loaded_module_name(%lu)\n", *cookie));
769 return ModuleManager::Default()->GetNextLoadedModuleName(cookie, name,
770 nameLength);
771 }
772
773
774 void *
open_module_list_etc(const char * prefix,const char * suffix)775 open_module_list_etc(const char *prefix, const char *suffix)
776 {
777 TRACE(("open_module_list_etc('%s', '%s')\n", prefix, suffix));
778 return (void*)ModuleManager::Default()->OpenModuleList(prefix, suffix);
779 }
780
781
782 void *
open_module_list(const char * prefix)783 open_module_list(const char *prefix)
784 {
785 TRACE(("open_module_list('%s')\n", prefix));
786 return (void*)ModuleManager::Default()->OpenModuleList(prefix);
787 }
788
789
790 status_t
read_next_module_name(void * cookie,char * buf,size_t * bufsize)791 read_next_module_name(void *cookie, char *buf, size_t *bufsize)
792 {
793 TRACE(("read_next_module_name(%p, %p, %lu)\n", cookie, buf, *bufsize));
794 return ModuleManager::Default()->ReadNextModuleName(
795 (module_name_list*)cookie, buf, bufsize);
796 }
797
798
799 status_t
close_module_list(void * cookie)800 close_module_list(void *cookie)
801 {
802 TRACE(("close_module_list(%p)\n", cookie));
803 return ModuleManager::Default()->CloseModuleList(
804 (module_name_list*)cookie);
805 }
806
807
808 status_t
start_watching_modules(const char * prefix,NotificationListener & listener)809 start_watching_modules(const char* prefix, NotificationListener& listener)
810 {
811 return B_NOT_SUPPORTED;
812 }
813
814
815 status_t
stop_watching_modules(const char * prefix,NotificationListener & listener)816 stop_watching_modules(const char* prefix, NotificationListener& listener)
817 {
818 return B_NOT_SUPPORTED;
819 }
820