Commit 1f818510 authored by Dan Winship's avatar Dan Winship

core: add monitor-connection-files=false and ReloadConnections

Add a "monitor-connection-files" config option, which can be set to
"false" to disable automatic reloading of connections on file change.

To go with this, add a new ReloadConnections method on
o.fd.NM.Settings that can be used to manually reload connections, and
add an nm-cli command to call it.
parent 4b74009b
......@@ -205,7 +205,8 @@ usage (void)
#endif
" down [ id | uuid | path | apath ] <ID>\n\n"
" add COMMON_OPTIONS TYPE_SPECIFIC_OPTIONS IP_OPTIONS\n\n"
" delete [ id | uuid | path ] <ID>\n\n\n"
" delete [ id | uuid | path ] <ID>\n\n"
" reload\n\n\n"
));
}
......@@ -284,6 +285,7 @@ static const char *real_con_commands[] = {
"down",
"add",
"delete",
"reload",
NULL
};
......@@ -3221,6 +3223,32 @@ finish:
return nmc->return_value;
}
static NMCResultCode
do_connection_reload (NmCli *nmc, int argc, char **argv)
{
GError *error = NULL;
nmc->return_value = NMC_RESULT_SUCCESS;
nmc->should_wait = FALSE;
if (!nm_client_get_manager_running (nmc->client)) {
g_string_printf (nmc->return_text, _("Error: NetworkManager is not running."));
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
return nmc->return_value;
}
if (!nm_remote_settings_reload_connections (nmc->system_settings, &error)) {
g_string_printf (nmc->return_text, _("Error: %s."), error->message);
if (error->code == NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE)
nmc->return_value = NMC_RESULT_ERROR_NM_NOT_RUNNING;
else
nmc->return_value = NMC_RESULT_ERROR_UNKNOWN;
g_clear_error (&error);
}
return nmc->return_value;
}
static NMCResultCode
parse_cmd (NmCli *nmc, int argc, char **argv)
{
......@@ -3263,6 +3291,9 @@ parse_cmd (NmCli *nmc, int argc, char **argv)
else if (matches(*argv, "delete") == 0) {
nmc->return_value = do_connection_delete (nmc, argc-1, argv+1);
}
else if (matches(*argv, "reload") == 0) {
nmc->return_value = do_connection_reload (nmc, argc-1, argv+1);
}
else if (nmc_arg_is_help (*argv)) {
usage ();
nmc->should_wait = FALSE;
......
......@@ -4,6 +4,15 @@
[main]
# Normally, NetworkManager reloads connection files on disk any time
# they are changed. Setting "monitor-connection-files=false" will
# disable this behavior, and NetworkManager will then only read
# connection files at startup, and when explicitly requested via
# D-Bus.
#monitor-connection-files=false
# Normally, if there is an ethernet device that is not matched by any
# existing configured connection, NetworkManager will create a
# "default" connection for that device, using automatic (DHCP/SLAAC)
......
......@@ -31,6 +31,11 @@
the connection to disk. Secrets may be part of the update request
and may sent to a Secret Agent for storage, depending on the the
flags associated with each secret.
Use the 'Save' method to save these changes to disk. Note
that unsaved changes will be lost if the connection is
reloaded from disk (either automatically on file change or
due to an explicit ReloadConnections call).
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_connection_update_unsaved"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
......
......@@ -62,6 +62,11 @@
operation does not start the network connection unless (1) device is
idle and able to connect to the network described by the new connection,
and (2) the connection is allowed to be started automatically.
Use the 'Save' method on the connection to save these changes
to disk. Note that unsaved changes will be lost if the
connection is reloaded from disk (either automatically on file
change or due to an explicit ReloadConnections call).
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_add_connection_unsaved"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
......@@ -77,6 +82,23 @@
</arg>
</method>
<method name="ReloadConnections">
<tp:docstring>
Tells NetworkManager to reload all connection files from disk,
including noticing any added or deleted connection files. By
default, connections are re-read automatically any time they
change, so you only need to use this command if you have set
"monitor-connection-files=false" in NetworkManager.conf.
</tp:docstring>
<annotation name="org.freedesktop.DBus.GLib.CSymbol" value="impl_settings_reload_connections"/>
<annotation name="org.freedesktop.DBus.GLib.Async" value=""/>
<arg name="status" type="b" direction="out">
<tp:docstring>
Success or failure.
</tp:docstring>
</arg>
</method>
<method name="SaveHostname">
<tp:docstring>
Save the hostname to persistent configuration.
......
......@@ -231,6 +231,7 @@ global:
nm_remote_settings_new;
nm_remote_settings_new_async;
nm_remote_settings_new_finish;
nm_remote_settings_reload_connections;
nm_remote_settings_save_hostname;
nm_secret_agent_delete_secrets;
nm_secret_agent_error_get_type;
......
......@@ -629,6 +629,47 @@ nm_remote_settings_add_connection_unsaved (NMRemoteSettings *settings,
return TRUE;
}
/**
* nm_remote_settings_reload_connections:
* @settings: the #NMRemoteSettings
* @error: return location for #GError
*
* Requests that the remote settings service reload all connection
* files from disk, adding, updating, and removing connections until
* the in-memory state matches the on-disk state.
*
* Return value: %TRUE on success, %FALSE on failure
*
* Since: 0.9.10
**/
gboolean
nm_remote_settings_reload_connections (NMRemoteSettings *settings,
GError **error)
{
NMRemoteSettingsPrivate *priv;
gboolean success;
g_return_val_if_fail (NM_IS_REMOTE_SETTINGS (settings), FALSE);
priv = NM_REMOTE_SETTINGS_GET_PRIVATE (settings);
_nm_remote_settings_ensure_inited (settings);
if (!priv->service_running) {
g_set_error_literal (error, NM_REMOTE_SETTINGS_ERROR,
NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE,
"NetworkManager is not running.");
return FALSE;
}
if (!dbus_g_proxy_call (priv->proxy, "ReloadConnections", error,
G_TYPE_INVALID,
G_TYPE_BOOLEAN, &success,
G_TYPE_INVALID))
return FALSE;
return success;
}
static void
clear_one_hash (GHashTable *table)
{
......
......@@ -45,6 +45,8 @@ G_BEGIN_DECLS
* was removed before it was completely initialized
* @NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE: the #NMRemoteConnection object
* is not visible or otherwise unreadable
* @NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE: NetworkManager is not running.
* (Since 0.9.10)
*
* Describes errors that may result from operations involving a #NMRemoteSettings.
*
......@@ -53,6 +55,7 @@ typedef enum {
NM_REMOTE_SETTINGS_ERROR_UNKNOWN = 0, /*< nick=UnknownError >*/
NM_REMOTE_SETTINGS_ERROR_CONNECTION_REMOVED, /*< nick=ConnectionRemoved >*/
NM_REMOTE_SETTINGS_ERROR_CONNECTION_UNAVAILABLE, /*< nick=ConnectionUnavailable >*/
NM_REMOTE_SETTINGS_ERROR_SERVICE_UNAVAILABLE, /*< nick=ServiceUnavailable >*/
} NMRemoteSettingsError;
#define NM_REMOTE_SETTINGS_ERROR nm_remote_settings_error_quark ()
......@@ -132,6 +135,9 @@ gboolean nm_remote_settings_add_connection_unsaved (NMRemoteSettings *settings,
NMRemoteSettingsAddConnectionFunc callback,
gpointer user_data);
gboolean nm_remote_settings_reload_connections (NMRemoteSettings *settings,
GError **error);
gboolean nm_remote_settings_save_hostname (NMRemoteSettings *settings,
const char *hostname,
NMRemoteSettingsSaveHostnameFunc callback,
......
......@@ -96,6 +96,16 @@ Copyright (C) 2010 - 2013 Red Hat, Inc.
connection, the error is returned to the user. See below
for available plugins.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>monitor-connection-files</varname></term>
<listitem><para>Whether the configured settings plugin(s)
should set up file monitors and immediately pick up changes
made to connection files while NetworkManager is running. This
is enabled by default; if this key is set to
'<literal>false</literal>', then NetworkManager will only read
the connection files at startup, and when explicitly requested
via the ReloadConnections D-Bus call.</para></listitem>
</varlistentry>
<varlistentry>
<term><varname>dhcp</varname></term>
<listitem><para>This key sets up what DHCP client
......
......@@ -238,7 +238,7 @@ NetworkManager connections
.br
Get information about \fINetworkManager\fP connections and manage them.
.TP
.SS \fICOMMAND\fP := { show | up | down | add | delete }
.SS \fICOMMAND\fP := { show | up | down | add | delete | reload }
.sp
.RS
.TP
......@@ -501,6 +501,13 @@ its name, UUID or D-Bus path. If <ID> is ambiguous, a keyword \fIid\fP,
\fIuuid\fP or \fIpath\fP can be used.
.br
See \fBshow active\fP above for the description of the <ID>-specifying keywords.
.TP
.B reload
.br
Reload all connection files from disk. By default, connections are re-read
automatically any time they change, so you only need to use this command when
the auto-loading feature is disabled ("monitor-connection-files=false"
in NetworkManager.conf).
.RE
.TP
......
......@@ -43,6 +43,7 @@ typedef struct {
GKeyFile *keyfile;
char **plugins;
gboolean monitor_connection_files;
char *dhcp_client;
char *dns_mode;
......@@ -81,6 +82,14 @@ nm_config_get_plugins (NMConfig *config)
return (const char **) NM_CONFIG_GET_PRIVATE (config)->plugins;
}
gboolean
nm_config_get_monitor_connection_files (NMConfig *config)
{
g_return_val_if_fail (config != NULL, FALSE);
return NM_CONFIG_GET_PRIVATE (config)->monitor_connection_files;
}
const char *
nm_config_get_dhcp_client (NMConfig *config)
{
......@@ -434,6 +443,7 @@ nm_config_new (GError **error)
GFileInfo *info;
GPtrArray *confs;
const char *name;
char *value;
int i;
g_assert (!singleton);
......@@ -492,6 +502,20 @@ nm_config_new (GError **error)
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);
value = g_key_file_get_value (priv->keyfile, "main", "monitor-connection-files", NULL);
if (value) {
if (!strcmp (value, "true") || !strcmp (value, "yes") || !strcmp (value, "on"))
priv->monitor_connection_files = TRUE;
else if (!strcmp (value, "false") || !strcmp (value, "no") || !strcmp (value, "off"))
priv->monitor_connection_files = FALSE;
else {
g_warning ("Unrecognized value for main.monitor-connection-files: %s. Assuming 'false'", value);
priv->monitor_connection_files = FALSE;
}
g_free (value);
} else
priv->monitor_connection_files = TRUE;
priv->dhcp_client = g_key_file_get_value (priv->keyfile, "main", "dhcp", NULL);
priv->dns_mode = g_key_file_get_value (priv->keyfile, "main", "dns", NULL);
......
......@@ -50,6 +50,7 @@ NMConfig *nm_config_get (void);
const char *nm_config_get_path (NMConfig *config);
const char **nm_config_get_plugins (NMConfig *config);
gboolean nm_config_get_monitor_connection_files (NMConfig *config);
const char *nm_config_get_dhcp_client (NMConfig *config);
const char *nm_config_get_dns_mode (NMConfig *config);
const char *nm_config_get_log_level (NMConfig *config);
......
......@@ -104,6 +104,9 @@ static void impl_settings_add_connection_unsaved (NMSettings *self,
GHashTable *settings,
DBusGMethodInvocation *context);
static void impl_settings_reload_connections (NMSettings *self,
DBusGMethodInvocation *context);
static void impl_settings_save_hostname (NMSettings *self,
const char *hostname,
DBusGMethodInvocation *context);
......@@ -1213,6 +1216,46 @@ impl_settings_add_connection_unsaved (NMSettings *self,
impl_settings_add_connection_helper (self, settings, FALSE, context);
}
static void
impl_settings_reload_connections (NMSettings *self,
DBusGMethodInvocation *context)
{
NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self);
GSList *iter;
gulong caller_uid;
GError *error = NULL;
if (!nm_dbus_manager_get_caller_info (priv->dbus_mgr, context, NULL, &caller_uid)) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Unable to determine request UID.");
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
if (caller_uid != 0) {
nm_log_warn (LOGD_SETTINGS, "ReloadConnections: permission denied to %lu", caller_uid);
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_PERMISSION_DENIED,
"Permission denied");
dbus_g_method_return_error (context, error);
g_error_free (error);
return;
}
if (!priv->connections_loaded) {
load_connections (self);
} else {
for (iter = priv->plugins; iter; iter = g_slist_next (iter)) {
NMSystemConfigInterface *plugin = NM_SYSTEM_CONFIG_INTERFACE (iter->data);
nm_system_config_interface_reload_connections (plugin);
}
}
dbus_g_method_return (context, TRUE);
}
static void
pk_hostname_cb (NMAuthChain *chain,
GError *chain_error,
......
......@@ -137,6 +137,15 @@ nm_system_config_interface_get_connections (NMSystemConfigInterface *config)
return NULL;
}
void
nm_system_config_interface_reload_connections (NMSystemConfigInterface *config)
{
g_return_if_fail (config != NULL);
if (NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->reload_connections)
NM_SYSTEM_CONFIG_INTERFACE_GET_INTERFACE (config)->reload_connections (config);
}
GSList *
nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config)
{
......
......@@ -89,6 +89,11 @@ struct _NMSystemConfigInterface {
*/
GSList * (*get_connections) (NMSystemConfigInterface *config);
/* Requests that the plugin reload all connection files from disk,
* and emit signals reflecting new, changed, and removed connections.
*/
void (*reload_connections) (NMSystemConfigInterface *config);
/*
* Return a string list of specifications of devices which NetworkManager
* should not manage. Returned list will be freed by the system settings
......@@ -137,6 +142,8 @@ void nm_system_config_interface_init (NMSystemConfigInterface *config,
GSList *nm_system_config_interface_get_connections (NMSystemConfigInterface *config);
void nm_system_config_interface_reload_connections (NMSystemConfigInterface *config);
GSList *nm_system_config_interface_get_unmanaged_specs (NMSystemConfigInterface *config);
NMSettingsConnection *nm_system_config_interface_add_connection (NMSystemConfigInterface *config,
......
......@@ -421,10 +421,9 @@ conf_file_changed (GFileMonitor *monitor,
}
/* This function starts the inotify monitors that watch the plugin's config
* file directory for new connections and changes to existing connections.
* At this time all plugins are expected to make NM aware of changes on-the-fly
* instead of requiring a SIGHUP or SIGUSR1 or some D-Bus method to say
* "reload".
* file directory for new connections and changes to existing connections
* (if not disabled by NetworkManager.conf), and for changes to the plugin's
* non-connection config files.
*/
static void
setup_monitoring (NMSystemConfigInterface *config)
......@@ -438,16 +437,18 @@ setup_monitoring (NMSystemConfigInterface *config)
*/
priv->connections = g_hash_table_new_full (g_str_hash, g_str_equal, NULL, g_object_unref);
/* Set up the watch for our config directory */
file = g_file_new_for_path (EXAMPLE_DIR);
monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
/* This registers the dir_changed() function to be called whenever
* the GFileMonitor object notices a change in the directory.
*/
priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
priv->monitor = monitor;
if (nm_config_get_monitor_connection_files (nm_config_get ())) {
/* Set up the watch for our config directory */
file = g_file_new_for_path (EXAMPLE_DIR);
monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
g_object_unref (file);
if (monitor) {
/* This registers the dir_changed() function to be called whenever
* the GFileMonitor object notices a change in the directory.
*/
priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
priv->monitor = monitor;
}
}
/* Set up a watch on our configuration file, basically just for watching
......
......@@ -28,6 +28,7 @@ INCLUDES = \
-I$(top_srcdir)/src/wifi \
-I$(top_srcdir)/src/settings \
-I$(top_srcdir)/src/posix-signals \
-I$(top_srcdir)/src/config \
-I$(top_srcdir)/include \
-I$(top_builddir)/include \
-I$(top_srcdir)/libnm-glib \
......
......@@ -44,10 +44,12 @@
#include "plugin.h"
#include "nm-system-config-interface.h"
#include "nm-settings-error.h"
#include "nm-config.h"
#include "nm-ifcfg-connection.h"
#include "nm-inotify-helper.h"
#include "shvar.h"
#include "reader.h"
#include "writer.h"
#include "utils.h"
......@@ -64,7 +66,8 @@ static gboolean impl_ifcfgrh_get_ifcfg_details (SCPluginIfcfg *plugin,
static void connection_new_or_changed (SCPluginIfcfg *plugin,
const char *path,
NMIfcfgConnection *existing);
NMIfcfgConnection *existing,
char **out_old_path);
static void system_config_interface_init (NMSystemConfigInterface *system_config_interface_class);
......@@ -109,7 +112,7 @@ connection_ifcfg_changed (NMIfcfgConnection *connection, gpointer user_data)
path = nm_ifcfg_connection_get_path (connection);
g_return_if_fail (path != NULL);
connection_new_or_changed (plugin, path, connection);
connection_new_or_changed (plugin, path, connection, NULL);
}
static NMIfcfgConnection *
......@@ -173,35 +176,6 @@ _internal_new_connection (SCPluginIfcfg *self,
return connection;
}
static void
read_connections (SCPluginIfcfg *plugin)
{
GDir *dir;
GError *err = NULL;
dir = g_dir_open (IFCFG_DIR, 0, &err);
if (dir) {
const char *item;
while ((item = g_dir_read_name (dir))) {
char *full_path;
if (utils_should_ignore_file (item, TRUE))
continue;
full_path = g_build_filename (IFCFG_DIR, item, NULL);
if (utils_get_ifcfg_name (full_path, TRUE))
_internal_new_connection (plugin, full_path, NULL, NULL);
g_free (full_path);
}
g_dir_close (dir);
} else {
PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Can not read directory '%s': %s", IFCFG_DIR, err->message);
g_error_free (err);
}
}
/* Monitoring */
static void
......@@ -242,10 +216,26 @@ find_by_path (SCPluginIfcfg *self, const char *path)
return NULL;
}
static NMIfcfgConnection *
find_by_uuid_from_path (SCPluginIfcfg *self, const char *path)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (self);
char *uuid;
g_return_val_if_fail (path != NULL, NULL);
uuid = uuid_from_file (path);
if (uuid)
return g_hash_table_lookup (priv->connections, uuid);
else
return NULL;
}
static void
connection_new_or_changed (SCPluginIfcfg *self,
const char *path,
NMIfcfgConnection *existing)
NMIfcfgConnection *existing,
char **out_old_path)
{
NMIfcfgConnection *new;
GError *error = NULL;
......@@ -255,6 +245,21 @@ connection_new_or_changed (SCPluginIfcfg *self,
g_return_if_fail (self != NULL);
g_return_if_fail (path != NULL);
if (out_old_path)
*out_old_path = NULL;
if (!existing) {
/* See if it's a rename */
existing = find_by_uuid_from_path (self, path);
if (existing) {
const char *old_path = nm_ifcfg_connection_get_path (existing);
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "renaming %s -> %s", old_path, path);
if (out_old_path)
*out_old_path = g_strdup (old_path);
nm_ifcfg_connection_set_path (existing, path);
}
}
if (!existing) {
/* New connection */
new = _internal_new_connection (self, path, NULL, NULL);
......@@ -371,7 +376,7 @@ ifcfg_dir_changed (GFileMonitor *monitor,
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
/* Update or new */
connection_new_or_changed (plugin, ifcfg_path, connection);
connection_new_or_changed (plugin, ifcfg_path, connection, NULL);
break;
default:
break;
......@@ -399,6 +404,65 @@ setup_ifcfg_monitoring (SCPluginIfcfg *plugin)
}
}
static void
read_connections (SCPluginIfcfg *plugin)
{
SCPluginIfcfgPrivate *priv = SC_PLUGIN_IFCFG_GET_PRIVATE (plugin);
GDir *dir;
GError *err = NULL;
const char *item;
GHashTable *oldconns;
GHashTableIter iter;
gpointer key, value;
NMIfcfgConnection *connection;
dir = g_dir_open (IFCFG_DIR, 0, &err);
if (!dir) {
PLUGIN_WARN (IFCFG_PLUGIN_NAME, "Can not read directory '%s': %s", IFCFG_DIR, err->message);
g_error_free (err);
return;
}
oldconns = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL);
g_hash_table_iter_init (&iter, priv->connections);
while (g_hash_table_iter_next (&iter, NULL, &value))
g_hash_table_insert (oldconns, g_strdup (nm_ifcfg_connection_get_path (value)), value);
while ((item = g_dir_read_name (dir))) {
char *full_path, *old_path;
if (utils_should_ignore_file (item, TRUE))
continue;
full_path = g_build_filename (IFCFG_DIR, item, NULL);
if (!utils_get_ifcfg_name (full_path, TRUE))
goto next;
connection = g_hash_table_lookup (oldconns, full_path);
g_hash_table_remove (oldconns, full_path);
connection_new_or_changed (plugin, full_path, connection, &old_path);
if (old_path) {
g_hash_table_remove (oldconns, old_path);
g_free (old_path);
}
next:
g_free (full_path);
}
g_dir_close (dir);
g_hash_table_iter_init (&iter, oldconns);
while (g_hash_table_iter_next (&iter, &key, &value)) {
PLUGIN_PRINT (IFCFG_PLUGIN_NAME, "removed %s.", (char *)key);
g_hash_table_iter_remove (&iter);
remove_connection (plugin, value);
}
g_hash_table_destroy (oldconns);
}
static GSList *
get_connections (NMSystemConfigInterface *config)
{
......@@ -409,7 +473,8 @@ get_connections (NMSystemConfigInterface *config)
NMIfcfgConnection *connection;
if (!priv->initialized) {
setup_ifcfg_monitoring (plugin);
if (nm_config_get_monitor_connection_files (nm_config_get ()))
setup_ifcfg_monitoring (plugin);
read_connections (plugin);
priv->initialized = TRUE;
}
......@@ -423,6 +488,14 @@ get_connections (NMSystemConfigInterface *config)
return list;
}
static void
reload_connections (NMSystemConfigInterface *config)
{
SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
read_connections (plugin);
}
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
{
......@@ -854,6 +927,7 @@ system_config_interface_init (NMSystemConfigInterface *system_config_interface_c
/* interface implementation */
system_config_interface_class->get_connections = get_connections;
system_config_interface_class->add_connection = add_connection;
system_config_interface_class->reload_connections = reload_connections;
system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs;
system_config_interface_class->init = init;
}
......
......@@ -4251,6 +4251,34 @@ ensure_unmanaged (shvarFile *ifcfg,
PLUGIN_WARN (IFCFG_PLUGIN_NAME, " warning: NM_CONTROLLED was false but device was not uniquely identified; device will be managed");
}
char *
uuid_from_file (const char *filename)
{
const char *ifcfg_name = NULL;
shvarFile *ifcfg;
char *uuid;
g_return_val_if_fail (filename != NULL, NULL);
ifcfg_name = utils_get_ifcfg_name (filename, TRUE);
if (!ifcfg_name)
return NULL;
ifcfg = svNewFile (filename);
if (!ifcfg)
return NULL;
/* Try for a UUID key before falling back to hashing the file name */
uuid = svGetValue (ifcfg, "UUID", FALSE);
if (!uuid || !strlen (uuid)) {
g_free (uuid);
uuid = nm_utils_uuid_generate_from_string (ifcfg->fileName);
}
svCloseFile (ifcfg);
return uuid;
}
NMConnection *
connection_from_file (const char *filename,
const char *network_file, /* for unit tests only */
......
......@@ -37,4 +37,6 @@ NMConnection *connection_from_file (const char *filename,
GError **error,
gboolean *ignore_error);
char *uuid_from_file (const char *filename);
#endif /* __READER_H__ */
......@@ -66,7 +66,7 @@ typedef struct {
static void system_config_interface_init (NMSystemConfigInterface *class);
static void reload_connections (gpointer config);
static void reload_connections (NMSystemConfigInterface *config);
G_DEFINE_TYPE_EXTENDED (SCPluginIfnet, sc_plugin_ifnet, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (NM_TYPE_SYSTEM_CONFIG_INTERFACE, system_config_interface_init))
......@@ -191,12 +191,15 @@ setup_monitors (NMIfnetConnection * connection, gpointer user_data)
priv->hostname_monitor =