core: split out config file handling
authorDan Williams <dcbw@redhat.com>
Thu, 22 Sep 2011 15:16:07 +0000 (10:16 -0500)
committerDan Williams <dcbw@redhat.com>
Tue, 27 Sep 2011 14:40:50 +0000 (09:40 -0500)
Make config file stuff somewhat clearer and easier to understand,
and possibly easier to extend later.

src/Makefile.am
src/main.c
src/nm-config.c [new file with mode: 0644]
src/nm-config.h [new file with mode: 0644]
src/settings/nm-settings.c
src/settings/nm-settings.h

index c8caefb..cbcfdc6 100644 (file)
@@ -142,6 +142,8 @@ NetworkManager_SOURCES = \
                nm-ip6-config.h \
                nm-active-connection.h \
                nm-active-connection.c \
+               nm-config.h \
+               nm-config.c \
                main.c \
                nm-policy.c \
                nm-policy.h \
index a9ffd38..8d37bc9 100644 (file)
 #include "nm-vpn-manager.h"
 #include "nm-logging.h"
 #include "nm-policy-hosts.h"
+#include "nm-config.h"
 
 #if !defined(NM_DIST_VERSION)
 # define NM_DIST_VERSION VERSION
 #endif
 
 #define NM_DEFAULT_PID_FILE          LOCALSTATEDIR"/run/NetworkManager.pid"
