From a2308fcab89f77146e0d44a0c6a20029bfb480aa Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Thu, 14 Mar 2013 14:34:36 -0400 Subject: [PATCH] config: parse $nmconfdir/conf.d/*.conf Add a new configuration directory ($nmconfdir/conf.d by default, overridable via the --config-dir command-line option) that can contain ".conf" files that will be parsed in asciibetical order to override the main NetworkManager.conf file. In addition to simple overrides, the conf files also support appending to the value of a previously-set list-valued key, by doing, eg, "plugins+=foo" https://bugzilla.gnome.org/show_bug.cgi?id=688857 --- man/NetworkManager.8.in | 8 +- man/NetworkManager.conf.5.in | 23 ++ src/config/nm-config.c | 303 ++++++++++++++-------- src/config/tests/Makefile.am | 5 +- src/config/tests/conf.d/00-overrides.conf | 11 + src/config/tests/conf.d/10-more.conf | 11 + src/config/tests/conf.d/90-last.conf | 5 + src/config/tests/test-config.c | 78 +++++- 8 files changed, 325 insertions(+), 119 deletions(-) create mode 100644 src/config/tests/conf.d/00-overrides.conf create mode 100644 src/config/tests/conf.d/10-more.conf create mode 100644 src/config/tests/conf.d/90-last.conf diff --git a/man/NetworkManager.8.in b/man/NetworkManager.8.in index ceefad686f..38a195fc7a 100644 --- a/man/NetworkManager.8.in +++ b/man/NetworkManager.8.in @@ -10,7 +10,7 @@ NetworkManager \- network management daemon .SH SYNOPSIS .B NetworkManager [\-\-version] | [\-\-help] .PP -.B NetworkManager [\-\-no\-daemon] [\-\-pid\-file=] [\-\-state\-file=] [\-\-config=] [\-\-plugins=,plugin2>,...] [\-\-log\-level=] [\-\-log\-domains=,,...] +.B NetworkManager [\-\-no\-daemon] [\-\-pid\-file=] [\-\-state\-file=] [\-\-config=] [\-\-config-dir=] [\-\-plugins=,plugin2>,...] [\-\-log\-level=] [\-\-log\-domains=,,...] .SH DESCRIPTION The \fINetworkManager\fP daemon attempts to make networking configuration and operation as painless and automatic as possible by managing the primary network @@ -102,6 +102,12 @@ the same directory; where is dependent on your distribution (usuall it's /etc). See \fBNetworkManager.conf\fP(5) for more information on configuration file. .TP +.I "\-\-config-dir=" +Specify configuration directory for files that override NetworkManager.conf. If not +specified, the default value of '/NetworkManager/conf.d' +is used. See \fBNetworkManager.conf\fP(5) for more information on configuration +file. +.TP .I "\-\-plugins=,, ... List plugins used to manage system-wide connection settings. This list has preference over plugins specified in the configuration file. Currently supported diff --git a/man/NetworkManager.conf.5.in b/man/NetworkManager.conf.5.in index 0a92e67180..ec1271793f 100644 --- a/man/NetworkManager.conf.5.in +++ b/man/NetworkManager.conf.5.in @@ -8,10 +8,14 @@ NetworkManager.conf \- NetworkManager configuration file .SH SYNOPSIS /etc/NetworkManager/NetworkManager.conf .br +/etc/NetworkManager/conf.d/*.conf +.br or .br \fI\fP/NetworkManager/NetworkManager.conf .br +\fI\fP/NetworkManager/conf.d/*.conf +.br where depends on your distribution or build. .SH DESCRIPTION .P @@ -20,6 +24,17 @@ is a configuration file for NetworkManager. It is used to set up various aspects of NetworkManager's behavior. The location of the file may be changed through use of the "\-\-config=" argument for \fBNetworkManager\fP (8). +.P +If a default +.I NetworkManager.conf +is provided by your distribution's packages, you should not modify it, +since your changes may get overwritten by package updates. Instead, +you can add additional +.I .conf +files to the +.I conf.d +directory. These will be read in order, with later files overriding +earlier ones. .SH "FILE FORMAT" .P The configuration file format is so-called key file (sort of ini-style format). @@ -36,6 +51,14 @@ Minimal system settings configuration file looks like this: plugins=keyfile .fi .P +As an extension to the normal keyfile format, you can also append a +value to a previously-set list-valued key by doing: +.P +.nf +[main] +plugins+=another-plugin +.fi +.P Description of sections and available keys follows: .SS [main] This section is the only mandatory section of the configuration file. diff --git a/src/config/nm-config.c b/src/config/nm-config.c index 2ec1aebea9..e7ad1e929d 100644 --- a/src/config/nm-config.c +++ b/src/config/nm-config.c @@ -27,14 +27,17 @@ #include "nm-logging.h" #include "nm-utils.h" +#include #include #define NM_DEFAULT_SYSTEM_CONF_FILE NMCONFDIR "/NetworkManager.conf" +#define NM_DEFAULT_SYSTEM_CONF_DIR NMCONFDIR "/conf.d" #define NM_OLD_SYSTEM_CONF_FILE NMCONFDIR "/nm-system-settings.conf" #define NM_NO_AUTO_DEFAULT_STATE_FILE NMSTATEDIR "/no-auto-default.state" typedef struct { - char *path; + char *nm_conf_path; + char *config_dir; char *no_auto_default_file; GKeyFile *keyfile; @@ -62,7 +65,7 @@ nm_config_get_path (NMConfig *config) { g_return_val_if_fail (config != NULL, NULL); - return NM_CONFIG_GET_PRIVATE (config)->path; + return NM_CONFIG_GET_PRIVATE (config)->nm_conf_path; } const char ** @@ -226,6 +229,7 @@ nm_config_set_ethernet_no_auto_default (NMConfig *config, NMConfigDevice *device /************************************************************************/ static char *cli_config_path; +static char *cli_config_dir; static char *cli_no_auto_default_file; static char *cli_plugins; static char *cli_log_level; @@ -236,6 +240,7 @@ static char *cli_connectivity_response; static GOptionEntry config_options[] = { { "config", 0, 0, G_OPTION_ARG_FILENAME, &cli_config_path, N_("Config file location"), N_("/path/to/config.file") }, + { "config-dir", 0, 0, G_OPTION_ARG_FILENAME, &cli_config_dir, N_("Config directory location"), N_("/path/to/config/dir") }, { "no-auto-default", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_FILENAME, &cli_no_auto_default_file, "no-auto-default.state location", NULL }, { "plugins", 0, 0, G_OPTION_ARG_STRING, &cli_plugins, N_("List of plugins separated by ','"), N_("plugin1,plugin2") }, { "log-level", 0, 0, G_OPTION_ARG_STRING, &cli_log_level, N_("Log level: one of [%s]"), "INFO" }, @@ -279,7 +284,9 @@ read_config (NMConfig *config, const char *path, GError **error) { NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config); GKeyFile *kf; - gboolean success = FALSE; + char **groups, **keys; + gsize ngroups, nkeys; + int g, k; if (g_file_test (path, G_FILE_TEST_EXISTS) == FALSE) { g_set_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND, "file %s not found", path); @@ -288,42 +295,102 @@ read_config (NMConfig *config, const char *path, GError **error) kf = g_key_file_new (); g_key_file_set_list_separator (kf, ','); - if (g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) { - priv->path = g_strdup (path); - - /* Only set stuff that's not already set, as CLI options override - * config file options. - */ - if (!priv->plugins) - priv->plugins = g_key_file_get_string_list (kf, "main", "plugins", NULL, NULL); - - priv->dhcp_client = g_key_file_get_value (kf, "main", "dhcp", NULL); - priv->dns_plugins = g_key_file_get_string_list (kf, "main", "dns", NULL, NULL); - - if (!priv->log_level) - priv->log_level = g_key_file_get_value (kf, "logging", "level", NULL); - - if (!priv->log_domains) - priv->log_domains = g_key_file_get_value (kf, "logging", "domains", NULL); - - if (!priv->connectivity_uri) - priv->connectivity_uri = g_key_file_get_value (kf, "connectivity", "uri", NULL); - - if (priv->connectivity_interval < 0) - priv->connectivity_interval = CLAMP (g_key_file_get_integer (kf, "connectivity", "interval", NULL), 0, G_MAXINT32); - - if (!priv->connectivity_response) - priv->connectivity_response = g_key_file_get_value (kf, "connectivity", "response", NULL); - - if (!priv->no_auto_default) - priv->no_auto_default = g_key_file_get_string_list (kf, "main", "no-auto-default", NULL, NULL); - - priv->keyfile = kf; - success = TRUE; - } else + if (!g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) { g_key_file_free (kf); + return FALSE; + } - return success; + /* Override the current settings with the new ones */ + groups = g_key_file_get_groups (kf, &ngroups); + for (g = 0; groups[g]; g++) { + keys = g_key_file_get_keys (kf, groups[g], &nkeys, NULL); + if (!keys) + continue; + for (k = 0; keys[k]; k++) { + int len = strlen (keys[k]); + if (keys[k][len - 1] == '+') { + char *base_key = g_strndup (keys[k], len - 1); + const char *old_val = g_key_file_get_value (priv->keyfile, groups[g], base_key, NULL); + const char *new_val = g_key_file_get_value (kf, groups[g], keys[k], NULL); + + if (old_val && *old_val) { + char *combined = g_strconcat (old_val, ",", new_val, NULL); + + g_key_file_set_value (priv->keyfile, groups[g], base_key, combined); + g_free (combined); + } else + g_key_file_set_value (priv->keyfile, groups[g], base_key, new_val); + + g_free (base_key); + continue; + } + + g_key_file_set_value (priv->keyfile, groups[g], keys[k], + g_key_file_get_value (kf, groups[g], keys[k], NULL)); + } + } + g_key_file_free (kf); + + return TRUE; +} + +static gboolean +find_base_config (NMConfig *config, GError **error) +{ + NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config); + GError *my_error = NULL; + + /* Try a user-specified config file first */ + if (cli_config_path) { + /* Bad user-specific config file path is a hard error */ + if (read_config (config, cli_config_path, error)) { + priv->nm_conf_path = g_strdup (cli_config_path); + return TRUE; + } else + return FALSE; + } + + /* Even though we prefer NetworkManager.conf, we need to check the + * old nm-system-settings.conf first to preserve compat with older + * setups. In package managed systems dropping a NetworkManager.conf + * onto the system would make NM use it instead of nm-system-settings.conf, + * changing behavior during an upgrade. We don't want that. + */ + + /* Try deprecated nm-system-settings.conf first */ + if (read_config (config, NM_OLD_SYSTEM_CONF_FILE, &my_error)) { + priv->nm_conf_path = g_strdup (NM_OLD_SYSTEM_CONF_FILE); + return TRUE; + } + + if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) { + g_warning ("Default config file %s invalid: %s\n", + NM_OLD_SYSTEM_CONF_FILE, + my_error->message); + } + g_clear_error (&my_error); + + /* Try the standard config file location next */ + if (read_config (config, NM_DEFAULT_SYSTEM_CONF_FILE, &my_error)) { + priv->nm_conf_path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE); + return TRUE; + } + + if (!g_error_matches (my_error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND)) { + g_warning ("Default config file %s invalid: %s\n", + NM_DEFAULT_SYSTEM_CONF_FILE, + my_error->message); + g_propagate_error (error, my_error); + return FALSE; + } + + /* If for some reason no config file exists, use the default + * config file path. + */ + priv->nm_conf_path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE); + g_warning ("No config file found or given; using %s\n", + NM_DEFAULT_SYSTEM_CONF_FILE); + return TRUE; } /************************************************************************/ @@ -335,107 +402,118 @@ nm_config_get (void) return singleton; } +static int +sort_asciibetically (gconstpointer a, gconstpointer b) +{ + const char *s1 = *(const char **)a; + const char *s2 = *(const char **)b; + + return strcmp (s1, s2); +} + /* call this function only once! */ NMConfig * nm_config_new (GError **error) { - GError *local = NULL; NMConfigPrivate *priv = NULL; + GFile *dir; + GFileEnumerator *direnum; + GFileInfo *info; + GPtrArray *confs; + const char *name; + int i; g_assert (!singleton); singleton = NM_CONFIG (g_object_new (NM_TYPE_CONFIG, NULL)); priv = NM_CONFIG_GET_PRIVATE (singleton); - /* Fill with command-line defaults */ - if (cli_plugins && cli_plugins[0]) - priv->plugins = g_strsplit_set (cli_plugins, ",", 0); - - if (cli_log_level && cli_log_level[0]) - priv->log_level = g_strdup (cli_log_level); - - if (cli_log_domains && cli_log_domains[0]) - priv->log_domains = g_strdup (cli_log_domains); - - if (cli_connectivity_uri && cli_connectivity_uri[0]) - priv->connectivity_uri = g_strdup (cli_connectivity_uri); - - if (cli_connectivity_interval >= 0) - priv->connectivity_interval = cli_connectivity_interval; - - if (cli_connectivity_response && cli_connectivity_response[0]) - priv->connectivity_response = g_strdup (cli_connectivity_response); - - /* Try a user-specified config file first */ - if (cli_config_path) { - /* Bad user-specific config file path is a hard error */ - if (!read_config (singleton, cli_config_path, error)) { - g_object_unref (singleton); - singleton = NULL; - return NULL; - } - goto got_config; - } - - /* Even though we prefer NetworkManager.conf, we need to check the - * old nm-system-settings.conf first to preserve compat with older - * setups. In package managed systems dropping a NetworkManager.conf - * onto the system would make NM use it instead of nm-system-settings.conf, - * changing behavior during an upgrade. We don't want that. - */ - - /* Try deprecated nm-system-settings.conf first */ - if (read_config (singleton, NM_OLD_SYSTEM_CONF_FILE, &local)) - goto got_config; - - if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) { - fprintf (stderr, "Default config file %s invalid: (%d) %s\n", - NM_OLD_SYSTEM_CONF_FILE, - local ? local->code : -1, - (local && local->message) ? local->message : "unknown"); - } - g_clear_error (&local); - - /* Try the standard config file location next */ - if (read_config (singleton, NM_DEFAULT_SYSTEM_CONF_FILE, &local)) - goto got_config; - - if (g_error_matches (local, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND) == FALSE) { - fprintf (stderr, "Default config file %s invalid: (%d) %s\n", - NM_DEFAULT_SYSTEM_CONF_FILE, - local ? local->code : -1, - (local && local->message) ? local->message : "unknown"); - g_propagate_error (error, local); + /* First read the base config file */ + if (!find_base_config (singleton, error)) { g_object_unref (singleton); + singleton = NULL; return NULL; } - /* If for some reason no config file exists, and NM wasn't given on on - * the command line, just use the default config file path. - */ - if (priv->path == NULL) { - priv->path = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE); - fprintf (stderr, "No config file found or given; using %s\n", - NM_DEFAULT_SYSTEM_CONF_FILE); + /* Now read the overrides in the config dir */ + if (cli_config_dir) + priv->config_dir = g_strdup (cli_config_dir); + else + priv->config_dir = g_strdup (NM_DEFAULT_SYSTEM_CONF_DIR); + + confs = g_ptr_array_new_with_free_func (g_free); + dir = g_file_new_for_path (priv->config_dir); + direnum = g_file_enumerate_children (dir, G_FILE_ATTRIBUTE_STANDARD_NAME, 0, NULL, NULL); + if (direnum) { + while ((info = g_file_enumerator_next_file (direnum, NULL, NULL))) { + name = g_file_info_get_name (info); + if (g_str_has_suffix (name, ".conf")) + g_ptr_array_add (confs, g_build_filename (priv->config_dir, name, NULL)); + g_object_unref (info); + } + g_object_unref (direnum); } + g_object_unref (dir); - /* ignore error if config file not found */ - g_clear_error (&local); + g_ptr_array_sort (confs, sort_asciibetically); + for (i = 0; i < confs->len; i++) { + if (!read_config (singleton, confs->pdata[i], error)) { + g_object_unref (singleton); + singleton = NULL; + break; + } + } + g_ptr_array_unref (confs); + if (!singleton) + return FALSE; - got_config: - /* Handle no-auto-default state file */ + /* Handle no-auto-default key and state file */ + priv->no_auto_default = g_key_file_get_string_list (priv->keyfile, "main", "no-auto-default", NULL, NULL); if (cli_no_auto_default_file) priv->no_auto_default_file = g_strdup (cli_no_auto_default_file); else priv->no_auto_default_file = g_strdup (NM_NO_AUTO_DEFAULT_STATE_FILE); merge_no_auto_default_state (singleton); + /* Now let command-line options override the config files, and fill in priv. */ + if (cli_plugins && cli_plugins[0]) + g_key_file_set_value (priv->keyfile, "main", "plugins", cli_plugins); + priv->plugins = g_key_file_get_string_list (priv->keyfile, "main", "plugins", NULL, NULL); + + priv->dhcp_client = g_key_file_get_value (priv->keyfile, "main", "dhcp", NULL); + priv->dns_plugins = g_key_file_get_string_list (priv->keyfile, "main", "dns", NULL, NULL); + + if (cli_log_level && cli_log_level[0]) + g_key_file_set_value (priv->keyfile, "logging", "level", cli_log_level); + priv->log_level = g_key_file_get_value (priv->keyfile, "logging", "level", NULL); + + if (cli_log_domains && cli_log_domains[0]) + g_key_file_set_value (priv->keyfile, "logging", "domains", cli_log_domains); + priv->log_domains = g_key_file_get_value (priv->keyfile, "logging", "domains", NULL); + + if (cli_connectivity_uri && cli_connectivity_uri[0]) + g_key_file_set_value (priv->keyfile, "connectivity", "uri", cli_connectivity_uri); + priv->connectivity_uri = g_key_file_get_value (priv->keyfile, "connectivity", "uri", NULL); + + if (cli_connectivity_interval >= 0) + g_key_file_set_integer (priv->keyfile, "connectivity", "interval", cli_connectivity_interval); + priv->connectivity_interval = g_key_file_get_integer (priv->keyfile, "connectivity", "interval", NULL); + + if (cli_connectivity_response && cli_connectivity_response[0]) + g_key_file_set_value (priv->keyfile, "connectivity", "response", cli_connectivity_response); + priv->connectivity_response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL); + return singleton; } static void nm_config_init (NMConfig *config) { - NM_CONFIG_GET_PRIVATE (config)->connectivity_interval = -1; + NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (config); + + priv->keyfile = g_key_file_new (); + g_key_file_set_list_separator (priv->keyfile, ','); + + priv->connectivity_interval = -1; } static void @@ -443,7 +521,9 @@ finalize (GObject *gobject) { NMConfigPrivate *priv = NM_CONFIG_GET_PRIVATE (gobject); - g_free (priv->path); + g_free (priv->nm_conf_path); + g_free (priv->config_dir); + g_free (priv->no_auto_default_file); g_clear_pointer (&priv->keyfile, g_key_file_unref); g_strfreev (priv->plugins); g_free (priv->dhcp_client); @@ -452,10 +532,13 @@ finalize (GObject *gobject) g_free (priv->log_domains); g_free (priv->connectivity_uri); g_free (priv->connectivity_response); + g_strfreev (priv->no_auto_default); singleton = NULL; g_clear_pointer (&cli_config_path, g_free); + g_clear_pointer (&cli_config_dir, g_free); + g_clear_pointer (&cli_no_auto_default_file, g_free); g_clear_pointer (&cli_plugins, g_free); g_clear_pointer (&cli_log_level, g_free); g_clear_pointer (&cli_log_domains, g_free); diff --git a/src/config/tests/Makefile.am b/src/config/tests/Makefile.am index c99c3848ef..40527d98d2 100644 --- a/src/config/tests/Makefile.am +++ b/src/config/tests/Makefile.am @@ -27,6 +27,9 @@ check-local: test-config EXTRA_DIST = \ NetworkManager.conf \ - bad.conf + bad.conf \ + conf.d/00-overrides.conf \ + conf.d/10-more.conf \ + conf.d/90-last.conf endif diff --git a/src/config/tests/conf.d/00-overrides.conf b/src/config/tests/conf.d/00-overrides.conf new file mode 100644 index 0000000000..0aa19d484c --- /dev/null +++ b/src/config/tests/conf.d/00-overrides.conf @@ -0,0 +1,11 @@ +[main] +dhcp=dhcpcd + +[logging] +domains=PLATFORM,DNS,WIFI + +[order] +a=0 +b=0 +c=0 + diff --git a/src/config/tests/conf.d/10-more.conf b/src/config/tests/conf.d/10-more.conf new file mode 100644 index 0000000000..b1424a4bc8 --- /dev/null +++ b/src/config/tests/conf.d/10-more.conf @@ -0,0 +1,11 @@ +[main] +extra=hello +new+=something + +[connectivity] +uri=http://example.net + +[order] +a=10 +b=10 + diff --git a/src/config/tests/conf.d/90-last.conf b/src/config/tests/conf.d/90-last.conf new file mode 100644 index 0000000000..dc1de394f1 --- /dev/null +++ b/src/config/tests/conf.d/90-last.conf @@ -0,0 +1,5 @@ +[main] +plugins+=one,two + +[order] +a=90 diff --git a/src/config/tests/test-config.c b/src/config/tests/test-config.c index f8df2709c9..02567979c0 100644 --- a/src/config/tests/test-config.c +++ b/src/config/tests/test-config.c @@ -28,7 +28,7 @@ #include "nm-test-device.h" static void -setup_config (const char *config_file, ...) +setup_config (const char *config_file, const char *config_dir, ...) { va_list ap; GPtrArray *args; @@ -40,8 +40,10 @@ setup_config (const char *config_file, ...) g_ptr_array_add (args, "test-config"); g_ptr_array_add (args, "--config"); g_ptr_array_add (args, (char *)config_file); + g_ptr_array_add (args, "--config-dir"); + g_ptr_array_add (args, (char *)config_dir); - va_start (ap, config_file); + va_start (ap, config_dir); while ((arg = va_arg (ap, char *))) g_ptr_array_add (args, arg); va_end (ap); @@ -65,7 +67,7 @@ test_config_simple (void) const char **plugins; char *value; - setup_config (SRCDIR "/NetworkManager.conf", NULL); + setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL); config = nm_config_new (&error); g_assert_no_error (error); @@ -101,7 +103,7 @@ test_config_non_existent (void) NMConfig *config; GError *error = NULL; - setup_config (SRCDIR "/no-such-file", NULL); + setup_config (SRCDIR "/no-such-file", "/no/such/dir", NULL); config = nm_config_new (&error); g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND); } @@ -112,7 +114,7 @@ test_config_parse_error (void) NMConfig *config; GError *error = NULL; - setup_config (SRCDIR "/bad.conf", NULL); + setup_config (SRCDIR "/bad.conf", "/no/such/dir", NULL); config = nm_config_new (&error); g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE); } @@ -164,7 +166,7 @@ test_config_no_auto_default (void) g_assert_cmpint (nwrote, ==, 18); close (fd); - setup_config (SRCDIR "/NetworkManager.conf", + setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir", "--no-auto-default", state_file, NULL); config = nm_config_new (&error); @@ -185,7 +187,7 @@ test_config_no_auto_default (void) g_object_unref (config); - setup_config (SRCDIR "/NetworkManager.conf", + setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir", "--no-auto-default", state_file, NULL); config = nm_config_new (&error); @@ -207,6 +209,66 @@ test_config_no_auto_default (void) g_free (state_file); } +static void +test_config_confdir (void) +{ + NMConfig *config; + GError *error = NULL; + const char **plugins; + char *value; + + setup_config (SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", NULL); + config = nm_config_new (&error); + g_assert_no_error (error); + + g_assert_cmpstr (nm_config_get_path (config), ==, SRCDIR "/NetworkManager.conf"); + g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhcpcd"); + g_assert_cmpstr (nm_config_get_log_level (config), ==, "INFO"); + g_assert_cmpstr (nm_config_get_log_domains (config), ==, "PLATFORM,DNS,WIFI"); + g_assert_cmpstr (nm_config_get_connectivity_uri (config), ==, "http://example.net"); + g_assert_cmpint (nm_config_get_connectivity_interval (config), ==, 100); + + plugins = nm_config_get_plugins (config); + g_assert_cmpint (g_strv_length ((char **)plugins), ==, 5); + g_assert_cmpstr (plugins[0], ==, "foo"); + g_assert_cmpstr (plugins[1], ==, "bar"); + g_assert_cmpstr (plugins[2], ==, "baz"); + g_assert_cmpstr (plugins[3], ==, "one"); + g_assert_cmpstr (plugins[4], ==, "two"); + + value = nm_config_get_value (config, "main", "extra", NULL); + g_assert_cmpstr (value, ==, "hello"); + g_free (value); + + value = nm_config_get_value (config, "main", "new", NULL); + g_assert_cmpstr (value, ==, "something"); /* not ",something" */ + g_free (value); + + value = nm_config_get_value (config, "order", "a", NULL); + g_assert_cmpstr (value, ==, "90"); + g_free (value); + value = nm_config_get_value (config, "order", "b", NULL); + g_assert_cmpstr (value, ==, "10"); + g_free (value); + value = nm_config_get_value (config, "order", "c", NULL); + g_assert_cmpstr (value, ==, "0"); + g_free (value); + + g_object_unref (config); +} + +static void +test_config_confdir_parse_error (void) +{ + NMConfig *config; + GError *error = NULL; + + /* Using SRCDIR as the conf dir will pick up bad.conf */ + setup_config (SRCDIR "/NetworkManager.conf", SRCDIR, NULL); + config = nm_config_new (&error); + g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE); +} + int main (int argc, char **argv) { @@ -217,6 +279,8 @@ main (int argc, char **argv) g_test_add_func ("/config/non-existent", test_config_non_existent); g_test_add_func ("/config/parse-error", test_config_parse_error); g_test_add_func ("/config/no-auto-default", test_config_no_auto_default); + g_test_add_func ("/config/confdir", test_config_confdir); + g_test_add_func ("/config/confdir-parse-error", test_config_confdir_parse_error); /* This one has to come last, because it leaves its values in * nm-config.c's global variables, and there's no way to reset