Annotation of embedaddon/lighttpd/src/plugin.c, revision 1.1.1.2

1.1.1.2 ! misho       1: #include "first.h"
        !             2: 
1.1       misho       3: #include "plugin.h"
                      4: #include "log.h"
                      5: 
                      6: #include <string.h>
                      7: #include <stdlib.h>
                      8: 
                      9: #include <stdio.h>
                     10: 
                     11: #ifdef HAVE_VALGRIND_VALGRIND_H
                     12: # include <valgrind/valgrind.h>
                     13: #endif
                     14: 
1.1.1.2 ! misho      15: #if !defined(__WIN32) && !defined(LIGHTTPD_STATIC)
1.1       misho      16: # include <dlfcn.h>
                     17: #endif
                     18: /*
                     19:  *
                     20:  * if you change this enum to add a new callback, be sure
                     21:  * - that PLUGIN_FUNC_SIZEOF is the last entry
                     22:  * - that you add PLUGIN_TO_SLOT twice:
                     23:  *   1. as callback-dispatcher
                     24:  *   2. in plugins_call_init()
                     25:  *
                     26:  */
                     27: 
                     28: typedef struct {
                     29:        PLUGIN_DATA;
                     30: } plugin_data;
                     31: 
                     32: typedef enum {
                     33:        PLUGIN_FUNC_UNSET,
                     34: 
1.1.1.2 ! misho      35:        PLUGIN_FUNC_HANDLE_URI_CLEAN,
        !            36:        PLUGIN_FUNC_HANDLE_URI_RAW,
        !            37:        PLUGIN_FUNC_HANDLE_REQUEST_DONE,
        !            38:        PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE,
        !            39:        PLUGIN_FUNC_HANDLE_TRIGGER,
        !            40:        PLUGIN_FUNC_HANDLE_SIGHUP,
        !            41:        PLUGIN_FUNC_HANDLE_SUBREQUEST,
        !            42:        PLUGIN_FUNC_HANDLE_SUBREQUEST_START,
        !            43:        PLUGIN_FUNC_HANDLE_DOCROOT,
        !            44:        PLUGIN_FUNC_HANDLE_PHYSICAL,
        !            45:        PLUGIN_FUNC_CONNECTION_RESET,
        !            46:        PLUGIN_FUNC_INIT,
        !            47:        PLUGIN_FUNC_CLEANUP,
        !            48:        PLUGIN_FUNC_SET_DEFAULTS,
        !            49: 
        !            50:        PLUGIN_FUNC_SIZEOF
1.1       misho      51: } plugin_t;
                     52: 
                     53: static plugin *plugin_init(void) {
                     54:        plugin *p;
                     55: 
                     56:        p = calloc(1, sizeof(*p));
1.1.1.2 ! misho      57:        force_assert(NULL != p);
1.1       misho      58: 
                     59:        return p;
                     60: }
                     61: 
                     62: static void plugin_free(plugin *p) {
1.1.1.2 ! misho      63: #if !defined(LIGHTTPD_STATIC)
1.1       misho      64:        int use_dlclose = 1;
1.1.1.2 ! misho      65: #endif
        !            66: 
1.1       misho      67:        if (p->name) buffer_free(p->name);
1.1.1.2 ! misho      68: #if defined(HAVE_VALGRIND_VALGRIND_H) && !defined(LIGHTTPD_STATIC)
1.1       misho      69:        /*if (RUNNING_ON_VALGRIND) use_dlclose = 0;*/
                     70: #endif
                     71: 
1.1.1.2 ! misho      72: #if !defined(LIGHTTPD_STATIC)
1.1       misho      73:        if (use_dlclose && p->lib) {
1.1.1.2 ! misho      74: #if defined(__WIN32)
        !            75: )              FreeLibrary(p->lib);
1.1       misho      76: #else
                     77:                dlclose(p->lib);
                     78: #endif
                     79:        }
                     80: #endif
                     81: 
                     82:        free(p);
                     83: }
                     84: 
                     85: static int plugins_register(server *srv, plugin *p) {
                     86:        plugin **ps;
                     87:        if (0 == srv->plugins.size) {
                     88:                srv->plugins.size = 4;
                     89:                srv->plugins.ptr  = malloc(srv->plugins.size * sizeof(*ps));
1.1.1.2 ! misho      90:                force_assert(NULL != srv->plugins.ptr);
1.1       misho      91:                srv->plugins.used = 0;
                     92:        } else if (srv->plugins.used == srv->plugins.size) {
                     93:                srv->plugins.size += 4;
                     94:                srv->plugins.ptr   = realloc(srv->plugins.ptr, srv->plugins.size * sizeof(*ps));
1.1.1.2 ! misho      95:                force_assert(NULL != srv->plugins.ptr);
1.1       misho      96:        }
                     97: 
                     98:        ps = srv->plugins.ptr;
                     99:        ps[srv->plugins.used++] = p;
                    100: 
                    101:        return 0;
                    102: }
                    103: 
                    104: /**
                    105:  *
                    106:  *
                    107:  *
                    108:  */
                    109: 
