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, &current))
                    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, &current))
                   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>