From 27c006f7aa3ea7a5a38bd68d06c0b60614f0ad3c Mon Sep 17 00:00:00 2001 From: Rusty Russell Date: Wed, 13 Jan 2021 13:30:24 +1030 Subject: [PATCH] libplugin: make init return a string. Signed-off-by: Rusty Russell Changelog-Added: libplugin: init can return a non-NULL string to disable the plugin. --- plugins/autoclean.c | 6 ++++-- plugins/bcli.c | 6 ++++-- plugins/fetchinvoice.c | 6 ++++-- plugins/keysend.c | 6 ++++-- plugins/libplugin.c | 21 +++++++++++++-------- plugins/libplugin.h | 5 +++-- plugins/offers.c | 8 +++++--- plugins/pay.c | 6 ++++-- plugins/spender/main.c | 3 ++- tests/plugins/test_libplugin.c | 15 ++++++++++++--- tests/test_plugin.py | 21 ++++++++++++++------- 11 files changed, 69 insertions(+), 34 deletions(-) diff --git a/plugins/autoclean.c b/plugins/autoclean.c index eecdd52f7..93b71923e 100644 --- a/plugins/autoclean.c +++ b/plugins/autoclean.c @@ -64,8 +64,8 @@ static struct command_result *json_autocleaninvoice(struct command *cmd, expired_by, cycle_seconds)); } -static void init(struct plugin *p, - const char *buf UNUSED, const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, + const char *buf UNUSED, const jsmntok_t *config UNUSED) { if (cycle_seconds) { plugin_log(p, LOG_INFORM, "autocleaning every %"PRIu64" seconds", cycle_seconds); @@ -73,6 +73,8 @@ static void init(struct plugin *p, do_clean, p); } else plugin_log(p, LOG_DBG, "autocleaning not active"); + + return NULL; } static const struct plugin_command commands[] = { { diff --git a/plugins/bcli.c b/plugins/bcli.c index ed40d9ee5..193767e6a 100644 --- a/plugins/bcli.c +++ b/plugins/bcli.c @@ -870,12 +870,14 @@ static void wait_and_check_bitcoind(struct plugin *p) tal_free(cmd); } -static void init(struct plugin *p, const char *buffer UNUSED, - const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, const char *buffer UNUSED, + const jsmntok_t *config UNUSED) { wait_and_check_bitcoind(p); plugin_log(p, LOG_INFORM, "bitcoin-cli initialized and connected to bitcoind."); + + return NULL; } static const struct plugin_command commands[] = { diff --git a/plugins/fetchinvoice.c b/plugins/fetchinvoice.c index dab08bc4e..a7e3ce284 100644 --- a/plugins/fetchinvoice.c +++ b/plugins/fetchinvoice.c @@ -1346,12 +1346,14 @@ static const struct plugin_command commands[] = { }, }; -static void init(struct plugin *p, const char *buf UNUSED, - const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, const char *buf UNUSED, + const jsmntok_t *config UNUSED) { rpc_scan(p, "getinfo", take(json_out_obj(NULL, NULL, NULL)), "{id:%}", JSON_SCAN(json_to_node_id, &local_id)); + + return NULL; } static const struct plugin_hook hooks[] = { diff --git a/plugins/keysend.c b/plugins/keysend.c index 74e28f0ae..51fe7fcf0 100644 --- a/plugins/keysend.c +++ b/plugins/keysend.c @@ -92,8 +92,8 @@ REGISTER_PAYMENT_MODIFIER(keysend, struct keysend_data *, keysend_init, * End of keysend modifier *****************************************************************************/ -static void init(struct plugin *p, const char *buf UNUSED, - const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, const char *buf UNUSED, + const jsmntok_t *config UNUSED) { rpc_scan(p, "getinfo", take(json_out_obj(NULL, NULL, NULL)), "{id:%}", JSON_SCAN(json_to_node_id, &my_id)); @@ -102,6 +102,8 @@ static void init(struct plugin *p, const char *buf UNUSED, take(json_out_obj(NULL, "config", "max-locktime-blocks")), "{max-locktime-blocks:%}", JSON_SCAN(json_to_number, &maxdelay_default)); + + return NULL; } struct payment_modifier *pay_mods[8] = { diff --git a/plugins/libplugin.c b/plugins/libplugin.c index 6701caf6c..20b0020f9 100644 --- a/plugins/libplugin.c +++ b/plugins/libplugin.c @@ -71,8 +71,8 @@ struct plugin { struct plugin_option *opts; /* Anything special to do at init ? */ - void (*init)(struct plugin *p, - const char *buf, const jsmntok_t *); + const char *(*init)(struct plugin *p, + const char *buf, const jsmntok_t *); /* Has the manifest been sent already ? */ bool manifested; /* Has init been received ? */ @@ -878,8 +878,12 @@ static struct command_result *handle_init(struct command *cmd, tal_free(opt); } - if (p->init) - p->init(p, buf, configtok); + if (p->init) { + const char *disable = p->init(p, buf, configtok); + if (disable) + return command_success(cmd, json_out_obj(cmd, "disable", + disable)); + } if (with_rpc) io_new_conn(p, p->rpc_conn->fd, rpc_conn_init, p); @@ -1296,8 +1300,9 @@ static struct io_plan *stdout_conn_init(struct io_conn *conn, } static struct plugin *new_plugin(const tal_t *ctx, - void (*init)(struct plugin *p, - const char *buf, const jsmntok_t *), + const char *(*init)(struct plugin *p, + const char *buf, + const jsmntok_t *), const enum plugin_restartability restartability, bool init_rpc, struct feature_set *features, @@ -1365,8 +1370,8 @@ static struct plugin *new_plugin(const tal_t *ctx, } void plugin_main(char *argv[], - void (*init)(struct plugin *p, - const char *buf, const jsmntok_t *), + const char *(*init)(struct plugin *p, + const char *buf, const jsmntok_t *), const enum plugin_restartability restartability, bool init_rpc, struct feature_set *features, diff --git a/plugins/libplugin.h b/plugins/libplugin.h index 1f62b3deb..fcda5baa7 100644 --- a/plugins/libplugin.h +++ b/plugins/libplugin.h @@ -277,8 +277,9 @@ char *flag_option(const char *arg, bool *i); /* The main plugin runner: append with 0 or more plugin_option(), then NULL. */ void NORETURN LAST_ARG_NULL plugin_main(char *argv[], - void (*init)(struct plugin *p, - const char *buf, const jsmntok_t *), + const char *(*init)(struct plugin *p, + const char *buf, + const jsmntok_t *), const enum plugin_restartability restartability, bool init_rpc, struct feature_set *features, diff --git a/plugins/offers.c b/plugins/offers.c index 0a68cff22..919a7653c 100644 --- a/plugins/offers.c +++ b/plugins/offers.c @@ -665,9 +665,9 @@ static struct command_result *json_decode(struct command *cmd, return command_finished(cmd, response); } -static void init(struct plugin *p, - const char *buf UNUSED, - const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, + const char *buf UNUSED, + const jsmntok_t *config UNUSED) { struct pubkey k; @@ -681,6 +681,8 @@ static void init(struct plugin *p, rpc_scan(p, "listconfigs", take(json_out_obj(NULL, "config", "cltv-final")), "{cltv-final:%}", JSON_SCAN(json_to_number, &cltv_final)); + + return NULL; } static const struct plugin_command commands[] = { diff --git a/plugins/pay.c b/plugins/pay.c index 26240f6a1..544cb8784 100644 --- a/plugins/pay.c +++ b/plugins/pay.c @@ -1902,8 +1902,8 @@ static struct command_result *json_listpays(struct command *cmd, return send_outreq(cmd->plugin, req); } -static void init(struct plugin *p, - const char *buf UNUSED, const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, + const char *buf UNUSED, const jsmntok_t *config UNUSED) { rpc_scan(p, "getinfo", take(json_out_obj(NULL, NULL, NULL)), "{id:%}", JSON_SCAN(json_to_node_id, &my_id)); @@ -1912,6 +1912,8 @@ static void init(struct plugin *p, take(json_out_obj(NULL, "config", "max-locktime-blocks")), "{max-locktime-blocks:%}", JSON_SCAN(json_to_number, &maxdelay_default)); + + return NULL; } struct payment_modifier *paymod_mods[] = { diff --git a/plugins/spender/main.c b/plugins/spender/main.c index 31b3e0842..86beee723 100644 --- a/plugins/spender/main.c +++ b/plugins/spender/main.c @@ -9,10 +9,11 @@ * spending from the onchain wallet. */ static -void spender_init(struct plugin *p, const char *b, const jsmntok_t *t) +const char *spender_init(struct plugin *p, const char *b, const jsmntok_t *t) { openchannel_init(p, b, t); /* whatever_init(p, b, t); */ + return NULL; } int main(int argc, char **argv) diff --git a/tests/plugins/test_libplugin.c b/tests/plugins/test_libplugin.c index ac2641304..cbccaa222 100644 --- a/tests/plugins/test_libplugin.c +++ b/tests/plugins/test_libplugin.c @@ -5,7 +5,7 @@ const char *name_option; - +static bool self_disable = false; static struct command_result *json_helloworld(struct command *cmd, const char *buf, @@ -86,10 +86,15 @@ static struct command_result *json_testrpc(struct command *cmd, return send_outreq(cmd->plugin, req); } -static void init(struct plugin *p, - const char *buf UNUSED, const jsmntok_t *config UNUSED) +static const char *init(struct plugin *p, + const char *buf UNUSED, + const jsmntok_t *config UNUSED) { plugin_log(p, LOG_DBG, "test_libplugin initialised!"); + + if (self_disable) + return "Disabled via selfdisable option"; + return NULL; } static const struct plugin_command commands[] = { { @@ -149,5 +154,9 @@ int main(int argc, char *argv[]) "string", "Who to say hello to.", charp_option, &name_option), + plugin_option("selfdisable", + "flag", + "Whether to disable.", + flag_option, &self_disable), NULL); } diff --git a/tests/test_plugin.py b/tests/test_plugin.py index 519bc7f59..8b0d67eac 100644 --- a/tests/test_plugin.py +++ b/tests/test_plugin.py @@ -2326,19 +2326,26 @@ def test_pyln_request_notify(node_factory): def test_self_disable(node_factory): """Test that plugin can disable itself without penalty. """ - plugin_path = os.path.join( - os.path.dirname(__file__), 'plugins/test_selfdisable' + # This disables in response to getmanifest. + p1 = os.path.join( + os.path.dirname(__file__), 'plugins/test_selfdisable_after_getmanifest' ) - l1 = node_factory.get_node(options={'important-plugin': plugin_path}) + # This disables in response to init. + p2 = os.path.join(os.getcwd(), "tests/plugins/test_libplugin") + l1 = node_factory.get_node(options={'important-plugin': [p1, p2], 'selfdisable': None}) # Could happen before it gets set up. l1.daemon.logsearch_start = 0 - l1.daemon.wait_for_log('test_selfdisable: disabled itself: "Self-disable test after getmanifest"') + l1.daemon.wait_for_logs(['test_selfdisable_after_getmanifest: disabled itself: "Self-disable test after getmanifest"', + 'test_libplugin: disabled itself at init: Disabled via selfdisable option']) - assert plugin_path not in [p['name'] for p in l1.rpc.plugin_list()['plugins']] + assert p1 not in [p['name'] for p in l1.rpc.plugin_list()['plugins']] + assert p2 not in [p['name'] for p in l1.rpc.plugin_list()['plugins']] # Also works with dynamic load attempts with pytest.raises(RpcError, match="Self-disable test after getmanifest"): - l1.rpc.plugin_start(plugin_path) + l1.rpc.plugin_start(p1) - # Now test the disable-in-init-response. + # Also works with dynamic load attempts + with pytest.raises(RpcError, match="Disabled via selfdisable option"): + l1.rpc.plugin_start(p2, selfdisable=True)