1.1.1.2 ! misho     110: #if defined(LIGHTTPD_STATIC)
        !           111: 
        !           112: /* pre-declare functions, as there is no header for them */
1.1       misho     113: #define PLUGIN_INIT(x)\
1.1.1.2 ! misho     114:        int x ## _plugin_init(plugin *p);
        !           115: 
        !           116: #include "plugin-static.h"
        !           117: 
        !           118: #undef PLUGIN_INIT
        !           119: 
        !           120: /* build NULL-terminated table of name + init-function */
        !           121: 
        !           122: typedef struct {
        !           123:        const char* name;
        !           124:        int (*plugin_init)(plugin *p);
        !           125: } plugin_load_functions;
        !           126: 
        !           127: static const plugin_load_functions load_functions[] = {
        !           128: #define PLUGIN_INIT(x) \
        !           129:        { #x, &x ## _plugin_init },
1.1       misho     130: 
                    131: #include "plugin-static.h"
                    132: 
1.1.1.2 ! misho     133:        { NULL, NULL }
        !           134: #undef PLUGIN_INIT
        !           135: };
        !           136: 
        !           137: int plugins_load(server *srv) {
        !           138:        plugin *p;
        !           139:        size_t i, j;
        !           140: 
        !           141:        for (i = 0; i < srv->srvconf.modules->used; i++) {
        !           142:                data_string *d = (data_string *)srv->srvconf.modules->data[i];
        !           143:                char *module = d->value->ptr;
        !           144: 
        !           145:                for (j = 0; j < i; j++) {
        !           146:                        if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
        !           147:                                log_error_write(srv, __FILE__, __LINE__, "sbs",
        !           148:                                        "Cannot load plugin", d->value,
        !           149:                                        "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
        !           150:                                continue;
        !           151:                        }
        !           152:                }
        !           153: 
        !           154:                for (j = 0; load_functions[j].name; ++j) {
        !           155:                        if (0 == strcmp(load_functions[j].name, module)) {
        !           156:                                p = plugin_init();
        !           157:                                if ((*load_functions[j].plugin_init)(p)) {
        !           158:                                        log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
        !           159:                                        plugin_free(p);
        !           160:                                        return -1;
        !           161:                                }
        !           162:                                plugins_register(srv, p);
        !           163:                                break;
        !           164:                        }
        !           165:                }
        !           166:                if (!load_functions[j].name) {
        !           167:                        log_error_write(srv, __FILE__, __LINE__, "ss", module, " plugin not found" );
        !           168:                        return -1;
        !           169:                }
        !           170:        }
        !           171: 
1.1       misho     172:        return 0;
                    173: }
1.1.1.2 ! misho     174: #else /* defined(LIGHTTPD_STATIC) */
1.1       misho     175: int plugins_load(server *srv) {
                    176:        plugin *p;
                    177:        int (*init)(plugin *pl);
                    178:        size_t i, j;
                    179: 
                    180:        for (i = 0; i < srv->srvconf.modules->used; i++) {
                    181:                data_string *d = (data_string *)srv->srvconf.modules->data[i];
1.1.1.2 ! misho     182:                char *module = d->value->ptr;
1.1       misho     183: 
                    184:                for (j = 0; j < i; j++) {
                    185:                        if (buffer_is_equal(d->value, ((data_string *) srv->srvconf.modules->data[j])->value)) {
1.1.1.2 ! misho     186:                                log_error_write(srv, __FILE__, __LINE__, "sbs",
        !           187:                                        "Cannot load plugin", d->value,
        !           188:                                        "more than once, please fix your config (lighttpd may not accept such configs in future releases)");
1.1       misho     189:                                continue;
                    190:                        }
                    191:                }
                    192: 
1.1.1.2 ! misho     193:                buffer_copy_buffer(srv->tmp_buf, srv->srvconf.modules_dir);
1.1       misho     194: 
                    195:                buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("/"));
1.1.1.2 ! misho     196:                buffer_append_string(srv->tmp_buf, module);
1.1       misho     197: #if defined(__WIN32) || defined(__CYGWIN__)
                    198:                buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".dll"));
                    199: #else
                    200:                buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN(".so"));
                    201: #endif
                    202: 
                    203:                p = plugin_init();
                    204: #ifdef __WIN32
                    205:                if (NULL == (p->lib = LoadLibrary(srv->tmp_buf->ptr))) {
                    206:                        LPVOID lpMsgBuf;
                    207:                        FormatMessage(
1.1.1.2 ! misho     208:                                FORMAT_MESSAGE_ALLOCATE_BUFFER |
        !           209:                                        FORMAT_MESSAGE_FROM_SYSTEM,
        !           210:                                NULL,
        !           211:                                GetLastError(),
        !           212:                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        !           213:                                (LPTSTR) &lpMsgBuf,
        !           214:                                0, NULL);
1.1       misho     215: 
                    216:                        log_error_write(srv, __FILE__, __LINE__, "ssb", "LoadLibrary() failed",
1.1.1.2 ! misho     217:                                lpMsgBuf, srv->tmp_buf);
1.1       misho     218: 
                    219:                        plugin_free(p);
                    220: 
                    221:                        return -1;
                    222: 
                    223:                }
                    224: #else
                    225:                if (NULL == (p->lib = dlopen(srv->tmp_buf->ptr, RTLD_NOW|RTLD_GLOBAL))) {
                    226:                        log_error_write(srv, __FILE__, __LINE__, "sbs", "dlopen() failed for:",
1.1.1.2 ! misho     227:                                srv->tmp_buf, dlerror());
1.1       misho     228: 
                    229:                        plugin_free(p);
                    230: 
                    231:                        return -1;
                    232:                }
                    233: 
                    234: #endif
                    235:                buffer_reset(srv->tmp_buf);
