2 * Copyright (c) 2012, Intel Corporation
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions are
8 * * Redistributions of source code must retain the above copyright notice,
9 * this list of conditions and the following disclaimer.
10 * * Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * * Neither the name of Intel Corporation nor the names of its contributors
14 * may be used to endorse or promote products derived from this software
15 * without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #include <sys/types.h>
37 #include <murphy/common/list.h>
38 #include <murphy/common/file-utils.h>
39 #include <murphy/core/plugin.h>
41 #define PLUGIN_PREFIX "plugin-"
45 #define __PARANOID_BLACKLIST_CHECK__
47 static mrp_plugin_descr_t *open_builtin(mrp_context_t *ctx, const char *name);
48 static mrp_plugin_descr_t *open_dynamic(mrp_context_t *ctx, const char *name,
50 static mrp_plugin_t *find_plugin(mrp_context_t *ctx, char *name);
51 static mrp_plugin_t *find_plugin_instance(mrp_context_t *ctx,
52 const char *instance);
53 static int parse_plugin_args(mrp_plugin_t *plugin,
54 mrp_plugin_arg_t *argv, int argc);
56 static int export_plugin_methods(mrp_plugin_t *plugin);
57 static int remove_plugin_methods(mrp_plugin_t *plugin);
58 static int import_plugin_methods(mrp_plugin_t *plugin);
59 static int release_plugin_methods(mrp_plugin_t *plugin);
63 * list of built-in in plugins
65 * Descriptors of built-in plugins, ie. plugins that are linked to
66 * the daemon, get collected to this list during startup.
69 static MRP_LIST_HOOK(builtin_plugins);
73 * plugin-related events
77 PLUGIN_EVENT_LOADED = 0, /* plugin has been loaded */
78 PLUGIN_EVENT_STARTED, /* plugin has been started */
79 PLUGIN_EVENT_FAILED, /* plugin failed to start */
80 PLUGIN_EVENT_STOPPING, /* plugin being stopped */
81 PLUGIN_EVENT_STOPPED, /* plugin has been stopped */
82 PLUGIN_EVENT_UNLOADED, /* plugin has been unloaded */
87 MRP_REGISTER_EVENTS(plugin_events,
88 MRP_EVENT(MRP_PLUGIN_EVENT_LOADED , PLUGIN_EVENT_LOADED ),
89 MRP_EVENT(MRP_PLUGIN_EVENT_STARTED , PLUGIN_EVENT_STARTED ),
90 MRP_EVENT(MRP_PLUGIN_EVENT_FAILED , PLUGIN_EVENT_FAILED ),
91 MRP_EVENT(MRP_PLUGIN_EVENT_STOPPING, PLUGIN_EVENT_STOPPING),
92 MRP_EVENT(MRP_PLUGIN_EVENT_STOPPED , PLUGIN_EVENT_STOPPED ),
93 MRP_EVENT(MRP_PLUGIN_EVENT_UNLOADED, PLUGIN_EVENT_UNLOADED));
96 static inline int is_listed(const char *list, const char *name)
98 const char *b, *n, *e;
100 if (list == NULL || name == NULL)
103 if ((list[0] == '*' && list[1] == '\0') || (!strcmp(list, "all")))
108 while (*b == ' ' || *b == '\t' || *b == ',')
111 if ((e = n = strchr(b, ',')) != NULL) {
112 while (e > b && (*e == ' ' || *e == '\t' || *e == ','))
116 if ((e != NULL && e > b && !strncmp(b, name, e - b)) ||
117 (e == NULL && !strcmp (b, name)))
120 if ((b[0] == '*' && (b[1] == ',' ||
121 b[1] == ' ' || b[1] == '\t' ||
123 (b[0] == 'a' && b[1] == 'l' && b[2] == 'l' &&
125 b[1] == ' ' || b[1] == '\t' ||
127 mrp_log_warning("Wildcard entry in blacklist/whitelist '%s'", list);
131 b = n ? n + 1 : NULL;
138 static inline int is_blacklisted(mrp_context_t *ctx, const char *name,
141 #define IS_WILDCARD(l) \
142 (((l) != NULL && (l)[0] == '*' && (l)[1] == '\0') || \
143 ((l) != NULL && !strcmp((l), "all")))
145 const char *bl, *wl, *type_bl, *type_wl;
146 int b, w, tb, tw, blacklist;
148 mrp_debug("checking if %s plugin %s is blacklisted",
149 builtin ? "builtin" : "dynamic", name);
151 bl = ctx->blacklist_plugins;
152 wl = ctx->whitelist_plugins;
153 b = is_listed(bl, name);
154 w = is_listed(wl, name);
157 type_bl = ctx->blacklist_builtin;
158 type_wl = ctx->whitelist_builtin;
161 type_bl = ctx->blacklist_dynamic;
162 type_wl = ctx->whitelist_dynamic;
165 tb = is_listed(type_bl, name);
166 tw = is_listed(type_wl, name);
168 mrp_debug("%s: b:(%s,%s), w:(%s,%s)", name,
169 b ? "true" : "false", tb ? "true" : "false",
170 w ? "true" : "false", tw ? "true" : "false");
172 if (IS_WILDCARD(bl) || IS_WILDCARD(type_bl)) {
181 if (IS_WILDCARD(wl) || IS_WILDCARD(type_wl)) {
190 blacklist = (( is_listed(bl, name) || is_listed(type_bl, name)) &&
191 !(is_listed(wl, name) || is_listed(type_wl, name)));
195 mrp_debug("%s: %sblacklisted", name, blacklist ? "" : "not ");
201 static int emit_plugin_event(int idx, mrp_plugin_t *plugin)
203 mrp_context_t *ctx = plugin->ctx;
204 mrp_mainloop_t *ml = ctx->ml;
205 uint16_t name = MRP_PLUGIN_TAG_PLUGIN;
206 uint16_t inst = MRP_PLUGIN_TAG_INSTANCE;
207 int flags = MRP_EVENT_SYNCHRONOUS;
209 if (ctx->plugin_bus == NULL)
210 ctx->plugin_bus = mrp_event_bus_get(ml, MRP_PLUGIN_BUS);
212 if (mrp_event_emit_msg(ctx->plugin_bus, plugin_events[idx].id, flags,
213 MRP_MSG_TAG_STRING(name, plugin->descriptor->name),
214 MRP_MSG_TAG_STRING(inst, plugin->instance)) < 0)
221 int mrp_register_builtin_plugin(mrp_plugin_descr_t *descriptor)
223 mrp_plugin_t *plugin;
225 if (descriptor->name && descriptor->init && descriptor->exit) {
226 if ((plugin = mrp_allocz(sizeof(*plugin))) != NULL) {
227 plugin->descriptor = descriptor;
228 mrp_list_append(&builtin_plugins, &plugin->hook);
236 mrp_log_error("Ignoring static plugin '%s' with an invalid or "
237 "incomplete plugin descriptor.", descriptor->path);
243 void mrp_block_blacklisted_plugins(mrp_context_t *ctx)
245 mrp_list_hook_t *p, *n;
246 mrp_plugin_t *builtin;
248 mrp_list_foreach(&builtin_plugins, p, n) {
249 builtin = mrp_list_entry(p, typeof(*builtin), hook);
251 if (is_blacklisted(ctx, builtin->descriptor->name, BUILTIN)) {
252 mrp_log_info("Unlinking blacklisted builtin plugin %s",
253 builtin->descriptor->name);
254 mrp_list_delete(&builtin->hook);
260 int mrp_plugin_exists(mrp_context_t *ctx, const char *name)
265 if (open_builtin(ctx, name))
268 if (is_blacklisted(ctx, name, DYNAMIC))
271 snprintf(path, sizeof(path), "%s/%s%s.so", ctx->plugin_dir,
272 PLUGIN_PREFIX, name);
273 if (stat(path, &st) == 0)
281 int mrp_plugin_loaded(mrp_context_t *ctx, const char *name)
283 mrp_list_hook_t *p, *n;
284 mrp_plugin_t *plugin;
286 mrp_list_foreach(&ctx->plugins, p, n) {
287 plugin = mrp_list_entry(p, typeof(*plugin), hook);
289 if (!strcmp(plugin->instance, name))
297 int mrp_plugin_running(mrp_context_t *ctx, const char *name)
299 mrp_list_hook_t *p, *n;
300 mrp_plugin_t *plugin;
302 mrp_list_foreach(&ctx->plugins, p, n) {
303 plugin = mrp_list_entry(p, typeof(*plugin), hook);
305 if (!strcmp(plugin->instance, name))
306 return (plugin->state == MRP_PLUGIN_RUNNING);
313 static inline int check_plugin_version(mrp_plugin_descr_t *descr)
317 major = MRP_VERSION_MAJOR(descr->mrp_version);
318 minor = MRP_VERSION_MINOR(descr->mrp_version);
320 if (major != MRP_PLUGIN_API_MAJOR || minor > MRP_PLUGIN_API_MINOR) {
321 mrp_log_error("Plugin '%s' uses incompatible version (%d.%d vs. %d.%d)",
322 descr->name, major, minor,
323 MRP_PLUGIN_API_MAJOR, MRP_PLUGIN_API_MINOR);
331 static inline int check_plugin_singleton(mrp_plugin_descr_t *descr)
333 if (descr->singleton && descr->ninstance > 1) {
334 mrp_log_error("Singleton plugin '%s' has already been instantiated.",
343 mrp_plugin_t *mrp_load_plugin(mrp_context_t *ctx, const char *name,
344 const char *instance, mrp_plugin_arg_t *args,
347 mrp_plugin_t *plugin;
349 mrp_plugin_descr_t *dynamic, *builtin, *descr;
351 mrp_console_group_t *cmds;
352 char grpbuf[PATH_MAX], *cmdgrp;
357 if (instance == NULL)
360 if (ctx->state == MRP_STATE_RUNNING && ctx->disable_runtime_load) {
361 mrp_log_error("Post-startup plugin loading has been disabled.");
365 if (find_plugin_instance(ctx, instance) != NULL) {
366 mrp_log_error("Plugin '%s' has already been loaded.", instance);
372 snprintf(path, sizeof(path), "%s/%s%s.so", ctx->plugin_dir,
373 PLUGIN_PREFIX, name);
375 dynamic = open_dynamic(ctx, name, &handle);
376 builtin = open_builtin(ctx, name);
378 if (dynamic != NULL) {
380 mrp_log_warning("Dynamic plugin '%s' shadows builtin plugin '%s'.",
381 path, builtin->path);
385 if (builtin == NULL) {
386 mrp_log_error("Could not find plugin '%s' to load '%s'.", name,
395 if (!check_plugin_version(descr) || !check_plugin_singleton(descr))
398 if ((plugin = mrp_allocz(sizeof(*plugin))) != NULL) {
399 mrp_list_init(&plugin->hook);
401 plugin->instance = mrp_strdup(instance);
402 plugin->path = mrp_strdup(handle ? path : descr->path);
404 if (plugin->instance == NULL || plugin->path == NULL) {
405 mrp_log_error("Failed to allocate plugin '%s'.", name);
409 if (descr->cmds != NULL) {
410 plugin->cmds = cmds = mrp_allocz(sizeof(*plugin->cmds));
413 mrp_list_init(&cmds->hook);
415 if (instance != name) {
416 snprintf(grpbuf, sizeof(grpbuf), "%s-%s", name, instance);
420 cmdgrp = (char *)name;
422 cmds->name = mrp_strdup(cmdgrp);
424 if (cmds->name == NULL) {
425 mrp_log_error("Failed to allocate plugin commands.");
429 cmds->commands = descr->cmds->commands;
430 cmds->ncommand = descr->cmds->ncommand;
432 if (MRP_UNLIKELY(descr->cmds->user_data != NULL))
433 cmds->user_data = descr->cmds->user_data;
435 cmds->user_data = plugin;
438 mrp_log_error("Failed to allocate plugin commands.");
445 plugin->descriptor = descr;
446 plugin->handle = handle;
448 mrp_refcnt_init(&plugin->refcnt);
450 if (!parse_plugin_args(plugin, args, narg))
453 if (plugin->cmds != NULL)
454 mrp_console_add_group(plugin->ctx, plugin->cmds);
456 if (!export_plugin_methods(plugin))
459 mrp_list_append(&ctx->plugins, &plugin->hook);
461 emit_plugin_event(PLUGIN_EVENT_LOADED, plugin);
463 if (ctx->state == MRP_STATE_STARTING || ctx->state == MRP_STATE_RUNNING)
464 mrp_start_plugin(plugin);
469 mrp_log_error("Could not allocate plugin '%s'.", name);
471 mrp_unload_plugin(plugin);
478 static int load_plugin_cb(const char *file, mrp_dirent_type_t type, void *data)
480 mrp_context_t *ctx = (mrp_context_t *)data;
481 char name[PATH_MAX], *start, *end;
486 if ((start = strstr(file, PLUGIN_PREFIX)) != NULL) {
487 start += sizeof(PLUGIN_PREFIX) - 1;
488 if ((end = strstr(start, ".so")) != NULL) {
490 strncpy(name, start, len);
492 mrp_load_plugin(ctx, name, NULL, NULL, 0);
500 int mrp_load_all_plugins(mrp_context_t *ctx)
502 mrp_dirent_type_t type;
504 mrp_list_hook_t *p, *n;
505 mrp_plugin_t *plugin;
507 type = MRP_DIRENT_REG;
508 pattern = PLUGIN_PREFIX".*\\.so$";
509 mrp_scan_dir(ctx->plugin_dir, pattern, type, load_plugin_cb, ctx);
511 mrp_list_foreach(&builtin_plugins, p, n) {
512 plugin = mrp_list_entry(p, typeof(*plugin), hook);
514 mrp_load_plugin(ctx, plugin->descriptor->name, NULL, NULL, 0);
521 int mrp_request_plugin(mrp_context_t *ctx, const char *name,
522 const char *instance)
524 mrp_plugin_t *plugin;
526 if (instance == NULL)
529 if ((plugin = find_plugin_instance(ctx, instance)) != NULL) {
530 if (instance == name || !strcmp(plugin->descriptor->name, name))
534 return (mrp_load_plugin(ctx, name, instance, NULL, 0) != NULL);
538 int mrp_unload_plugin(mrp_plugin_t *plugin)
540 mrp_plugin_arg_t *pa, *da, *ra;
543 if (plugin != NULL) {
544 if (plugin->refcnt == 0) {
545 mrp_list_delete(&plugin->hook);
548 da = plugin->descriptor->args;
551 for (i = 0; i < plugin->descriptor->narg; i++) {
553 case MRP_PLUGIN_ARG_TYPE_STRING:
554 if (pa->str != da->str)
558 case MRP_PLUGIN_ARG_TYPE_OBJECT:
559 mrp_json_unref(pa->obj.json);
562 case MRP_PLUGIN_ARG_TYPE_UNDECL:
564 for (j = 0; j < pa->rest.narg; j++) {
567 case MRP_PLUGIN_ARG_TYPE_STRING:
570 case MRP_PLUGIN_ARG_TYPE_OBJECT:
571 mrp_json_unref(ra->obj.json);
586 mrp_free(plugin->args);
589 plugin->descriptor->ninstance--;
591 emit_plugin_event(PLUGIN_EVENT_UNLOADED, plugin);
593 if (plugin->handle != NULL)
594 dlclose(plugin->handle);
596 if (plugin->cmds != NULL) {
597 mrp_console_del_group(plugin->ctx, plugin->cmds);
599 mrp_free(plugin->cmds->name);
600 mrp_free(plugin->cmds);
603 release_plugin_methods(plugin);
604 remove_plugin_methods(plugin);
606 mrp_free(plugin->instance);
607 mrp_free(plugin->path);
620 int mrp_start_plugins(mrp_context_t *ctx)
622 mrp_list_hook_t *p, *n;
623 mrp_plugin_t *plugin;
625 mrp_list_foreach(&ctx->plugins, p, n) {
626 plugin = mrp_list_entry(p, typeof(*plugin), hook);
628 if (!import_plugin_methods(plugin)) {
629 if (!plugin->may_fail)
635 if (!mrp_start_plugin(plugin)) {
636 if (!plugin->may_fail)
640 mrp_unload_plugin(plugin);
644 /* XXX TODO: argh, ugly kludge for plugins loading plugins... */
645 if (plugin->hook.next != n)
646 n = plugin->hook.next;
653 int mrp_start_plugin(mrp_plugin_t *plugin)
655 if (plugin != NULL) {
656 if (plugin->state == MRP_PLUGIN_LOADED) {
657 if (!plugin->descriptor->init(plugin)) {
658 mrp_log_error("Failed to start plugin %s (%s).",
659 plugin->instance, plugin->descriptor->name);
661 emit_plugin_event(PLUGIN_EVENT_FAILED, plugin);
665 plugin->state = MRP_PLUGIN_RUNNING;
666 emit_plugin_event(PLUGIN_EVENT_STARTED, plugin);
677 int mrp_stop_plugin(mrp_plugin_t *plugin)
679 if (plugin != NULL) {
680 if (plugin->refcnt <= 1) {
681 emit_plugin_event(PLUGIN_EVENT_STOPPING, plugin);
682 plugin->descriptor->exit(plugin);
684 plugin->state = MRP_PLUGIN_STOPPED;
685 emit_plugin_event(PLUGIN_EVENT_STOPPED, plugin);
697 static mrp_plugin_t *find_plugin_instance(mrp_context_t *ctx,
698 const char *instance)
700 mrp_list_hook_t *p, *n;
703 MRP_UNUSED(find_plugin);
705 mrp_list_foreach(&ctx->plugins, p, n) {
706 plg = mrp_list_entry(p, typeof(*plg), hook);
708 if (!strcmp(plg->instance, instance))
716 static mrp_plugin_t *find_plugin(mrp_context_t *ctx, char *name)
718 mrp_list_hook_t *p, *n;
721 mrp_list_foreach(&ctx->plugins, p, n) {
722 plg = mrp_list_entry(p, typeof(*plg), hook);
724 if (!strcmp(plg->descriptor->name, name))
732 static mrp_plugin_descr_t *open_dynamic(mrp_context_t *ctx, const char *name,
735 mrp_plugin_descr_t *(*describe)(void);
736 mrp_plugin_descr_t *d;
740 snprintf(path, sizeof(path), "%s/%s%s.so", ctx->plugin_dir,
741 PLUGIN_PREFIX, name);
743 if (is_blacklisted(ctx, name, DYNAMIC))
746 if ((h = dlopen(path, RTLD_LAZY | RTLD_LOCAL)) != NULL) {
747 if ((describe = dlsym(h, "mrp_get_plugin_descriptor")) != NULL) {
748 if ((d = describe()) != NULL) {
749 if (d->init != NULL && d->exit != NULL && d->name != NULL) {
753 *handle = dlopen(path,
754 RTLD_LAZY|RTLD_GLOBAL|RTLD_NOLOAD);
761 mrp_log_error("Ignoring plugin '%s' with invalid "
762 "plugin descriptor.", path);
765 mrp_log_error("Plugin '%s' provided NULL descriptor.", path);
768 mrp_log_error("Plugin '%s' does not provide a descriptor.", path);
771 if (access(path, F_OK) == 0) {
772 char *err = dlerror();
774 mrp_log_error("Failed to dlopen plugin '%s' (%s).", path,
775 err ? err : "unknown error");
787 static mrp_plugin_descr_t *open_builtin(mrp_context_t *ctx, const char *name)
789 mrp_list_hook_t *p, *n;
790 mrp_plugin_t *plugin;
792 mrp_list_foreach(&builtin_plugins, p, n) {
793 plugin = mrp_list_entry(p, typeof(*plugin), hook);
795 if (!strcmp(plugin->descriptor->name, name)) {
796 #ifdef __PARANOID_BLACKLIST_CHECK__
797 if (is_blacklisted(ctx, name, BUILTIN)) {
798 mrp_log_warning("Hmm... blacklisted builtin %s still "
799 "reachable, blocking it.", name);
804 return plugin->descriptor;
812 static int parse_plugin_arg(mrp_plugin_arg_t *arg, mrp_plugin_arg_t *parg)
819 switch (parg->type) {
820 case MRP_PLUGIN_ARG_TYPE_STRING:
821 if (arg->str != NULL) {
822 parg->str = arg->str;
827 case MRP_PLUGIN_ARG_TYPE_BOOL:
828 if (arg->str != NULL) {
829 if (!strcasecmp(arg->str, "TRUE"))
831 else if (!strcasecmp(arg->str, "FALSE"))
840 case MRP_PLUGIN_ARG_TYPE_UINT32:
841 parg->u32 = (uint32_t)strtoul(arg->str, &end, 0);
847 case MRP_PLUGIN_ARG_TYPE_INT32:
848 parg->i32 = (int32_t)strtol(arg->str, &end, 0);
854 case MRP_PLUGIN_ARG_TYPE_DOUBLE:
855 parg->dbl = strtod(arg->str, &end);
861 case MRP_PLUGIN_ARG_TYPE_OBJECT:
864 json = &parg->obj.json;
865 if (mrp_json_parse_object(&jstr, &jlen, json) < 0 || jlen != 0)
876 static int parse_undeclared_arg(mrp_plugin_arg_t *arg, mrp_plugin_arg_t *pa)
882 if (mrp_reallocz(pa->rest.args, pa->rest.narg, pa->rest.narg + 1)) {
883 a = pa->rest.args + pa->rest.narg++;
884 a->key = mrp_strdup(arg->key);
889 if (arg->str == NULL) {
890 a->type = MRP_PLUGIN_ARG_TYPE_STRING;
896 if (!strncmp(arg->str, "string:", 7)) {
897 value = arg->str + 7;
899 a->type = MRP_PLUGIN_ARG_TYPE_STRING;
900 a->str = mrp_strdup(value);
907 else if (!strncmp(arg->str, "bool:", 5)) {
908 a->type = MRP_PLUGIN_ARG_TYPE_BOOL;
909 if (!strcasecmp(arg->str + 5, "TRUE")) a->bln = TRUE;
910 else if (!strcasecmp(arg->str + 5, "FALSE")) a->bln = FALSE;
913 else if (!strncmp(arg->str, "int32:", 6)) {
914 a->type = MRP_PLUGIN_ARG_TYPE_INT32;
915 a->i32 = (int32_t)strtol(arg->str + 6, &end, 0);
922 else if (!strncmp(arg->str, "uint32:", 7)) {
923 a->type = MRP_PLUGIN_ARG_TYPE_UINT32;
924 a->u32 = (uint32_t)strtoul(arg->str + 7, &end, 0);
931 else if (!strncmp(arg->str, "double:", 7)) {
932 a->type = MRP_PLUGIN_ARG_TYPE_DOUBLE;
933 a->dbl = strtod(arg->str + 7, &end);
940 else if (!strncmp(arg->str, "object:", prfx=7) ||
941 !strncmp(arg->str, "json:" , prfx=5)) {
942 mrp_json_t **json = &a->obj.json;
943 char *jstr = a->obj.str + prfx;
944 int jlen = strlen(jstr);
946 if (mrp_json_parse_object(&jstr, &jlen, json) < 0 || jlen != 0)
949 a->type = MRP_PLUGIN_ARG_TYPE_OBJECT;
954 if (!strcasecmp(arg->str, "TRUE") ||
955 !strcasecmp(arg->str, "FALSE")) {
956 a->type = MRP_PLUGIN_ARG_TYPE_BOOL;
957 a->bln = arg->str[0] == 't' || arg->str[0] == 'T';
961 if (arg->str[0] == '-' || arg->str[0] == '+' ||
962 (arg->str[0] == '0' && arg->str[1] == 'x') ||
963 ('0' <= arg->str[0] && arg->str[0] <= '9')) {
964 a->i32 = strtol(arg->str, &end, 0);
967 a->type = MRP_PLUGIN_ARG_TYPE_INT32;
970 a->dbl = strtod(arg->str, &end);
973 a->type = MRP_PLUGIN_ARG_TYPE_DOUBLE;
988 static int parse_plugin_args(mrp_plugin_t *plugin,
989 mrp_plugin_arg_t *argv, int argc)
991 mrp_plugin_descr_t *descr;
992 mrp_plugin_arg_t *valid, *args, *pa, *a, *rest;
996 plugin->args = plugin->descriptor->args;
1000 descr = plugin->descriptor;
1001 valid = descr->args;
1003 if (valid == NULL && argv != NULL) {
1004 mrp_log_error("Plugin '%s' (%s) does not take any arguments.",
1005 plugin->instance, descr->name);
1009 if ((args = mrp_allocz_array(typeof(*args), descr->narg)) == NULL) {
1010 mrp_log_error("Failed to allocate arguments for plugin '%s'.",
1015 memcpy(args, descr->args, descr->narg * sizeof(*args));
1016 plugin->args = args;
1018 for (i = 0, pa = plugin->args; i < descr->narg; i++, pa++) {
1019 if (pa->type == MRP_PLUGIN_ARG_TYPE_OBJECT) {
1020 mrp_json_t **json = &pa->obj.json;
1021 char *jstr = pa->obj.str;
1022 int jlen = strlen(jstr);
1024 if (mrp_json_parse_object(&jstr, &jlen, json) < 0 || jlen != 0)
1031 for (i = 0, a = argv; i < argc; i++, a++) {
1032 for (cnt = 0, pa = NULL; pa == NULL && cnt < descr->narg; cnt++) {
1033 if (args[j].type != MRP_PLUGIN_ARG_TYPE_UNDECL) {
1034 if (!strcmp(a->key, args[j].key))
1040 if (++j >= descr->narg)
1045 if (!parse_plugin_arg(a, pa)) {
1046 mrp_log_error("Invalid argument '%s' for plugin '%s'.",
1047 a->key, plugin->instance);
1051 else if (rest != NULL) {
1052 if (!parse_undeclared_arg(a, rest)) {
1053 mrp_log_error("Failed to parse argument '%s' for plugin '%s'.",
1054 a->key, plugin->instance);
1059 mrp_log_error("Plugin '%s' (%s) does not support argument '%s'",
1060 plugin->instance, descr->name, a->key);
1069 mrp_plugin_arg_t *mrp_plugin_find_undecl_arg(mrp_plugin_arg_t *unspec,
1071 mrp_plugin_arg_type_t type)
1073 mrp_plugin_arg_t *arg;
1076 for (i = 0, arg = unspec->rest.args; i < unspec->rest.narg; i++, arg++)
1077 if (!strcmp(arg->key, key) && (!type || type == arg->type))
1084 static int export_plugin_methods(mrp_plugin_t *plugin)
1086 mrp_method_descr_t *methods = plugin->descriptor->exports, *m;
1087 int nmethod = plugin->descriptor->nexport, i;
1089 for (i = 0, m = methods; i < nmethod; i++, m++) {
1091 if (mrp_export_method(m) != 0) {
1092 mrp_log_error("Failed to export method %s from plugin %s.",
1093 m->name, plugin->instance);
1102 static int remove_plugin_methods(mrp_plugin_t *plugin)
1104 mrp_method_descr_t *methods = plugin->descriptor->exports, *m;
1105 int nmethod = plugin->descriptor->nexport, i;
1108 for (i = 0, m = methods; i < nmethod; i++, m++) {
1110 if (mrp_remove_method(m) != 0) {
1111 mrp_log_error("Failed to remove exported method %s of plugin %s.",
1112 m->name, plugin->instance);
1121 static int import_plugin_methods(mrp_plugin_t *plugin)
1123 mrp_method_descr_t *methods = plugin->descriptor->imports, *m;
1124 int nmethod = plugin->descriptor->nimport, i;
1126 for (i = 0, m = methods; i < nmethod; i++, m++) {
1127 if (mrp_import_method(m->name, m->signature,
1128 (void **)m->native_ptr, NULL, NULL) != 0) {
1129 mrp_log_error("Failed to import method %s (%s) for plugin %s.",
1130 m->name, m->signature, plugin->instance);
1139 static int release_plugin_methods(mrp_plugin_t *plugin)
1141 mrp_method_descr_t *methods = plugin->descriptor->imports, *m;
1142 int nmethod = plugin->descriptor->nimport, i;
1145 for (i = 0, m = methods; i < nmethod; i++, m++) {
1146 if (mrp_release_method(m->name, m->signature,
1147 (void **)m->native_ptr, NULL) != 0) {
1148 mrp_log_error("Failed to release imported method %s of plugin %s.",
1149 m->name, plugin->instance);