Annotation of embedaddon/strongswan/src/libstrongswan/plugins/plugin_loader.c, revision 1.1.1.1
1.1 misho 1: /*
2: * Copyright (C) 2010-2014 Tobias Brunner
3: * Copyright (C) 2007 Martin Willi
4: * HSR 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 <sys/types.h>
21: #include <sys/stat.h>
22: #include <unistd.h>
23: #include <string.h>
24: #ifdef HAVE_DLADDR
25: #include <dlfcn.h>
26: #endif
27: #include <limits.h>
28: #include <stdio.h>
29:
30: #include <utils/debug.h>
31: #include <library.h>
32: #include <collections/hashtable.h>
33: #include <collections/array.h>
34: #include <collections/linked_list.h>
35: #include <plugins/plugin.h>
36: #include <utils/integrity_checker.h>
37:
38: typedef struct private_plugin_loader_t private_plugin_loader_t;
39: typedef struct registered_feature_t registered_feature_t;
40: typedef struct provided_feature_t provided_feature_t;
41: typedef struct plugin_entry_t plugin_entry_t;
42:
43: #ifdef STATIC_PLUGIN_CONSTRUCTORS
44: /**
45: * Statically registered constructors
46: */
47: static hashtable_t *plugin_constructors = NULL;
48: #endif
49:
50: /**
51: * private data of plugin_loader
52: */
53: struct private_plugin_loader_t {
54:
55: /**
56: * public functions
57: */
58: plugin_loader_t public;
59:
60: /**
61: * List of plugins, as plugin_entry_t
62: */
63: linked_list_t *plugins;
64:
65: /**
66: * Hashtable for registered features, as registered_feature_t
67: */
68: hashtable_t *features;
69:
70: /**
71: * Loaded features (stored in reverse order), as provided_feature_t
72: */
73: linked_list_t *loaded;
74:
75: /**
76: * List of paths to search for plugins
77: */
78: linked_list_t *paths;
79:
80: /**
81: * List of names of loaded plugins
82: */
83: char *loaded_plugins;
84:
85: /**
86: * Statistics collected while loading features
87: */
88: struct {
89: /** Number of features that failed to load */
90: int failed;
91: /** Number of features that failed because of unmet dependencies */
92: int depends;
93: /** Number of features in critical plugins that failed to load */
94: int critical;
95: } stats;
96: };
97:
98: /**
99: * Registered plugin feature
100: */
101: struct registered_feature_t {
102:
103: /**
104: * The registered feature
105: */
106: plugin_feature_t *feature;
107:
108: /**
109: * List of plugins providing this feature, as provided_feature_t
110: */
111: linked_list_t *plugins;
112: };
113:
114: /**
115: * Hash a registered feature
116: */
117: static u_int registered_feature_hash(registered_feature_t *this)
118: {
119: return plugin_feature_hash(this->feature);
120: }
121:
122: /**
123: * Compare two registered features
124: */
125: static bool registered_feature_equals(registered_feature_t *a,
126: registered_feature_t *b)
127: {
128: return plugin_feature_equals(a->feature, b->feature);
129: }
130:
131: /**
132: * Feature as provided by a plugin
133: */
134: struct provided_feature_t {
135:
136: /**
137: * Plugin providing the feature
138: */
139: plugin_entry_t *entry;
140:
141: /**
142: * FEATURE_REGISTER or FEATURE_CALLBACK entry
143: */
144: plugin_feature_t *reg;
145:
146: /**
147: * The provided feature (followed by dependencies)
148: */
149: plugin_feature_t *feature;
150:
151: /**
152: * Maximum number of dependencies (following feature)
153: */
154: int dependencies;
155:
156: /**
157: * TRUE if currently loading this feature (to prevent loops)
158: */
159: bool loading;
160:
161: /**
162: * TRUE if feature loaded
163: */
164: bool loaded;
165:
166: /**
167: * TRUE if feature failed to load
168: */
169: bool failed;
170: };
171:
172: /**
173: * Entry for a plugin
174: */
175: struct plugin_entry_t {
176:
177: /**
178: * Plugin instance
179: */
180: plugin_t *plugin;
181:
182: /**
183: * TRUE, if the plugin is marked as critical
184: */
185: bool critical;
186:
187: /**
188: * dlopen handle, if in separate lib
189: */
190: void *handle;
191:
192: /**
193: * List of features, as provided_feature_t
194: */
195: linked_list_t *features;
196: };
197:
198: /**
199: * Destroy a plugin entry
200: */
201: static void plugin_entry_destroy(plugin_entry_t *entry)
202: {
203: DESTROY_IF(entry->plugin);
204: if (entry->handle)
205: {
206: dlclose(entry->handle);
207: }
208: entry->features->destroy(entry->features);
209: free(entry);
210: }
211:
212: /**
213: * Wrapper for static plugin features
214: */
215: typedef struct {
216:
217: /**
218: * Implements plugin_t interface
219: */
220: plugin_t public;
221:
222: /**
223: * Name of the module registering these features
224: */
225: char *name;
226:
227: /**
228: * Optional reload function for features
229: */
230: bool (*reload)(void *data);
231:
232: /**
233: * User data to pass to reload function
234: */
235: void *reload_data;
236:
237: /**
238: * Static plugin features
239: */
240: plugin_feature_t *features;
241:
242: /**
243: * Number of plugin features
244: */
245: int count;
246:
247: } static_features_t;
248:
249: METHOD(plugin_t, get_static_name, char*,
250: static_features_t *this)
251: {
252: return this->name;
253: }
254:
255: METHOD(plugin_t, get_static_features, int,
256: static_features_t *this, plugin_feature_t *features[])
257: {
258: *features = this->features;
259: return this->count;
260: }
261:
262: METHOD(plugin_t, static_reload, bool,
263: static_features_t *this)
264: {
265: if (this->reload)
266: {
267: return this->reload(this->reload_data);
268: }
269: return FALSE;
270: }
271:
272: METHOD(plugin_t, static_destroy, void,
273: static_features_t *this)
274: {
275: free(this->features);
276: free(this->name);
277: free(this);
278: }
279:
280: /**
281: * Create a wrapper around static plugin features.
282: */
283: static plugin_t *static_features_create(const char *name,
284: plugin_feature_t features[], int count,
285: bool (*reload)(void*), void *reload_data)
286: {
287: static_features_t *this;
288:
289: INIT(this,
290: .public = {
291: .get_name = _get_static_name,
292: .get_features = _get_static_features,
293: .reload = _static_reload,
294: .destroy = _static_destroy,
295: },
296: .name = strdup(name),
297: .reload = reload,
298: .reload_data = reload_data,
299: .features = calloc(count, sizeof(plugin_feature_t)),
300: .count = count,
301: );
302:
303: memcpy(this->features, features, sizeof(plugin_feature_t) * count);
304:
305: return &this->public;
306: }
307:
308: #ifdef STATIC_PLUGIN_CONSTRUCTORS
309: /*
310: * Described in header.
311: */
312: void plugin_constructor_register(char *name, void *constructor)
313: {
314: bool old = FALSE;
315:
316: if (lib && lib->leak_detective)
317: {
318: old = lib->leak_detective->set_state(lib->leak_detective, FALSE);
319: }
320:
321: if (!plugin_constructors)
322: {
323: chunk_hash_seed();
324: plugin_constructors = hashtable_create(hashtable_hash_str,
325: hashtable_equals_str, 32);
326: }
327: if (constructor)
328: {
329: plugin_constructors->put(plugin_constructors, name, constructor);
330: }
331: else
332: {
333: plugin_constructors->remove(plugin_constructors, name);
334: if (!plugin_constructors->get_count(plugin_constructors))
335: {
336: plugin_constructors->destroy(plugin_constructors);
337: plugin_constructors = NULL;
338: }
339: }
340:
341: if (lib && lib->leak_detective)
342: {
343: lib->leak_detective->set_state(lib->leak_detective, old);
344: }
345: }
346: #endif
347:
348: /**
349: * create a plugin
350: * returns: NOT_FOUND, if the constructor was not found
351: * FAILED, if the plugin could not be constructed
352: */
353: static status_t create_plugin(private_plugin_loader_t *this, void *handle,
354: char *name, bool integrity, bool critical,
355: plugin_entry_t **entry)
356: {
357: char create[128];
358: plugin_t *plugin;
359: plugin_constructor_t constructor = NULL;
360:
361: if (snprintf(create, sizeof(create), "%s_plugin_create",
362: name) >= sizeof(create))
363: {
364: return FAILED;
365: }
366: translate(create, "-", "_");
367: #ifdef STATIC_PLUGIN_CONSTRUCTORS
368: if (plugin_constructors)
369: {
370: constructor = plugin_constructors->get(plugin_constructors, name);
371: }
372: if (!constructor)
373: #endif
374: {
375: constructor = dlsym(handle, create);
376: }
377: if (!constructor)
378: {
379: return NOT_FOUND;
380: }
381: if (integrity && lib->integrity)
382: {
383: if (!lib->integrity->check_segment(lib->integrity, name, constructor))
384: {
385: DBG1(DBG_LIB, "plugin '%s': failed segment integrity test", name);
386: return FAILED;
387: }
388: DBG1(DBG_LIB, "plugin '%s': passed file and segment integrity tests",
389: name);
390: }
391: plugin = constructor();
392: if (plugin == NULL)
393: {
394: DBG1(DBG_LIB, "plugin '%s': failed to load - %s returned NULL", name,
395: create);
396: return FAILED;
397: }
398: INIT(*entry,
399: .plugin = plugin,
400: .critical = critical,
401: .features = linked_list_create(),
402: );
403: DBG2(DBG_LIB, "plugin '%s': loaded successfully", name);
404: return SUCCESS;
405: }
406:
407: /**
408: * load a single plugin
409: */
410: static plugin_entry_t *load_plugin(private_plugin_loader_t *this, char *name,
411: char *file, bool critical)
412: {
413: plugin_entry_t *entry;
414: void *handle;
415: int flag = RTLD_LAZY;
416:
417: switch (create_plugin(this, RTLD_DEFAULT, name, FALSE, critical, &entry))
418: {
419: case SUCCESS:
420: this->plugins->insert_last(this->plugins, entry);
421: return entry;
422: case NOT_FOUND:
423: if (file)
424: { /* try to load the plugin from a file */
425: break;
426: }
427: /* fall-through */
428: default:
429: return NULL;
430: }
431: if (lib->integrity)
432: {
433: if (!lib->integrity->check_file(lib->integrity, name, file))
434: {
435: DBG1(DBG_LIB, "plugin '%s': failed file integrity test of '%s'",
436: name, file);
437: return NULL;
438: }
439: }
440: if (lib->settings->get_bool(lib->settings, "%s.dlopen_use_rtld_now",
441: FALSE, lib->ns))
442: {
443: flag = RTLD_NOW;
444: }
445: #ifdef RTLD_NODELETE
446: /* If supported, do not unload the library when unloading a plugin. It
447: * really doesn't matter in productive systems, but causes many (dependency)
448: * library reloads during unit tests. Some libraries can't handle that, e.g.
449: * GnuTLS leaks file descriptors in its library load/unload functions. */
450: flag |= RTLD_NODELETE;
451: #endif
452: handle = dlopen(file, flag);
453: if (handle == NULL)
454: {
455: DBG1(DBG_LIB, "plugin '%s' failed to load: %s", name, dlerror());
456: return NULL;
457: }
458: if (create_plugin(this, handle, name, TRUE, critical, &entry) != SUCCESS)
459: {
460: dlclose(handle);
461: return NULL;
462: }
463: entry->handle = handle;
464: this->plugins->insert_last(this->plugins, entry);
465: return entry;
466: }
467:
468: CALLBACK(feature_filter, bool,
469: void *null, enumerator_t *orig, va_list args)
470: {
471: provided_feature_t *provided;
472: plugin_feature_t **feature;
473:
474: VA_ARGS_VGET(args, feature);
475:
476: while (orig->enumerate(orig, &provided))
477: {
478: if (provided->loaded)
479: {
480: *feature = provided->feature;
481: return TRUE;
482: }
483: }
484: return FALSE;
485: }
486:
487: CALLBACK(plugin_filter, bool,
488: void *null, enumerator_t *orig, va_list args)
489: {
490: plugin_entry_t *entry;
491: linked_list_t **list;
492: plugin_t **plugin;
493:
494: VA_ARGS_VGET(args, plugin, list);
495:
496: if (orig->enumerate(orig, &entry))
497: {
498: *plugin = entry->plugin;
499: if (list)
500: {
501: enumerator_t *features;
502: features = enumerator_create_filter(
503: entry->features->create_enumerator(entry->features),
504: feature_filter, NULL, NULL);
505: *list = linked_list_create_from_enumerator(features);
506: }
507: return TRUE;
508: }
509: return FALSE;
510: }
511:
512: METHOD(plugin_loader_t, create_plugin_enumerator, enumerator_t*,
513: private_plugin_loader_t *this)
514: {
515: return enumerator_create_filter(
516: this->plugins->create_enumerator(this->plugins),
517: plugin_filter, NULL, NULL);
518: }
519:
520: METHOD(plugin_loader_t, has_feature, bool,
521: private_plugin_loader_t *this, plugin_feature_t feature)
522: {
523: enumerator_t *plugins, *features;
524: plugin_t *plugin;
525: linked_list_t *list;
526: plugin_feature_t *current;
527: bool found = FALSE;
528:
529: plugins = create_plugin_enumerator(this);
530: while (plugins->enumerate(plugins, &plugin, &list))
531: {
532: features = list->create_enumerator(list);
533: while (features->enumerate(features, ¤t))
534: {
535: if (plugin_feature_matches(&feature, current))
536: {
537: found = TRUE;
538: break;
539: }
540: }
541: features->destroy(features);
542: list->destroy(list);
543: }
544: plugins->destroy(plugins);
545:
546: return found;
547: }
548:
549: /**
550: * Create a list of the names of all loaded plugins
551: */
552: static char* loaded_plugins_list(private_plugin_loader_t *this)
553: {
554: int buf_len = 128, len = 0;
555: char *buf, *name;
556: enumerator_t *enumerator;
557: plugin_t *plugin;
558:
559: buf = malloc(buf_len);
560: buf[0] = '\0';
561: enumerator = create_plugin_enumerator(this);
562: while (enumerator->enumerate(enumerator, &plugin, NULL))
563: {
564: name = plugin->get_name(plugin);
565: if (len + (strlen(name) + 1) >= buf_len)
566: {
567: buf_len <<= 1;
568: buf = realloc(buf, buf_len);
569: }
570: len += snprintf(&buf[len], buf_len - len, "%s ", name);
571: }
572: enumerator->destroy(enumerator);
573: if (len > 0 && buf[len - 1] == ' ')
574: {
575: buf[len - 1] = '\0';
576: }
577: return buf;
578: }
579:
580: /**
581: * Check if a plugin is already loaded
582: */
583: static bool plugin_loaded(private_plugin_loader_t *this, char *name)
584: {
585: enumerator_t *enumerator;
586: bool found = FALSE;
587: plugin_t *plugin;
588:
589: enumerator = create_plugin_enumerator(this);
590: while (enumerator->enumerate(enumerator, &plugin, NULL))
591: {
592: if (streq(plugin->get_name(plugin), name))
593: {
594: found = TRUE;
595: break;
596: }
597: }
598: enumerator->destroy(enumerator);
599: return found;
600: }
601:
602: /**
603: * Forward declaration
604: */
605: static void load_provided(private_plugin_loader_t *this,
606: provided_feature_t *provided,
607: int level);
608:
609: CALLBACK(is_feature_loaded, bool,
610: provided_feature_t *item, va_list args)
611: {
612: return item->loaded;
613: }
614:
615: CALLBACK(is_feature_loadable, bool,
616: provided_feature_t *item, va_list args)
617: {
618: return !item->loading && !item->loaded && !item->failed;
619: }
620:
621: /**
622: * Find a loaded and matching feature
623: */
624: static bool loaded_feature_matches(registered_feature_t *a,
625: registered_feature_t *b)
626: {
627: if (plugin_feature_matches(a->feature, b->feature))
628: {
629: return b->plugins->find_first(b->plugins, is_feature_loaded, NULL);
630: }
631: return FALSE;
632: }
633:
634: /**
635: * Find a loadable module that equals the requested feature
636: */
637: static bool loadable_feature_equals(registered_feature_t *a,
638: registered_feature_t *b)
639: {
640: if (plugin_feature_equals(a->feature, b->feature))
641: {
642: return b->plugins->find_first(b->plugins, is_feature_loadable, NULL);
643: }
644: return FALSE;
645: }
646:
647: /**
648: * Find a loadable module that matches the requested feature
649: */
650: static bool loadable_feature_matches(registered_feature_t *a,
651: registered_feature_t *b)
652: {
653: if (plugin_feature_matches(a->feature, b->feature))
654: {
655: return b->plugins->find_first(b->plugins, is_feature_loadable, NULL);
656: }
657: return FALSE;
658: }
659:
660: /**
661: * Returns a compatible plugin feature for the given dependency
662: */
663: static bool find_compatible_feature(private_plugin_loader_t *this,
664: plugin_feature_t *dependency)
665: {
666: registered_feature_t *feature, lookup = {
667: .feature = dependency,
668: };
669:
670: feature = this->features->get_match(this->features, &lookup,
671: (void*)loaded_feature_matches);
672: return feature != NULL;
673: }
674:
675: /**
676: * Load a registered plugin feature
677: */
678: static void load_registered(private_plugin_loader_t *this,
679: registered_feature_t *registered,
680: int level)
681: {
682: enumerator_t *enumerator;
683: provided_feature_t *provided;
684:
685: enumerator = registered->plugins->create_enumerator(registered->plugins);
686: while (enumerator->enumerate(enumerator, &provided))
687: {
688: load_provided(this, provided, level);
689: }
690: enumerator->destroy(enumerator);
691: }
692:
693: /**
694: * Try to load dependencies of the given feature
695: */
696: static bool load_dependencies(private_plugin_loader_t *this,
697: provided_feature_t *provided,
698: int level)
699: {
700: registered_feature_t *registered, lookup;
701: int i;
702:
703: /* first entry is provided feature, followed by dependencies */
704: for (i = 1; i < provided->dependencies; i++)
705: {
706: if (provided->feature[i].kind != FEATURE_DEPENDS &&
707: provided->feature[i].kind != FEATURE_SDEPEND)
708: { /* end of dependencies */
709: break;
710: }
711:
712: /* we load the feature even if a compatible one is already loaded,
713: * otherwise e.g. a specific database implementation loaded before
714: * another might cause a plugin feature loaded in-between to fail */
715: lookup.feature = &provided->feature[i];
716: do
717: { /* prefer an exactly matching feature, could be omitted but
718: * results in a more predictable behavior */
719: registered = this->features->get_match(this->features,
720: &lookup,
721: (void*)loadable_feature_equals);
722: if (!registered)
723: { /* try fuzzy matching */
724: registered = this->features->get_match(this->features,
725: &lookup,
726: (void*)loadable_feature_matches);
727: }
728: if (registered)
729: {
730: load_registered(this, registered, level);
731: }
732: /* we could stop after finding one but for dependencies like
733: * DB_ANY it might be needed to load all matching features */
734: }
735: while (registered);
736:
737: if (!find_compatible_feature(this, &provided->feature[i]))
738: {
739: bool soft = provided->feature[i].kind == FEATURE_SDEPEND;
740:
741: #ifndef USE_FUZZING
742: char *name, *provide, *depend;
743: int indent = level * 2;
744:
745: name = provided->entry->plugin->get_name(provided->entry->plugin);
746: provide = plugin_feature_get_string(&provided->feature[0]);
747: depend = plugin_feature_get_string(&provided->feature[i]);
748: if (soft)
749: {
750: DBG3(DBG_LIB, "%*sfeature %s in plugin '%s' has unmet soft "
751: "dependency: %s", indent, "", provide, name, depend);
752: }
753: else if (provided->entry->critical)
754: {
755: DBG1(DBG_LIB, "feature %s in critical plugin '%s' has unmet "
756: "dependency: %s", provide, name, depend);
757: }
758: else
759: {
760: DBG2(DBG_LIB, "feature %s in plugin '%s' has unmet dependency: "
761: "%s", provide, name, depend);
762: }
763: free(provide);
764: free(depend);
765: #endif /* !USE_FUZZING */
766:
767: if (soft)
768: { /* it's ok if we can't resolve soft dependencies */
769: continue;
770: }
771: return FALSE;
772: }
773: }
774: return TRUE;
775: }
776:
777: /**
778: * Load registered plugin features
779: */
780: static void load_feature(private_plugin_loader_t *this,
781: provided_feature_t *provided,
782: int level)
783: {
784: if (load_dependencies(this, provided, level))
785: {
786: if (plugin_feature_load(provided->entry->plugin, provided->feature,
787: provided->reg))
788: {
789: provided->loaded = TRUE;
790: /* insert first so we can unload the features in reverse order */
791: this->loaded->insert_first(this->loaded, provided);
792: return;
793: }
794:
795: #ifndef USE_FUZZING
796: char *name, *provide;
797:
798: name = provided->entry->plugin->get_name(provided->entry->plugin);
799: provide = plugin_feature_get_string(&provided->feature[0]);
800: if (provided->entry->critical)
801: {
802: DBG1(DBG_LIB, "feature %s in critical plugin '%s' failed to load",
803: provide, name);
804: }
805: else
806: {
807: DBG2(DBG_LIB, "feature %s in plugin '%s' failed to load",
808: provide, name);
809: }
810: free(provide);
811: #endif /* !USE_FUZZING */
812: }
813: else
814: { /* TODO: we could check the current level and set a different flag when
815: * being loaded as dependency. If there are loops there is a chance the
816: * feature can be loaded later when loading the feature directly. */
817: this->stats.depends++;
818: }
819: provided->failed = TRUE;
820: this->stats.critical += provided->entry->critical ? 1 : 0;
821: this->stats.failed++;
822: }
823:
824: /**
825: * Load a provided feature
826: */
827: static void load_provided(private_plugin_loader_t *this,
828: provided_feature_t *provided,
829: int level)
830: {
831:
832: if (provided->loaded || provided->failed)
833: {
834: return;
835: }
836:
837: #ifndef USE_FUZZING
838: char *name, *provide;
839: int indent = level * 2;
840:
841: name = provided->entry->plugin->get_name(provided->entry->plugin);
842: provide = plugin_feature_get_string(provided->feature);
843: if (provided->loading)
844: { /* prevent loop */
845: DBG3(DBG_LIB, "%*sloop detected while loading %s in plugin '%s'",
846: indent, "", provide, name);
847: free(provide);
848: return;
849: }
850: DBG3(DBG_LIB, "%*sloading feature %s in plugin '%s'",
851: indent, "", provide, name);
852: free(provide);
853: #else
854: if (provided->loading)
855: {
856: return;
857: }
858: #endif /* USE_FUZZING */
859:
860: provided->loading = TRUE;
861: load_feature(this, provided, level + 1);
862: provided->loading = FALSE;
863: }
864:
865: /**
866: * Load registered plugin features
867: */
868: static void load_features(private_plugin_loader_t *this)
869: {
870: enumerator_t *enumerator, *inner;
871: plugin_entry_t *plugin;
872: provided_feature_t *provided;
873:
874: /* we do this in plugin order to allow implicit dependencies to be resolved
875: * by reordering plugins */
876: enumerator = this->plugins->create_enumerator(this->plugins);
877: while (enumerator->enumerate(enumerator, &plugin))
878: {
879: inner = plugin->features->create_enumerator(plugin->features);
880: while (inner->enumerate(inner, &provided))
881: {
882: load_provided(this, provided, 0);
883: }
884: inner->destroy(inner);
885: }
886: enumerator->destroy(enumerator);
887: }
888:
889: /**
890: * Register plugin features provided by the given plugin
891: */
892: static void register_features(private_plugin_loader_t *this,
893: plugin_entry_t *entry)
894: {
895: plugin_feature_t *feature, *reg;
896: registered_feature_t *registered, lookup;
897: provided_feature_t *provided;
898: int count, i;
899:
900: if (!entry->plugin->get_features)
901: { /* feature interface not supported */
902: DBG1(DBG_LIB, "plugin '%s' does not provide features, deprecated",
903: entry->plugin->get_name(entry->plugin));
904: return;
905: }
906: reg = NULL;
907: count = entry->plugin->get_features(entry->plugin, &feature);
908: for (i = 0; i < count; i++)
909: {
910: switch (feature->kind)
911: {
912: case FEATURE_PROVIDE:
913: lookup.feature = feature;
914: registered = this->features->get(this->features, &lookup);
915: if (!registered)
916: {
917: INIT(registered,
918: .feature = feature,
919: .plugins = linked_list_create(),
920: );
921: this->features->put(this->features, registered, registered);
922: }
923: INIT(provided,
924: .entry = entry,
925: .feature = feature,
926: .reg = reg,
927: .dependencies = count - i,
928: );
929: registered->plugins->insert_last(registered->plugins,
930: provided);
931: entry->features->insert_last(entry->features, provided);
932: break;
933: case FEATURE_REGISTER:
934: case FEATURE_CALLBACK:
935: reg = feature;
936: break;
937: default:
938: break;
939: }
940: feature++;
941: }
942: }
943:
944: /**
945: * Unregister a plugin feature
946: */
947: static void unregister_feature(private_plugin_loader_t *this,
948: provided_feature_t *provided)
949: {
950: registered_feature_t *registered, lookup;
951:
952: lookup.feature = provided->feature;
953: registered = this->features->get(this->features, &lookup);
954: if (registered)
955: {
956: registered->plugins->remove(registered->plugins, provided, NULL);
957: if (registered->plugins->get_count(registered->plugins) == 0)
958: {
959: this->features->remove(this->features, &lookup);
960: registered->plugins->destroy(registered->plugins);
961: free(registered);
962: }
963: else if (registered->feature == provided->feature)
964: { /* update feature in case the providing plugin gets unloaded */
965: provided_feature_t *first;
966:
967: registered->plugins->get_first(registered->plugins, (void**)&first);
968: registered->feature = first->feature;
969: }
970: }
971: free(provided);
972: }
973:
974: /**
975: * Unregister plugin features
976: */
977: static void unregister_features(private_plugin_loader_t *this,
978: plugin_entry_t *entry)
979: {
980: provided_feature_t *provided;
981: enumerator_t *enumerator;
982:
983: enumerator = entry->features->create_enumerator(entry->features);
984: while (enumerator->enumerate(enumerator, &provided))
985: {
986: entry->features->remove_at(entry->features, enumerator);
987: unregister_feature(this, provided);
988: }
989: enumerator->destroy(enumerator);
990: }
991:
992: /**
993: * Remove plugins we were not able to load any plugin features from.
994: */
995: static void purge_plugins(private_plugin_loader_t *this)
996: {
997: enumerator_t *enumerator;
998: plugin_entry_t *entry;
999:
1000: enumerator = this->plugins->create_enumerator(this->plugins);
1001: while (enumerator->enumerate(enumerator, &entry))
1002: {
1003: if (!entry->plugin->get_features)
1004: { /* feature interface not supported */
1005: continue;
1006: }
1007: if (!entry->features->find_first(entry->features, is_feature_loaded,
1008: NULL))
1009: {
1010: DBG2(DBG_LIB, "unloading plugin '%s' without loaded features",
1011: entry->plugin->get_name(entry->plugin));
1012: this->plugins->remove_at(this->plugins, enumerator);
1013: unregister_features(this, entry);
1014: plugin_entry_destroy(entry);
1015: }
1016: }
1017: enumerator->destroy(enumerator);
1018: }
1019:
1020: METHOD(plugin_loader_t, add_static_features, void,
1021: private_plugin_loader_t *this, const char *name,
1022: plugin_feature_t features[], int count, bool critical,
1023: bool (*reload)(void*), void *reload_data)
1024: {
1025: plugin_entry_t *entry;
1026: plugin_t *plugin;
1027:
1028: plugin = static_features_create(name, features, count, reload, reload_data);
1029:
1030: INIT(entry,
1031: .plugin = plugin,
1032: .critical = critical,
1033: .features = linked_list_create(),
1034: );
1035: this->plugins->insert_last(this->plugins, entry);
1036: register_features(this, entry);
1037: }
1038:
1039: /**
1040: * Tries to find the plugin with the given name in the given path.
1041: */
1042: static bool find_plugin(char *path, char *name, char *buf, char **file)
1043: {
1044: struct stat stb;
1045:
1046: if (path && snprintf(buf, PATH_MAX, "%s/libstrongswan-%s.so",
1047: path, name) < PATH_MAX)
1048: {
1049: if (stat(buf, &stb) == 0)
1050: {
1051: *file = buf;
1052: return TRUE;
1053: }
1054: }
1055: return FALSE;
1056: }
1057:
1058: CALLBACK(find_plugin_cb, bool,
1059: char *path, va_list args)
1060: {
1061: char *name, *buf, **file;
1062:
1063: VA_ARGS_VGET(args, name, buf, file);
1064: return find_plugin(path, name, buf, file);
1065: }
1066:
1067: /**
1068: * Used to sort plugins by priority
1069: */
1070: typedef struct {
1071: /* name of the plugin */
1072: char *name;
1073: /* the plugins priority */
1074: int prio;
1075: /* default priority */
1076: int def;
1077: } plugin_priority_t;
1078:
1079: static void plugin_priority_free(const plugin_priority_t *this, int idx,
1080: void *user)
1081: {
1082: free(this->name);
1083: }
1084:
1085: /**
1086: * Sort plugins and their priority by name
1087: */
1088: static int plugin_priority_cmp_name(const plugin_priority_t *a,
1089: const plugin_priority_t *b)
1090: {
1091: return strcmp(a->name, b->name);
1092: }
1093:
1094: /**
1095: * Sort plugins by decreasing priority or default priority then by name
1096: */
1097: static int plugin_priority_cmp(const plugin_priority_t *a,
1098: const plugin_priority_t *b, void *user)
1099: {
1100: int diff;
1101:
1102: diff = b->prio - a->prio;
1103: if (!diff)
1104: { /* the same priority, use default order */
1105: diff = b->def - a->def;
1106: if (!diff)
1107: { /* same default priority (i.e. both were not found in that list) */
1108: return strcmp(a->name, b->name);
1109: }
1110: }
1111: return diff;
1112: }
1113:
1114: CALLBACK(plugin_priority_filter, bool,
1115: void *null, enumerator_t *orig, va_list args)
1116: {
1117: plugin_priority_t *prio;
1118: char **name;
1119:
1120: VA_ARGS_VGET(args, name);
1121:
1122: if (orig->enumerate(orig, &prio))
1123: {
1124: *name = prio->name;
1125: return TRUE;
1126: }
1127: return FALSE;
1128: }
1129:
1130: /**
1131: * Determine the list of plugins to load via load option in each plugin's
1132: * config section.
1133: */
1134: static char *modular_pluginlist(char *list)
1135: {
1136: enumerator_t *enumerator;
1137: array_t *given, *final;
1138: plugin_priority_t item, *current, found;
1139: char *plugin, *plugins = NULL;
1140: int i = 0, max_prio;
1141: bool load_def = FALSE;
1142:
1143: given = array_create(sizeof(plugin_priority_t), 0);
1144: final = array_create(sizeof(plugin_priority_t), 0);
1145:
1146: enumerator = enumerator_create_token(list, " ", " ");
1147: while (enumerator->enumerate(enumerator, &plugin))
1148: {
1149: item.name = strdup(plugin);
1150: item.prio = i++;
1151: array_insert(given, ARRAY_TAIL, &item);
1152: }
1153: enumerator->destroy(enumerator);
1154: array_sort(given, (void*)plugin_priority_cmp_name, NULL);
1155: /* the maximum priority used for plugins not found in this list */
1156: max_prio = i + 1;
1157:
1158: if (lib->settings->get_bool(lib->settings, "%s.load_modular", FALSE,
1159: lib->ns))
1160: {
1161: enumerator = lib->settings->create_section_enumerator(lib->settings,
1162: "%s.plugins", lib->ns);
1163: }
1164: else
1165: {
1166: enumerator = enumerator_create_filter(array_create_enumerator(given),
1167: plugin_priority_filter, NULL, NULL);
1168: load_def = TRUE;
1169: }
1170: while (enumerator->enumerate(enumerator, &plugin))
1171: {
1172: item.prio = lib->settings->get_int(lib->settings,
1173: "%s.plugins.%s.load", 0, lib->ns, plugin);
1174: if (!item.prio)
1175: {
1176: if (!lib->settings->get_bool(lib->settings,
1177: "%s.plugins.%s.load", load_def, lib->ns, plugin))
1178: {
1179: continue;
1180: }
1181: item.prio = 1;
1182: }
1183: item.name = plugin;
1184: item.def = max_prio;
1185: if (array_bsearch(given, &item, (void*)plugin_priority_cmp_name,
1186: &found) != -1)
1187: {
1188: item.def = max_prio - found.prio;
1189: }
1190: array_insert(final, ARRAY_TAIL, &item);
1191: }
1192: enumerator->destroy(enumerator);
1193:
1194: array_sort(final, (void*)plugin_priority_cmp, NULL);
1195:
1196: plugins = strdup("");
1197: enumerator = array_create_enumerator(final);
1198: while (enumerator->enumerate(enumerator, ¤t))
1199: {
1200: char *prev = plugins;
1201: if (asprintf(&plugins, "%s %s", plugins ?: "", current->name) < 0)
1202: {
1203: plugins = prev;
1204: break;
1205: }
1206: free(prev);
1207: }
1208: enumerator->destroy(enumerator);
1209: array_destroy_function(given, (void*)plugin_priority_free, NULL);
1210: array_destroy(final);
1211: return plugins;
1212: }
1213:
1214: METHOD(plugin_loader_t, load_plugins, bool,
1215: private_plugin_loader_t *this, char *list)
1216: {
1217: enumerator_t *enumerator;
1218: char *default_path = NULL, *plugins, *token;
1219: bool critical_failed = FALSE;
1220:
1221: #ifdef PLUGINDIR
1222: default_path = PLUGINDIR;
1223: #endif /* PLUGINDIR */
1224:
1225: plugins = modular_pluginlist(list);
1226:
1227: enumerator = enumerator_create_token(plugins, " ", " ");
1228: while (!critical_failed && enumerator->enumerate(enumerator, &token))
1229: {
1230: plugin_entry_t *entry;
1231: bool critical = FALSE;
1232: char buf[PATH_MAX], *file = NULL;
1233: int len;
1234:
1235: token = strdup(token);
1236: len = strlen(token);
1237: if (token[len-1] == '!')
1238: {
1239: critical = TRUE;
1240: token[len-1] = '\0';
1241: }
1242: if (plugin_loaded(this, token))
1243: {
1244: free(token);
1245: continue;
1246: }
1247: if (this->paths)
1248: {
1249: this->paths->find_first(this->paths, find_plugin_cb, NULL, token,
1250: buf, &file);
1251: }
1252: if (!file)
1253: {
1254: find_plugin(default_path, token, buf, &file);
1255: }
1256: entry = load_plugin(this, token, file, critical);
1257: if (entry)
1258: {
1259: register_features(this, entry);
1260: }
1261: else if (critical)
1262: {
1263: critical_failed = TRUE;
1264: DBG1(DBG_LIB, "loading critical plugin '%s' failed", token);
1265: }
1266: free(token);
1267: }
1268: enumerator->destroy(enumerator);
1269: if (!critical_failed)
1270: {
1271: load_features(this);
1272: if (this->stats.critical > 0)
1273: {
1274: critical_failed = TRUE;
1275: DBG1(DBG_LIB, "failed to load %d critical plugin feature%s",
1276: this->stats.critical, this->stats.critical == 1 ? "" : "s");
1277: }
1278: /* unload plugins that we were not able to load any features for */
1279: purge_plugins(this);
1280: }
1281: if (!critical_failed)
1282: {
1283: free(this->loaded_plugins);
1284: this->loaded_plugins = loaded_plugins_list(this);
1285: }
1286: if (plugins != list)
1287: {
1288: free(plugins);
1289: }
1290: return !critical_failed;
1291: }
1292:
1293: /**
1294: * Unload plugin features, they are registered in reverse order
1295: */
1296: static void unload_features(private_plugin_loader_t *this)
1297: {
1298: enumerator_t *enumerator;
1299: provided_feature_t *provided;
1300: plugin_entry_t *entry;
1301:
1302: enumerator = this->loaded->create_enumerator(this->loaded);
1303: while (enumerator->enumerate(enumerator, &provided))
1304: {
1305: entry = provided->entry;
1306: plugin_feature_unload(entry->plugin, provided->feature, provided->reg);
1307: this->loaded->remove_at(this->loaded, enumerator);
1308: entry->features->remove(entry->features, provided, NULL);
1309: unregister_feature(this, provided);
1310: }
1311: enumerator->destroy(enumerator);
1312: }
1313:
1314: METHOD(plugin_loader_t, unload, void,
1315: private_plugin_loader_t *this)
1316: {
1317: plugin_entry_t *entry;
1318:
1319: /* unload features followed by plugins, in reverse order */
1320: unload_features(this);
1321: while (this->plugins->remove_last(this->plugins, (void**)&entry) == SUCCESS)
1322: {
1323: if (lib->leak_detective)
1324: { /* keep handle to report leaks properly */
1325: entry->handle = NULL;
1326: }
1327: unregister_features(this, entry);
1328: plugin_entry_destroy(entry);
1329: }
1330: free(this->loaded_plugins);
1331: this->loaded_plugins = NULL;
1332: memset(&this->stats, 0, sizeof(this->stats));
1333: }
1334:
1335: METHOD(plugin_loader_t, add_path, void,
1336: private_plugin_loader_t *this, char *path)
1337: {
1338: if (!this->paths)
1339: {
1340: this->paths = linked_list_create();
1341: }
1342: this->paths->insert_last(this->paths, strdupnull(path));
1343: }
1344:
1345: /**
1346: * Reload a plugin by name, NULL for all
1347: */
1348: static u_int reload_by_name(private_plugin_loader_t *this, char *name)
1349: {
1350: u_int reloaded = 0;
1351: enumerator_t *enumerator;
1352: plugin_t *plugin;
1353:
1354: enumerator = create_plugin_enumerator(this);
1355: while (enumerator->enumerate(enumerator, &plugin, NULL))
1356: {
1357: if (name == NULL || streq(name, plugin->get_name(plugin)))
1358: {
1359: if (plugin->reload && plugin->reload(plugin))
1360: {
1361: DBG2(DBG_LIB, "reloaded configuration of '%s' plugin",
1362: plugin->get_name(plugin));
1363: reloaded++;
1364: }
1365: }
1366: }
1367: enumerator->destroy(enumerator);
1368: return reloaded;
1369: }
1370:
1371: METHOD(plugin_loader_t, reload, u_int,
1372: private_plugin_loader_t *this, char *list)
1373: {
1374: u_int reloaded = 0;
1375: enumerator_t *enumerator;
1376: char *name;
1377:
1378: if (list == NULL)
1379: {
1380: return reload_by_name(this, NULL);
1381: }
1382: enumerator = enumerator_create_token(list, " ", "");
1383: while (enumerator->enumerate(enumerator, &name))
1384: {
1385: reloaded += reload_by_name(this, name);
1386: }
1387: enumerator->destroy(enumerator);
1388: return reloaded;
1389: }
1390:
1391: METHOD(plugin_loader_t, loaded_plugins, char*,
1392: private_plugin_loader_t *this)
1393: {
1394: return this->loaded_plugins ?: "";
1395: }
1396:
1397: METHOD(plugin_loader_t, status, void,
1398: private_plugin_loader_t *this, level_t level)
1399: {
1400: if (this->loaded_plugins)
1401: {
1402: dbg(DBG_LIB, level, "loaded plugins: %s", this->loaded_plugins);
1403:
1404: if (this->stats.failed)
1405: {
1406: DBG2(DBG_LIB, "unable to load %d plugin feature%s (%d due to unmet "
1407: "dependencies)", this->stats.failed,
1408: this->stats.failed == 1 ? "" : "s", this->stats.depends);
1409: }
1410: }
1411: }
1412:
1413: METHOD(plugin_loader_t, destroy, void,
1414: private_plugin_loader_t *this)
1415: {
1416: unload(this);
1417: this->features->destroy(this->features);
1418: this->loaded->destroy(this->loaded);
1419: this->plugins->destroy(this->plugins);
1420: DESTROY_FUNCTION_IF(this->paths, free);
1421: free(this->loaded_plugins);
1422: free(this);
1423: }
1424:
1425: /*
1426: * see header file
1427: */
1428: plugin_loader_t *plugin_loader_create()
1429: {
1430: private_plugin_loader_t *this;
1431:
1432: INIT(this,
1433: .public = {
1434: .add_static_features = _add_static_features,
1435: .load = _load_plugins,
1436: .add_path = _add_path,
1437: .reload = _reload,
1438: .unload = _unload,
1439: .create_plugin_enumerator = _create_plugin_enumerator,
1440: .has_feature = _has_feature,
1441: .loaded_plugins = _loaded_plugins,
1442: .status = _status,
1443: .destroy = _destroy,
1444: },
1445: .plugins = linked_list_create(),
1446: .loaded = linked_list_create(),
1447: .features = hashtable_create(
1448: (hashtable_hash_t)registered_feature_hash,
1449: (hashtable_equals_t)registered_feature_equals, 64),
1450: );
1451:
1452: return &this->public;
1453: }
1454:
1455: /*
1456: * See header
1457: */
1458: void plugin_loader_add_plugindirs(char *basedir, char *plugins)
1459: {
1460: enumerator_t *enumerator;
1461: char *name, path[PATH_MAX], dir[64];
1462:
1463: enumerator = enumerator_create_token(plugins, " ", "!");
1464: while (enumerator->enumerate(enumerator, &name))
1465: {
1466: snprintf(dir, sizeof(dir), "%s", name);
1467: translate(dir, "-", "_");
1468: snprintf(path, sizeof(path), "%s/%s/.libs", basedir, dir);
1469: lib->plugins->add_path(lib->plugins, path);
1470: }
1471: enumerator->destroy(enumerator);
1472: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>