828a620bfab773dab566933c60d5a46cb6113acd
[strongswan.git] / src / libstrongswan / plugins / plugin_loader.c
1 /*
2 * Copyright (C) 2010-2013 Tobias Brunner
3 * Copyright (C) 2007 Martin Willi
4 * Hochschule fuer Technik Rapperswil
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the
8 * Free Software Foundation; either version 2 of the License, or (at your
9 * option) any later version. See <http://www.fsf.org/copyleft/gpl.txt>.
10 *
11 * This program is distributed in the hope that it will be useful, but
12 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13 * or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 * for more details.
15 */
16
17 #define _GNU_SOURCE
18 #include "plugin_loader.h"
19
20 #include <string.h>
21 #include <dlfcn.h>
22 #include <limits.h>
23 #include <stdio.h>
24
25 #include <utils/debug.h>
26 #include <library.h>
27 #include <collections/hashtable.h>
28 #include <collections/linked_list.h>
29 #include <plugins/plugin.h>
30 #include <utils/integrity_checker.h>
31
32 typedef struct private_plugin_loader_t private_plugin_loader_t;
33 typedef struct registered_feature_t registered_feature_t;
34 typedef struct provided_feature_t provided_feature_t;
35 typedef struct plugin_entry_t plugin_entry_t;
36
37 /**
38 * private data of plugin_loader
39 */
40 struct private_plugin_loader_t {
41
42 /**
43 * public functions
44 */
45 plugin_loader_t public;
46
47 /**
48 * List of plugins, as plugin_entry_t
49 */
50 linked_list_t *plugins;
51
52 /**
53 * Hashtable for registered features, as registered_feature_t
54 */
55 hashtable_t *features;
56
57 /**
58 * Loaded features (stored in reverse order), as provided_feature_t
59 */
60 linked_list_t *loaded;
61
62 /**
63 * List of names of loaded plugins
64 */
65 char *loaded_plugins;
66 };
67
68 /**
69 * Registered plugin feature
70 */
71 struct registered_feature_t {
72
73 /**
74 * The registered feature
75 */
76 plugin_feature_t *feature;
77
78 /**
79 * List of plugins providing this feature, as provided_feature_t
80 */
81 linked_list_t *plugins;
82 };
83
84 /**
85 * Hash a registered feature
86 */
87 static bool registered_feature_hash(registered_feature_t *this)
88 {
89 return plugin_feature_hash(this->feature);
90 }
91
92 /**
93 * Compare two registered features
94 */
95 static bool registered_feature_equals(registered_feature_t *a,
96 registered_feature_t *b)
97 {
98 return plugin_feature_equals(a->feature, b->feature);
99 }
100
101 /**
102 * Feature as provided by a plugin
103 */
104 struct provided_feature_t {
105
106 /**
107 * Plugin providing the feature
108 */
109 plugin_entry_t *entry;
110
111 /**
112 * FEATURE_REGISTER or FEATURE_CALLBACK entry
113 */
114 plugin_feature_t *reg;
115
116 /**
117 * The provided feature (followed by dependencies)
118 */
119 plugin_feature_t *feature;
120
121 /**
122 * Maximum number of dependencies (following feature)
123 */
124 int dependencies;
125
126 /**
127 * TRUE if currently loading this feature (to prevent loops)
128 */
129 bool loading;
130
131 /**
132 * TRUE if feature loaded
133 */
134 bool loaded;
135
136 /**
137 * TRUE if feature failed to load
138 */
139 bool failed;
140 };
141
142 /**
143 * Entry for a plugin
144 */
145 struct plugin_entry_t {
146
147 /**
148 * Plugin instance
149 */
150 plugin_t *plugin;
151
152 /**
153 * TRUE, if the plugin is marked as critical
154 */
155 bool critical;
156
157 /**
158 * dlopen handle, if in separate lib
159 */
160 void *handle;
161
162 /**
163 * List of features, as provided_feature_t
164 */
165 linked_list_t *features;
166 };
167
168 /**
169 * Destroy a plugin entry
170 */
171 static void plugin_entry_destroy(plugin_entry_t *entry)
172 {
173 DESTROY_IF(entry->plugin);
174 if (entry->handle)
175 {
176 dlclose(entry->handle);
177 }
178 entry->features->destroy(entry->features);
179 free(entry);
180 }
181
182 /**
183 * Wrapper for static plugin features
184 */
185 typedef struct {
186
187 /**
188 * Implements plugin_t interface
189 */
190 plugin_t public;
191
192 /**
193 * Name of the module registering these features
194 */
195 char *name;
196
197 /**
198 * Static plugin features
199 */
200 plugin_feature_t *features;
201
202 /**
203 * Number of plugin features
204 */
205 int count;
206
207 } static_features_t;
208
209 METHOD(plugin_t, get_static_name, char*,
210 static_features_t *this)
211 {
212 return this->name;
213 }
214
215 METHOD(plugin_t, get_static_features, int,
216 static_features_t *this, plugin_feature_t *features[])
217 {
218 *features = this->features;
219 return this->count;
220 }
221
222 METHOD(plugin_t, static_destroy, void,
223 static_features_t *this)
224 {
225 free(this->features);
226 free(this->name);
227 free(this);
228 }
229
230 /**
231 * Create a wrapper around static plugin features.
232 */
233 static plugin_t *static_features_create(const char *name,
234 plugin_feature_t features[], int count)
235 {
236 static_features_t *this;
237
238 INIT(this,
239 .public = {
240 .get_name = _get_static_name,
241 .get_features = _get_static_features,
242 .destroy = _static_destroy,
243 },
244 .name = strdup(name),
245 .features = calloc(count, sizeof(plugin_feature_t)),
246 .count = count,
247 );
248
249 memcpy(this->features, features, sizeof(plugin_feature_t) * count);
250
251 return &this->public;
252 }
253
254 /**
255 * create a plugin
256 * returns: NOT_FOUND, if the constructor was not found
257 * FAILED, if the plugin could not be constructed
258 */
259 static status_t create_plugin(private_plugin_loader_t *this, void *handle,
260 char *name, bool integrity, bool critical,
261 plugin_entry_t **entry)
262 {
263 char create[128];
264 plugin_t *plugin;
265 plugin_constructor_t constructor;
266
267 if (snprintf(create, sizeof(create), "%s_plugin_create",
268 name) >= sizeof(create))
269 {
270 return FAILED;
271 }
272 translate(create, "-", "_");
273 constructor = dlsym(handle, create);
274 if (constructor == NULL)
275 {
276 return NOT_FOUND;
277 }
278 if (integrity && lib->integrity)
279 {
280 if (!lib->integrity->check_segment(lib->integrity, name, constructor))
281 {
282 DBG1(DBG_LIB, "plugin '%s': failed segment integrity test", name);
283 return FAILED;
284 }
285 DBG1(DBG_LIB, "plugin '%s': passed file and segment integrity tests",
286 name);
287 }
288 plugin = constructor();
289 if (plugin == NULL)
290 {
291 DBG1(DBG_LIB, "plugin '%s': failed to load - %s returned NULL", name,
292 create);
293 return FAILED;
294 }
295 INIT(*entry,
296 .plugin = plugin,
297 .critical = critical,
298 .features = linked_list_create(),
299 );
300 DBG2(DBG_LIB, "plugin '%s': loaded successfully", name);
301 return SUCCESS;
302 }
303
304 /**
305 * load a single plugin
306 */
307 static plugin_entry_t *load_plugin(private_plugin_loader_t *this, char *name,
308 char *file, bool critical)
309 {
310 plugin_entry_t *entry;
311 void *handle;
312
313 switch (create_plugin(this, RTLD_DEFAULT, name, FALSE, critical, &entry))
314 {
315 case SUCCESS:
316 this->plugins->insert_last(this->plugins, entry);
317 return entry;
318 case NOT_FOUND:
319 if (file)
320 { /* try to load the plugin from a file */
321 break;
322 }
323 /* fall-through */
324 default:
325 return NULL;
326 }
327 if (lib->integrity)
328 {
329 if (!lib->integrity->check_file(lib->integrity, name, file))
330 {
331 DBG1(DBG_LIB, "plugin '%s': failed file integrity test of '%s'",
332 name, file);
333 return NULL;
334 }
335 }
336 handle = dlopen(file, RTLD_LAZY);
337 if (handle == NULL)
338 {
339 DBG1(DBG_LIB, "plugin '%s' failed to load: %s", name, dlerror());
340 return NULL;
341 }
342 if (create_plugin(this, handle, name, TRUE, critical, &entry) != SUCCESS)
343 {
344 dlclose(handle);
345 return NULL;
346 }
347 entry->handle = handle;
348 this->plugins->insert_last(this->plugins, entry);
349 return entry;
350 }
351
352 /**
353 * Convert enumerated provided_feature_t to plugin_feature_t
354 */
355 static bool feature_filter(void *null, provided_feature_t **provided,
356 plugin_feature_t **feature)
357 {
358 *feature = (*provided)->feature;
359 return (*provided)->loaded;
360 }
361
362 /**
363 * Convert enumerated entries to plugin_t
364 */
365 static bool plugin_filter(void *null, plugin_entry_t **entry, plugin_t **plugin,
366 void *in, linked_list_t **list)
367 {
368 plugin_entry_t *this = *entry;
369
370 *plugin = this->plugin;
371 if (list)
372 {
373 enumerator_t *features;
374 features = enumerator_create_filter(
375 this->features->create_enumerator(this->features),
376 (void*)feature_filter, NULL, NULL);
377 *list = linked_list_create_from_enumerator(features);
378 }
379 return TRUE;
380 }
381
382 METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
383 private_plugin_loader_t *this)
384 {
385 return enumerator_create_filter(
386 this->plugins->create_enumerator(this->plugins),
387 (void*)plugin_filter, NULL, NULL);
388 }
389
390 METHOD(plugin_loader_t, has_feature, bool,
391 private_plugin_loader_t *this, plugin_feature_t feature)
392 {
393 enumerator_t *plugins, *features;
394 plugin_t *plugin;
395 linked_list_t *list;
396 plugin_feature_t *current;
397 bool found = FALSE;
398
399 plugins = create_plugin_enumerator(this);
400 while (plugins->enumerate(plugins, &plugin, &list))
401 {
402 features = list->create_enumerator(list);
403 while (features->enumerate(features, &current))
404 {
405 if (plugin_feature_matches(&feature, current))
406 {
407 found = TRUE;
408 break;
409 }
410 }
411 features->destroy(features);
412 list->destroy(list);
413 }
414 plugins->destroy(plugins);
415
416 return found;
417 }
418
419 /**
420 * Create a list of the names of all loaded plugins
421 */
422 static char* loaded_plugins_list(private_plugin_loader_t *this)
423 {
424 int buf_len = 128, len = 0;
425 char *buf, *name;
426 enumerator_t *enumerator;
427 plugin_t *plugin;
428
429 buf = malloc(buf_len);
430 buf[0] = '\0';
431 enumerator = create_plugin_enumerator(this);
432 while (enumerator->enumerate(enumerator, &plugin, NULL))
433 {
434 name = plugin->get_name(plugin);
435 if (len + (strlen(name) + 1) >= buf_len)
436 {
437 buf_len <<= 1;
438 buf = realloc(buf, buf_len);
439 }
440 len += snprintf(&buf[len], buf_len - len, "%s ", name);
441 }
442 enumerator->destroy(enumerator);
443 if (len > 0 && buf[len - 1] == ' ')
444 {
445 buf[len - 1] = '\0';
446 }
447 return buf;
448 }
449
450 /**
451 * Check if a plugin is already loaded
452 */
453 static bool plugin_loaded(private_plugin_loader_t *this, char *name)
454 {
455 enumerator_t *enumerator;
456 bool found = FALSE;
457 plugin_t *plugin;
458
459 enumerator = create_plugin_enumerator(this);
460 while (enumerator->enumerate(enumerator, &plugin, NULL))
461 {
462 if (streq(plugin->get_name(plugin), name))
463 {
464 found = TRUE;
465 break;
466 }
467 }
468 enumerator->destroy(enumerator);
469 return found;
470 }
471
472 /**
473 * Forward declaration
474 */
475 static void load_provided(private_plugin_loader_t *this,
476 provided_feature_t *provided,
477 int level);
478
479 /**
480 * Used to find a loaded feature
481 */
482 static bool is_feature_loaded(provided_feature_t *item)
483 {
484 return item->loaded;
485 }
486
487 /**
488 * Used to find a loadable feature
489 */
490 static bool is_feature_loadable(provided_feature_t *item)
491 {
492 return !item->loading && !item->loaded && !item->failed;
493 }
494
495 /**
496 * Find a loaded and matching feature
497 */
498 static bool loaded_feature_matches(registered_feature_t *a,
499 registered_feature_t *b)
500 {
501 if (plugin_feature_matches(a->feature, b->feature))
502 {
503 return b->plugins->find_first(b->plugins, (void*)is_feature_loaded,
504 NULL) == SUCCESS;
505 }
506 return FALSE;
507 }
508
509 /**
510 * Find a loadable module that equals the requested feature
511 */
512 static bool loadable_feature_equals(registered_feature_t *a,
513 registered_feature_t *b)
514 {
515 if (plugin_feature_equals(a->feature, b->feature))
516 {
517 return b->plugins->find_first(b->plugins, (void*)is_feature_loadable,
518 NULL) == SUCCESS;
519 }
520 return FALSE;
521 }
522
523 /**
524 * Find a loadable module that matches the requested feature
525 */
526 static bool loadable_feature_matches(registered_feature_t *a,
527 registered_feature_t *b)
528 {
529 if (plugin_feature_matches(a->feature, b->feature))
530 {
531 return b->plugins->find_first(b->plugins, (void*)is_feature_loadable,
532 NULL) == SUCCESS;
533 }
534 return FALSE;
535 }
536
537 /**
538 * Returns a compatible plugin feature for the given depencency
539 */
540 static bool find_compatible_feature(private_plugin_loader_t *this,
541 plugin_feature_t *dependency)
542 {
543 registered_feature_t *feature, lookup = {
544 .feature = dependency,
545 };
546
547 feature = this->features->get_match(this->features, &lookup,
548 (void*)loaded_feature_matches);
549 return feature != NULL;
550 }
551
552 /**
553 * Load a registered plugin feature
554 */
555 static void load_registered(private_plugin_loader_t *this,
556 registered_feature_t *registered,
557 int level)
558 {
559 enumerator_t *enumerator;
560 provided_feature_t *provided;
561
562 enumerator = registered->plugins->create_enumerator(registered->plugins);
563 while (enumerator->enumerate(enumerator, &provided))
564 {
565 load_provided(this, provided, level);
566 }
567 enumerator->destroy(enumerator);
568 }
569
570 /**
571 * Try to load dependencies of the given feature
572 */
573 static bool load_dependencies(private_plugin_loader_t *this,
574 provided_feature_t *provided,
575 int level)
576 {
577 registered_feature_t *registered, lookup;
578 int indent = level * 2;
579 int i;
580
581 /* first entry is provided feature, followed by dependencies */
582 for (i = 1; i < provided->dependencies; i++)
583 {
584 if (provided->feature[i].kind != FEATURE_DEPENDS &&
585 provided->feature[i].kind != FEATURE_SDEPEND)
586 { /* end of dependencies */
587 break;
588 }
589
590 /* we load the feature even if a compatible one is already loaded,
591 * otherwise e.g. a specific database implementation loaded before
592 * another might cause a plugin feature loaded in-between to fail */
593 lookup.feature = &provided->feature[i];
594 do
595 { /* prefer an exactly matching feature, could be omitted but
596 * results in a more predictable behavior */
597 registered = this->features->get_match(this->features,
598 &lookup,
599 (void*)loadable_feature_equals);
600 if (!registered)
601 { /* try fuzzy matching */
602 registered = this->features->get_match(this->features,
603 &lookup,
604 (void*)loadable_feature_matches);
605 }
606 if (registered)
607 {
608 load_registered(this, registered, level);
609 }
610 /* we could stop after finding one but for dependencies like
611 * DB_ANY it might be needed to load all matching features */
612 }
613 while (registered);
614
615 if (!find_compatible_feature(this, &provided->feature[i]))
616 {
617 char *name, *provide, *depend;
618 bool soft = provided->feature[i].kind == FEATURE_SDEPEND;
619
620 name = provided->entry->plugin->get_name(provided->entry->plugin);
621 provide = plugin_feature_get_string(&provided->feature[0]);
622 depend = plugin_feature_get_string(&provided->feature[i]);
623 if (soft)
624 {
625 DBG3(DBG_LIB, "%*sfeature %s in plugin '%s' has unmet soft "
626 "dependency: %s", indent, "", provide, name, depend);
627 }
628 else
629 {
630 DBG2(DBG_LIB, "feature %s in plugin '%s' has unmet dependency: "
631 "%s", provide, name, depend);
632 }
633 free(provide);
634 free(depend);
635 if (soft)
636 { /* it's ok if we can't resolve soft dependencies */
637 continue;
638 }
639 return FALSE;
640 }
641 }
642 return TRUE;
643 }
644
645 /**
646 * Load registered plugin features
647 */
648 static void load_feature(private_plugin_loader_t *this,
649 provided_feature_t *provided,
650 int level)
651 {
652 if (load_dependencies(this, provided, level))
653 {
654 if (plugin_feature_load(provided->entry->plugin, provided->feature,
655 provided->reg))
656 {
657 provided->loaded = TRUE;
658 /* insert first so we can unload the features in reverse order */
659 this->loaded->insert_first(this->loaded, provided);
660 }
661 else
662 {
663 provided->failed = TRUE;
664 }
665 }
666 else
667 { /* TODO: we could check the current level and set a different flag when
668 * being loaded as dependency. If there are loops there is a chance the
669 * feature can be loaded later when loading the feature directly. */
670 provided->failed = TRUE;
671 }
672 }
673
674 /**
675 * Load a provided feature
676 */
677 static void load_provided(private_plugin_loader_t *this,
678 provided_feature_t *provided,
679 int level)
680 {
681 char *name, *provide;
682 int indent = level * 2;
683
684 if (provided->loaded || provided->failed)
685 {
686 return;
687 }
688 name = provided->entry->plugin->get_name(provided->entry->plugin);
689 provide = plugin_feature_get_string(provided->feature);
690 if (provided->loading)
691 { /* prevent loop */
692 DBG3(DBG_LIB, "%*sloop detected while loading %s in plugin '%s'",
693 indent, "", provide, name);
694 free(provide);
695 return;
696 }
697 DBG3(DBG_LIB, "%*sloading feature %s in plugin '%s'",
698 indent, "", provide, name);
699 free(provide);
700
701 provided->loading = TRUE;
702 load_feature(this, provided, level + 1);
703 provided->loading = FALSE;
704 }
705
706 /**
707 * Load registered plugin features
708 */
709 static void load_features(private_plugin_loader_t *this)
710 {
711 enumerator_t *enumerator, *inner;
712 plugin_entry_t *plugin;
713 provided_feature_t *provided;
714
715 /* we do this in plugin order to allow implicit dependencies to be resolved
716 * by reordering plugins */
717 enumerator = this->plugins->create_enumerator(this->plugins);
718 while (enumerator->enumerate(enumerator, &plugin))
719 {
720 inner = plugin->features->create_enumerator(plugin->features);
721 while (inner->enumerate(inner, &provided))
722 {
723 load_provided(this, provided, 0);
724 }
725 inner->destroy(inner);
726 }
727 enumerator->destroy(enumerator);
728 }
729
730 /**
731 * Register plugin features provided by the given plugin
732 */
733 static void register_features(private_plugin_loader_t *this,
734 plugin_entry_t *entry)
735 {
736 plugin_feature_t *feature, *reg;
737 registered_feature_t *registered, lookup;
738 provided_feature_t *provided;
739 int count, i;
740
741 if (!entry->plugin->get_features)
742 { /* feature interface not supported */
743 DBG1(DBG_LIB, "plugin '%s' does not provide features, deprecated",
744 entry->plugin->get_name(entry->plugin));
745 return;
746 }
747 reg = NULL;
748 count = entry->plugin->get_features(entry->plugin, &feature);
749 for (i = 0; i < count; i++)
750 {
751 switch (feature->kind)
752 {
753 case FEATURE_PROVIDE:
754 lookup.feature = feature;
755 registered = this->features->get(this->features, &lookup);
756 if (!registered)
757 {
758 INIT(registered,
759 .feature = feature,
760 .plugins = linked_list_create(),
761 );
762 this->features->put(this->features, registered, registered);
763 }
764 INIT(provided,
765 .entry = entry,
766 .feature = feature,
767 .reg = reg,
768 .dependencies = count - i,
769 );
770 registered->plugins->insert_last(registered->plugins,
771 provided);
772 entry->features->insert_last(entry->features, provided);
773 break;
774 case FEATURE_REGISTER:
775 case FEATURE_CALLBACK:
776 reg = feature;
777 break;
778 default:
779 break;
780 }
781 feature++;
782 }
783 }
784
785 /**
786 * Unregister a plugin feature
787 */
788 static void unregister_feature(private_plugin_loader_t *this,
789 provided_feature_t *provided)
790 {
791 registered_feature_t *registered, lookup;
792
793 lookup.feature = provided->feature;
794 registered = this->features->get(this->features, &lookup);
795 if (registered)
796 {
797 registered->plugins->remove(registered->plugins, provided, NULL);
798 if (registered->plugins->get_count(registered->plugins) == 0)
799 {
800 this->features->remove(this->features, &lookup);
801 registered->plugins->destroy(registered->plugins);
802 free(registered);
803 }
804 else if (registered->feature == provided->feature)
805 { /* update feature in case the providing plugin gets unloaded */
806 provided_feature_t *first;
807
808 registered->plugins->get_first(registered->plugins, (void**)&first);
809 registered->feature = first->feature;
810 }
811 }
812 free(provided);
813 }
814
815 /**
816 * Unregister plugin features
817 */
818 static void unregister_features(private_plugin_loader_t *this,
819 plugin_entry_t *entry)
820 {
821 provided_feature_t *provided;
822 enumerator_t *enumerator;
823
824 enumerator = entry->features->create_enumerator(entry->features);
825 while (enumerator->enumerate(enumerator, &provided))
826 {
827 entry->features->remove_at(entry->features, enumerator);
828 unregister_feature(this, provided);
829 }
830 enumerator->destroy(enumerator);
831 }
832
833 /**
834 * Check that we have all features loaded for critical plugins
835 */
836 static bool missing_critical_features(private_plugin_loader_t *this)
837 {
838 enumerator_t *enumerator, *features;
839 plugin_entry_t *entry;
840 bool critical_failed = FALSE;
841
842 enumerator = this->plugins->create_enumerator(this->plugins);
843 while (enumerator->enumerate(enumerator, &entry))
844 {
845 provided_feature_t *provided;
846 char *name, *provide;
847 int failed = 0;
848
849 if (!entry->plugin->get_features ||
850 !entry->critical)
851 { /* feature interface not supported, or not critical */
852 continue;
853 }
854
855 name = entry->plugin->get_name(entry->plugin);
856 features = entry->features->create_enumerator(entry->features);
857 while (features->enumerate(features, &provided))
858 {
859 if (!provided->loaded)
860 {
861 provide = plugin_feature_get_string(provided->feature);
862 DBG2(DBG_LIB, " failed to load %s in critical plugin '%s'",
863 provide, name);
864 free(provide);
865 failed++;
866 }
867 }
868 features->destroy(features);
869 if (failed)
870 {
871 DBG1(DBG_LIB, "failed to load %d feature%s in critical plugin '%s'",
872 failed, failed > 1 ? "s" : "", name);
873 critical_failed = TRUE;
874 }
875 }
876 enumerator->destroy(enumerator);
877
878 return critical_failed;
879 }
880
881 /**
882 * Remove plugins we were not able to load any plugin features from.
883 */
884 static void purge_plugins(private_plugin_loader_t *this)
885 {
886 enumerator_t *enumerator;
887 plugin_entry_t *entry;
888
889 enumerator = this->plugins->create_enumerator(this->plugins);
890 while (enumerator->enumerate(enumerator, &entry))
891 {
892 if (!entry->plugin->get_features)
893 { /* feature interface not supported */
894 continue;
895 }
896 if (entry->features->find_first(entry->features,
897 (void*)is_feature_loaded, NULL) != SUCCESS)
898 {
899 DBG2(DBG_LIB, "unloading plugin '%s' without loaded features",
900 entry->plugin->get_name(entry->plugin));
901 this->plugins->remove_at(this->plugins, enumerator);
902 unregister_features(this, entry);
903 plugin_entry_destroy(entry);
904 }
905 }
906 enumerator->destroy(enumerator);
907 }
908
909 METHOD(plugin_loader_t, add_static_features, void,
910 private_plugin_loader_t *this, const char *name,
911 plugin_feature_t features[], int count, bool critical)
912 {
913 plugin_entry_t *entry;
914 plugin_t *plugin;
915
916 plugin = static_features_create(name, features, count);
917
918 INIT(entry,
919 .plugin = plugin,
920 .critical = critical,
921 .features = linked_list_create(),
922 );
923 this->plugins->insert_last(this->plugins, entry);
924 register_features(this, entry);
925 }
926
927 METHOD(plugin_loader_t, load_plugins, bool,
928 private_plugin_loader_t *this, char *path, char *list)
929 {
930 enumerator_t *enumerator;
931 char *token;
932 bool critical_failed = FALSE;
933
934 #ifdef PLUGINDIR
935 if (path == NULL)
936 {
937 path = PLUGINDIR;
938 }
939 #endif /* PLUGINDIR */
940
941 enumerator = enumerator_create_token(list, " ", " ");
942 while (!critical_failed && enumerator->enumerate(enumerator, &token))
943 {
944 plugin_entry_t *entry;
945 bool critical = FALSE;
946 char buf[PATH_MAX], *file = NULL;
947 int len;
948
949 token = strdup(token);
950 len = strlen(token);
951 if (token[len-1] == '!')
952 {
953 critical = TRUE;
954 token[len-1] = '\0';
955 }
956 if (plugin_loaded(this, token))
957 {
958 free(token);
959 continue;
960 }
961 if (path)
962 {
963 if (snprintf(buf, sizeof(buf), "%s/libstrongswan-%s.so",
964 path, token) >= sizeof(buf))
965 {
966 return FALSE;
967 }
968 file = buf;
969 }
970 entry = load_plugin(this, token, file, critical);
971 if (entry)
972 {
973 register_features(this, entry);
974 }
975 else if (critical)
976 {
977 critical_failed = TRUE;
978 DBG1(DBG_LIB, "loading critical plugin '%s' failed", token);
979 }
980 free(token);
981 }
982 enumerator->destroy(enumerator);
983 if (!critical_failed)
984 {
985 load_features(this);
986 /* check for unloaded features provided by critical plugins */
987 critical_failed = missing_critical_features(this);
988 /* unload plugins that we were not able to load any features for */
989 purge_plugins(this);
990 }
991 if (!critical_failed)
992 {
993 free(this->loaded_plugins);
994 this->loaded_plugins = loaded_plugins_list(this);
995 }
996 return !critical_failed;
997 }
998
999 /**
1000 * Unload plugin features, they are registered in reverse order
1001 */
1002 static void unload_features(private_plugin_loader_t *this)
1003 {
1004 enumerator_t *enumerator;
1005 provided_feature_t *provided;
1006 plugin_entry_t *entry;
1007
1008 enumerator = this->loaded->create_enumerator(this->loaded);
1009 while (enumerator->enumerate(enumerator, &provided))
1010 {
1011 entry = provided->entry;
1012 plugin_feature_unload(entry->plugin, provided->feature, provided->reg);
1013 this->loaded->remove_at(this->loaded, enumerator);
1014 entry->features->remove(entry->features, provided, NULL);
1015 unregister_feature(this, provided);
1016 }
1017 enumerator->destroy(enumerator);
1018 }
1019
1020 METHOD(plugin_loader_t, unload, void,
1021 private_plugin_loader_t *this)
1022 {
1023 plugin_entry_t *entry;
1024
1025 /* unload features followed by plugins, in reverse order */
1026 unload_features(this);
1027 while (this->plugins->remove_last(this->plugins, (void**)&entry) == SUCCESS)
1028 {
1029 if (lib->leak_detective)
1030 { /* keep handle to report leaks properly */
1031 entry->handle = NULL;
1032 }
1033 unregister_features(this, entry);
1034 plugin_entry_destroy(entry);
1035 }
1036 free(this->loaded_plugins);
1037 this->loaded_plugins = NULL;
1038 }
1039
1040 /**
1041 * Reload a plugin by name, NULL for all
1042 */
1043 static u_int reload_by_name(private_plugin_loader_t *this, char *name)
1044 {
1045 u_int reloaded = 0;
1046 enumerator_t *enumerator;
1047 plugin_t *plugin;
1048
1049 enumerator = create_plugin_enumerator(this);
1050 while (enumerator->enumerate(enumerator, &plugin, NULL))
1051 {
1052 if (name == NULL || streq(name, plugin->get_name(plugin)))
1053 {
1054 if (plugin->reload && plugin->reload(plugin))
1055 {
1056 DBG2(DBG_LIB, "reloaded configuration of '%s' plugin",
1057 plugin->get_name(plugin));
1058 reloaded++;
1059 }
1060 }
1061 }
1062 enumerator->destroy(enumerator);
1063 return reloaded;
1064 }
1065
1066 METHOD(plugin_loader_t, reload, u_int,
1067 private_plugin_loader_t *this, char *list)
1068 {
1069 u_int reloaded = 0;
1070 enumerator_t *enumerator;
1071 char *name;
1072
1073 if (list == NULL)
1074 {
1075 return reload_by_name(this, NULL);
1076 }
1077 enumerator = enumerator_create_token(list, " ", "");
1078 while (enumerator->enumerate(enumerator, &name))
1079 {
1080 reloaded += reload_by_name(this, name);
1081 }
1082 enumerator->destroy(enumerator);
1083 return reloaded;
1084 }
1085
1086 METHOD(plugin_loader_t, loaded_plugins, char*,
1087 private_plugin_loader_t *this)
1088 {
1089 return this->loaded_plugins ?: "";
1090 }
1091
1092 METHOD(plugin_loader_t, destroy, void,
1093 private_plugin_loader_t *this)
1094 {
1095 unload(this);
1096 this->features->destroy(this->features);
1097 this->loaded->destroy(this->loaded);
1098 this->plugins->destroy(this->plugins);
1099 free(this->loaded_plugins);
1100 free(this);
1101 }
1102
1103 /*
1104 * see header file
1105 */
1106 plugin_loader_t *plugin_loader_create()
1107 {
1108 private_plugin_loader_t *this;
1109
1110 INIT(this,
1111 .public = {
1112 .add_static_features = _add_static_features,
1113 .load = _load_plugins,
1114 .reload = _reload,
1115 .unload = _unload,
1116 .create_plugin_enumerator = _create_plugin_enumerator,
1117 .has_feature = _has_feature,
1118 .loaded_plugins = _loaded_plugins,
1119 .destroy = _destroy,
1120 },
1121 .plugins = linked_list_create(),
1122 .loaded = linked_list_create(),
1123 .features = hashtable_create(
1124 (hashtable_hash_t)registered_feature_hash,
1125 (hashtable_equals_t)registered_feature_equals, 64),
1126 );
1127
1128 return &this->public;
1129 }