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