1.1.1.2 ! misho     236:                buffer_copy_string(srv->tmp_buf, module);
1.1       misho     237:                buffer_append_string_len(srv->tmp_buf, CONST_STR_LEN("_plugin_init"));
                    238: 
                    239: #ifdef __WIN32
                    240:                init = GetProcAddress(p->lib, srv->tmp_buf->ptr);
                    241: 
1.1.1.2 ! misho     242:                if (init == NULL) {
1.1       misho     243:                        LPVOID lpMsgBuf;
                    244:                        FormatMessage(
1.1.1.2 ! misho     245:                                FORMAT_MESSAGE_ALLOCATE_BUFFER |
        !           246:                                        FORMAT_MESSAGE_FROM_SYSTEM,
        !           247:                                NULL,
        !           248:                                GetLastError(),
        !           249:                                MAKELANGID(LANG_NEUTRAL, SUBLANG_DEFAULT),
        !           250:                                (LPTSTR) &lpMsgBuf,
        !           251:                                0, NULL);
1.1       misho     252: 
                    253:                        log_error_write(srv, __FILE__, __LINE__, "sbs", "getprocaddress failed:", srv->tmp_buf, lpMsgBuf);
                    254: 
                    255:                        plugin_free(p);
                    256:                        return -1;
                    257:                }
                    258: 
                    259: #else
                    260: #if 1
                    261:                init = (int (*)(plugin *))(intptr_t)dlsym(p->lib, srv->tmp_buf->ptr);
                    262: #else
                    263:                *(void **)(&init) = dlsym(p->lib, srv->tmp_buf->ptr);
                    264: #endif
1.1.1.2 ! misho     265:                if (NULL == init) {
        !           266:                        const char *error = dlerror();
        !           267:                        if (error != NULL) {
        !           268:                                log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym:", error);
        !           269:                        } else {
        !           270:                                log_error_write(srv, __FILE__, __LINE__, "ss", "dlsym symbol not found:", srv->tmp_buf->ptr);
        !           271:                        }
1.1       misho     272: 
                    273:                        plugin_free(p);
                    274:                        return -1;
                    275:                }
                    276: 
                    277: #endif
                    278:                if ((*init)(p)) {
1.1.1.2 ! misho     279:                        log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin init failed" );
1.1       misho     280: 
                    281:                        plugin_free(p);
                    282:                        return -1;
                    283:                }
                    284: #if 0
1.1.1.2 ! misho     285:                log_error_write(srv, __FILE__, __LINE__, "ss", module, "plugin loaded" );
1.1       misho     286: #endif
                    287:                plugins_register(srv, p);
                    288:        }
                    289: 
                    290:        return 0;
                    291: }
1.1.1.2 ! misho     292: #endif /* defined(LIGHTTPD_STATIC) */
1.1       misho     293: 
                    294: #define PLUGIN_TO_SLOT(x, y) \
                    295:        handler_t plugins_call_##y(server *srv, connection *con) {\
                    296:                plugin **slot;\
                    297:                size_t j;\
1.1.1.2 ! misho     298:                if (!srv->plugin_slots) return HANDLER_GO_ON;\
        !           299:                slot = ((plugin ***)(srv->plugin_slots))[x];\
1.1       misho     300:                if (!slot) return HANDLER_GO_ON;\
                    301:                for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
                    302:                        plugin *p = slot[j];\
                    303:                        handler_t r;\
                    304:                        switch(r = p->y(srv, con, p->data)) {\
                    305:                        case HANDLER_GO_ON:\
                    306:                                break;\
                    307:                        case HANDLER_FINISHED:\
                    308:                        case HANDLER_COMEBACK:\
                    309:                        case HANDLER_WAIT_FOR_EVENT:\
                    310:                        case HANDLER_WAIT_FOR_FD:\
                    311:                        case HANDLER_ERROR:\
                    312:                                return r;\
                    313:                        default:\
                    314:                                log_error_write(srv, __FILE__, __LINE__, "sbs", #x, p->name, "unknown state");\
                    315:                                return HANDLER_ERROR;\
                    316:                        }\
                    317:                }\
                    318:                return HANDLER_GO_ON;\
                    319:        }
                    320: 
                    321: /**
                    322:  * plugins that use
                    323:  *
                    324:  * - server *srv
                    325:  * - connection *con
                    326:  * - void *p_d (plugin_data *)
                    327:  */
                    328: 
                    329: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean)
                    330: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw)
                    331: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done)
                    332: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close)
                    333: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest)
                    334: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start)
                    335: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot)
                    336: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical)
                    337: PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset)
                    338: 
                    339: #undef PLUGIN_TO_SLOT
                    340: 
                    341: #define PLUGIN_TO_SLOT(x, y) \
                    342:        handler_t plugins_call_##y(server *srv) {\
                    343:                plugin **slot;\
                    344:                size_t j;\
1.1.1.2 ! misho     345:                if (!srv->plugin_slots) return HANDLER_GO_ON;\
        !           346:                slot = ((plugin ***)(srv->plugin_slots))[x];\
1.1       misho     347:                if (!slot) return HANDLER_GO_ON;\
                    348:                for (j = 0; j < srv->plugins.used && slot[j]; j++) { \
                    349:                        plugin *p = slot[j];\
                    350:                        handler_t r;\
                    351:                        switch(r = p->y(srv, p->data)) {\
                    352:                        case HANDLER_GO_ON:\
                    353:                                break;\
                    354:                        case HANDLER_FINISHED:\
                    355:                        case HANDLER_COMEBACK:\
                    356:                        case HANDLER_WAIT_FOR_EVENT:\
                    357:                        case HANDLER_WAIT_FOR_FD:\
                    358:                        case HANDLER_ERROR:\
                    359:                                return r;\
                    360:                        default:\
                    361:                                log_error_write(srv, __FILE__, __LINE__, "sbsd", #x, p->name, "unknown state:", r);\
                    362:                                return HANDLER_ERROR;\
                    363:                        }\
                    364:                }\
                    365:                return HANDLER_GO_ON;\
                    366:        }
                    367: 
                    368: /**
                    369:  * plugins that use
                    370:  *
                    371:  * - server *srv
                    372:  * - void *p_d (plugin_data *)
                    373:  */
                    374: 
                    375: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger)
                    376: PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup)
                    377: PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup)
                    378: PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults)
                    379: 
                    380: #undef PLUGIN_TO_SLOT
                    381: 
                    382: #if 0
                    383: /**
                    384:  *
                    385:  * special handler
                    386:  *
                    387:  */
                    388: handler_t plugins_call_handle_fdevent(server *srv, const fd_conn *fdc) {
                    389:        size_t i;
                    390:        plugin **ps;
                    391: 
                    392:        ps = srv->plugins.ptr;
                    393: 
                    394:        for (i = 0; i < srv->plugins.used; i++) {
                    395:                plugin *p = ps[i];
                    396:                if (p->handle_fdevent) {
                    397:                        handler_t r;
                    398:                        switch(r = p->handle_fdevent(srv, fdc, p->data)) {
                    399:                        case HANDLER_GO_ON:
                    400:                                break;
                    401:                        case HANDLER_FINISHED:
                    402:                        case HANDLER_COMEBACK:
                    403:                        case HANDLER_WAIT_FOR_EVENT:
                    404:                        case HANDLER_ERROR:
                    405:                                return r;
                    406:                        default:
                    407:                                log_error_write(srv, __FILE__, __LINE__, "d", r);
                    408:                                break;
                    409:                        }
                    410:                }
                    411:        }
                    412: 
                    413:        return HANDLER_GO_ON;
                    414: }
                    415: #endif
                    416: /**
                    417:  *
                    418:  * - call init function of all plugins to init the plugin-internals
                    419:  * - added each plugin that supports has callback to the corresponding slot
                    420:  *
                    421:  * - is only called once.
                    422:  */
                    423: 
                    424: handler_t plugins_call_init(server *srv) {
                    425:        size_t i;
                    426:        plugin **ps;
                    427: 
                    428:        ps = srv->plugins.ptr;
                    429: 
                    430:        /* fill slots */
                    431: 
                    432:        srv->plugin_slots = calloc(PLUGIN_FUNC_SIZEOF, sizeof(ps));
1.1.1.2 ! misho     433:        force_assert(NULL != srv->plugin_slots);
1.1       misho     434: 
                    435:        for (i = 0; i < srv->plugins.used; i++) {
                    436:                size_t j;
                    437:                /* check which calls are supported */
                    438: 
                    439:                plugin *p = ps[i];
                    440: 
                    441: #define PLUGIN_TO_SLOT(x, y) \
                    442:        if (p->y) { \
                    443:                plugin **slot = ((plugin ***)(srv->plugin_slots))[x]; \
                    444:                if (!slot) { \
                    445:                        slot = calloc(srv->plugins.used, sizeof(*slot));\
1.1.1.2 ! misho     446:                        force_assert(NULL != slot); \
1.1       misho     447:                        ((plugin ***)(srv->plugin_slots))[x] = slot; \
                    448:                } \
                    449:                for (j = 0; j < srv->plugins.used; j++) { \
                    450:                        if (slot[j]) continue;\
                    451:                        slot[j] = p;\
                    452:                        break;\
                    453:                }\
                    454:        }
                    455: 
                    456: 
                    457:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_CLEAN, handle_uri_clean);
                    458:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_URI_RAW, handle_uri_raw);
                    459:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_REQUEST_DONE, handle_request_done);
                    460:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_CONNECTION_CLOSE, handle_connection_close);
                    461:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_TRIGGER, handle_trigger);
                    462:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SIGHUP, handle_sighup);
                    463:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST, handle_subrequest);
                    464:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_SUBREQUEST_START, handle_subrequest_start);
                    465:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_DOCROOT, handle_docroot);
                    466:                PLUGIN_TO_SLOT(PLUGIN_FUNC_HANDLE_PHYSICAL, handle_physical);
                    467:                PLUGIN_TO_SLOT(PLUGIN_FUNC_CONNECTION_RESET, connection_reset);
                    468:                PLUGIN_TO_SLOT(PLUGIN_FUNC_CLEANUP, cleanup);
                    469:                PLUGIN_TO_SLOT(PLUGIN_FUNC_SET_DEFAULTS, set_defaults);
                    470: #undef PLUGIN_TO_SLOT
                    471: 
                    472:                if (p->init) {
                    473:                        if (NULL == (p->data = p->init())) {
                    474:                                log_error_write(srv, __FILE__, __LINE__, "sb",
                    475:                                                "plugin-init failed for module", p->name);
                    476:                                return HANDLER_ERROR;
                    477:                        }
                    478: 
                    479:                        /* used for con->mode, DIRECT == 0, plugins above that */
                    480:                        ((plugin_data *)(p->data))->id = i + 1;
                    481: 
                    482:                        if (p->version != LIGHTTPD_VERSION_ID) {
                    483:                                log_error_write(srv, __FILE__, __LINE__, "sb",
                    484:                                                "plugin-version doesn't match lighttpd-version for", p->name);
                    485:                                return HANDLER_ERROR;
                    486:                        }
                    487:                } else {
                    488:                        p->data = NULL;
                    489:                }
                    490:        }
                    491: 
                    492:        return HANDLER_GO_ON;
                    493: }
                    494: 
                    495: void plugins_free(server *srv) {
                    496:        size_t i;
                    497:        plugins_call_cleanup(srv);
                    498: 
                    499:        for (i = 0; i < srv->plugins.used; i++) {
                    500:                plugin *p = ((plugin **)srv->plugins.ptr)[i];
                    501: 
                    502:                plugin_free(p);
                    503:        }
                    504: 
                    505:        for (i = 0; srv->plugin_slots && i < PLUGIN_FUNC_SIZEOF; i++) {
                    506:                plugin **slot = ((plugin ***)(srv->plugin_slots))[i];
                    507: 
                    508:                if (slot) free(slot);
                    509:        }
                    510: 
                    511:        free(srv->plugin_slots);
                    512:        srv->plugin_slots = NULL;
                    513: 
                    514:        free(srv->plugins.ptr);
                    515:        srv->plugins.ptr = NULL;
                    516:        srv->plugins.used = 0;
                    517: }

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>