plugin-loader: Log message when failing to load plugin
[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 char *name, *provide;
664
665 name = provided->entry->plugin->get_name(provided->entry->plugin);
666 provide = plugin_feature_get_string(&provided->feature[0]);
667 DBG2(DBG_LIB, "feature %s in plugin '%s' failed to load",
668 provide, name);
669 free(provide);
670
671 provided->failed = TRUE;
672 }
673 }
674 else
675 { /* TODO: we could check the current level and set a different flag when
676 * being loaded as dependency. If there are loops there is a chance the
677 * feature can be loaded later when loading the feature directly. */
678 provided->failed = TRUE;
679 }
680 }
681
682 /**
683 * Load a provided feature
684 */
685 static void load_provided(private_plugin_loader_t *this,
686 provided_feature_t *provided,
687 int level)
688 {
689 char *name, *provide;
690 int indent = level * 2;
691
692 if (provided->loaded || provided->failed)
693 {
694 return;
695 }
696 name = provided->entry->plugin->get_name(provided->entry->plugin);
697 provide = plugin_feature_get_string(provided->feature);
698 if (provided->loading)
699 { /* prevent loop */
700 DBG3(DBG_LIB, "%*sloop detected while loading %s in plugin '%s'",
701 indent, "", provide, name);
702 free(provide);
703 return;
704 }
705 DBG3(DBG_LIB, "%*sloading feature %s in plugin '%s'",
706 indent, "", provide, name);
707 free(provide);
708
709 provided->loading = TRUE;
710 load_feature(this, provided, level + 1);
711 provided->loading = FALSE;
712 }
713
714 /**
715 * Load registered plugin features
716 */
717 static void load_features(private_plugin_loader_t *this)
718 {
719 enumerator_t *enumerator, *inner;
720 plugin_entry_t *plugin;
721 provided_feature_t *provided;
722
723 /* we do this in plugin order to allow implicit dependencies to be resolved
724 * by reordering plugins */
725 enumerator = this->plugins->create_enumerator(this->plugins);
726 while (enumerator->enumerate(enumerator, &plugin))
727 {
728 inner = plugin->features->create_enumerator(plugin->features);
729 while (inner->enumerate(inner, &provided))
730 {
731 load_provided(this, provided, 0);
732 }
733 inner->destroy(inner);
734 }
735 enumerator->destroy(enumerator);
736 }
737
738 /**
739 * Register plugin features provided by the given plugin
740 */
741 static void register_features(private_plugin_loader_t *this,
742 plugin_entry_t *entry)
743 {
744 plugin_feature_t *feature, *reg;
745 registered_feature_t *registered, lookup;
746 provided_feature_t *provided;
747 int count, i;
748
749 if (!entry->plugin->get_features)
750 { /* feature interface not supported */
751 DBG1(DBG_LIB, "plugin '%s' does not provide features, deprecated",
752 entry->plugin->get_name(entry->plugin));
753 return;
754 }
755 reg = NULL;
756 count = entry->plugin->get_features(entry->plugin, &feature);
757 for (i = 0; i < count; i++)
758 {
759 switch (feature->kind)
760 {
761 case FEATURE_PROVIDE:
762 lookup.feature = feature;
763 registered = this->features->get(this->features, &lookup);
764 if (!registered)
765 {
766 INIT(registered,
767 .feature = feature,
768 .plugins = linked_list_create(),
769 );
770 this->features->put(this->features, registered, registered);
771 }
772 INIT(provided,
773 .entry = entry,
774 .feature = feature,
775 .reg = reg,
776 .dependencies = count - i,
777 );
778 registered->plugins->insert_last(registered->plugins,
779 provided);
780 entry->features->insert_last(entry->features, provided);
781 break;
782 case FEATURE_REGISTER:
783 case FEATURE_CALLBACK:
784 reg = feature;
785 break;
786 default:
787 break;
788 }
789 feature++;
790 }
791 }
792
793 /**
794 * Unregister a plugin feature
795 */
796 static void unregister_feature(private_plugin_loader_t *this,
797 provided_feature_t *provided)
798 {
799 registered_feature_t *registered, lookup;
800
801 lookup.feature = provided->feature;
802 registered = this->features->get(this->features, &lookup);
803 if (registered)
804 {
805 registered->plugins->remove(registered->plugins, provided, NULL);
806 if (registered->plugins->get_count(registered->plugins) == 0)
807 {
808 this->features->remove(this->features, &lookup);
809 registered->plugins->destroy(registered->plugins);
810 free(registered);
811 }
812 else if (registered->feature == provided->feature)
813 { /* update feature in case the providing plugin gets unloaded */
814 provided_feature_t *first;
815
816 registered->plugins->get_first(registered->plugins, (void**)&first);
817 registered->feature = first->feature;
818 }
819 }
820 free(provided);
821 }
822
823 /**
824 * Unregister plugin features
825 */
826 static void unregister_features(private_plugin_loader_t *this,
827 plugin_entry_t *entry)
828 {
829 provided_feature_t *provided;
830 enumerator_t *enumerator;
831
832 enumerator = entry->features->create_enumerator(entry->features);
833 while (enumerator->enumerate(enumerator, &provided))
834 {
835 entry->features->remove_at(entry->features, enumerator);
836 unregister_feature(this, provided);
837 }
838 enumerator->destroy(enumerator);
839 }
840
841 /**
842 * Check that we have all features loaded for critical plugins
843 */
844 static bool missing_critical_features(private_plugin_loader_t *this)
845 {
846 enumerator_t *enumerator, *features;
847 plugin_entry_t *entry;
848 bool critical_failed = FALSE;
849
850 enumerator = this->plugins->create_enumerator(this->plugins);
851 while (enumerator->enumerate(enumerator, &entry))
852 {
853 provided_feature_t *provided;
854 char *name, *provide;
855 int failed = 0;
856
857 if (!entry->plugin->get_features ||
858 !entry->critical)
859 { /* feature interface not supported, or not critical */
860 continue;
861 }
862
863 name = entry->plugin->get_name(entry->plugin);
864 features = entry->features->create_enumerator(entry->features);
865 while (features->enumerate(features, &provided))
866 {
867 if (!provided->loaded)
868 {
869 provide = plugin_feature_get_string(provided->feature);
870 DBG2(DBG_LIB, " failed to load %s in critical plugin '%s'",
871 provide, name);
872 free(provide);
873 failed++;
874 }
875 }
876 features->destroy(features);
877 if (failed)
878 {
879 DBG1(DBG_LIB, "failed to load %d feature%s in critical plugin '%s'",
880 failed, failed > 1 ? "s" : "", name);
881 critical_failed = TRUE;
882 }
883 }
884 enumerator->destroy(enumerator);
885
886 return critical_failed;
887 }
888
889 /**
890 * Remove plugins we were not able to load any plugin features from.
891 */
892 static void purge_plugins(private_plugin_loader_t *this)
893 {
894 enumerator_t *enumerator;
895 plugin_entry_t *entry;
896
897 enumerator = this->plugins->create_enumerator(this->plugins);
898 while (enumerator->enumerate(enumerator, &entry))
899 {
900 if (!entry->plugin->get_features)
901 { /* feature interface not supported */
902 continue;
903 }
904 if (entry->features->find_first(entry->features,
905 (void*)is_feature_loaded, NULL) != SUCCESS)
906 {
907 DBG2(DBG_LIB, "unloading plugin '%s' without loaded features",
908 entry->plugin->get_name(entry->plugin));
909 this->plugins->remove_at(this->plugins, enumerator);
910 unregister_features(this, entry);
911 plugin_entry_destroy(entry);
912 }
913 }
914 enumerator->destroy(enumerator);
915 }
916
917 METHOD(plugin_loader_t, add_static_features, void,
918 private_plugin_loader_t *this, const char *name,
919 plugin_feature_t features[], int count, bool critical)
920 {
921 plugin_entry_t *entry;
922 plugin_t *plugin;
923
924 plugin = static_features_create(name, features, count);
925
926 INIT(entry,
927 .plugin = plugin,
928 .critical = critical,
929 .features = linked_list_create(),
930 );
931 this->plugins->insert_last(this->plugins, entry);
932 register_features(this, entry);
933 }
934
935 METHOD(plugin_loader_t, load_plugins, bool,
936 private_plugin_loader_t *this, char *path, char *list)
937 {
938 enumerator_t *enumerator;
939 char *token;
940 bool critical_failed = FALSE;
941
942 #ifdef PLUGINDIR
943 if (path == NULL)
944 {
945 path = PLUGINDIR;
946 }
947 #endif /* PLUGINDIR */
948
949 enumerator = enumerator_create_token(list, " ", " ");
950 while (!critical_failed && enumerator->enumerate(enumerator, &token))
951 {
952 plugin_entry_t *entry;
953 bool critical = FALSE;
954 char buf[PATH_MAX], *file = NULL;
955 int len;
956
957 token = strdup(token);
958 len = strlen(token);
959 if (token[len-1] == '!')
960 {
961 critical = TRUE;
962 token[len-1] = '\0';
963 }
964 if (plugin_loaded(this, token))
965 {
966 free(token);
967 continue;
968 }
969 if (path)
970 {
971 if (snprintf(buf, sizeof(buf), "%s/libstrongswan-%s.so",
972 path, token) >= sizeof(buf))
973 {
974 return FALSE;
975 }
976 file = buf;
977 }
978 entry = load_plugin(this, token, file, critical);
979 if (entry)
980 {
981 register_features(this, entry);
982 }
983 else if (critical)
984 {
985 critical_failed = TRUE;
986 DBG1(DBG_LIB, "loading critical plugin '%s' failed", token);
987 }
988 free(token);
989 }
990 enumerator->destroy(enumerator);
991 if (!critical_failed)
992 {
993 load_features(this);
994 /* check for unloaded features provided by critical plugins */
995 critical_failed = missing_critical_features(this);
996 /* unload plugins that we were not able to load any features for */
997 purge_plugins(this);
998 }
999 if (!critical_failed)
1000 {
1001 free(this->loaded_plugins);
1002 this->loaded_plugins = loaded_plugins_list(this);
1003 }
1004 return !critical_failed;
1005 }
1006
1007 /**
1008 * Unload plugin features, they are registered in reverse order
1009 */
1010 static void unload_features(private_plugin_loader_t *this)
1011 {
1012 enumerator_t *enumerator;
1013 provided_feature_t *provided;
1014 plugin_entry_t *entry;
1015
1016 enumerator = this->loaded->create_enumerator(this->loaded);
1017 while (enumerator->enumerate(enumerator, &provided))
1018 {
1019 entry = provided->entry;
1020 plugin_feature_unload(entry->plugin, provided->feature, provided->reg);
1021 this->loaded->remove_at(this->loaded, enumerator);
1022 entry->features->remove(entry->features, provided, NULL);
1023 unregister_feature(this, provided);
1024 }
1025 enumerator->destroy(enumerator);
1026 }
1027
1028 METHOD(plugin_loader_t, unload, void,
1029 private_plugin_loader_t *this)
1030 {
1031 plugin_entry_t *entry;
1032
1033 /* unload features followed by plugins, in reverse order */
1034 unload_features(this);
1035 while (this->plugins->remove_last(this->plugins, (void**)&entry) == SUCCESS)
1036 {
1037 if (lib->leak_detective)
1038 { /* keep handle to report leaks properly */
1039 entry->handle = NULL;
1040 }
1041 unregister_features(this, entry);
1042 plugin_entry_destroy(entry);
1043 }
1044 free(this->loaded_plugins);
1045 this->loaded_plugins = NULL;
1046 }
1047
1048 /**
1049 * Reload a plugin by name, NULL for all
1050 */
1051 static u_int reload_by_name(private_plugin_loader_t *this, char *name)
1052 {
1053 u_int reloaded = 0;
1054 enumerator_t *enumerator;
1055 plugin_t *plugin;
1056
1057 enumerator = create_plugin_enumerator(this);
1058 while (enumerator->enumerate(enumerator, &plugin, NULL))
1059 {
1060 if (name == NULL || streq(name, plugin->get_name(plugin)))
1061 {
1062 if (plugin->reload && plugin->reload(plugin))
1063 {
1064 DBG2(DBG_LIB, "reloaded configuration of '%s' plugin",
1065 plugin->get_name(plugin));
1066 reloaded++;
1067 }
1068 }
1069 }
1070 enumerator->destroy(enumerator);
1071 return reloaded;
1072 }
1073
1074 METHOD(plugin_loader_t, reload, u_int,
1075 private_plugin_loader_t *this, char *list)
1076 {
1077 u_int reloaded = 0;
1078 enumerator_t *enumerator;
1079 char *name;
1080
1081 if (list == NULL)
1082 {
1083 return reload_by_name(this, NULL);
1084 }
1085 enumerator = enumerator_create_token(list, " ", "");
1086 while (enumerator->enumerate(enumerator, &name))
1087 {
1088 reloaded += reload_by_name(this, name);
1089 }
1090 enumerator->destroy(enumerator);
1091 return reloaded;
1092 }
1093
1094 METHOD(plugin_loader_t, loaded_plugins, char*,
1095 private_plugin_loader_t *this)
1096 {
1097 return this->loaded_plugins ?: "";
1098 }
1099
1100 METHOD(plugin_loader_t, destroy, void,
1101 private_plugin_loader_t *this)
1102 {
1103 unload(this);
1104 this->features->destroy(this->features);
1105 this->loaded->destroy(this->loaded);
1106 this->plugins->destroy(this->plugins);
1107 free(this->loaded_plugins);
1108 free(this);
1109 }
1110
1111 /*
1112 * see header file
1113 */
1114 plugin_loader_t *plugin_loader_create()
1115 {
1116 private_plugin_loader_t *this;
1117
1118 INIT(this,
1119 .public = {
1120 .add_static_features = _add_static_features,
1121 .load = _load_plugins,
1122 .reload = _reload,
1123 .unload = _unload,
1124 .create_plugin_enumerator = _create_plugin_enumerator,
1125 .has_feature = _has_feature,
1126 .loaded_plugins = _loaded_plugins,
1127 .destroy = _destroy,
1128 },
1129 .plugins = linked_list_create(),
1130 .loaded = linked_list_create(),
1131 .features = hashtable_create(
1132 (hashtable_hash_t)registered_feature_hash,
1133 (hashtable_equals_t)registered_feature_equals, 64),
1134 );
1135
1136 return &this->public;
1137 }