#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"
));
}
"down",
"add",
"delete",
+ "reload",
NULL
};
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)
{
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;
[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)
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=""/>
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=""/>
</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.
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;
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)
{
* 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.
*
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 ()
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,
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
.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
\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
GKeyFile *keyfile;
char **plugins;
+ gboolean monitor_connection_files;
char *dhcp_client;
char *dns_mode;
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)
{
GFileInfo *info;
GPtrArray *confs;
const char *name;
+ char *value;
int i;
g_assert (!singleton);
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);
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);
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);
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,
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)
{
*/
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
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,
}
/* 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)
*/
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
-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 \
#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"
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);
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 *
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
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;
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);
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;
}
}
+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)
{
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;
}
return list;
}
+static void
+reload_connections (NMSystemConfigInterface *config)
+{
+ SCPluginIfcfg *plugin = SC_PLUGIN_IFCFG (config);
+
+ read_connections (plugin);
+}
+
static GSList *
get_unmanaged_specs (NMSystemConfigInterface *config)
{
/* 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;
}
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 */
GError **error,
gboolean *ignore_error);
+char *uuid_from_file (const char *filename);
+
#endif /* __READER_H__ */
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))
priv->hostname_monitor =
monitor_file_changes (IFNET_SYSTEM_HOSTNAME_FILE,
- update_system_hostname, user_data);
- priv->net_monitor =
- monitor_file_changes (CONF_NET_FILE, reload_connections, user_data);
- priv->wpa_monitor =
- monitor_file_changes (WPA_SUPPLICANT_CONF, reload_connections,
- user_data);
+ update_system_hostname, user_data);
+ if (nm_config_get_monitor_connection_files (nm_config_get ())) {
+ priv->net_monitor =
+ monitor_file_changes (CONF_NET_FILE, (FileChangedFn) reload_connections,
+ user_data);
+ priv->wpa_monitor =
+ monitor_file_changes (WPA_SUPPLICANT_CONF, (FileChangedFn) reload_connections,
+ user_data);
+ }
}
static void
}
static void
-reload_connections (gpointer config)
+reload_connections (NMSystemConfigInterface *config)
{
SCPluginIfnet *self = SC_PLUGIN_IFNET (config);
SCPluginIfnetPrivate *priv = SC_PLUGIN_IFNET_GET_PRIVATE (self);
class->get_connections = get_connections;
class->get_unmanaged_specs = get_unmanaged_specs;
class->add_connection = add_connection;
+ class->reload_connections = reload_connections;
}
static void
return (NMSettingsConnection *) connection;
}
-static void
-read_connections (NMSystemConfigInterface *config)
-{
- SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
- GDir *dir;
- GError *error = NULL;
- const char *item;
-
- dir = g_dir_open (KEYFILE_DIR, 0, &error);
- if (!dir) {
- PLUGIN_WARN (KEYFILE_PLUGIN_NAME, "Cannot read directory '%s': (%d) %s",
- KEYFILE_DIR,
- error ? error->code : -1,
- error && error->message ? error->message : "(unknown)");
- g_clear_error (&error);
- return;
- }
-
- while ((item = g_dir_read_name (dir))) {
- NMSettingsConnection *connection;
- char *full_path;
-
- if (nm_keyfile_plugin_utils_should_ignore_file (item))
- continue;
-
- full_path = g_build_filename (KEYFILE_DIR, item, NULL);
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "parsing %s ... ", item);
-
- connection = _internal_new_connection (self, full_path, NULL, &error);
- if (connection) {
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " read connection '%s'",
- nm_connection_get_id (NM_CONNECTION (connection)));
- } else {
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s",
- (error && error->message) ? error->message : "(unknown)");
- }
- g_clear_error (&error);
- g_free (full_path);
- }
- g_dir_close (dir);
-}
-
/* Monitoring */
static void
{
g_return_if_fail (connection != NULL);
+ PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "removed %s.", nm_keyfile_connection_get_path (connection));
+
/* Removing from the hash table should drop the last reference */
g_object_ref (connection);
g_hash_table_remove (SC_PLUGIN_KEYFILE_GET_PRIVATE (self)->connections,
g_object_unref (connection);
}
+static void
+update_connection (SCPluginKeyfile *self,
+ NMKeyfileConnection *connection,
+ const char *name)
+{
+ NMKeyfileConnection *tmp;
+ GError *error = NULL;
+
+ tmp = nm_keyfile_connection_new (NULL, name, &error);
+ if (!tmp) {
+ /* Error; remove the connection */
+ PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s",
+ (error && error->message) ? error->message : "(unknown)");
+ g_clear_error (&error);
+ remove_connection (self, connection);
+ return;
+ }
+
+ if (!nm_connection_compare (NM_CONNECTION (connection),
+ NM_CONNECTION (tmp),
+ NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
+ NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
+ PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", name);
+ if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
+ NM_CONNECTION (tmp),
+ FALSE, /* don't set Unsaved */
+ &error)) {
+ /* Shouldn't ever get here as 'new' was verified by the reader already */
+ g_assert_no_error (error);
+ }
+ }
+ g_object_unref (tmp);
+}
+
static NMKeyfileConnection *
find_by_path (SCPluginKeyfile *self, const char *path)
{
return NULL;
}
+static void
+new_connection (SCPluginKeyfile *self,
+ const char *name,
+ char **out_old_path)
+{
+ SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
+ NMKeyfileConnection *tmp, *connection;
+ GError *error = NULL;
+
+ if (out_old_path)
+ *out_old_path = NULL;
+
+ tmp = nm_keyfile_connection_new (NULL, name, &error);
+ if (!tmp) {
+ PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error in connection %s: %s", name,
+ (error && error->message) ? error->message : "(unknown)");
+ g_clear_error (&error);
+ return;
+ }
+
+ /* Connection renames will show as different paths but same UUID */
+ connection = g_hash_table_lookup (priv->connections, nm_connection_get_uuid (NM_CONNECTION (tmp)));
+ if (connection) {
+ PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "rename %s -> %s",
+ nm_keyfile_connection_get_path (connection), name);
+ if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
+ NM_CONNECTION (tmp),
+ FALSE, /* don't set Unsaved */
+ &error)) {
+ /* Shouldn't ever get here as 'tmp' was verified by the reader already */
+ g_assert_no_error (error);
+ }
+ g_object_unref (tmp);
+ if (out_old_path)
+ *out_old_path = g_strdup (nm_keyfile_connection_get_path (connection));
+ nm_keyfile_connection_set_path (connection, name);
+ } else {
+ PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "new connection %s", name);
+ g_hash_table_insert (priv->connections,
+ (gpointer) nm_connection_get_uuid (NM_CONNECTION (tmp)),
+ tmp);
+ g_signal_emit_by_name (self, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, tmp);
+ }
+}
+
static void
dir_changed (GFileMonitor *monitor,
GFile *file,
{
NMSystemConfigInterface *config = NM_SYSTEM_CONFIG_INTERFACE (user_data);
SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
- SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
+ NMKeyfileConnection *connection;
char *full_path;
- NMKeyfileConnection *connection, *tmp;
- GError *error = NULL;
full_path = g_file_get_path (file);
if (nm_keyfile_plugin_utils_should_ignore_file (full_path)) {
switch (event_type) {
case G_FILE_MONITOR_EVENT_DELETED:
- if (connection) {
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "removed %s.", full_path);
+ if (connection)
remove_connection (SC_PLUGIN_KEYFILE (config), connection);
- }
break;
case G_FILE_MONITOR_EVENT_CREATED:
case G_FILE_MONITOR_EVENT_CHANGES_DONE_HINT:
- if (connection) {
- /* Update */
- tmp = nm_keyfile_connection_new (NULL, full_path, &error);
- if (tmp) {
- if (!nm_connection_compare (NM_CONNECTION (connection),
- NM_CONNECTION (tmp),
- NM_SETTING_COMPARE_FLAG_IGNORE_AGENT_OWNED_SECRETS |
- NM_SETTING_COMPARE_FLAG_IGNORE_NOT_SAVED_SECRETS)) {
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", full_path);
- if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
- NM_CONNECTION (tmp),
- FALSE, /* don't set Unsaved */
- &error)) {
- /* Shouldn't ever get here as 'new' was verified by the reader already */
- g_assert_no_error (error);
- }
- }
- g_object_unref (tmp);
- } else {
- /* Error; remove the connection */
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s",
- (error && error->message) ? error->message : "(unknown)");
- g_clear_error (&error);
- remove_connection (SC_PLUGIN_KEYFILE (config), connection);
- }
- } else {
- /* New */
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, "updating %s", full_path);
- tmp = nm_keyfile_connection_new (NULL, full_path, &error);
- if (tmp) {
- /* Connection renames will show as different paths but same UUID */
- connection = g_hash_table_lookup (priv->connections, nm_connection_get_uuid (NM_CONNECTION (tmp)));
- if (connection) {
- if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (connection),
- NM_CONNECTION (tmp),
- FALSE, /* don't set Unsaved */
- &error)) {
- /* Shouldn't ever get here as 'tmp' was verified by the reader already */
- g_assert_no_error (error);
- }
- g_object_unref (tmp);
- nm_keyfile_connection_set_path (connection, full_path);
- } else {
- g_hash_table_insert (priv->connections,
- (gpointer) nm_connection_get_uuid (NM_CONNECTION (tmp)),
- tmp);
- g_signal_emit_by_name (config, NM_SYSTEM_CONFIG_INTERFACE_CONNECTION_ADDED, tmp);
- }
- } else {
- PLUGIN_PRINT (KEYFILE_PLUGIN_NAME, " error: %s",
- (error && error->message) ? error->message : "(unknown)");
- g_clear_error (&error);
- }
- }
+ if (connection)
+ update_connection (SC_PLUGIN_KEYFILE (config), connection, full_path);
+ else
+ new_connection (SC_PLUGIN_KEYFILE (config), full_path, NULL);
break;
default:
break;
GFile *file;
GFileMonitor *monitor;
- file = g_file_new_for_path (KEYFILE_DIR);
- monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
- g_object_unref (file);
+ if (nm_config_get_monitor_connection_files (nm_config_get ())) {
+ file = g_file_new_for_path (KEYFILE_DIR);
+ monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+ g_object_unref (file);
- if (monitor) {
- priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
- priv->monitor = monitor;
+ if (monitor) {
+ priv->monitor_id = g_signal_connect (monitor, "changed", G_CALLBACK (dir_changed), config);
+ priv->monitor = monitor;
+ }
}
if (priv->conf_file) {
}
}
+static void
+read_connections (NMSystemConfigInterface *config)
+{
+ SCPluginKeyfile *self = SC_PLUGIN_KEYFILE (config);
+ SCPluginKeyfilePrivate *priv = SC_PLUGIN_KEYFILE_GET_PRIVATE (self);
+ GDir *dir;
+ GError *error = NULL;
+ const char *item;
+ GHashTable *oldconns;
+ GHashTableIter iter;
+ gpointer data;
+
+ dir = g_dir_open (KEYFILE_DIR, 0, &error);
+ if (!dir) {
+ PLUGIN_WARN (KEYFILE_PLUGIN_NAME, "Cannot read directory '%s': (%d) %s",
+ KEYFILE_DIR,
+ error ? error->code : -1,
+ error && error->message ? error->message : "(unknown)");
+ g_clear_error (&error);
+ 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, &data))
+ g_hash_table_insert (oldconns, g_strdup (nm_keyfile_connection_get_path (data)), data);
+
+ while ((item = g_dir_read_name (dir))) {
+ NMKeyfileConnection *connection;
+ char *full_path, *old_path;
+
+ if (nm_keyfile_plugin_utils_should_ignore_file (item))
+ continue;
+
+ full_path = g_build_filename (KEYFILE_DIR, item, NULL);
+
+ connection = g_hash_table_lookup (oldconns, full_path);
+ if (connection) {
+ g_hash_table_remove (oldconns, full_path);
+ update_connection (self, connection, full_path);
+ } else {
+ new_connection (self, full_path, &old_path);
+ if (old_path) {
+ g_hash_table_remove (oldconns, old_path);
+ g_free (old_path);
+ }
+ }
+
+ g_free (full_path);
+ }
+ g_dir_close (dir);
+
+ g_hash_table_iter_init (&iter, oldconns);
+ while (g_hash_table_iter_next (&iter, NULL, &data)) {
+ g_hash_table_iter_remove (&iter);
+ remove_connection (self, data);
+ }
+ g_hash_table_destroy (oldconns);
+}
+
/* Plugin */
static GSList *
return list;
}
+static void
+reload_connections (NMSystemConfigInterface *config)
+{
+ read_connections (config);
+}
+
static NMSettingsConnection *
add_connection (NMSystemConfigInterface *config,
NMConnection *connection,
{
/* interface implementation */
system_config_interface_class->get_connections = get_connections;
+ system_config_interface_class->reload_connections = reload_connections;
system_config_interface_class->add_connection = add_connection;
system_config_interface_class->get_unmanaged_specs = get_unmanaged_specs;
}