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