mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-04 06:00:32 +01:00
settings: track whether connection is saved to disk or not
Use the new NMConnection 'changed' signal to mark connections as dirty/unsaved, and reset that when they get flushed to disk. Previously, the 'Updated' signal was emitted only when the connection was changed and flushed to disk, but now we have more granular needs, and the signal is emitted whenever the connection actually *is* changed, regardless of whether its flushed to disk or not.
This commit is contained in:
parent
87517ba6df
commit
cd5d92705d
8 changed files with 157 additions and 26 deletions
|
|
@ -88,6 +88,16 @@
|
|||
</tp:docstring>
|
||||
</signal>
|
||||
|
||||
<property name="Unsaved" type="b" access="read">
|
||||
<tp:docstring>
|
||||
If set, indicates that the in-memory state of the
|
||||
connection does not match the on-disk state. This flag
|
||||
will be set when UpdateUnsaved() is called or when any
|
||||
connection details change, and cleared when the connection
|
||||
is saved to disk via Save() or from internal operations.
|
||||
</tp:docstring>
|
||||
</property>
|
||||
|
||||
</interface>
|
||||
|
||||
</node>
|
||||
|
|
|
|||
|
|
@ -414,9 +414,12 @@ nm_connection_replace_settings_from_connection (NMConnection *connection,
|
|||
*/
|
||||
g_hash_table_remove_all (NM_CONNECTION_GET_PRIVATE (connection)->settings);
|
||||
|
||||
g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (new_connection)->settings);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting))
|
||||
nm_connection_add_setting (connection, nm_setting_duplicate (setting));
|
||||
if (g_hash_table_size (NM_CONNECTION_GET_PRIVATE (new_connection)->settings)) {
|
||||
g_hash_table_iter_init (&iter, NM_CONNECTION_GET_PRIVATE (new_connection)->settings);
|
||||
while (g_hash_table_iter_next (&iter, NULL, (gpointer) &setting))
|
||||
nm_connection_add_setting (connection, nm_setting_duplicate (setting));
|
||||
} else
|
||||
g_signal_emit (connection, signals[CHANGED], 0);
|
||||
|
||||
return nm_connection_verify (connection, error);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2008 Novell, Inc.
|
||||
* (C) Copyright 2008 - 2012 Red Hat, Inc.
|
||||
* (C) Copyright 2008 - 2013 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
|
@ -40,6 +40,7 @@
|
|||
#include "nm-manager-auth.h"
|
||||
#include "nm-agent-manager.h"
|
||||
#include "NetworkManagerUtils.h"
|
||||
#include "nm-properties-changed-signal.h"
|
||||
|
||||
#define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps"
|
||||
#define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids"
|
||||
|
|
@ -69,6 +70,7 @@ G_DEFINE_TYPE (NMSettingsConnection, nm_settings_connection, NM_TYPE_CONNECTION)
|
|||
enum {
|
||||
PROP_0 = 0,
|
||||
PROP_VISIBLE,
|
||||
PROP_UNSAVED,
|
||||
};
|
||||
|
||||
enum {
|
||||
|
|
@ -86,6 +88,13 @@ typedef struct {
|
|||
NMSessionMonitor *session_monitor;
|
||||
guint session_changed_id;
|
||||
|
||||
/* TRUE if the connection has not yet been saved to disk,
|
||||
* or it it contains changes that have not been saved to disk.
|
||||
*/
|
||||
gboolean unsaved;
|
||||
|
||||
guint updated_idle_id;
|
||||
|
||||
GSList *pending_auths; /* List of pending authentication requests */
|
||||
gboolean visible; /* Is this connection is visible by some session? */
|
||||
GSList *reqs; /* in-progress secrets requests */
|
||||
|
|
@ -366,12 +375,45 @@ secrets_cleared_cb (NMSettingsConnection *self)
|
|||
priv->agent_secrets = NULL;
|
||||
}
|
||||
|
||||
static gboolean
|
||||
emit_updated (NMSettingsConnection *self)
|
||||
{
|
||||
NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->updated_idle_id = 0;
|
||||
g_signal_emit (self, signals[UPDATED], 0);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
static void
|
||||
set_unsaved (NMSettingsConnection *self, gboolean now_unsaved)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
if (priv->unsaved != now_unsaved) {
|
||||
priv->unsaved = now_unsaved;
|
||||
g_object_notify (G_OBJECT (self), NM_SETTINGS_CONNECTION_UNSAVED);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
changed_cb (NMSettingsConnection *self, gpointer user_data)
|
||||
{
|
||||
gboolean update_unsaved = !!user_data;
|
||||
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self);
|
||||
|
||||
if (update_unsaved)
|
||||
set_unsaved (self, TRUE);
|
||||
if (priv->updated_idle_id == 0)
|
||||
priv->updated_idle_id = g_idle_add ((GSourceFunc) emit_updated, self);
|
||||
}
|
||||
|
||||
/* Update the settings of this connection to match that of 'new_connection',
|
||||
* taking care to make a private copy of secrets.
|
||||
*/
|
||||
gboolean
|
||||
nm_settings_connection_replace_settings (NMSettingsConnection *self,
|
||||
NMConnection *new_connection,
|
||||
gboolean update_unsaved,
|
||||
GError **error)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv;
|
||||
|
|
@ -390,6 +432,11 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
|
|||
return TRUE;
|
||||
}
|
||||
|
||||
/* Disconnect the changed signal to ensure we don't set Unsaved when
|
||||
* it's not required.
|
||||
*/
|
||||
g_signal_handlers_block_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
|
||||
|
||||
if (nm_connection_replace_settings_from_connection (NM_CONNECTION (self),
|
||||
new_connection,
|
||||
error)) {
|
||||
|
|
@ -411,7 +458,15 @@ nm_settings_connection_replace_settings (NMSettingsConnection *self,
|
|||
}
|
||||
|
||||
nm_settings_connection_recheck_visibility (self);
|
||||
|
||||
/* Manually emit changed signal since we disconnected the handler, but
|
||||
* only update Unsaved if the caller wanted us to.
|
||||
*/
|
||||
changed_cb (self, GUINT_TO_POINTER (update_unsaved));
|
||||
}
|
||||
|
||||
g_signal_handlers_unblock_by_func (self, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
|
||||
|
||||
return success;
|
||||
}
|
||||
|
||||
|
|
@ -438,7 +493,7 @@ nm_settings_connection_replace_and_commit (NMSettingsConnection *self,
|
|||
g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self));
|
||||
g_return_if_fail (NM_IS_CONNECTION (new_connection));
|
||||
|
||||
if (nm_settings_connection_replace_settings (self, new_connection, &error)) {
|
||||
if (nm_settings_connection_replace_settings (self, new_connection, TRUE, &error)) {
|
||||
nm_settings_connection_commit_changes (self, callback ? callback : ignore_cb, user_data);
|
||||
} else {
|
||||
if (callback)
|
||||
|
|
@ -447,6 +502,21 @@ nm_settings_connection_replace_and_commit (NMSettingsConnection *self,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
commit_changes (NMSettingsConnection *self,
|
||||
NMSettingsConnectionCommitFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* Subclasses only call this function if the save was successful, so at
|
||||
* this point the connection is synced to disk and no longer unsaved.
|
||||
*/
|
||||
set_unsaved (self, FALSE);
|
||||
|
||||
g_object_ref (self);
|
||||
callback (self, NULL, user_data);
|
||||
g_object_unref (self);
|
||||
}
|
||||
|
||||
void
|
||||
nm_settings_connection_commit_changes (NMSettingsConnection *connection,
|
||||
NMSettingsConnectionCommitFunc callback,
|
||||
|
|
@ -489,17 +559,6 @@ nm_settings_connection_delete (NMSettingsConnection *connection,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
commit_changes (NMSettingsConnection *connection,
|
||||
NMSettingsConnectionCommitFunc callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_object_ref (connection);
|
||||
g_signal_emit (connection, signals[UPDATED], 0);
|
||||
callback (connection, NULL, user_data);
|
||||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_entry_from_db (NMSettingsConnection *connection, const char* db_name)
|
||||
{
|
||||
|
|
@ -1397,6 +1456,14 @@ nm_settings_connection_signal_remove (NMSettingsConnection *self)
|
|||
g_signal_emit_by_name (self, "unregister");
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_settings_connection_get_unsaved (NMSettingsConnection *self)
|
||||
{
|
||||
return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->unsaved;
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
/**
|
||||
* nm_settings_connection_get_timestamp:
|
||||
* @connection: the #NMSettingsConnection
|
||||
|
|
@ -1729,7 +1796,8 @@ nm_settings_connection_init (NMSettingsConnection *self)
|
|||
|
||||
priv->seen_bssids = g_hash_table_new_full (mac_hash, mac_equal, g_free, g_free);
|
||||
|
||||
g_signal_connect (self, "secrets-cleared", G_CALLBACK (secrets_cleared_cb), NULL);
|
||||
g_signal_connect (self, NM_CONNECTION_SECRETS_CLEARED, G_CALLBACK (secrets_cleared_cb), NULL);
|
||||
g_signal_connect (self, NM_CONNECTION_CHANGED, G_CALLBACK (changed_cb), GUINT_TO_POINTER (TRUE));
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
@ -1743,6 +1811,11 @@ dispose (GObject *object)
|
|||
goto out;
|
||||
priv->disposed = TRUE;
|
||||
|
||||
if (priv->updated_idle_id) {
|
||||
g_source_remove (priv->updated_idle_id);
|
||||
priv->updated_idle_id = 0;
|
||||
}
|
||||
|
||||
if (priv->system_secrets)
|
||||
g_object_unref (priv->system_secrets);
|
||||
if (priv->agent_secrets)
|
||||
|
|
@ -1776,9 +1849,14 @@ static void
|
|||
get_property (GObject *object, guint prop_id,
|
||||
GValue *value, GParamSpec *pspec)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (object);
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_VISIBLE:
|
||||
g_value_set_boolean (value, NM_SETTINGS_CONNECTION_GET_PRIVATE (object)->visible);
|
||||
g_value_set_boolean (value, priv->visible);
|
||||
break;
|
||||
case PROP_UNSAVED:
|
||||
g_value_set_boolean (value, priv->unsaved);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
@ -1818,6 +1896,16 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
|
|||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
g_object_class_install_property
|
||||
(object_class, PROP_UNSAVED,
|
||||
g_param_spec_boolean (NM_SETTINGS_CONNECTION_UNSAVED,
|
||||
"Unsaved",
|
||||
"TRUE when the connection has not yet been saved "
|
||||
"to permanent storage (eg disk) or when it "
|
||||
"has been changed but not yet saved.",
|
||||
FALSE,
|
||||
G_PARAM_READABLE));
|
||||
|
||||
/* Signals */
|
||||
signals[UPDATED] =
|
||||
g_signal_new (NM_SETTINGS_CONNECTION_UPDATED,
|
||||
|
|
@ -1847,6 +1935,7 @@ nm_settings_connection_class_init (NMSettingsConnectionClass *class)
|
|||
g_cclosure_marshal_VOID__VOID,
|
||||
G_TYPE_NONE, 0);
|
||||
|
||||
dbus_g_object_type_install_info (G_TYPE_FROM_CLASS (class),
|
||||
&dbus_glib_nm_settings_connection_object_info);
|
||||
nm_dbus_manager_register_exported_type (nm_dbus_manager_get (),
|
||||
G_TYPE_FROM_CLASS (class),
|
||||
&dbus_glib_nm_settings_connection_object_info);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,7 +16,7 @@
|
|||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2008 Novell, Inc.
|
||||
* (C) Copyright 2008 - 2011 Red Hat, Inc.
|
||||
* (C) Copyright 2008 - 2013 Red Hat, Inc.
|
||||
*/
|
||||
|
||||
#ifndef NM_SETTINGS_CONNECTION_H
|
||||
|
|
@ -35,15 +35,17 @@ G_BEGIN_DECLS
|
|||
#define NM_IS_SETTINGS_CONNECTION_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), NM_TYPE_SETTINGS_CONNECTION))
|
||||
#define NM_SETTINGS_CONNECTION_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), NM_TYPE_SETTINGS_CONNECTION, NMSettingsConnectionClass))
|
||||
|
||||
/* Signals */
|
||||
#define NM_SETTINGS_CONNECTION_UPDATED "updated"
|
||||
#define NM_SETTINGS_CONNECTION_REMOVED "removed"
|
||||
#define NM_SETTINGS_CONNECTION_GET_SECRETS "get-secrets"
|
||||
#define NM_SETTINGS_CONNECTION_CANCEL_SECRETS "cancel-secrets"
|
||||
|
||||
/* Properties */
|
||||
#define NM_SETTINGS_CONNECTION_VISIBLE "visible"
|
||||
#define NM_SETTINGS_CONNECTION_UNSAVED "unsaved"
|
||||
|
||||
typedef struct _NMSettingsConnection NMSettingsConnection;
|
||||
|
||||
typedef struct _NMSettingsConnectionClass NMSettingsConnectionClass;
|
||||
|
||||
typedef void (*NMSettingsConnectionCommitFunc) (NMSettingsConnection *connection,
|
||||
|
|
@ -82,6 +84,7 @@ void nm_settings_connection_commit_changes (NMSettingsConnection *connection,
|
|||
|
||||
gboolean nm_settings_connection_replace_settings (NMSettingsConnection *self,
|
||||
NMConnection *new_connection,
|
||||
gboolean update_unsaved,
|
||||
GError **error);
|
||||
|
||||
void nm_settings_connection_replace_and_commit (NMSettingsConnection *self,
|
||||
|
|
@ -122,6 +125,8 @@ gboolean nm_settings_connection_check_permission (NMSettingsConnection *self,
|
|||
|
||||
void nm_settings_connection_signal_remove (NMSettingsConnection *self);
|
||||
|
||||
gboolean nm_settings_connection_get_unsaved (NMSettingsConnection *self);
|
||||
|
||||
gboolean nm_settings_connection_get_timestamp (NMSettingsConnection *connection,
|
||||
guint64 *out_timestamp);
|
||||
|
||||
|
|
|
|||
|
|
@ -77,7 +77,10 @@ nm_example_connection_new (const char *full_path,
|
|||
/* Update our settings with what was read from the file or what got passed
|
||||
* in as a source NMConnection.
|
||||
*/
|
||||
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) {
|
||||
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
|
||||
tmp,
|
||||
TRUE,
|
||||
error)) {
|
||||
g_object_unref (object);
|
||||
object = NULL;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -109,6 +109,7 @@ nm_ifcfg_connection_new (const char *full_path,
|
|||
char *routefile = NULL;
|
||||
char *route6file = NULL;
|
||||
NMInotifyHelper *ih;
|
||||
gboolean update_unsaved = TRUE;
|
||||
|
||||
g_return_val_if_fail (full_path != NULL, NULL);
|
||||
|
||||
|
|
@ -125,6 +126,9 @@ nm_ifcfg_connection_new (const char *full_path,
|
|||
ignore_error);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
|
||||
/* If we just read the connection from disk, it's clearly not Unsaved */
|
||||
update_unsaved = FALSE;
|
||||
}
|
||||
|
||||
object = (GObject *) g_object_new (NM_TYPE_IFCFG_CONNECTION,
|
||||
|
|
@ -134,7 +138,10 @@ nm_ifcfg_connection_new (const char *full_path,
|
|||
goto out;
|
||||
|
||||
/* Update our settings with what was read from the file */
|
||||
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) {
|
||||
if (nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
|
||||
tmp,
|
||||
update_unsaved,
|
||||
error)) {
|
||||
g_object_unref (object);
|
||||
object = NULL;
|
||||
goto out;
|
||||
|
|
|
|||
|
|
@ -62,6 +62,7 @@ nm_ifnet_connection_new (const char *conn_name, NMConnection *source)
|
|||
NMConnection *tmp;
|
||||
GObject *object;
|
||||
GError *error = NULL;
|
||||
gboolean update_unsaved = TRUE;
|
||||
|
||||
g_return_val_if_fail (conn_name != NULL, NULL);
|
||||
|
||||
|
|
@ -73,11 +74,17 @@ nm_ifnet_connection_new (const char *conn_name, NMConnection *source)
|
|||
g_error_free (error);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/* If we just read the connection from disk, it's clearly not Unsaved */
|
||||
update_unsaved = FALSE;
|
||||
}
|
||||
|
||||
object = (GObject *) g_object_new (NM_TYPE_IFNET_CONNECTION, NULL);
|
||||
NM_IFNET_CONNECTION_GET_PRIVATE (object)->conn_name = g_strdup (conn_name);
|
||||
nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, NULL);
|
||||
nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
|
||||
tmp,
|
||||
update_unsaved,
|
||||
NULL);
|
||||
g_object_unref (tmp);
|
||||
|
||||
return NM_IFNET_CONNECTION (object);
|
||||
|
|
|
|||
|
|
@ -49,6 +49,7 @@ nm_keyfile_connection_new (const char *full_path,
|
|||
NMKeyfileConnectionPrivate *priv;
|
||||
NMConnection *tmp;
|
||||
const char *uuid;
|
||||
gboolean update_unsaved = TRUE;
|
||||
|
||||
g_return_val_if_fail (full_path != NULL, NULL);
|
||||
|
||||
|
|
@ -59,6 +60,9 @@ nm_keyfile_connection_new (const char *full_path,
|
|||
tmp = nm_keyfile_plugin_connection_from_file (full_path, error);
|
||||
if (!tmp)
|
||||
return NULL;
|
||||
|
||||
/* If we just read the connection from disk, it's clearly not Unsaved */
|
||||
update_unsaved = FALSE;
|
||||
}
|
||||
|
||||
object = (GObject *) g_object_new (NM_TYPE_KEYFILE_CONNECTION, NULL);
|
||||
|
|
@ -67,7 +71,10 @@ nm_keyfile_connection_new (const char *full_path,
|
|||
priv->path = g_strdup (full_path);
|
||||
|
||||
/* Update our settings with what was read from the file */
|
||||
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object), tmp, error)) {
|
||||
if (!nm_settings_connection_replace_settings (NM_SETTINGS_CONNECTION (object),
|
||||
tmp,
|
||||
update_unsaved,
|
||||
error)) {
|
||||
g_object_unref (object);
|
||||
object = NULL;
|
||||
goto out;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue