Browse Source

lightningd: add --plugin-dir option to load directory full of plugins.

Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
plugin-6
Rusty Russell 6 years ago
committed by Christian Decker
parent
commit
a4287f99fd
  1. 13
      lightningd/options.c
  2. 56
      lightningd/plugin.c
  3. 6
      lightningd/plugin.h
  4. 6
      tests/test_plugin.py

13
lightningd/options.c

@ -293,6 +293,11 @@ static char *opt_add_plugin(const char *arg, struct lightningd *ld)
return NULL; return NULL;
} }
static char *opt_add_plugin_dir(const char *arg, struct lightningd *ld)
{
return add_plugin_dir(ld->plugins, arg);
}
static void config_register_opts(struct lightningd *ld) static void config_register_opts(struct lightningd *ld)
{ {
opt_register_early_arg("--conf=<file>", opt_set_talstr, NULL, opt_register_early_arg("--conf=<file>", opt_set_talstr, NULL,
@ -302,7 +307,10 @@ static void config_register_opts(struct lightningd *ld)
/* Register plugins as an early argc, so we can initialize them and have /* Register plugins as an early argc, so we can initialize them and have
* them register more command line options */ * them register more command line options */
opt_register_early_arg("--plugin", opt_add_plugin, NULL, ld, opt_register_early_arg("--plugin", opt_add_plugin, NULL, ld,
"Add a plugin to be run."); "Add a plugin to be run (can be used multiple times)");
opt_register_early_arg("--plugin-dir", opt_add_plugin_dir,
NULL, ld,
"Add a directory to load plugins from (can be used multiple times)");
opt_register_noarg("--daemon", opt_set_bool, &ld->daemon, opt_register_noarg("--daemon", opt_set_bool, &ld->daemon,
"Run in the background, suppress stdout/stderr"); "Run in the background, suppress stdout/stderr");
@ -989,6 +997,9 @@ static void add_config(struct lightningd *ld,
answer = fmt_wireaddr(name0, ld->proxyaddr); answer = fmt_wireaddr(name0, ld->proxyaddr);
} else if (opt->cb_arg == (void *)opt_add_plugin) { } else if (opt->cb_arg == (void *)opt_add_plugin) {
json_add_opt_plugins(response, ld->plugins); json_add_opt_plugins(response, ld->plugins);
} else if (opt->cb_arg == (void *)opt_add_plugin_dir) {
/* FIXME: We actually treat it as if they specified
* --plugin for each one, so ignore this */
#if DEVELOPER #if DEVELOPER
} else if (strstarts(name, "dev-")) { } else if (strstarts(name, "dev-")) {
/* Ignore dev settings */ /* Ignore dev settings */

56
lightningd/plugin.c

@ -5,13 +5,18 @@
#include <ccan/list/list.h> #include <ccan/list/list.h>
#include <ccan/opt/opt.h> #include <ccan/opt/opt.h>
#include <ccan/pipecmd/pipecmd.h> #include <ccan/pipecmd/pipecmd.h>
#include <ccan/tal/path/path.h>
#include <ccan/tal/str/str.h> #include <ccan/tal/str/str.h>
#include <ccan/utf8/utf8.h>
#include <common/memleak.h> #include <common/memleak.h>
#include <dirent.h>
#include <errno.h> #include <errno.h>
#include <lightningd/json.h> #include <lightningd/json.h>
#include <lightningd/jsonrpc_errors.h> #include <lightningd/jsonrpc_errors.h>
#include <lightningd/lightningd.h> #include <lightningd/lightningd.h>
#include <signal.h> #include <signal.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
struct plugin { struct plugin {
@ -22,6 +27,7 @@ struct plugin {
struct io_conn *stdin_conn, *stdout_conn; struct io_conn *stdin_conn, *stdout_conn;
bool stop; bool stop;
struct plugins *plugins; struct plugins *plugins;
const char **plugin_path;
/* Stuff we read */ /* Stuff we read */
char *buffer; char *buffer;
@ -602,6 +608,56 @@ static void plugin_manifest_cb(const struct plugin_request *req, struct plugin *
plugin_kill(plugin, "Failed to register options or methods"); plugin_kill(plugin, "Failed to register options or methods");
} }
/* If this is a valid plugin return full path name, otherwise NULL */
static const char *plugin_fullpath(const tal_t *ctx, const char *dir,
const char *basename)
{
struct stat st;
const char *fullname;
struct utf8_state utf8 = UTF8_STATE_INIT;
for (size_t i = 0; basename[i]; i++) {
if (!utf8_decode(&utf8, basename[i]))
continue;
/* Not valid UTF8? Let's not go there... */
if (errno != 0)
return NULL;
if (utf8.used_len != 1)
continue;
if (!cispunct(utf8.c))
continue;
if (utf8.c != '-' && utf8.c != '_' && utf8.c != '.')
return NULL;
}
fullname = path_join(ctx, dir, basename);
if (stat(fullname, &st) != 0)
return tal_free(fullname);
if (!(st.st_mode & (S_IXUSR|S_IXGRP|S_IXOTH)))
return tal_free(fullname);
return fullname;
}
char *add_plugin_dir(struct plugins *plugins, const char *dir)
{
struct dirent *di;
DIR *d = opendir(dir);
if (!d)
return tal_fmt("Failed to open plugin-dir %s: %s",
dir, strerror(errno));
while ((di = readdir(d)) != NULL) {
const char *fullpath;
if (streq(di->d_name, ".") || streq(di->d_name, ".."))
continue;
fullpath = plugin_fullpath(NULL, dir, di->d_name);
if (fullpath)
plugin_register(plugins, take(fullpath));
}
return NULL;
}
void plugins_init(struct plugins *plugins) void plugins_init(struct plugins *plugins)
{ {
struct plugin *p; struct plugin *p;

6
lightningd/plugin.h

@ -56,4 +56,10 @@ void plugins_config(struct plugins *plugins);
void json_add_opt_plugins(struct json_stream *response, void json_add_opt_plugins(struct json_stream *response,
const struct plugins *plugins); const struct plugins *plugins);
/**
* Add a directory to the plugin path to automatically load plugins.
*/
char *add_plugin_dir(struct plugins *plugins, const char *dir);
#endif /* LIGHTNING_LIGHTNINGD_PLUGIN_H */ #endif /* LIGHTNING_LIGHTNINGD_PLUGIN_H */

6
tests/test_plugin.py

@ -51,3 +51,9 @@ def test_rpc_passthrough(node_factory):
assert(greet == "Hello Sun") assert(greet == "Hello Sun")
with pytest.raises(RpcError): with pytest.raises(RpcError):
n.rpc.fail() n.rpc.fail()
def test_plugin_dir(node_factory):
"""--plugin-dir works"""
plugin_dir = 'contrib/plugins'
node_factory.get_node(options={'plugin-dir': plugin_dir, 'greeting': 'Mars'})

Loading…
Cancel
Save