config: add nm_config_setup() to initialize config singleton

Make nm_config_new() usable without accessing static/singleton data.

nm_config_setup() is now used to initialize the singleton.
Still, you must not call nm_config_get() before calling
nm_config_setup() or after freeing the provided singleton
instance.
This commit is contained in:
Thomas Haller
2014-07-09 15:17:01 +02:00
parent 9387e8e8a7
commit 1ff5154369
7 changed files with 199 additions and 118 deletions

View File

@@ -177,7 +177,8 @@ nm_main_utils_early_setup (const char *progname,
char **argv[],
int *argc,
GOptionEntry *options,
GOptionEntry *more_options,
void (*option_context_hook) (gpointer user_data, GOptionContext *opt_ctx),
gpointer option_context_hook_data,
const char *summary)
{
GOptionContext *opt_ctx = NULL;
@@ -220,9 +221,9 @@ nm_main_utils_early_setup (const char *progname,
g_option_context_set_ignore_unknown_options (opt_ctx, FALSE);
g_option_context_set_help_enabled (opt_ctx, TRUE);
g_option_context_add_main_entries (opt_ctx, options, NULL);
if (more_options)
g_option_context_add_main_entries (opt_ctx, more_options, NULL);
g_option_context_set_summary (opt_ctx, summary);
if (option_context_hook)
option_context_hook (option_context_hook_data, opt_ctx);
success = g_option_context_parse (opt_ctx, argc, argv, &error);
if (!success) {

View File

@@ -33,7 +33,8 @@ gboolean nm_main_utils_early_setup (const char *progname,
char **argv[],
int *argc,
GOptionEntry *options,
GOptionEntry *more_options,
void (*option_context_hook) (gpointer user_data, GOptionContext *opt_ctx),
gpointer option_context_hook_data,
const char *summary);
#endif /* __MAIN_UTILS_H__ */

View File

@@ -204,6 +204,7 @@ main (int argc, char *argv[])
GError *error = NULL;
gboolean wrote_pidfile = FALSE;
char *bad_domains = NULL;
NMConfigCmdLineOptions *config_cli;
GOptionEntry options[] = {
{ "version", 'V', 0, G_OPTION_ARG_NONE, &show_version, N_("Print NetworkManager version and exit"), NULL },
@@ -224,11 +225,13 @@ main (int argc, char *argv[])
main_loop = g_main_loop_new (NULL, FALSE);
config_cli = nm_config_cmd_line_options_new ();
if (!nm_main_utils_early_setup ("NetworkManager",
&argv,
&argc,
options,
nm_config_get_options (),
(void (*)(gpointer, GOptionContext *)) nm_config_cmd_line_options_add_to_entries,
config_cli,
_("NetworkManager monitors all network connections and automatically\nchooses the best connection to use. It also allows the user to\nspecify wireless access points which wireless cards in the computer\nshould associate with.")))
exit (1);
@@ -290,7 +293,9 @@ main (int argc, char *argv[])
exit (1);
/* Read the config file and CLI overrides */
config = nm_config_new (&error);
config = nm_config_setup (config_cli, &error);
nm_config_cmd_line_options_free (config_cli);
config_cli = NULL;
if (config == NULL) {
fprintf (stderr, _("Failed to read configuration: (%d) %s\n"),
error ? error->code : -1,

View File

@@ -38,7 +38,23 @@
#define NM_OLD_SYSTEM_CONF_FILE NMCONFDIR "/nm-system-settings.conf"
#define NM_NO_AUTO_DEFAULT_STATE_FILE NMSTATEDIR "/no-auto-default.state"
struct NMConfigCmdLineOptions {
char *config_path;
char *config_dir;
char *no_auto_default_file;
char *plugins;
char *connectivity_uri;
/* We store interval as signed internally to track whether it's
* set or not via GOptionEntry
*/
int connectivity_interval;
char *connectivity_response;
};
typedef struct {
NMConfigCmdLineOptions cli;
char *nm_conf_path;
char *config_dir;
char *config_description;
@@ -57,7 +73,7 @@ typedef struct {
char *debug;
char *connectivity_uri;
gint connectivity_interval;
guint connectivity_interval;
char *connectivity_response;
char **no_auto_default;
@@ -66,8 +82,6 @@ typedef struct {
gboolean configure_and_quit;
} NMConfigPrivate;
static NMConfig *singleton = NULL;
G_DEFINE_TYPE (NMConfig, nm_config, G_TYPE_OBJECT)
#define NM_CONFIG_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_CONFIG, NMConfigPrivate))
@@ -202,10 +216,7 @@ nm_config_get_connectivity_interval (NMConfig *config)
{
g_return_val_if_fail (config != NULL, 0);
/* We store interval as signed internally to track whether it's
* set or not, but report as unsigned to callers.
*/
return MAX (NM_CONFIG_GET_PRIVATE (config)->connectivity_interval, 0);
return NM_CONFIG_GET_PRIVATE (config)->connectivity_interval;
}
const char *
@@ -348,30 +359,76 @@ nm_config_set_ethernet_no_auto_default (NMConfig *config, NMDevice *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_connectivity_uri;
static int cli_connectivity_interval = -1;
static char *cli_connectivity_response;
static void
_nm_config_cmd_line_options_clear (NMConfigCmdLineOptions *cli)
{
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->connectivity_uri, g_free);
g_clear_pointer (&cli->connectivity_response, g_free);
cli->connectivity_interval = -1;
}
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") },
static void
_nm_config_cmd_line_options_copy (const NMConfigCmdLineOptions *cli, NMConfigCmdLineOptions *dst)
{
g_return_if_fail (cli);
g_return_if_fail (dst);
g_return_if_fail (cli != dst);
_nm_config_cmd_line_options_clear (dst);
dst->config_dir = g_strdup (cli->config_dir);
dst->config_path = g_strdup (cli->config_path);
dst->no_auto_default_file = g_strdup (cli->no_auto_default_file);
dst->plugins = g_strdup (cli->plugins);
dst->connectivity_uri = g_strdup (cli->connectivity_uri);
dst->connectivity_response = g_strdup (cli->connectivity_response);
dst->connectivity_interval = cli->connectivity_interval;
}
NMConfigCmdLineOptions *
nm_config_cmd_line_options_new ()
{
NMConfigCmdLineOptions *cli = g_new0 (NMConfigCmdLineOptions, 1);
_nm_config_cmd_line_options_clear (cli);
return cli;
}
void
nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli)
{
g_return_if_fail (cli);
_nm_config_cmd_line_options_clear (cli);
g_free (cli);
}
void
nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
GOptionContext *opt_ctx)
{
g_return_if_fail (opt_ctx);
g_return_if_fail (cli);
{
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") },
/* These three are hidden for now, and should eventually just go away. */
{ "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli_connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
{ "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli_connectivity_interval, N_("The interval between connectivity checks (in seconds)"), "60" },
{ "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli_connectivity_response, N_("The expected start of the response"), N_("Bingo!") },
{NULL}
};
GOptionEntry *
nm_config_get_options (void)
{
return config_options;
{ "connectivity-uri", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_uri, N_("An http(s) address for checking internet connectivity"), "http://example.com" },
{ "connectivity-interval", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_INT, &cli->connectivity_interval, N_("The interval between connectivity checks (in seconds)"), "60" },
{ "connectivity-response", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &cli->connectivity_response, N_("The expected start of the response"), N_("Bingo!") },
{ 0 },
};
g_option_context_add_main_entries (opt_ctx, config_options, NULL);
}
}
/************************************************************************/
@@ -445,10 +502,10 @@ find_base_config (NMConfig *config, GError **error)
GError *my_error = NULL;
/* Try a user-specified config file first */
if (cli_config_path) {
if (priv->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);
if (read_config (config, priv->cli.config_path, error)) {
priv->nm_conf_path = g_strdup (priv->cli.config_path);
return TRUE;
} else
return FALSE;
@@ -500,11 +557,25 @@ find_base_config (NMConfig *config, GError **error)
/************************************************************************/
NM_DEFINE_SINGLETON_DESTRUCTOR (NMConfig);
NM_DEFINE_SINGLETON_WEAK_REF (NMConfig);
NMConfig *
nm_config_get (void)
{
g_assert (singleton);
return singleton;
g_assert (singleton_instance);
return singleton_instance;
}
NMConfig *
nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error)
{
g_assert (!singleton_instance);
singleton_instance = nm_config_new (cli, error);
if (singleton_instance)
nm_singleton_instance_weak_ref_register ();
return singleton_instance;
}
static int
@@ -516,9 +587,8 @@ sort_asciibetically (gconstpointer a, gconstpointer b)
return strcmp (s1, s2);
}
/* call this function only once! */
NMConfig *
nm_config_new (GError **error)
nm_config_new (const NMConfigCmdLineOptions *cli, GError **error)
{
NMConfigPrivate *priv = NULL;
GFile *dir;
@@ -528,21 +598,25 @@ nm_config_new (GError **error)
const char *name;
int i;
GString *config_description;
NMConfig *self;
g_assert (!singleton);
singleton = NM_CONFIG (g_object_new (NM_TYPE_CONFIG, NULL));
priv = NM_CONFIG_GET_PRIVATE (singleton);
self = NM_CONFIG (g_object_new (NM_TYPE_CONFIG, NULL));
priv = NM_CONFIG_GET_PRIVATE (self);
if (!cli)
_nm_config_cmd_line_options_clear (&priv->cli);
else
_nm_config_cmd_line_options_copy (cli, &priv->cli);
/* First read the base config file */
if (!find_base_config (singleton, error)) {
g_object_unref (singleton);
singleton = NULL;
if (!find_base_config (self, error)) {
g_object_unref (self);
return NULL;
}
/* Now read the overrides in the config dir */
if (cli_config_dir)
priv->config_dir = g_strdup (cli_config_dir);
if (priv->cli.config_dir)
priv->config_dir = g_strdup (priv->cli.config_dir);
else
priv->config_dir = g_strdup (NM_DEFAULT_SYSTEM_CONF_DIR);
@@ -570,27 +644,27 @@ nm_config_new (GError **error)
g_ptr_array_sort (confs, sort_asciibetically);
priv->config_description = g_string_free (config_description, FALSE);
for (i = 0; i < confs->len; i++) {
if (!read_config (singleton, confs->pdata[i], error)) {
g_object_unref (singleton);
singleton = NULL;
if (!read_config (self, confs->pdata[i], error)) {
g_object_unref (self);
self = NULL;
break;
}
}
g_ptr_array_unref (confs);
if (!singleton)
if (!self)
return NULL;
/* 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);
if (priv->cli.no_auto_default_file)
priv->no_auto_default_file = g_strdup (priv->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);
merge_no_auto_default_state (self);
/* 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);
if (priv->cli.plugins && priv->cli.plugins[0])
g_key_file_set_value (priv->keyfile, "main", "plugins", priv->cli.plugins);
priv->plugins = g_key_file_get_string_list (priv->keyfile, "main", "plugins", NULL, NULL);
if (!priv->plugins && STRLEN (CONFIG_PLUGINS_DEFAULT) > 0)
priv->plugins = g_strsplit (CONFIG_PLUGINS_DEFAULT, ",", -1);
@@ -607,23 +681,23 @@ nm_config_new (GError **error)
priv->debug = g_key_file_get_value (priv->keyfile, "main", "debug", NULL);
if (cli_connectivity_uri && cli_connectivity_uri[0])
g_key_file_set_value (priv->keyfile, "connectivity", "uri", cli_connectivity_uri);
if (priv->cli.connectivity_uri && priv->cli.connectivity_uri[0])
g_key_file_set_value (priv->keyfile, "connectivity", "uri", priv->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);
if (priv->cli.connectivity_interval >= 0)
g_key_file_set_integer (priv->keyfile, "connectivity", "interval", priv->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);
if (priv->cli.connectivity_response && priv->cli.connectivity_response[0])
g_key_file_set_value (priv->keyfile, "connectivity", "response", priv->cli.connectivity_response);
priv->connectivity_response = g_key_file_get_value (priv->keyfile, "connectivity", "response", NULL);
priv->ignore_carrier = g_key_file_get_string_list (priv->keyfile, "main", "ignore-carrier", NULL, NULL);
priv->configure_and_quit = _get_bool_value (priv->keyfile, "main", "configure-and-quit", FALSE);
return singleton;
return self;
}
static void
@@ -635,8 +709,6 @@ nm_config_init (NMConfig *config)
priv->keyfile = g_key_file_new ();
g_key_file_set_list_separator (priv->keyfile, ',');
priv->connectivity_interval = -1;
}
static void
@@ -660,14 +732,7 @@ finalize (GObject *gobject)
g_strfreev (priv->no_auto_default);
g_strfreev (priv->ignore_carrier);
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_connectivity_uri, g_free);
g_clear_pointer (&cli_connectivity_response, g_free);
_nm_config_cmd_line_options_clear (&priv->cli);
G_OBJECT_CLASS (nm_config_parent_class)->finalize (gobject);
}

View File

@@ -36,6 +36,8 @@ G_BEGIN_DECLS
#define NM_IS_CONFIG_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_CONFIG))
#define NM_CONFIG_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_CONFIG, NMConfigClass))
typedef struct NMConfigCmdLineOptions NMConfigCmdLineOptions;
struct _NMConfig {
GObject parent;
};
@@ -71,8 +73,13 @@ gboolean nm_config_get_ignore_carrier (NMConfig *config, NMDevice *device);
char *nm_config_get_value (NMConfig *config, const char *group, const char *key, GError **error);
/* for main.c only */
GOptionEntry *nm_config_get_options (void);
NMConfig *nm_config_new (GError **error);
NMConfigCmdLineOptions *nm_config_cmd_line_options_new (void);
void nm_config_cmd_line_options_free (NMConfigCmdLineOptions *cli);
void nm_config_cmd_line_options_add_to_entries (NMConfigCmdLineOptions *cli,
GOptionContext *opt_ctx);
NMConfig *nm_config_new (const NMConfigCmdLineOptions *cli, GError **error);
NMConfig *nm_config_setup (const NMConfigCmdLineOptions *cli, GError **error);
G_END_DECLS

View File

@@ -315,6 +315,7 @@ main (int argc, char *argv[])
&argc,
options,
NULL,
NULL,
_("nm-iface-helper is a small, standalone process that manages a single network interface.")))
exit (1);

View File

@@ -28,8 +28,8 @@
#include "nm-test-device.h"
#include "nm-fake-platform.h"
static void
setup_config (const char *config_file, const char *config_dir, ...)
static NMConfig *
setup_config (GError **error, const char *config_file, const char *config_dir, ...)
{
va_list ap;
GPtrArray *args;
@@ -37,6 +37,11 @@ setup_config (const char *config_file, const char *config_dir, ...)
int argc;
GOptionContext *context;
gboolean success;
NMConfig *config;
GError *local_error = NULL;
NMConfigCmdLineOptions *cli;
g_assert (!error || !*error);
args = g_ptr_array_new ();
g_ptr_array_add (args, "test-config");
@@ -53,8 +58,10 @@ setup_config (const char *config_file, const char *config_dir, ...)
argv = (char **)args->pdata;
argc = args->len;
cli = nm_config_cmd_line_options_new ();
context = g_option_context_new (NULL);
g_option_context_add_main_entries (context, nm_config_get_options (), NULL);
nm_config_cmd_line_options_add_to_entries (cli, context);
success = g_option_context_parse (context, &argc, &argv, NULL);
g_option_context_free (context);
@@ -62,6 +69,18 @@ setup_config (const char *config_file, const char *config_dir, ...)
g_printerr ("Invalid options.\n");
g_ptr_array_free (args, TRUE);
config = nm_config_setup (cli, &local_error);
if (error) {
g_assert (!config);
g_assert (local_error);
g_propagate_error (error, local_error);
} else {
g_assert (config);
g_assert_no_error (local_error);
}
nm_config_cmd_line_options_free (cli);
return config;
}
static void
@@ -72,9 +91,7 @@ test_config_simple (void)
const char **plugins;
char *value;
setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL);
config = nm_config_new (&error);
g_assert_no_error (error);
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir", NULL);
g_assert_cmpstr (nm_config_get_path (config), ==, SRCDIR "/NetworkManager.conf");
g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhclient");
@@ -107,40 +124,33 @@ test_config_simple (void)
static void
test_config_non_existent (void)
{
NMConfig *config;
GError *error = NULL;
setup_config (SRCDIR "/no-such-file", "/no/such/dir", NULL);
config = nm_config_new (&error);
g_assert (!config);
setup_config (&error, SRCDIR "/no-such-file", "/no/such/dir", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_NOT_FOUND);
g_clear_error (&error);
}
static void
test_config_parse_error (void)
{
NMConfig *config;
GError *error = NULL;
setup_config (SRCDIR "/bad.conf", "/no/such/dir", NULL);
config = nm_config_new (&error);
g_assert (!config);
setup_config (&error, SRCDIR "/bad.conf", "/no/such/dir", NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
g_clear_error (&error);
}
static void
test_config_override (void)
{
NMConfig *config;
GError *error = NULL;
const char **plugins;
setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir",
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
"--plugins", "alpha,beta,gamma,delta",
"--connectivity-interval", "12",
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), ==, "dhclient");
@@ -175,11 +185,9 @@ test_config_no_auto_default (void)
g_assert_cmpint (nwrote, ==, 18);
close (fd);
setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir",
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
"--no-auto-default", state_file,
NULL);
config = nm_config_new (&error);
g_assert_no_error (error);
dev1 = nm_test_device_new ("11:11:11:11:11:11");
dev2 = nm_test_device_new ("22:22:22:22:22:22");
@@ -196,11 +204,9 @@ test_config_no_auto_default (void)
g_object_unref (config);
setup_config (SRCDIR "/NetworkManager.conf", "/no/such/dir",
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", "/no/such/dir",
"--no-auto-default", state_file,
NULL);
config = nm_config_new (&error);
g_assert_no_error (error);
g_assert (!nm_config_get_ethernet_can_auto_default (config, dev1));
g_assert (!nm_config_get_ethernet_can_auto_default (config, dev2));
@@ -222,13 +228,10 @@ 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);
config = setup_config (NULL, SRCDIR "/NetworkManager.conf", SRCDIR "/conf.d", NULL);
g_assert_cmpstr (nm_config_get_path (config), ==, SRCDIR "/NetworkManager.conf");
g_assert_cmpstr (nm_config_get_dhcp_client (config), ==, "dhcpcd");
@@ -269,14 +272,12 @@ test_config_confdir (void)
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 (!config);
setup_config (&error, SRCDIR "/NetworkManager.conf", SRCDIR, NULL);
g_assert_error (error, G_KEY_FILE_ERROR, G_KEY_FILE_ERROR_PARSE);
g_clear_error (&error);
}
int