-#define NM_DEFAULT_SYSTEM_CONF_FILE  SYSCONFDIR"/NetworkManager/NetworkManager.conf"
-#define NM_OLD_SYSTEM_CONF_FILE      SYSCONFDIR"/NetworkManager/nm-system-settings.conf"
 #define NM_DEFAULT_SYSTEM_STATE_FILE LOCALSTATEDIR"/lib/NetworkManager/NetworkManager.state"
 
 /*
@@ -310,46 +309,6 @@ done:
 }
 
 static gboolean
-parse_config_file (const char *filename,
-                   char **plugins,
-                   char **dhcp_client,
-                   char ***dns_plugins,
-                   char **log_level,
-                   char **log_domains,
-                   GError **error)
-{
-       GKeyFile *config;
-       gboolean success = FALSE;
-
-       config = g_key_file_new ();
-       if (!config) {
-               g_set_error (error, 0, 0,
-                            "Not enough memory to load config file.");
-               return FALSE;
-       }
-
-       g_key_file_set_list_separator (config, ',');
-       if (!g_key_file_load_from_file (config, filename, G_KEY_FILE_NONE, error))
-               goto out;
-
-       *plugins = g_key_file_get_value (config, "main", "plugins", error);
-       if (*error)
-               goto out;
-
-       *dhcp_client = g_key_file_get_value (config, "main", "dhcp", NULL);
-       *dns_plugins = g_key_file_get_string_list (config, "main", "dns", NULL, NULL);
-
-       *log_level = g_key_file_get_value (config, "logging", "level", NULL);
-       *log_domains = g_key_file_get_value (config, "logging", "domains", NULL);
-
-       success = TRUE;
-
-out:
-       g_key_file_free (config);
-       return success;
-}
-
-static gboolean
 parse_state_file (const char *filename,
                   gboolean *net_enabled,
                   gboolean *wifi_enabled,
@@ -469,10 +428,9 @@ main (int argc, char *argv[])
        GOptionContext *opt_ctx = NULL;
        gboolean become_daemon = FALSE;
        gboolean g_fatal_warnings = FALSE;
-       char *pidfile = NULL, *state_file = NULL, *dhcp = NULL;
-       char *config = NULL, *plugins = NULL, *conf_plugins = NULL;
+       char *pidfile = NULL, *state_file = NULL;
+       char *config_path = NULL, *plugins = NULL;
        char *log_level = NULL, *log_domains = NULL;
-       char **dns = NULL;
        gboolean wifi_enabled = TRUE, net_enabled = TRUE, wwan_enabled = TRUE, wimax_enabled = TRUE;
        gboolean success, show_version = FALSE;
        NMPolicy *policy = NULL;
@@ -482,9 +440,9 @@ main (int argc, char *argv[])
        NMSupplicantManager *sup_mgr = NULL;
        NMDHCPManager *dhcp_mgr = NULL;
        NMSettings *settings = NULL;
+       NMConfig *config;
        GError *error = NULL;
        gboolean wrote_pidfile = FALSE;
-       char *cfg_log_level = NULL, *cfg_log_domains = NULL;
 
        GOptionEntry options[] = {
                { "version", 0, 0, G_OPTION_ARG_NONE, &show_version, "Print NetworkManager version and exit", NULL },
@@ -492,7 +450,7 @@ main (int argc, char *argv[])
                { "g-fatal-warnings", 0, 0, G_OPTION_ARG_NONE, &g_fatal_warnings, "Make all warnings fatal", NULL },
                { "pid-file", 0, 0, G_OPTION_ARG_FILENAME, &pidfile, "Specify the location of a PID file", "filename" },
                { "state-file", 0, 0, G_OPTION_ARG_FILENAME, &state_file, "State file location", "/path/to/state.file" },
-               { "config", 0, 0, G_OPTION_ARG_FILENAME, &config, "Config file location", "/path/to/config.file" },
+               { "config", 0, 0, G_OPTION_ARG_FILENAME, &config_path, "Config file location", "/path/to/config.file" },
                { "plugins", 0, 0, G_OPTION_ARG_STRING, &plugins, "List of plugins separated by ','", "plugin1,plugin2" },
                { "log-level", 0, 0, G_OPTION_ARG_STRING, &log_level, "Log level: one of [ERR, WARN, INFO, DEBUG]", "INFO" },
                { "log-domains", 0, 0, G_OPTION_ARG_STRING, &log_domains,
@@ -554,58 +512,18 @@ main (int argc, char *argv[])
        if (check_pidfile (pidfile))
                exit (1);
 
-       /* Parse the config file */
-       if (config) {
-               if (!parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error)) {
-                       fprintf (stderr, "Config file %s invalid: (%d) %s\n",
-                                config,
-                                error ? error->code : -1,
-                                (error && error->message) ? error->message : "unknown");
-                       exit (1);
-               }
-       } else {
-               gboolean parsed = 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 (g_file_test (NM_OLD_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) {
-                       config = g_strdup (NM_OLD_SYSTEM_CONF_FILE);
-                       parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error);
-                       if (!parsed) {
-                               fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
-                                        config,
-                                        error ? error->code : -1,
-                                        (error && error->message) ? error->message : "unknown");
-                               g_free (config);
-                               config = NULL;
-                               g_clear_error (&error);
-                       }
-               }
-
-               /* Try the preferred NetworkManager.conf last */
-               if (!parsed && g_file_test (NM_DEFAULT_SYSTEM_CONF_FILE, G_FILE_TEST_EXISTS)) {
-                       config = g_strdup (NM_DEFAULT_SYSTEM_CONF_FILE);
-                       parsed = parse_config_file (config, &conf_plugins, &dhcp, &dns, &cfg_log_level, &cfg_log_domains, &error);
-                       if (!parsed) {
-                               fprintf (stderr, "Default config file %s invalid: (%d) %s\n",
-                                        config,
-                                        error ? error->code : -1,
-                                        (error && error->message) ? error->message : "unknown");
-                               g_free (config);
-                               config = NULL;
-                               g_clear_error (&error);
-                       }
-               }
+       /* Read the config file and CLI overrides */
+       config = nm_config_new (config_path, plugins, log_level, log_domains, &error);
+       if (config == NULL) {
+               fprintf (stderr, "Failed to read configuration: (%d) %s\n",
+                        error ? error->code : -1,
+                        (error && error->message) ? error->message : "unknown");
+               exit (1);
        }
+
        /* Logging setup */
