Annotation of embedaddon/strongswan/src/libstrongswan/plugins/plugin_loader.c, revision 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>