mirror of
https://github.com/ElementsProject/lightning.git
synced 2025-01-18 21:35:11 +01:00
lightningd: switch parsing to common/configvar
Now we wire in the code which gathers configvars and parses from there; lightningd keeps the array of configuration variables for future use. Note that lightning-cli also needs to read the config, but it has its own options (including short ones!) and doesn't want to use this configvar mechanism, so we have a different API for that now. Signed-off-by: Rusty Russell <rusty@rustcorp.com.au>
This commit is contained in:
parent
f54e4f3084
commit
edbaa944da
@ -650,7 +650,7 @@ int main(int argc, char *argv[])
|
||||
jsmntok_t *toks;
|
||||
const jsmntok_t *result, *error, *id;
|
||||
const tal_t *ctx = tal(NULL, char);
|
||||
char *config_filename, *lightning_dir, *net_dir, *rpc_filename;
|
||||
char *net_dir, *rpc_filename;
|
||||
jsmn_parser parser;
|
||||
int parserr;
|
||||
enum format format = DEFAULT_FORMAT;
|
||||
@ -667,9 +667,8 @@ int main(int argc, char *argv[])
|
||||
|
||||
setup_option_allocators();
|
||||
|
||||
initial_config_opts(ctx, argc, argv,
|
||||
&config_filename, &lightning_dir, &net_dir,
|
||||
&rpc_filename);
|
||||
opt_exitcode = ERROR_USAGE;
|
||||
minimal_config_opts(ctx, argc, argv, &net_dir, &rpc_filename);
|
||||
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
"<command> [<params>...]", "Show this message. Use the command help (without hyphens -- \"lightning-cli help\") to get a list of all RPC commands");
|
||||
@ -695,8 +694,6 @@ int main(int argc, char *argv[])
|
||||
NULL, &commando,
|
||||
"Send this as a commando command to nodeid:rune");
|
||||
|
||||
opt_register_version();
|
||||
|
||||
opt_early_parse(argc, argv, opt_log_stderr_exit_usage);
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit_usage);
|
||||
|
||||
|
@ -10,6 +10,7 @@ ALL_TEST_PROGRAMS += $(CLI_TEST_PROGRAMS)
|
||||
CLI_TEST_COMMON_OBJS := \
|
||||
common/autodata.o \
|
||||
common/configdir.o \
|
||||
common/configvar.o \
|
||||
common/daemon_conn.o \
|
||||
common/htlc_state.o \
|
||||
common/json_parse_simple.o \
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <common/amount.h>
|
||||
#include <common/bigsize.h>
|
||||
#include <common/channel_id.h>
|
||||
#include <common/configvar.h>
|
||||
#include <common/json_stream.h>
|
||||
#include <common/node_id.h>
|
||||
#include <common/setup.h>
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <common/amount.h>
|
||||
#include <common/bigsize.h>
|
||||
#include <common/channel_id.h>
|
||||
#include <common/configvar.h>
|
||||
#include <common/json_stream.h>
|
||||
#include <common/node_id.h>
|
||||
#include <common/setup.h>
|
||||
|
@ -3,6 +3,7 @@
|
||||
#include <common/amount.h>
|
||||
#include <common/bigsize.h>
|
||||
#include <common/channel_id.h>
|
||||
#include <common/configvar.h>
|
||||
#include <common/json_stream.h>
|
||||
#include <common/node_id.h>
|
||||
#include <common/setup.h>
|
||||
|
@ -4,17 +4,21 @@
|
||||
#include <ccan/cast/cast.h>
|
||||
#include <ccan/err/err.h>
|
||||
#include <ccan/opt/opt.h>
|
||||
#include <ccan/opt/private.h>
|
||||
#include <ccan/tal/grab_file/grab_file.h>
|
||||
#include <ccan/tal/path/path.h>
|
||||
#include <ccan/tal/str/str.h>
|
||||
#include <common/configdir.h>
|
||||
#include <common/configvar.h>
|
||||
#include <common/utils.h>
|
||||
#include <common/version.h>
|
||||
|
||||
bool deprecated_apis = true;
|
||||
int opt_exitcode = 1;
|
||||
|
||||
/* The regrettable globals */
|
||||
static const tal_t *options_ctx;
|
||||
static struct configvar *current_cv;
|
||||
|
||||
/* Override a tal string; frees the old one. */
|
||||
char *opt_set_talstr(const char *arg, char **p)
|
||||
@ -50,113 +54,55 @@ static void tal_freefn(void *ptr)
|
||||
tal_free(ptr);
|
||||
}
|
||||
|
||||
static int config_parse_line_number;
|
||||
|
||||
static void config_log_stderr_exit(const char *fmt, ...)
|
||||
{
|
||||
char *msg;
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
|
||||
/* This is the format we expect:*/
|
||||
if (streq(fmt, "%s: %.*s: %s")) {
|
||||
const char *argv0 = va_arg(ap, const char *);
|
||||
unsigned int len = va_arg(ap, unsigned int);
|
||||
const char *arg = va_arg(ap, const char *);
|
||||
const char *problem = va_arg(ap, const char *);
|
||||
|
||||
assert(argv0 != NULL);
|
||||
assert(arg != NULL);
|
||||
assert(problem != NULL);
|
||||
/*mangle it to remove '--' and add the line number.*/
|
||||
msg = tal_fmt(NULL, "%s line %d: %.*s: %s",
|
||||
argv0,
|
||||
config_parse_line_number, len-2, arg+2, problem);
|
||||
} else {
|
||||
msg = tal_vfmt(NULL, fmt, ap);
|
||||
}
|
||||
va_end(ap);
|
||||
|
||||
errx(1, "%s", msg);
|
||||
}
|
||||
|
||||
static void parse_include(const char *filename, bool must_exist, bool early,
|
||||
size_t depth)
|
||||
static struct configvar **gather_file_configvars(const tal_t *ctx,
|
||||
enum configvar_src src,
|
||||
const char *filename,
|
||||
bool must_exist,
|
||||
size_t include_depth)
|
||||
{
|
||||
char *contents, **lines;
|
||||
char **all_args; /*For each line: either `--`argument, include file, or NULL*/
|
||||
char *argv[3];
|
||||
int i, argc;
|
||||
struct configvar **cvs = tal_arr(ctx, struct configvar *, 0);
|
||||
|
||||
contents = grab_file(NULL, filename);
|
||||
contents = grab_file(tmpctx, filename);
|
||||
|
||||
/* The default config doesn't have to exist, but if the config was
|
||||
* specified on the command line it has to exist. */
|
||||
if (!contents) {
|
||||
if (must_exist)
|
||||
err(1, "Opening and reading %s", filename);
|
||||
return;
|
||||
return cvs;
|
||||
}
|
||||
|
||||
/* Break into lines. */
|
||||
lines = tal_strsplit(contents, contents, "\r\n", STR_EMPTY_OK);
|
||||
for (size_t i = 0; i < tal_count(lines) - 1; i++) {
|
||||
/* Comments & blank lines*/
|
||||
if (strstarts(lines[i], "#") || streq(lines[i], ""))
|
||||
continue;
|
||||
|
||||
/* We have to keep all_args around, since opt will point into it: use
|
||||
* magic tal name to tell memleak this isn't one. */
|
||||
all_args = tal_arr_label(options_ctx, char *, tal_count(lines) - 1,
|
||||
TAL_LABEL(options_array_notleak, ""));
|
||||
if (strstarts(lines[i], "include ")) {
|
||||
const char *included = lines[i] + strlen("include ");
|
||||
struct configvar **sub;
|
||||
|
||||
if (include_depth > 100)
|
||||
errx(1, "Include loop with %s and %s", filename, included);
|
||||
|
||||
for (i = 0; i < tal_count(lines) - 1; i++) {
|
||||
if (strstarts(lines[i], "#")) {
|
||||
all_args[i] = NULL;
|
||||
} else if (strstarts(lines[i], "include ")) {
|
||||
/* If relative, it's relative to current config file */
|
||||
all_args[i] = path_join(all_args,
|
||||
take(path_dirname(NULL,
|
||||
filename)),
|
||||
lines[i] + strlen("include "));
|
||||
} else {
|
||||
/* Only valid forms are "foo" and "foo=bar" */
|
||||
all_args[i] = tal_fmt(all_args, "--%s", lines[i]);
|
||||
}
|
||||
/* This isn't a leak either */
|
||||
if (all_args[i])
|
||||
tal_set_name(all_args[i], TAL_LABEL(config_notleak, ""));
|
||||
}
|
||||
|
||||
/*
|
||||
For each line we construct a fake argc,argv commandline.
|
||||
argv[1] is the only element that changes between iterations.
|
||||
*/
|
||||
argc = 2;
|
||||
argv[0] = cast_const(char *, filename);
|
||||
argv[argc] = NULL;
|
||||
|
||||
for (i = 0; i < tal_count(all_args); i++) {
|
||||
if (all_args[i] == NULL)
|
||||
continue;
|
||||
|
||||
if (!strstarts(all_args[i], "--")) {
|
||||
/* There could be more, but this gives a hint. */
|
||||
if (depth > 100)
|
||||
errx(1, "Include loop with %s and %s",
|
||||
filename, all_args[i]);
|
||||
parse_include(all_args[i], true, early, ++depth);
|
||||
sub = gather_file_configvars(NULL,
|
||||
src,
|
||||
path_join(tmpctx,
|
||||
take(path_dirname(NULL, filename)),
|
||||
included),
|
||||
true,
|
||||
include_depth + 1);
|
||||
cvs = configvar_join(ctx, take(cvs), take(sub));
|
||||
continue;
|
||||
}
|
||||
|
||||
config_parse_line_number = i + 1;
|
||||
argv[1] = all_args[i];
|
||||
if (early) {
|
||||
opt_early_parse_incomplete(argc, argv,
|
||||
config_log_stderr_exit);
|
||||
} else {
|
||||
opt_parse(&argc, argv, config_log_stderr_exit);
|
||||
argc = 2; /* opt_parse might have changed it */
|
||||
}
|
||||
tal_arr_expand(&cvs,
|
||||
configvar_new(cvs, src, filename, i+1, lines[i]));
|
||||
}
|
||||
|
||||
tal_free(contents);
|
||||
return cvs;
|
||||
}
|
||||
|
||||
static char *default_base_configdir(const tal_t *ctx)
|
||||
@ -179,6 +125,12 @@ static char *opt_set_network(const char *arg, void *unused)
|
||||
{
|
||||
assert(arg != NULL);
|
||||
|
||||
/* Ignore if called directly from opt (e.g. lightning-cli) */
|
||||
if (!current_cv)
|
||||
return NULL;
|
||||
|
||||
if (current_cv->src == CONFIGVAR_NETWORK_CONF)
|
||||
return "not permitted in network-specific configuration files";
|
||||
/* Set the global chainparams instance */
|
||||
chainparams = chainparams_for_network(arg);
|
||||
if (!chainparams)
|
||||
@ -197,46 +149,27 @@ static bool opt_show_network(char *buf, size_t len, const void *unused)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* We track where we're getting options from, so we can detect misuse */
|
||||
enum parse_state {
|
||||
CMDLINE = 1,
|
||||
FORCED_CONFIG = 2,
|
||||
TOPLEVEL_CONFIG = 4,
|
||||
NETWORK_CONFIG = 8,
|
||||
};
|
||||
static enum parse_state parse_state = CMDLINE;
|
||||
|
||||
static char *opt_restricted_cmdline(const char *arg, const void *unused)
|
||||
static char *opt_set_config_filename(const char *arg, char **p)
|
||||
{
|
||||
if (parse_state != CMDLINE)
|
||||
return "not permitted in configuration files";
|
||||
return NULL;
|
||||
/* Ignore if called directly from opt (e.g. lightning-cli) */
|
||||
if (!current_cv)
|
||||
return NULL;
|
||||
|
||||
if (current_cv->src == CONFIGVAR_CMDLINE)
|
||||
return opt_set_abspath(arg, p);
|
||||
return "not permitted in configuration files";
|
||||
}
|
||||
|
||||
static char *opt_restricted_toplevel_noarg(const void *unused)
|
||||
static char *opt_set_lightning_dir(const char *arg, char **p)
|
||||
{
|
||||
if (parse_state == NETWORK_CONFIG)
|
||||
return "not permitted in network-specific configuration files";
|
||||
return NULL;
|
||||
}
|
||||
/* Ignore if called directly from opt (e.g. lightning-cli) */
|
||||
if (!current_cv)
|
||||
return NULL;
|
||||
|
||||
static char *opt_restricted_toplevel(const char *arg, const void *unused)
|
||||
{
|
||||
return opt_restricted_toplevel_noarg(NULL);
|
||||
}
|
||||
|
||||
static char *opt_restricted_forceconf_only(const char *arg, const void *unused)
|
||||
{
|
||||
if (parse_state != CMDLINE && parse_state != FORCED_CONFIG)
|
||||
return "not permitted in implicit configuration files";
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bool is_restricted_ignored(const void *fn)
|
||||
{
|
||||
return fn == opt_restricted_toplevel_noarg
|
||||
|| fn == opt_restricted_toplevel
|
||||
|| fn == opt_restricted_forceconf_only;
|
||||
if (current_cv->src == CONFIGVAR_CMDLINE
|
||||
|| current_cv->src == CONFIGVAR_EXPLICIT_CONF)
|
||||
return opt_set_abspath(arg, p);
|
||||
return "not permitted in implicit configuration files";
|
||||
}
|
||||
|
||||
void setup_option_allocators(void)
|
||||
@ -245,103 +178,155 @@ void setup_option_allocators(void)
|
||||
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
|
||||
}
|
||||
|
||||
/* network is NULL for parsing top-level config file. */
|
||||
static void parse_implied_config_file(const char *config_basedir,
|
||||
const char *network,
|
||||
bool early)
|
||||
static void parse_configvars(struct configvar **cvs,
|
||||
bool early,
|
||||
bool full_knowledge)
|
||||
{
|
||||
const char *dir, *filename;
|
||||
for (size_t i = 0; i < tal_count(cvs); i++) {
|
||||
const char *problem;
|
||||
bool should_know;
|
||||
|
||||
if (config_basedir)
|
||||
dir = path_join(NULL, take(path_cwd(NULL)), config_basedir);
|
||||
else
|
||||
dir = default_base_configdir(NULL);
|
||||
should_know = full_knowledge;
|
||||
/* We should always know cmdline args in final parse */
|
||||
if (!early && cvs[i]->src == CONFIGVAR_CMDLINE)
|
||||
should_know = true;
|
||||
|
||||
if (network)
|
||||
dir = path_join(NULL, take(dir), network);
|
||||
current_cv = cvs[i];
|
||||
problem = configvar_parse(cvs[i],
|
||||
early,
|
||||
should_know,
|
||||
IFDEV(true, false));
|
||||
current_cv = NULL;
|
||||
if (!problem)
|
||||
continue;
|
||||
|
||||
filename = path_join(NULL, take(dir), "config");
|
||||
parse_include(filename, false, early, 0);
|
||||
tal_free(filename);
|
||||
if (cvs[i]->file) {
|
||||
errx(opt_exitcode, "Config file %s line %u: %s: %s",
|
||||
cvs[i]->file, cvs[i]->linenum,
|
||||
cvs[i]->configline, problem);
|
||||
} else {
|
||||
errx(opt_exitcode, "--%s: %s", cvs[i]->configline, problem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* If they specify --conf, we just read that.
|
||||
* Otherwise we read <lightning-dir>/config then <lightning-dir>/<network>/config
|
||||
*/
|
||||
void parse_config_files(const char *config_filename,
|
||||
const char *config_basedir,
|
||||
bool early)
|
||||
static void finished_arg(int *argc, char **argv, size_t *idx,
|
||||
bool remove_args)
|
||||
{
|
||||
if (config_filename) {
|
||||
parse_state = FORCED_CONFIG;
|
||||
parse_include(config_filename, true, early, 0);
|
||||
parse_state = CMDLINE;
|
||||
if (!remove_args) {
|
||||
(*idx)++;
|
||||
return;
|
||||
}
|
||||
|
||||
parse_state = TOPLEVEL_CONFIG;
|
||||
parse_implied_config_file(config_basedir, NULL, early);
|
||||
parse_state = NETWORK_CONFIG;
|
||||
parse_implied_config_file(config_basedir, chainparams->network_name, early);
|
||||
parse_state = CMDLINE;
|
||||
memmove(argv + *idx, argv + 1 + *idx, (*argc - *idx) * sizeof(char *));
|
||||
(*argc)--;
|
||||
}
|
||||
|
||||
void initial_config_opts(const tal_t *ctx,
|
||||
/* Now all options are known, we can turn cmdline into configvars */
|
||||
static struct configvar **gather_cmdline_args(const tal_t *ctx,
|
||||
int *argc, char **argv,
|
||||
bool remove_args)
|
||||
{
|
||||
struct configvar **cvs = tal_arr(ctx, struct configvar *, 0);
|
||||
|
||||
assert(argv[*argc] == NULL);
|
||||
for (size_t i = 1; argv[i];) {
|
||||
struct opt_table *ot;
|
||||
const char *configline, *arg, *optarg;
|
||||
enum configvar_src src;
|
||||
bool extra_arg;
|
||||
|
||||
/* End of options? */
|
||||
if (streq(argv[i], "--"))
|
||||
break;
|
||||
|
||||
if (!strstarts(argv[i], "-")) {
|
||||
i++;
|
||||
continue;
|
||||
}
|
||||
|
||||
if (strstarts(argv[i], "--")) {
|
||||
arg = argv[i] + 2;
|
||||
ot = opt_find_long(arg, &optarg);
|
||||
src = CONFIGVAR_CMDLINE;
|
||||
} else {
|
||||
/* FIXME: We don't handle multiple short
|
||||
* options here! */
|
||||
arg = argv[i] + 1;
|
||||
ot = opt_find_short(arg[0]);
|
||||
optarg = NULL;
|
||||
src = CONFIGVAR_CMDLINE_SHORT;
|
||||
}
|
||||
if (ot) {
|
||||
extra_arg = (ot->type & OPT_HASARG) && !optarg;
|
||||
} else {
|
||||
/* Unknown (yet!). Guess if next arg is for this! */
|
||||
extra_arg = ((src == CONFIGVAR_CMDLINE_SHORT
|
||||
|| !strchr(arg, '='))
|
||||
&& argv[i+1]
|
||||
&& !strstarts(argv[i+1], "-"));
|
||||
}
|
||||
finished_arg(argc, argv, &i, remove_args);
|
||||
/* We turn `--foo bar` into `--foo=bar` here */
|
||||
if (extra_arg) {
|
||||
configline = tal_fmt(tmpctx, "%s=%s", arg, argv[i]);
|
||||
finished_arg(argc, argv, &i, remove_args);
|
||||
} else {
|
||||
configline = arg;
|
||||
}
|
||||
tal_arr_expand(&cvs, configvar_new(cvs, src,
|
||||
NULL, 0, configline));
|
||||
}
|
||||
assert(argv[*argc] == NULL);
|
||||
return cvs;
|
||||
}
|
||||
|
||||
void minimal_config_opts(const tal_t *ctx,
|
||||
int argc, char *argv[],
|
||||
char **config_filename,
|
||||
char **config_basedir,
|
||||
char **config_netdir,
|
||||
char **rpc_filename)
|
||||
{
|
||||
char *unused_filename, *unused_basedir;
|
||||
|
||||
initial_config_opts(tmpctx, &argc, argv, false,
|
||||
&unused_filename,
|
||||
&unused_basedir,
|
||||
config_netdir,
|
||||
rpc_filename);
|
||||
tal_steal(ctx, *config_netdir);
|
||||
tal_steal(ctx, *rpc_filename);
|
||||
}
|
||||
|
||||
struct configvar **initial_config_opts(const tal_t *ctx,
|
||||
int *argc, char *argv[],
|
||||
bool remove_args,
|
||||
char **config_filename,
|
||||
char **config_basedir,
|
||||
char **config_netdir,
|
||||
char **rpc_filename)
|
||||
{
|
||||
struct configvar **cmdline_cvs, **config_cvs, **cvs;
|
||||
|
||||
options_ctx = ctx;
|
||||
|
||||
/* First, they could specify a config, which specifies a lightning dir
|
||||
* or a network. */
|
||||
/* This helps opt_usage. */
|
||||
opt_argv0 = argv[0];
|
||||
|
||||
/* Default chain (a global) is bitcoin. */
|
||||
chainparams = chainparams_for_network("bitcoin");
|
||||
|
||||
/* First, they could specify a config, or base dir. */
|
||||
*config_filename = NULL;
|
||||
opt_register_early_arg("--conf=<file>", opt_set_abspath, NULL,
|
||||
config_filename,
|
||||
"Specify configuration file");
|
||||
|
||||
/* Cmdline can also set lightning-dir. */
|
||||
*config_basedir = NULL;
|
||||
opt_register_early_arg("--lightning-dir=<dir>",
|
||||
opt_set_abspath, NULL,
|
||||
config_basedir,
|
||||
"Set base directory: network-specific subdirectory is under here");
|
||||
|
||||
/* Handle --version (and exit) here too */
|
||||
opt_register_version();
|
||||
|
||||
opt_early_parse_incomplete(argc, argv, opt_log_stderr_exit);
|
||||
|
||||
/* Now, reset and ignore --conf option from now on. */
|
||||
opt_free_table();
|
||||
|
||||
/* This is only ever valid on cmdline */
|
||||
opt_register_early_arg("--conf=<file>",
|
||||
opt_restricted_cmdline,
|
||||
/* This doesn't show if NULL! */
|
||||
opt_set_config_filename,
|
||||
/* Doesn't show if it's NULL! */
|
||||
opt_show_charp,
|
||||
config_filename,
|
||||
"Specify configuration file");
|
||||
|
||||
/* If they set --conf it can still set --lightning-dir */
|
||||
if (!*config_filename) {
|
||||
opt_register_early_arg("--lightning-dir=<dir>",
|
||||
opt_restricted_forceconf_only, opt_show_charp,
|
||||
config_basedir,
|
||||
"Set base directory: network-specific subdirectory is under here");
|
||||
} else {
|
||||
opt_register_early_arg("--lightning-dir=<dir>",
|
||||
opt_set_abspath, NULL,
|
||||
config_basedir,
|
||||
"Set base directory: network-specific subdirectory is under here");
|
||||
}
|
||||
|
||||
/* Now, config file (or cmdline) can set network and lightning-dir */
|
||||
|
||||
/* We need to know network early, so we can set defaults (which normal
|
||||
* options can change) and default config_netdir */
|
||||
*config_basedir = default_base_configdir(ctx);
|
||||
opt_register_early_arg("--lightning-dir=<dir>",
|
||||
opt_set_lightning_dir, opt_show_charp,
|
||||
config_basedir,
|
||||
"Set base directory: network-specific subdirectory is under here");
|
||||
opt_register_early_arg("--network", opt_set_network, opt_show_network,
|
||||
NULL,
|
||||
"Select the network parameters (bitcoin, testnet,"
|
||||
@ -355,70 +340,81 @@ void initial_config_opts(const tal_t *ctx,
|
||||
opt_register_early_noarg("--mainnet",
|
||||
opt_set_specific_network, "bitcoin",
|
||||
"Alias for --network=bitcoin");
|
||||
/* Handle --version (and exit) here too */
|
||||
opt_register_version();
|
||||
|
||||
/* For convenience, we set deprecated_apis and rpc_filename now, too */
|
||||
opt_register_early_arg("--allow-deprecated-apis",
|
||||
opt_set_bool_arg, opt_show_bool,
|
||||
&deprecated_apis,
|
||||
"Enable deprecated options, JSONRPC commands, fields, etc.");
|
||||
|
||||
/* Read config file first, since cmdline must override */
|
||||
if (*config_filename)
|
||||
parse_include(*config_filename, true, true, 0);
|
||||
else
|
||||
parse_implied_config_file(*config_basedir, NULL, true);
|
||||
opt_early_parse_incomplete(argc, argv, opt_log_stderr_exit);
|
||||
/* Allow them to override rpc-file too. */
|
||||
*rpc_filename = default_rpcfile(ctx);
|
||||
opt_register_early_arg("--rpc-file", opt_set_talstr, opt_show_charp,
|
||||
rpc_filename,
|
||||
"Set JSON-RPC socket (or /dev/tty)");
|
||||
|
||||
/* We use a global (in common/utils.h) for the chainparams. */
|
||||
if (!chainparams)
|
||||
chainparams = chainparams_for_network("bitcoin");
|
||||
cmdline_cvs = gather_cmdline_args(tmpctx, argc, argv, remove_args);
|
||||
parse_configvars(cmdline_cvs, true, false);
|
||||
|
||||
if (!*config_basedir)
|
||||
*config_basedir = default_base_configdir(ctx);
|
||||
/* Base default or direct config can set network */
|
||||
if (*config_filename) {
|
||||
config_cvs = gather_file_configvars(NULL,
|
||||
CONFIGVAR_EXPLICIT_CONF,
|
||||
*config_filename, true, 0);
|
||||
} else {
|
||||
struct configvar **base_cvs, **net_cvs;
|
||||
char *dir = path_join(tmpctx, take(path_cwd(NULL)), *config_basedir);
|
||||
/* Optional: .lightning/config */
|
||||
base_cvs = gather_file_configvars(tmpctx,
|
||||
CONFIGVAR_BASE_CONF,
|
||||
path_join(tmpctx, dir, "config"),
|
||||
false, 0);
|
||||
/* This might set network! */
|
||||
parse_configvars(configvar_join(tmpctx, base_cvs, cmdline_cvs),
|
||||
true, false);
|
||||
|
||||
/* Now, we can get network config */
|
||||
dir = path_join(tmpctx, dir, chainparams->network_name);
|
||||
net_cvs = gather_file_configvars(tmpctx,
|
||||
CONFIGVAR_NETWORK_CONF,
|
||||
path_join(tmpctx, dir, "config"),
|
||||
false, 0);
|
||||
config_cvs = configvar_join(NULL, take(base_cvs), take(net_cvs));
|
||||
}
|
||||
cvs = configvar_join(ctx, take(config_cvs), cmdline_cvs);
|
||||
|
||||
/* This will be called again, once caller has added their own
|
||||
* early vars! */
|
||||
parse_configvars_early(cvs);
|
||||
|
||||
*config_netdir
|
||||
= path_join(NULL, *config_basedir, chainparams->network_name);
|
||||
|
||||
/* Make sure it's absolute */
|
||||
*config_netdir = path_join(ctx, take(path_cwd(NULL)), take(*config_netdir));
|
||||
|
||||
/* Now, reset and ignore those options from now on. */
|
||||
opt_free_table();
|
||||
|
||||
opt_register_early_arg("--conf=<file>",
|
||||
opt_restricted_cmdline,
|
||||
/* This doesn't show if NULL! */
|
||||
opt_show_charp,
|
||||
config_filename,
|
||||
"Specify configuration file");
|
||||
|
||||
/* This is never in a default config file (since we used the defaults to find it!). */
|
||||
opt_register_early_arg("--lightning-dir=<dir>",
|
||||
opt_restricted_forceconf_only, opt_show_charp,
|
||||
config_basedir,
|
||||
"Set base directory: network-specific subdirectory is under here");
|
||||
opt_register_early_arg("--network",
|
||||
opt_restricted_toplevel, opt_show_network,
|
||||
NULL,
|
||||
"Select the network parameters (bitcoin, testnet,"
|
||||
" signet, regtest, litecoin or litecoin-testnet)");
|
||||
opt_register_early_noarg("--mainnet",
|
||||
opt_restricted_toplevel_noarg, NULL,
|
||||
"Alias for --network=bitcoin");
|
||||
opt_register_early_noarg("--testnet",
|
||||
opt_restricted_toplevel_noarg, NULL,
|
||||
"Alias for --network=testnet");
|
||||
opt_register_early_noarg("--signet",
|
||||
opt_restricted_toplevel_noarg, NULL,
|
||||
"Alias for --network=signet");
|
||||
|
||||
/* They can set this later, it's just less effective. */
|
||||
opt_register_early_arg("--allow-deprecated-apis",
|
||||
opt_set_bool_arg, opt_show_bool,
|
||||
&deprecated_apis,
|
||||
"Enable deprecated options, JSONRPC commands, fields, etc.");
|
||||
|
||||
/* Set this up for when they parse cmdline proper. */
|
||||
*rpc_filename = default_rpcfile(ctx);
|
||||
opt_register_arg("--rpc-file", opt_set_talstr, opt_show_charp,
|
||||
rpc_filename,
|
||||
"Set JSON-RPC socket (or /dev/tty)");
|
||||
return cvs;
|
||||
}
|
||||
|
||||
void parse_configvars_early(struct configvar **cvs)
|
||||
{
|
||||
parse_configvars(cvs, true, false);
|
||||
}
|
||||
|
||||
void parse_configvars_final(struct configvar **cvs,
|
||||
bool full_knowledge)
|
||||
{
|
||||
parse_configvars(cvs, false, full_knowledge);
|
||||
configvar_finalize_overrides(cvs);
|
||||
}
|
||||
|
||||
bool is_restricted_ignored(const void *fn)
|
||||
{
|
||||
return fn == opt_set_specific_network;
|
||||
}
|
||||
|
||||
bool is_restricted_print_if_nonnull(const void *fn)
|
||||
{
|
||||
return fn == opt_set_config_filename;
|
||||
}
|
||||
|
@ -7,26 +7,37 @@
|
||||
* them early. */
|
||||
extern bool deprecated_apis;
|
||||
|
||||
/* Unless overridden, we exit with status 1 when option parsing fails */
|
||||
extern int opt_exitcode;
|
||||
|
||||
/* Helper for options which are tal() strings. */
|
||||
char *opt_set_talstr(const char *arg, char **p);
|
||||
|
||||
/* Initial options setup */
|
||||
void setup_option_allocators(void);
|
||||
|
||||
/* Parse minimal config options and files */
|
||||
void initial_config_opts(const tal_t *ctx,
|
||||
/* Minimal config parsing for tools: use opt_early_parse/opt_parse after */
|
||||
void minimal_config_opts(const tal_t *ctx,
|
||||
int argc, char *argv[],
|
||||
char **config_filename,
|
||||
char **config_basedir,
|
||||
char **config_netdir,
|
||||
char **rpc_filename);
|
||||
|
||||
/* If they specify --conf, we just read that.
|
||||
* Otherwise, we read basedir/config (toplevel), and basedir/<network>/config
|
||||
* (network-level) */
|
||||
void parse_config_files(const char *config_filename,
|
||||
const char *config_basedir,
|
||||
bool early);
|
||||
/* Parse initial config options and files */
|
||||
struct configvar **initial_config_opts(const tal_t *ctx,
|
||||
int *argc, char *argv[],
|
||||
bool remove_args,
|
||||
char **config_filename,
|
||||
char **config_basedir,
|
||||
char **config_netdir,
|
||||
char **rpc_filename);
|
||||
|
||||
/* This is called before we know all the options. */
|
||||
void parse_configvars_early(struct configvar **cvs);
|
||||
|
||||
/* This is called once, after we know all the options (if full_knowledge
|
||||
* is false, ignore unknown non-cmdline options). */
|
||||
void parse_configvars_final(struct configvar **cvs,
|
||||
bool full_knowledge);
|
||||
|
||||
/* For listconfigs to detect. */
|
||||
bool is_restricted_ignored(const void *fn);
|
||||
|
@ -24,7 +24,6 @@ DEVTOOLS_COMMON_OBJS := \
|
||||
common/bolt11.o \
|
||||
common/blockheight_states.o \
|
||||
common/channel_id.o \
|
||||
common/configdir.o \
|
||||
common/decode_array.o \
|
||||
common/features.o \
|
||||
common/fee_states.o \
|
||||
@ -87,7 +86,7 @@ devtools/mkgossip: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/
|
||||
|
||||
devtools/mkencoded: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/mkencoded.o
|
||||
|
||||
devtools/checkchannels: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/configdir.o wire/fromwire.o wire/towire.o devtools/checkchannels.o
|
||||
devtools/checkchannels: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/checkchannels.o common/configdir.o common/configvar.o
|
||||
|
||||
devtools/mkquery: $(DEVTOOLS_COMMON_OBJS) $(BITCOIN_OBJS) wire/fromwire.o wire/towire.o devtools/mkquery.o
|
||||
|
||||
|
@ -414,6 +414,8 @@ static bool print_extra_fields(const struct tlv_field *fields)
|
||||
return ok;
|
||||
}
|
||||
|
||||
bool deprecated_apis = true;
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
const tal_t *ctx = tal(NULL, char);
|
||||
@ -424,7 +426,6 @@ int main(int argc, char *argv[])
|
||||
bool to_hex = false;
|
||||
|
||||
common_setup(argv[0]);
|
||||
deprecated_apis = true;
|
||||
|
||||
opt_set_alloc(opt_allocfn, tal_reallocfn, tal_freefn);
|
||||
opt_register_noarg("--help|-h", opt_usage_and_exit,
|
||||
|
@ -109,7 +109,7 @@ static void copy_column(void *dst, size_t size,
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
{
|
||||
char *config_dir, *net_dir, *config_filename, *rpc_filename, *hsmfile, *dbfile;
|
||||
char *net_dir, *rpc_filename, *hsmfile, *dbfile;
|
||||
sqlite3 *sql;
|
||||
sqlite3_stmt *stmt;
|
||||
int flags = SQLITE_OPEN_READONLY, dberr;
|
||||
@ -124,14 +124,13 @@ int main(int argc, char *argv[])
|
||||
|
||||
setup_option_allocators();
|
||||
|
||||
initial_config_opts(top_ctx, argc, argv,
|
||||
&config_filename, &config_dir, &net_dir,
|
||||
&rpc_filename);
|
||||
minimal_config_opts(top_ctx, argc, argv, &net_dir, &rpc_filename);
|
||||
|
||||
opt_register_noarg("-v|--verbose", opt_set_bool, &verbose,
|
||||
"Print everything");
|
||||
|
||||
opt_parse(&argc, argv, opt_log_stderr_exit);
|
||||
|
||||
if (argc != 1)
|
||||
errx(1, "no arguments accepted");
|
||||
|
||||
|
@ -85,6 +85,7 @@ LIGHTNINGD_COMMON_OBJS := \
|
||||
common/channel_type.o \
|
||||
common/coin_mvt.o \
|
||||
common/configdir.o \
|
||||
common/configvar.o \
|
||||
common/daemon.o \
|
||||
common/derive_basepoints.o \
|
||||
common/ecdh_hsmd.o \
|
||||
|
@ -1020,7 +1020,7 @@ int main(int argc, char *argv[])
|
||||
fatal("Could not initialize the plugins, see above for details.");
|
||||
|
||||
/*~ Handle options and config. */
|
||||
handle_opts(ld, argc, argv);
|
||||
handle_opts(ld);
|
||||
|
||||
/*~ Now create the PID file: this errors out if there's already a
|
||||
* daemon running, so we call before doing almost anything else. */
|
||||
|
@ -128,6 +128,8 @@ struct lightningd {
|
||||
char *config_filename;
|
||||
/* Configuration settings. */
|
||||
struct config config;
|
||||
/* Where each configuration setting came from */
|
||||
struct configvar **configvars;
|
||||
|
||||
/* This log_book is owned by all the struct logs */
|
||||
struct log_book *log_book;
|
||||
|
@ -27,20 +27,6 @@
|
||||
#include <sys/stat.h>
|
||||
#include <sys/wait.h>
|
||||
|
||||
/* Unless overridden, we exit with status 1 when option parsing fails */
|
||||
static int opt_exitcode = 1;
|
||||
|
||||
static void opt_log_stderr_exitcode(const char *fmt, ...)
|
||||
{
|
||||
va_list ap;
|
||||
|
||||
va_start(ap, fmt);
|
||||
vfprintf(stderr, fmt, ap);
|
||||
fprintf(stderr, "\n");
|
||||
va_end(ap);
|
||||
exit(opt_exitcode);
|
||||
}
|
||||
|
||||
/* FIXME: Put into ccan/time. */
|
||||
#define TIME_FROM_SEC(sec) { { .tv_nsec = 0, .tv_sec = sec } }
|
||||
#define TIME_FROM_MSEC(msec) \
|
||||
@ -1562,11 +1548,14 @@ void handle_early_opts(struct lightningd *ld, int argc, char *argv[])
|
||||
ld, opt_hidden);
|
||||
|
||||
/*~ This does enough parsing to get us the base configuration options */
|
||||
initial_config_opts(ld, argc, argv,
|
||||
&ld->config_filename,
|
||||
&ld->config_basedir,
|
||||
&ld->config_netdir,
|
||||
&ld->rpc_filename);
|
||||
ld->configvars = initial_config_opts(ld, &argc, argv, true,
|
||||
&ld->config_filename,
|
||||
&ld->config_basedir,
|
||||
&ld->config_netdir,
|
||||
&ld->rpc_filename);
|
||||
|
||||
if (argc != 1)
|
||||
errx(1, "no arguments accepted");
|
||||
|
||||
/* Copy in default config, to be modified by further options */
|
||||
if (chainparams->testnet)
|
||||
@ -1611,28 +1600,20 @@ void handle_early_opts(struct lightningd *ld, int argc, char *argv[])
|
||||
* mimic this API here, even though they're on separate lines.*/
|
||||
register_opts(ld);
|
||||
|
||||
/* Now look inside config file(s), but only handle the early
|
||||
/* Now, first-pass of parsing. But only handle the early
|
||||
* options (testnet, plugins etc), others may be added on-demand */
|
||||
parse_config_files(ld->config_filename, ld->config_basedir, true);
|
||||
|
||||
/* Early cmdline options now override config file options. */
|
||||
opt_early_parse_incomplete(argc, argv, opt_log_stderr_exit);
|
||||
parse_configvars_early(ld->configvars);
|
||||
|
||||
/* Finalize the logging subsystem now. */
|
||||
logging_options_parsed(ld->log_book);
|
||||
}
|
||||
|
||||
void handle_opts(struct lightningd *ld, int argc, char *argv[])
|
||||
void handle_opts(struct lightningd *ld)
|
||||
{
|
||||
/* Now look for config file, but only handle non-early
|
||||
* options, early ones have been parsed in
|
||||
* handle_early_opts */
|
||||
parse_config_files(ld->config_filename, ld->config_basedir, false);
|
||||
/* Now we know all the options, finish parsing and finish
|
||||
* populating ld->configvars with cmdline. */
|
||||
parse_configvars_final(ld->configvars, true);
|
||||
|
||||
/* Now parse cmdline, which overrides config. */
|
||||
opt_parse(&argc, argv, opt_log_stderr_exitcode);
|
||||
if (argc != 1)
|
||||
errx(1, "no arguments accepted");
|
||||
/* We keep a separate variable rather than overriding always_use_proxy,
|
||||
* so listconfigs shows the correct thing. */
|
||||
if (tal_count(ld->proposed_wireaddr) != 0
|
||||
@ -1784,7 +1765,7 @@ static void add_config(struct lightningd *ld,
|
||||
* OPT_HASARG options. */
|
||||
} else {
|
||||
/* Insert more decodes here! */
|
||||
assert(!"A noarg option was added but was not handled");
|
||||
errx(1, "Unknown decode for %s", opt->names);
|
||||
}
|
||||
} else if (opt->type & OPT_HASARG) {
|
||||
if (opt->desc == opt_hidden) {
|
||||
@ -1886,7 +1867,7 @@ static void add_config(struct lightningd *ld,
|
||||
#endif
|
||||
} else {
|
||||
/* Insert more decodes here! */
|
||||
abort();
|
||||
errx(1, "Unknown decode for %s", opt->names);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -9,7 +9,7 @@ struct lightningd;
|
||||
void handle_early_opts(struct lightningd *ld, int argc, char *argv[]);
|
||||
|
||||
/* After this we're in the .lightning dir, and we've parsed all options */
|
||||
void handle_opts(struct lightningd *ld, int argc, char *argv[]);
|
||||
void handle_opts(struct lightningd *ld);
|
||||
|
||||
/* Derive default color and alias from the pubkey. */
|
||||
void setup_color_and_alias(struct lightningd *ld);
|
||||
|
@ -99,7 +99,7 @@ void gossip_notify_new_block(struct lightningd *ld UNNEEDED, u32 blockheight UNN
|
||||
void handle_early_opts(struct lightningd *ld UNNEEDED, int argc UNNEEDED, char *argv[])
|
||||
{ fprintf(stderr, "handle_early_opts called!\n"); abort(); }
|
||||
/* Generated stub for handle_opts */
|
||||
void handle_opts(struct lightningd *ld UNNEEDED, int argc UNNEEDED, char *argv[])
|
||||
void handle_opts(struct lightningd *ld UNNEEDED)
|
||||
{ fprintf(stderr, "handle_opts called!\n"); abort(); }
|
||||
/* Generated stub for hash_htlc_key */
|
||||
size_t hash_htlc_key(const struct htlc_key *htlc_key UNNEEDED)
|
||||
|
@ -20,6 +20,7 @@ FUZZ_COMMON_OBJS := \
|
||||
common/channel_config.o \
|
||||
common/close_tx.o \
|
||||
common/configdir.o \
|
||||
common/configvar.o \
|
||||
common/channel_id.o \
|
||||
common/channel_type.o \
|
||||
common/daemon.o \
|
||||
|
@ -2253,7 +2253,7 @@ def test_config_in_subdir(node_factory, chainparams):
|
||||
|
||||
out = subprocess.run(['lightningd/lightningd',
|
||||
'--lightning-dir={}'.format(l1.daemon.opts.get("lightning-dir"))],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE, timeout=TIMEOUT)
|
||||
assert out.returncode == 1
|
||||
assert "conf: not permitted in configuration files" in out.stderr.decode('utf-8')
|
||||
|
||||
@ -2272,7 +2272,7 @@ def test_config_in_subdir(node_factory, chainparams):
|
||||
'--lightning-dir={}'.format(l1.daemon.opts.get("lightning-dir"))],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
assert out.returncode == 1
|
||||
assert "network: not permitted in network-specific configuration files" in out.stderr.decode('utf-8')
|
||||
assert "network={}: not permitted in network-specific configuration files".format(network) in out.stderr.decode('utf-8')
|
||||
|
||||
# lightning-dir only allowed if we explicitly use --conf
|
||||
os.unlink(os.path.join(subdir, "config"))
|
||||
@ -2283,7 +2283,7 @@ def test_config_in_subdir(node_factory, chainparams):
|
||||
'--lightning-dir={}'.format(l1.daemon.opts.get("lightning-dir"))],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
assert out.returncode == 1
|
||||
assert "lightning-dir: not permitted in implicit configuration files" in out.stderr.decode('utf-8')
|
||||
assert "lightning-dir={}/test: not permitted in implicit configuration files".format(l1.daemon.opts.get("lightning-dir")) in out.stderr.decode('utf-8')
|
||||
|
||||
l1.daemon.opts['conf'] = os.path.join(l1.daemon.opts.get("lightning-dir"), "config")
|
||||
l1.start()
|
||||
|
@ -113,7 +113,7 @@ def test_option_types(node_factory):
|
||||
# the node should fail after start, and we get a stderr msg
|
||||
n.daemon.start(wait_for_initialized=False, stderr_redir=True)
|
||||
assert n.daemon.wait() == 1
|
||||
wait_for(lambda: n.daemon.is_in_stderr('bool_opt: ! does not parse as type bool'))
|
||||
wait_for(lambda: n.daemon.is_in_stderr('--bool_opt=!: ! does not parse as type bool'))
|
||||
|
||||
# What happens if we give it a bad int-option?
|
||||
n = node_factory.get_node(options={
|
||||
@ -126,7 +126,7 @@ def test_option_types(node_factory):
|
||||
# the node should fail after start, and we get a stderr msg
|
||||
n.daemon.start(wait_for_initialized=False, stderr_redir=True)
|
||||
assert n.daemon.wait() == 1
|
||||
assert n.daemon.is_in_stderr('--int_opt: notok does not parse as type int')
|
||||
assert n.daemon.is_in_stderr('--int_opt=notok: notok does not parse as type int')
|
||||
|
||||
# Flag opts shouldn't allow any input
|
||||
n = node_factory.get_node(options={
|
||||
@ -140,7 +140,7 @@ def test_option_types(node_factory):
|
||||
# the node should fail after start, and we get a stderr msg
|
||||
n.daemon.start(wait_for_initialized=False, stderr_redir=True)
|
||||
assert n.daemon.wait() == 1
|
||||
assert n.daemon.is_in_stderr("--flag_opt: doesn't allow an argument")
|
||||
assert n.daemon.is_in_stderr("--flag_opt=True: doesn't allow an argument")
|
||||
|
||||
n = node_factory.get_node(options={
|
||||
'plugin': plugin_path,
|
||||
@ -1568,7 +1568,7 @@ def test_libplugin(node_factory):
|
||||
l1.daemon.start(wait_for_initialized=False, stderr_redir=True)
|
||||
# Will exit with failure code.
|
||||
assert l1.daemon.wait() == 1
|
||||
assert l1.daemon.is_in_stderr(r"somearg-deprecated: deprecated option")
|
||||
assert l1.daemon.is_in_stderr(r"somearg-deprecated=test_opt: deprecated option")
|
||||
|
||||
del l1.daemon.opts["somearg-deprecated"]
|
||||
l1.start()
|
||||
|
@ -17,7 +17,7 @@ tools/headerversions: $(FORCE) tools/headerversions.o libccan.a
|
||||
|
||||
tools/check-bolt: tools/check-bolt.o $(TOOLS_COMMON_OBJS)
|
||||
|
||||
tools/hsmtool: tools/hsmtool.o $(TOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/amount.o common/autodata.o common/bech32.o common/bigsize.o common/configdir.o common/derive_basepoints.o common/descriptor_checksum.o common/hsm_encryption.o common/node_id.o common/type_to_string.o common/version.o wire/fromwire.o wire/towire.o
|
||||
tools/hsmtool: tools/hsmtool.o $(TOOLS_COMMON_OBJS) $(BITCOIN_OBJS) common/amount.o common/autodata.o common/bech32.o common/bigsize.o common/configdir.o common/configvar.o common/derive_basepoints.o common/descriptor_checksum.o common/hsm_encryption.o common/node_id.o common/type_to_string.o common/version.o wire/fromwire.o wire/towire.o
|
||||
|
||||
tools/lightning-hsmtool: tools/hsmtool
|
||||
cp $< $@
|
||||
|
Loading…
Reference in New Issue
Block a user