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