From cdf12d06bab6053c4e31d155a777fe2a2d90407d Mon Sep 17 00:00:00 2001
From: Simon Vrouwe <s_github@protonmail.com>
Date: Mon, 20 Jun 2022 10:52:37 +0300
Subject: [PATCH] lightningd: Make sure plugins don't register the same option
 "name"

The extra entry in opt_table would never be called, leaving plugins
clueless why options keep defaulting.

Note that option registration outside startup does nothing.
Instead, dynamic plugins can use `plugin start [second_parameter]` to pass options.
---
 lightningd/plugin.c | 29 ++++++++++++++++++++---------
 1 file changed, 20 insertions(+), 9 deletions(-)

diff --git a/lightningd/plugin.c b/lightningd/plugin.c
index b8564817b..07bb6fa01 100644
--- a/lightningd/plugin.c
+++ b/lightningd/plugin.c
@@ -886,10 +886,24 @@ char *plugin_opt_set(const char *arg, struct plugin_opt *popt)
 	return NULL;
 }
 
+/* Returns true if "name" was already registered and now overwritten. */
+static bool plugin_opt_register(struct plugin_opt *popt)
+{
+	bool was_registered = opt_unregister(popt->name);
+	if (streq(popt->type, "flag"))
+		opt_register_noarg(popt->name, plugin_opt_flag_set, popt,
+				   popt->description);
+	else
+		opt_register_arg(popt->name, plugin_opt_set, NULL, popt,
+				 popt->description);
+
+	return was_registered;
+}
+
 static void destroy_plugin_opt(struct plugin_opt *opt)
 {
-	if (!opt_unregister(opt->name))
-		fatal("Could not unregister %s", opt->name);
+	/* does nothing when "name" registration replaced its double */
+	opt_unregister(opt->name);
 	list_del(&opt->list);
 }
 
@@ -978,13 +992,10 @@ static const char *plugin_opt_add(struct plugin *plugin, const char *buffer,
 
 	list_add_tail(&plugin->plugin_opts, &popt->list);
 
-	if (streq(popt->type, "flag"))
-		opt_register_noarg(popt->name, plugin_opt_flag_set, popt,
-				   popt->description);
-
-	else
-		opt_register_arg(popt->name, plugin_opt_set, NULL, popt,
-				 popt->description);
+	/* Command line options are parsed only during ld's startup and each "name"
+	 * only once. Always registers to satisfy destructor */
+	if (plugin_opt_register(popt) && plugin->plugins->startup)
+		fatal("error starting plugin '%s': option name '%s' is already taken", plugin->cmd, popt->name);
 
 	tal_add_destructor(popt, destroy_plugin_opt);
 	return NULL;