summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDavid Goulet <dgoulet@torproject.org>2019-09-11 09:42:31 -0400
committerDavid Goulet <dgoulet@torproject.org>2019-09-11 09:42:31 -0400
commit41261c3b5cd505f5a601c319eb484866903814af (patch)
tree3264e3e0293865ab9012d53aaf835f3713d8c6ef
parent049705fc1c9d1c0cee120dc8cbd1a719c6e45e85 (diff)
parent478141e617a333ac4d998e3747c073246e04b5ae (diff)
downloadtor-41261c3b5cd505f5a601c319eb484866903814af.tar.gz
tor-41261c3b5cd505f5a601c319eb484866903814af.zip
Merge branch 'tor-github/pr/1296'
-rw-r--r--changes/ticket316254
-rw-r--r--src/app/config/config.c13
-rw-r--r--src/app/config/confparse.c124
-rw-r--r--src/app/config/confparse.h5
-rw-r--r--src/lib/conf/confmacros.h2
-rw-r--r--src/lib/conf/conftypes.h58
-rw-r--r--src/lib/confmgt/structvar.c23
-rw-r--r--src/lib/confmgt/structvar.h5
-rw-r--r--src/lib/confmgt/type_defs.c22
-rw-r--r--src/lib/confmgt/typedvar.c29
-rw-r--r--src/lib/confmgt/typedvar.h4
-rw-r--r--src/lib/confmgt/var_type_def_st.h16
-rw-r--r--src/test/include.am6
-rwxr-xr-xsrc/test/test_cmdline.sh48
-rw-r--r--src/test/test_config.c26
15 files changed, 269 insertions, 116 deletions
diff --git a/changes/ticket31625 b/changes/ticket31625
new file mode 100644
index 0000000000..822a921e4f
--- /dev/null
+++ b/changes/ticket31625
@@ -0,0 +1,4 @@
+ o Code simplification and refactoring:
+ - Replace our ad-hoc set of flags for configuration variables and
+ configuration variable types with fine-grained orthogonal flags
+ corresponding to the actual behavior we want. Closes ticket 31625.
diff --git a/src/app/config/config.c b/src/app/config/config.c
index 1babb0d4f8..b4bccd9351 100644
--- a/src/app/config/config.c
+++ b/src/app/config/config.c
@@ -267,10 +267,10 @@ DUMMY_TYPECHECK_INSTANCE(or_options_t);
#define VAR_NODUMP(varname,conftype,member,initvalue) \
CONFIG_VAR_ETYPE(or_options_t, varname, conftype, member, \
- CVFLAG_NODUMP, initvalue)
+ CFLG_NODUMP, initvalue)
#define VAR_INVIS(varname,conftype,member,initvalue) \
CONFIG_VAR_ETYPE(or_options_t, varname, conftype, member, \
- CVFLAG_NODUMP|CVFLAG_INVISIBLE, initvalue)
+ CFLG_NODUMP | CFLG_NOSET | CFLG_NOLIST, initvalue)
#define V(member,conftype,initvalue) \
VAR(#member, conftype, member, initvalue)
@@ -2671,6 +2671,9 @@ list_torrc_options(void)
{
smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
+ /* Possibly this should check listable, rather than (or in addition to)
+ * settable. See ticket 31654.
+ */
if (! config_var_is_settable(var)) {
/* This variable cannot be set, or cannot be set by this name. */
continue;
@@ -2685,6 +2688,8 @@ static void
list_deprecated_options(void)
{
smartlist_t *deps = config_mgr_list_deprecated_vars(get_options_mgr());
+ /* Possibly this should check whether the variables are listable,
+ * but currently it does not. See ticket 31654. */
SMARTLIST_FOREACH(deps, const char *, name,
printf("%s\n", name));
smartlist_free(deps);
@@ -8133,7 +8138,7 @@ getinfo_helper_config(control_connection_t *conn,
smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
/* don't tell controller about invisible options */
- if (config_var_is_invisible(var))
+ if (! config_var_is_listable(var))
continue;
const char *type = struct_var_get_typename(&var->member);
if (!type)
@@ -8147,6 +8152,8 @@ getinfo_helper_config(control_connection_t *conn,
} else if (!strcmp(question, "config/defaults")) {
smartlist_t *sl = smartlist_new();
int dirauth_lines_seen = 0, fallback_lines_seen = 0;
+ /* Possibly this should check whether the variables are listable,
+ * but currently it does not. See ticket 31654. */
smartlist_t *vars = config_mgr_list_vars(get_options_mgr());
SMARTLIST_FOREACH_BEGIN(vars, const config_var_t *, var) {
if (var->initvalue != NULL) {
diff --git a/src/app/config/confparse.c b/src/app/config/confparse.c
index 0e941bab6c..9f7fdc5c35 100644
--- a/src/app/config/confparse.c
+++ b/src/app/config/confparse.c
@@ -511,32 +511,112 @@ config_count_options(const config_mgr_t *mgr)
return smartlist_len(mgr->all_vars);
}
-bool
-config_var_is_cumulative(const config_var_t *var)
+/**
+ * Return true iff at least one bit from <b>flag</b> is set on <b>var</b>,
+ * either in <b>var</b>'s flags, or on the flags of its type.
+ **/
+static bool
+config_var_has_flag(const config_var_t *var, uint32_t flag)
{
- return struct_var_is_cumulative(&var->member);
+ uint32_t have_flags = var->flags | struct_var_get_flags(&var->member);
+
+ return (have_flags & flag) != 0;
}
+
+/**
+ * Return true if assigning a value to <b>var</b> replaces the previous
+ * value. Return false if assigning a value to <b>var</b> appends
+ * to the previous value.
+ **/
+static bool
+config_var_is_replaced_on_set(const config_var_t *var)
+{
+ return ! config_var_has_flag(var, CFLG_NOREPLACE);
+}
+
+/**
+ * Return true iff <b>var</b> may be assigned by name (e.g., via the
+ * CLI, the configuration files, or the controller API).
+ **/
bool
config_var_is_settable(const config_var_t *var)
{
- if (var->flags & CVFLAG_OBSOLETE)
- return false;
- return struct_var_is_settable(&var->member);
+ return ! config_var_has_flag(var, CFLG_NOSET);
}
-bool
-config_var_is_contained(const config_var_t *var)
+
+/**
+ * Return true iff the controller is allowed to fetch the value of
+ * <b>var</b>.
+ **/
+static bool
+config_var_is_gettable(const config_var_t *var)
{
- return struct_var_is_contained(&var->member);
+ /* Arguably, invisible or obsolete options should not be gettable. However,
+ * they have been gettable for a long time, and making them ungettable could
+ * have compatibility effects. For now, let's leave them alone.
+ */
+
+ // return ! config_var_has_flag(var, CVFLAG_OBSOLETE|CFGLAGS_INVISIBLE);
+ (void)var;
+ return true;
}
-bool
-config_var_is_invisible(const config_var_t *var)
+
+/**
+ * Return true iff we need to check <b>var</b> for changes when we are
+ * comparing config options for changes.
+ *
+ * A false result might mean that the variable is a derived variable, and that
+ * comparing the variable it derives from compares this one too-- or it might
+ * mean that there is no data to compare.
+ **/
+static bool
+config_var_should_list_changes(const config_var_t *var)
{
- return (var->flags & CVFLAG_INVISIBLE) != 0;
+ return ! config_var_has_flag(var, CFLG_NOCMP);
}
+
+/**
+ * Return true iff we need to copy the data for <b>var</b> when we are
+ * copying a config option.
+ *
+ * A false option might mean that the variable is a derived variable, and that
+ * copying the variable it derives from copies it-- or it might mean that
+ * there is no data to copy.
+ **/
+static bool
+config_var_needs_copy(const config_var_t *var)
+{
+ return ! config_var_has_flag(var, CFLG_NOCOPY);
+}
+
+/**
+ * Return true iff variable <b>var</b> should appear on list of variable
+ * names given to the controller or the CLI.
+ *
+ * (Note that this option is imperfectly obeyed. The
+ * --list-torrc-options command looks at the "settable" flag, whereas
+ * "GETINFO config/defaults" and "list_deprecated_*()" do not filter
+ * their results. It would be good for consistency to try to converge
+ * these behaviors in the future.)
+ **/
bool
+config_var_is_listable(const config_var_t *var)
+{
+ return ! config_var_has_flag(var, CFLG_NOLIST);
+}
+
+/**
+ * Return true iff variable <b>var</b> should be written out when we
+ * are writing our configuration to disk, to a controller, or via the
+ * --dump-config command.
+ *
+ * This option may be set because a variable is hidden, or because it is
+ * derived from another variable which will already be written out.
+ **/
+static bool
config_var_is_dumpable(const config_var_t *var)
{
- return (var->flags & CVFLAG_NODUMP) == 0;
+ return ! config_var_has_flag(var, CFLG_NODUMP);
}
/*
@@ -650,7 +730,8 @@ config_assign_line(const config_mgr_t *mgr, void *options,
if (!strlen(c->value)) {
/* reset or clear it, then return */
if (!clear_first) {
- if (config_var_is_cumulative(cvar) && c->command != CONFIG_LINE_CLEAR) {
+ if (! config_var_is_replaced_on_set(cvar) &&
+ c->command != CONFIG_LINE_CLEAR) {
/* We got an empty linelist from the torrc or command line.
As a special case, call this an error. Warn and ignore. */
log_warn(LD_CONFIG,
@@ -671,7 +752,7 @@ config_assign_line(const config_mgr_t *mgr, void *options,
// LCOV_EXCL_STOP
}
- if (options_seen && ! config_var_is_cumulative(cvar)) {
+ if (options_seen && config_var_is_replaced_on_set(cvar)) {
/* We're tracking which options we've seen, and this option is not
* supposed to occur more than once. */
tor_assert(var_index >= 0);
@@ -750,6 +831,11 @@ config_get_assigned_option(const config_mgr_t *mgr, const void *options,
log_warn(LD_CONFIG, "Unknown option '%s'. Failing.", key);
return NULL;
}
+ if (! config_var_is_gettable(var->cvar)) {
+ log_warn(LD_CONFIG, "Option '%s' is obsolete or unfetchable. Failing.",
+ key);
+ return NULL;
+ }
const void *object = config_mgr_get_obj(mgr, options, var->object_idx);
result = struct_var_kvencode(object, &var->cvar->member);
@@ -989,7 +1075,7 @@ config_get_changes(const config_mgr_t *mgr,
config_line_t *result = NULL;
config_line_t **next = &result;
SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
- if (config_var_is_contained(mv->cvar)) {
+ if (! config_var_should_list_changes(mv->cvar)) {
/* something else will check this var, or it doesn't need checking */
continue;
}
@@ -1025,7 +1111,7 @@ config_dup(const config_mgr_t *mgr, const void *old)
newopts = config_new(mgr);
SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
- if (config_var_is_contained(mv->cvar)) {
+ if (! config_var_needs_copy(mv->cvar)) {
// Something else will copy this option, or it doesn't need copying.
continue;
}
@@ -1092,10 +1178,6 @@ config_dump(const config_mgr_t *mgr, const void *default_options,
elements = smartlist_new();
SMARTLIST_FOREACH_BEGIN(mgr->all_vars, managed_var_t *, mv) {
int comment_option = 0;
- if (config_var_is_contained(mv->cvar)) {
- // Something else will dump this option, or it doesn't need dumping.
- continue;
- }
/* Don't save 'hidden' control variables. */
if (! config_var_is_dumpable(mv->cvar))
continue;
diff --git a/src/app/config/confparse.h b/src/app/config/confparse.h
index 6a7a567273..054348d8d4 100644
--- a/src/app/config/confparse.h
+++ b/src/app/config/confparse.h
@@ -189,11 +189,8 @@ const char *config_expand_abbrev(const config_mgr_t *mgr,
int command_line, int warn_obsolete);
void warn_deprecated_option(const char *what, const char *why);
-bool config_var_is_cumulative(const config_var_t *var);
bool config_var_is_settable(const config_var_t *var);
-bool config_var_is_contained(const config_var_t *var);
-bool config_var_is_invisible(const config_var_t *var);
-bool config_var_is_dumpable(const config_var_t *var);
+bool config_var_is_listable(const config_var_t *var);
/* Helper macros to compare an option across two configuration objects */
#define CFG_EQ_BOOL(a,b,opt) ((a)->opt == (b)->opt)
diff --git a/src/lib/conf/confmacros.h b/src/lib/conf/confmacros.h
index 2a15f09aac..68121891f1 100644
--- a/src/lib/conf/confmacros.h
+++ b/src/lib/conf/confmacros.h
@@ -61,7 +61,7 @@
#define CONFIG_VAR_OBSOLETE(varname) \
{ .member = { .name = varname, .type = CONFIG_TYPE_OBSOLETE }, \
- .flags = CVFLAG_OBSOLETE \
+ .flags = CFLG_GROUP_OBSOLETE \
}
#endif /* !defined(TOR_LIB_CONF_CONFMACROS_H) */
diff --git a/src/lib/conf/conftypes.h b/src/lib/conf/conftypes.h
index 4609564b34..274065cff2 100644
--- a/src/lib/conf/conftypes.h
+++ b/src/lib/conf/conftypes.h
@@ -132,22 +132,58 @@ typedef struct struct_magic_decl_t {
} struct_magic_decl_t;
/**
- * Flag to indicate that an option is obsolete. Any attempt to set or
- * fetch this option should produce a warning.
+ * Flag to indicate that an option or type is "undumpable". An
+ * undumpable option is never saved to disk.
+ *
+ * For historical reasons its name is usually is prefixed with __.
+ **/
+#define CFLG_NODUMP (1u<<0)
+/**
+ * Flag to indicate that an option or type is "unlisted".
+ *
+ * We don't tell the controller about unlisted options when it asks for a
+ * list of them.
**/
-#define CVFLAG_OBSOLETE (1u<<0)
+#define CFLG_NOLIST (1u<<1)
/**
- * Flag to indicate that an option is undumpable. An undumpable option is
- * never saved to disk. For historical reasons it is prefixed with __ but
- * not with ___.
+ * Flag to indicate that an option or type is "unsettable".
+ *
+ * An unsettable option can never be set directly by name.
+ **/
+#define CFLG_NOSET (1u<<2)
+/**
+ * Flag to indicate that an option or type does not need to be copied when
+ * copying the structure that contains it.
+ *
+ * (Usually, if an option does not need to be copied, then either it contains
+ * no data, or the data that it does contain is completely contained within
+ * another option.)
**/
-#define CVFLAG_NODUMP (1u<<1)
+#define CFLG_NOCOPY (1u<<3)
+/**
+ * Flag to indicate that an option or type does not need to be compared
+ * when telling the controller about the differences between two
+ * configurations.
+ *
+ * (Usually, if an option does not need to be compared, then either it
+ * contains no data, or the data that it does contain is completely contained
+ * within another option.)
+ **/
+#define CFLG_NOCMP (1u<<4)
+/**
+ * Flag to indicate that an option or type should not be replaced when setting
+ * it.
+ *
+ * For most options, setting them replaces their old value. For some options,
+ * however, setting them appends to their old value.
+ */
+#define CFLG_NOREPLACE (1u<<5)
+
/**
- * Flag to indicate that an option is "invisible". An invisible option
- * is always undumpable, and we don't tell the controller about it.
- * For historical reasons it is prefixed with ___.
+ * A group of flags that should be set on all obsolete options and types.
**/
-#define CVFLAG_INVISIBLE (1u<<2)
+#define CFLG_GROUP_OBSOLETE \
+ (CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP|CFLG_NOSET|CFLG_NOLIST)
/** A variable allowed in the configuration file or on the command line. */
typedef struct config_var_t {
diff --git a/src/lib/confmgt/structvar.c b/src/lib/confmgt/structvar.c
index 75edda2c38..de678d18c8 100644
--- a/src/lib/confmgt/structvar.c
+++ b/src/lib/confmgt/structvar.c
@@ -211,26 +211,11 @@ struct_var_get_typename(const struct_member_t *member)
return def ? def->name : NULL;
}
-bool
-struct_var_is_cumulative(const struct_member_t *member)
-{
- const var_type_def_t *def = get_type_def(member);
-
- return def ? def->is_cumulative : false;
-}
-
-bool
-struct_var_is_settable(const struct_member_t *member)
-{
- const var_type_def_t *def = get_type_def(member);
-
- return def ? !def->is_unsettable : true;
-}
-
-bool
-struct_var_is_contained(const struct_member_t *member)
+/** Return all of the flags set for this struct member. */
+uint32_t
+struct_var_get_flags(const struct_member_t *member)
{
const var_type_def_t *def = get_type_def(member);
- return def ? def->is_contained : false;
+ return def ? def->flags : 0;
}
diff --git a/src/lib/confmgt/structvar.h b/src/lib/confmgt/structvar.h
index 9783d1ec27..bcb4b58c3f 100644
--- a/src/lib/confmgt/structvar.h
+++ b/src/lib/confmgt/structvar.h
@@ -17,6 +17,7 @@ struct struct_member_t;
struct config_line_t;
#include <stdbool.h>
+#include "lib/cc/torint.h"
void struct_set_magic(void *object,
const struct struct_magic_decl_t *decl);
@@ -41,9 +42,7 @@ void struct_var_mark_fragile(void *object,
const char *struct_var_get_name(const struct struct_member_t *member);
const char *struct_var_get_typename(const struct struct_member_t *member);
-bool struct_var_is_cumulative(const struct struct_member_t *member);
-bool struct_var_is_settable(const struct struct_member_t *member);
-bool struct_var_is_contained(const struct struct_member_t *member);
+uint32_t struct_var_get_flags(const struct struct_member_t *member);
int struct_var_kvassign(void *object, const struct config_line_t *line,
char **errmsg,
diff --git a/src/lib/confmgt/type_defs.c b/src/lib/confmgt/type_defs.c
index f8b2681aa0..324b62e56c 100644
--- a/src/lib/confmgt/type_defs.c
+++ b/src/lib/confmgt/type_defs.c
@@ -725,16 +725,22 @@ static const var_type_def_t type_definitions_table[] = {
[CONFIG_TYPE_CSV_INTERVAL] = { .name="TimeInterval",
.fns=&legacy_csv_interval_fns, },
[CONFIG_TYPE_LINELIST] = { .name="LineList", .fns=&linelist_fns,
- .is_cumulative=true},
+ .flags=CFLG_NOREPLACE },
+ /*
+ * A "linelist_s" is a derived view of a linelist_v: inspecting
+ * it gets part of a linelist_v, and setting it adds to the linelist_v.
+ */
[CONFIG_TYPE_LINELIST_S] = { .name="Dependent", .fns=&linelist_s_fns,
- .is_cumulative=true,
- .is_contained=true, },
+ .flags=CFLG_NOREPLACE|
+ /* The operations we disable here are
+ * handled by the linelist_v. */
+ CFLG_NOCOPY|CFLG_NOCMP|CFLG_NODUMP },
[CONFIG_TYPE_LINELIST_V] = { .name="Virtual", .fns=&linelist_v_fns,
- .is_cumulative=true,
- .is_unsettable=true },
- [CONFIG_TYPE_OBSOLETE] = { .name="Obsolete", .fns=&ignore_fns,
- .is_unsettable=true,
- .is_contained=true, }
+ .flags=CFLG_NOREPLACE|CFLG_NOSET },
+ [CONFIG_TYPE_OBSOLETE] = {
+ .name="Obsolete", .fns=&ignore_fns,
+ .flags=CFLG_GROUP_OBSOLETE,
+ }
};
/**
diff --git a/src/lib/confmgt/typedvar.c b/src/lib/confmgt/typedvar.c
index 43040e1e05..219a2d15bc 100644
--- a/src/lib/confmgt/typedvar.c
+++ b/src/lib/confmgt/typedvar.c
@@ -225,32 +225,3 @@ typed_var_mark_fragile(void *value, const var_type_def_t *def)
if (def->fns->mark_fragile)
def->fns->mark_fragile(value, def->params);
}
-
-/**
- * Return true iff multiple assignments to a variable will extend its
- * value, rather than replacing it.
- **/
-bool
-var_type_is_cumulative(const var_type_def_t *def)
-{
- return def->is_cumulative;
-}
-
-/**
- * Return true iff this variable type is always contained in another variable,
- * and as such doesn't need to be dumped or copied independently.
- **/
-bool
-var_type_is_contained(const var_type_def_t *def)
-{
- return def->is_contained;
-}
-
-/**
- * Return true iff this type can not be assigned directly by the user.
- **/
-bool
-var_type_is_settable(const var_type_def_t *def)
-{
- return ! def->is_unsettable;
-}
diff --git a/src/lib/confmgt/typedvar.h b/src/lib/confmgt/typedvar.h
index 23fd8c13e4..22f2e3c58e 100644
--- a/src/lib/confmgt/typedvar.h
+++ b/src/lib/confmgt/typedvar.h
@@ -35,8 +35,4 @@ struct config_line_t *typed_var_kvencode(const char *key, const void *value,
void typed_var_mark_fragile(void *value, const var_type_def_t *def);
-bool var_type_is_cumulative(const var_type_def_t *def);
-bool var_type_is_contained(const var_type_def_t *def);
-bool var_type_is_settable(const var_type_def_t *def);
-
#endif /* !defined(TOR_LIB_CONFMGT_TYPEDVAR_H) */
diff --git a/src/lib/confmgt/var_type_def_st.h b/src/lib/confmgt/var_type_def_st.h
index 4157cb8ff6..f1131ff116 100644
--- a/src/lib/confmgt/var_type_def_st.h
+++ b/src/lib/confmgt/var_type_def_st.h
@@ -151,17 +151,11 @@ struct var_type_def_t {
* calling the functions in this type's function table.
*/
const void *params;
-
- /** True iff a variable of this type can never be set directly by name. */
- bool is_unsettable;
- /** True iff a variable of this type is always contained in another
- * variable, and as such doesn't need to be dumped or copied
- * independently. */
- bool is_contained;
- /** True iff a variable of this type can be set more than once without
- * destroying older values. Such variables should implement "mark_fragile".
- */
- bool is_cumulative;
+ /**
+ * A bitwise OR of one or more VTFLAG_* values, describing properties
+ * for all values of this type.
+ **/
+ uint32_t flags;
};
#endif /* !defined(TOR_LIB_CONFMGT_VAR_TYPE_DEF_ST_H) */
diff --git a/src/test/include.am b/src/test/include.am
index 1ec54a286f..931e054988 100644
--- a/src/test/include.am
+++ b/src/test/include.am
@@ -23,7 +23,8 @@ TESTSCRIPTS = \
src/test/test_workqueue_pipe.sh \
src/test/test_workqueue_pipe2.sh \
src/test/test_workqueue_socketpair.sh \
- src/test/test_switch_id.sh
+ src/test/test_switch_id.sh \
+ src/test/test_cmdline.sh
if USE_RUST
TESTSCRIPTS += \
@@ -412,7 +413,8 @@ EXTRA_DIST += \
src/test/test_workqueue_efd2.sh \
src/test/test_workqueue_pipe.sh \
src/test/test_workqueue_pipe2.sh \
- src/test/test_workqueue_socketpair.sh
+ src/test/test_workqueue_socketpair.sh \
+ src/test/test_cmdline.sh
test-rust:
$(TESTS_ENVIRONMENT) "$(abs_top_srcdir)/src/test/test_rust.sh"
diff --git a/src/test/test_cmdline.sh b/src/test/test_cmdline.sh
new file mode 100755
index 0000000000..cf758c3851
--- /dev/null
+++ b/src/test/test_cmdline.sh
@@ -0,0 +1,48 @@
+#!/bin/sh
+
+umask 077
+set -e
+
+if [ $# -ge 1 ]; then
+ TOR_BINARY="${1}"
+ shift
+else
+ TOR_BINARY="${TESTING_TOR_BINARY:-./src/app/tor}"
+fi
+
+echo "TOR BINARY IS ${TOR_BINARY}"
+
+die() { echo "$1" >&2 ; exit 5; }
+
+echo "A"
+
+DATA_DIR=$(mktemp -d -t tor_cmdline_tests.XXXXXX)
+trap 'rm -rf "$DATA_DIR"' 0
+
+# 1. Test list-torrc-options.
+OUT="${DATA_DIR}/output"
+
+echo "B"
+"${TOR_BINARY}" --list-torrc-options > "$OUT"
+
+echo "C"
+
+# regular options are given.
+grep -i "SocksPort" "$OUT" >/dev/null || die "Did not find SocksPort"
+
+
+echo "D"
+
+# unlisted options are given, since they do not have the NOSET flag.
+grep -i "__SocksPort" "$OUT" > /dev/null || die "Did not find __SocksPort"
+
+echo "E"
+
+# unsettable options are not given.
+if grep -i "DisableIOCP" "$OUT" /dev/null; then
+ die "Found DisableIOCP"
+fi
+if grep -i "HiddenServiceOptions" "$OUT" /dev/null ; then
+ die "Found HiddenServiceOptions"
+fi
+echo "OK"
diff --git a/src/test/test_config.c b/src/test/test_config.c
index 58e05e5094..9b715b2ecf 100644
--- a/src/test/test_config.c
+++ b/src/test/test_config.c
@@ -5983,6 +5983,31 @@ test_config_kvline_parse(void *arg)
tor_free(enc);
}
+static void
+test_config_getinfo_config_names(void *arg)
+{
+ (void)arg;
+ char *answer = NULL;
+ const char *error = NULL;
+ int rv;
+
+ rv = getinfo_helper_config(NULL, "config/names", &answer, &error);
+ tt_int_op(rv, OP_EQ, 0);
+ tt_ptr_op(error, OP_EQ, NULL);
+
+ // ContactInfo should be listed.
+ tt_assert(strstr(answer, "\nContactInfo String\n"));
+
+ // V1AuthoritativeDirectory should not be listed, since it is obsolete.
+ tt_assert(! strstr(answer, "V1AuthoritativeDirectory"));
+
+ // ___UsingTestNetworkDefaults should not be listed, since it is invisible.
+ tt_assert(! strstr(answer, "UsingTestNetworkDefaults"));
+
+ done:
+ tor_free(answer);
+}
+
#define CONFIG_TEST(name, flags) \
{ #name, test_config_ ## name, flags, NULL, NULL }
@@ -6035,5 +6060,6 @@ struct testcase_t config_tests[] = {
CONFIG_TEST(compute_max_mem_in_queues, 0),
CONFIG_TEST(extended_fmt, 0),
CONFIG_TEST(kvline_parse, 0),
+ CONFIG_TEST(getinfo_config_names, 0),
END_OF_TESTCASES
};