-       if (!nm_logging_setup (log_level ? log_level : cfg_log_level,
-                              log_domains ? log_domains : cfg_log_domains,
+       if (!nm_logging_setup (nm_config_get_log_level (config),
+                              nm_config_get_log_domains (config),
                               &error)) {
                fprintf (stderr,
                         _("%s.  Please use --help to see a list of valid options.\n"),
@@ -613,10 +531,6 @@ main (int argc, char *argv[])
                exit (1);
        }
 
-       /* Plugins specified with '--plugins' override those of config file */
-       plugins = plugins ? plugins : g_strdup (conf_plugins);
-       g_free (conf_plugins);
-
        /* Parse the state file */
        if (!parse_state_file (state_file, &net_enabled, &wifi_enabled, &wwan_enabled, &wimax_enabled, &error)) {
                fprintf (stderr, "State file %s parsing failed: (%d) %s\n",
@@ -683,8 +597,7 @@ main (int argc, char *argv[])
        nm_log_info (LOGD_CORE, "NetworkManager (version " NM_DIST_VERSION ") is starting...");
        success = FALSE;
 
-       if (config)
-               nm_log_info (LOGD_CORE, "Read config file %s", config);
+       nm_log_info (LOGD_CORE, "Read config file %s", nm_config_get_path (config));
 
        main_loop = g_main_loop_new (NULL, FALSE);
 
@@ -704,13 +617,15 @@ main (int argc, char *argv[])
                goto done;
        }
 
-       dns_mgr = nm_dns_manager_get ((const char **) dns);
+       dns_mgr = nm_dns_manager_get (nm_config_get_dns_plugins (config));
        if (!dns_mgr) {
                nm_log_err (LOGD_CORE, "failed to start the DNS manager.");
                goto done;
        }
 
-       settings = nm_settings_new (config, plugins, &error);
+       settings = nm_settings_new (nm_config_get_path (config),
+                                   nm_config_get_plugins (config),
+                                   &error);
        if (!settings) {
                nm_log_err (LOGD_CORE, "failed to initialize settings storage: %s",
                            error && error->message ? error->message : "(unknown)");
@@ -744,7 +659,7 @@ main (int argc, char *argv[])
        }
 
        /* Initialize DHCP manager */
-       dhcp_mgr = nm_dhcp_manager_new (dhcp, &error);
+       dhcp_mgr = nm_dhcp_manager_new (nm_config_get_dhcp_client (config), &error);
        if (!dhcp_mgr) {
                nm_log_err (LOGD_CORE, "failed to start the DHCP manager: %s.", error->message);
                goto done;
@@ -804,17 +719,15 @@ done:
        if (pidfile && wrote_pidfile)
                unlink (pidfile);
 
+       nm_config_free (config);
+
        /* Free options */
        g_free (pidfile);
        g_free (state_file);
-       g_free (config);
+       g_free (config_path);
        g_free (plugins);
-       g_free (dhcp);
-       g_strfreev (dns);
        g_free (log_level);
        g_free (log_domains);
-       g_free (cfg_log_level);
-       g_free (cfg_log_domains);
 
        nm_log_info (LOGD_CORE, "exiting (%s)", success ? "success" : "error");
        exit (success ? 0 : 1);
diff --git a/src/nm-config.c b/src/nm-config.c
new file mode 100644 (file)
index 0000000..f52f06f
--- /dev/null
@@ -0,0 +1,243 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ */
+
+#include <config.h>
+#include <string.h>
+#include <stdio.h>
+
+#include "nm-config.h"
+
+#define NM_DEFAULT_SYSTEM_CONF_FILE  SYSCONFDIR"/NetworkManager/NetworkManager.conf"
+#define NM_OLD_SYSTEM_CONF_FILE      SYSCONFDIR"/NetworkManager/nm-system-settings.conf"
+
+struct NMConfig {
+       char *path;
+       char **plugins;
+       char *dhcp_client;
+       char **dns_plugins;
+       char *log_level;
+       char *log_domains;
+};
+
+/************************************************************************/
+
+GQuark
+nm_config_error_quark (void)
+{
+       static GQuark quark = 0;
+       if (!quark)
+               quark = g_quark_from_static_string ("nm-config-error");
+       return quark;
+}
+
+/* This should really be standard. */
+#define ENUM_ENTRY(NAME, DESC) { NAME, "" #NAME "", DESC }
+
+GType
+nm_config_error_get_type (void)
+{
+       static GType etype = 0;
+
+       if (etype == 0) {
+               static const GEnumValue values[] = {
+                       /* Not enough memory to parse the config file. */
+                       ENUM_ENTRY (NM_CONFIG_ERROR_NO_MEMORY, "NoMemory"),
+                       { 0, 0, 0 }
+               };
+               etype = g_enum_register_static ("NMConfigError", values);
+       }
+       return etype;
+}
+
+/************************************************************************/
+
+const char *
+nm_config_get_path (NMConfig *config)
+{
+       g_return_val_if_fail (config != NULL, NULL);
+
+       return config->path;
+}
+
+const char **
+nm_config_get_plugins (NMConfig *config)
+{
+       g_return_val_if_fail (config != NULL, NULL);
+
+       return (const char **) config->plugins;
+}
+
+const char *
+nm_config_get_dhcp_client (NMConfig *config)
+{
+       g_return_val_if_fail (config != NULL, NULL);
+
+       return config->dhcp_client;
+}
+
+const char **
+nm_config_get_dns_plugins (NMConfig *config)
+{
+       g_return_val_if_fail (config != NULL, NULL);
+
+       return (const char **) config->dns_plugins;
+}
+
+const char *
+nm_config_get_log_level (NMConfig *config)
+{
+       g_return_val_if_fail (config != NULL, NULL);
+
+       return config->log_level;
+}
+
+const char *
+nm_config_get_log_domains (NMConfig *config)
+{
+       g_return_val_if_fail (config != NULL, NULL);
+
+       return config->log_domains;
+}
+
+/************************************************************************/
+
+static gboolean
+fill_from_file (NMConfig *config,
+                const char *path,
+                const char *cli_plugins,
+                const char *cli_log_level,
+                const char *cli_log_domains,
+                GError **error)
+{
+       GKeyFile *kf;
+       gboolean success = FALSE;
+
+       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 not found");
+               return FALSE;
+       }
+
+       kf = g_key_file_new ();
+       if (!kf) {
+               g_set_error (error, NM_CONFIG_ERROR, NM_CONFIG_ERROR_NO_MEMORY,
+                            "Not enough memory to load config file");
+               return FALSE;
+       }
+
+       g_key_file_set_list_separator (kf, ',');
+       if (g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, error)) {
+               config->path = g_strdup (path);
+
+               /* CLI provided options override config file options */
+               if (cli_plugins && strlen (cli_plugins))
+                       config->plugins = g_strsplit_set (cli_plugins, ",", 0);
+               else
+                       config->plugins = g_key_file_get_string_list (kf, "main", "plugins", NULL, NULL);
+
+               config->dhcp_client = g_key_file_get_value (kf, "main", "dhcp", NULL);
+               config->dns_plugins = g_key_file_get_string_list (kf, "main", "dns", NULL, NULL);
+
+               if (cli_log_level && strlen (cli_log_level))
+                       config->log_level = g_strdup (cli_log_level);
+               else
+                       config->log_level = g_key_file_get_value (kf, "logging", "level", NULL);
+
+               if (cli_log_domains && strlen (cli_log_domains))
+                       config->log_domains = g_strdup (cli_log_domains);
+               else
+                       config->log_domains = g_key_file_get_value (kf, "logging", "domains", NULL);
+               success = TRUE;
+       }
+
+       g_key_file_free (kf);
+       return success;
+}
+
+NMConfig *
+nm_config_new (const char *cli_config_path,
+               const char *cli_plugins,
+               const char *cli_log_level,
+               const char *cli_log_domains,
+               GError **error)
+{
+       NMConfig *config;
+       GError *local = NULL;
+
+       config = g_malloc0 (sizeof (*config));
+
+       if (cli_config_path) {
+               /* Bad user-specific config file path is a hard error */
+               if (!fill_from_file (config, cli_config_path, cli_plugins, cli_log_level, cli_log_domains, error)) {
+                       nm_config_free (config);
+                       return NULL;
+               }
+               return 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 (fill_from_file (config, NM_OLD_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains, &local))
+               return 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 (fill_from_file (config, NM_DEFAULT_SYSTEM_CONF_FILE, cli_plugins, cli_log_level, cli_log_domains, &local))
+               return 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);
+       return config;
+}
+
+void
+nm_config_free (NMConfig *config)
+{
+       g_return_if_fail (config != NULL);
+
+       g_free (config->path);
+       g_strfreev (config->plugins);
+       g_free (config->dhcp_client);
+       g_strfreev (config->dns_plugins);
+       g_free (config->log_level);
+       g_free (config->log_domains);
+
+       memset (config, 0, sizeof (*config));
+       g_free (config);
+}
+
diff --git a/src/nm-config.h b/src/nm-config.h
new file mode 100644 (file)
index 0000000..fae344f
--- /dev/null
@@ -0,0 +1,55 @@
+/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
+/* NetworkManager -- Network link manager
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2 of the License, or
+ * (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License along
+ * with this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+ *
+ * Copyright (C) 2011 Red Hat, Inc.
+ */
+
+#ifndef NM_CONFIG_H
+#define NM_CONFIG_H
+
+#include <glib.h>
+#include <glib-object.h>
+
+typedef struct NMConfig NMConfig;
+
+typedef enum {
+       NM_CONFIG_ERROR_NO_MEMORY = 0,
+} NMConfigError;
+
+#define NM_CONFIG_ERROR (nm_config_error_quark ())
+GQuark nm_config_error_quark (void);
+#define NM_TYPE_CONFIG_ERROR (nm_config_error_get_type ())
+GType nm_config_error_get_type (void);
+
+
+NMConfig *nm_config_new (const char *cli_config_path,
+                         const char *cli_plugins,
+                         const char *cli_log_level,
+                         const char *cli_log_domains,
+                         GError **error);
+
+const char *nm_config_get_path (NMConfig *config);
+const char **nm_config_get_plugins (NMConfig *config);
+const char *nm_config_get_dhcp_client (NMConfig *config);
+const char **nm_config_get_dns_plugins (NMConfig *config);
+const char *nm_config_get_log_level (NMConfig *config);
+const char *nm_config_get_log_domains (NMConfig *config);
+
+void nm_config_free (NMConfig *config);
+
+#endif /* NM_CONFIG_H */
+
index cb094e9..f0bfc16 100644 (file)
@@ -27,6 +27,7 @@
 
 #include <unistd.h>
 #include <string.h>
+#include <ctype.h>
 #include <gmodule.h>
 #include <net/ethernet.h>
 #include <netinet/ether.h>
@@ -546,24 +547,23 @@ find_plugin (GSList *list, const char *pname)
 }
 
 static gboolean
-load_plugins (NMSettings *self, const char *plugins, GError **error)
+load_plugins (NMSettings *self, const char **plugins, GError **error)
 {
        GSList *list = NULL;
-       char **plist;
-       char **iter;
+       const char **iter;
        gboolean success = TRUE;
 
-       plist = g_strsplit (plugins, ",", 0);
-       if (!plist)
-               return FALSE;
-
-       for (iter = plist; *iter; iter++) {
+       for (iter = plugins; *iter; iter++) {
                GModule *plugin;
                char *full_name, *path;
-               const char *pname = g_strstrip (*iter);
+               const char *pname = *iter;
                GObject *obj;
                GObject * (*factory_func) (void);
 
+               /* strip leading spaces */
+               while (isblank (*pname))
+                       pname++;
+
                /* keyfile plugin built in now */
                if (!strcmp (pname, "keyfile"))
                        continue;
@@ -616,8 +616,6 @@ load_plugins (NMSettings *self, const char *plugins, GError **error)
                list = g_slist_append (list, obj);
        }
 
-       g_strfreev (plist);
-
        g_slist_foreach (list, (GFunc) g_object_unref, NULL);
        g_slist_free (list);
 
@@ -1494,7 +1492,7 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device)
 
 NMSettings *
 nm_settings_new (const char *config_file,
-                 const char *plugins,
+                 const char **plugins,
                  GError **error)
 {
        NMSettings *self;
index 66d41cc..77485e1 100644 (file)
@@ -77,7 +77,7 @@ typedef struct {
 GType nm_settings_get_type (void);
 
 NMSettings *nm_settings_new (const char *config_file,
-                             const char *plugins,
+                             const char **plugins,
                              GError **error);
 
 typedef void (*NMSettingsForEachFunc) (NMSettings *settings,