mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-02-08 15:00:35 +01:00
core: timestamp handling - don't touch /etc when updating timestamps (bgo #637825)
NM updates timestamp for active connections every 5 min. We don't want to touch files in /etc due to this. This commit solves that by not updating timestamp in the connection's property. Rather it updates the timestamp internally. All timestamps are also kept track of in /var/lib/NetworkManager/timestamps file. When settings are requested via D-Bus GetSettings(), the proper timestamp is put in the connection setting before returning.
This commit is contained in:
parent
580ee0fc27
commit
83d8677963
4 changed files with 174 additions and 40 deletions
|
|
@ -467,39 +467,6 @@ nm_manager_update_state (NMManager *manager)
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
ignore_cb (NMSettingsConnection *connection, GError *error, gpointer user_data)
|
||||
{
|
||||
}
|
||||
|
||||
static void
|
||||
update_active_connection_timestamp (NMManager *manager, NMDevice *device)
|
||||
{
|
||||
NMActRequest *req;
|
||||
NMConnection *connection;
|
||||
NMSettingConnection *s_con;
|
||||
NMManagerPrivate *priv;
|
||||
|
||||
g_return_if_fail (NM_IS_DEVICE (device));
|
||||
|
||||
priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||
req = nm_device_get_act_request (device);
|
||||
if (!req)
|
||||
return;
|
||||
|
||||
connection = nm_act_request_get_connection (req);
|
||||
g_assert (connection);
|
||||
|
||||
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (connection, NM_TYPE_SETTING_CONNECTION));
|
||||
g_assert (s_con);
|
||||
g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, (guint64) time (NULL), NULL);
|
||||
|
||||
if (nm_setting_connection_get_read_only (s_con))
|
||||
return;
|
||||
|
||||
nm_settings_connection_commit_changes (NM_SETTINGS_CONNECTION (connection), ignore_cb, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
manager_device_state_changed (NMDevice *device,
|
||||
NMDeviceState new_state,
|
||||
|
|
@ -523,8 +490,14 @@ manager_device_state_changed (NMDevice *device,
|
|||
|
||||
nm_manager_update_state (manager);
|
||||
|
||||
if (new_state == NM_DEVICE_STATE_ACTIVATED)
|
||||
update_active_connection_timestamp (manager, device);
|
||||
if (new_state == NM_DEVICE_STATE_ACTIVATED) {
|
||||
NMActRequest *req;
|
||||
|
||||
req = nm_device_get_act_request (device);
|
||||
if (req)
|
||||
nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
|
||||
(guint64) time (NULL));
|
||||
}
|
||||
}
|
||||
|
||||
/* Removes a device from a device list; returns the start of the new device list */
|
||||
|
|
@ -3347,7 +3320,8 @@ periodic_update_active_connection_timestamps (gpointer user_data)
|
|||
|
||||
req = nm_manager_get_act_request_by_path (manager, active_path, &device);
|
||||
if (device && nm_device_get_state (device) == NM_DEVICE_STATE_ACTIVATED)
|
||||
update_active_connection_timestamp (manager, device);
|
||||
nm_settings_connection_update_timestamp (NM_SETTINGS_CONNECTION (nm_act_request_get_connection (req)),
|
||||
(guint64) time (NULL));
|
||||
}
|
||||
|
||||
return TRUE;
|
||||
|
|
|
|||
|
|
@ -38,6 +38,8 @@
|
|||
#include "nm-marshal.h"
|
||||
#include "nm-agent-manager.h"
|
||||
|
||||
#define SETTINGS_TIMESTAMPS_FILE LOCALSTATEDIR"/lib/NetworkManager/timestamps"
|
||||
|
||||
static void impl_settings_connection_get_settings (NMSettingsConnection *connection,
|
||||
DBusGMethodInvocation *context);
|
||||
|
||||
|
|
@ -88,6 +90,8 @@ typedef struct {
|
|||
|
||||
NMSessionMonitor *session_monitor;
|
||||
guint session_changed_id;
|
||||
|
||||
guint64 timestamp; /* Up-to-date timestamp of connection use */
|
||||
} NMSettingsConnectionPrivate;
|
||||
|
||||
/**************************************************************/
|
||||
|
|
@ -330,6 +334,34 @@ commit_changes (NMSettingsConnection *connection,
|
|||
g_object_unref (connection);
|
||||
}
|
||||
|
||||
static void
|
||||
remove_timestamp_from_db (NMSettingsConnection *connection)
|
||||
{
|
||||
GKeyFile *timestamps_file;
|
||||
|
||||
timestamps_file = g_key_file_new ();
|
||||
if (g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) {
|
||||
const char *connection_uuid;
|
||||
char *data;
|
||||
gsize len;
|
||||
GError *error = NULL;
|
||||
|
||||
connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection));
|
||||
|
||||
g_key_file_remove_key (timestamps_file, "timestamps", connection_uuid, NULL);
|
||||
data = g_key_file_to_data (timestamps_file, &len, &error);
|
||||
if (data) {
|
||||
g_file_set_contents (SETTINGS_TIMESTAMPS_FILE, data, len, &error);
|
||||
g_free (data);
|
||||
}
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_SETTINGS, "error writing timestamps file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
}
|
||||
g_key_file_free (timestamps_file);
|
||||
}
|
||||
|
||||
static void
|
||||
do_delete (NMSettingsConnection *connection,
|
||||
NMSettingsConnectionDeleteFunc callback,
|
||||
|
|
@ -346,6 +378,9 @@ do_delete (NMSettingsConnection *connection,
|
|||
nm_connection_clear_secrets (for_agents);
|
||||
nm_agent_manager_delete_secrets (priv->agent_mgr, for_agents, FALSE, 0);
|
||||
|
||||
/* Remove timestamp from timestamps database file */
|
||||
remove_timestamp_from_db (connection);
|
||||
|
||||
/* Signal the connection is removed and deleted */
|
||||
g_signal_emit (connection, signals[REMOVED], 0);
|
||||
callback (connection, NULL, user_data);
|
||||
|
|
@ -865,15 +900,35 @@ get_settings_auth_cb (NMSettingsConnection *self,
|
|||
dbus_g_method_return_error (context, error);
|
||||
else {
|
||||
GHashTable *settings;
|
||||
NMConnection *dupl_con;
|
||||
NMSettingConnection *s_con;
|
||||
guint64 timestamp;
|
||||
|
||||
dupl_con = nm_connection_duplicate (NM_CONNECTION (self));
|
||||
g_assert (dupl_con);
|
||||
|
||||
/* Timestamp is not updated in connection's 'timestamp' property,
|
||||
* because it would force updating the connection and in turn
|
||||
* writing to /etc periodically, which we want to avoid. Rather real
|
||||
* timestamps are kept track of in a private variable. So, substitute
|
||||
* timestamp property with the real one here before returning the settings.
|
||||
*/
|
||||
timestamp = nm_settings_connection_get_timestamp (self);
|
||||
if (timestamp) {
|
||||
s_con = NM_SETTING_CONNECTION (nm_connection_get_setting (NM_CONNECTION (dupl_con), NM_TYPE_SETTING_CONNECTION));
|
||||
g_assert (s_con);
|
||||
g_object_set (s_con, NM_SETTING_CONNECTION_TIMESTAMP, timestamp, NULL);
|
||||
}
|
||||
|
||||
/* Secrets should *never* be returned by the GetSettings method, they
|
||||
* get returned by the GetSecrets method which can be better
|
||||
* protected against leakage of secrets to unprivileged callers.
|
||||
*/
|
||||
settings = nm_connection_to_hash (NM_CONNECTION (self), NM_SETTING_HASH_FLAG_NO_SECRETS);
|
||||
settings = nm_connection_to_hash (NM_CONNECTION (dupl_con), NM_SETTING_HASH_FLAG_NO_SECRETS);
|
||||
g_assert (settings);
|
||||
dbus_g_method_return (context, settings);
|
||||
g_hash_table_destroy (settings);
|
||||
g_object_unref (dupl_con);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -1194,6 +1249,99 @@ nm_settings_connection_signal_remove (NMSettingsConnection *self)
|
|||
g_signal_emit_by_name (self, "unregister");
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_get_timestamp:
|
||||
* @connection: the #NMSettingsConnection
|
||||
*
|
||||
* Returns current connection's timestamp.
|
||||
*
|
||||
* Returns: timestamp of the last connection use (0 when it's not used)
|
||||
**/
|
||||
guint64
|
||||
nm_settings_connection_get_timestamp (NMSettingsConnection *connection)
|
||||
{
|
||||
g_return_val_if_fail (NM_SETTINGS_CONNECTION (connection), 0);
|
||||
|
||||
return NM_SETTINGS_CONNECTION_GET_PRIVATE (connection)->timestamp;
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_update_timestamp:
|
||||
* @connection: the #NMSettingsConnection
|
||||
* @timestamp: timestamp to set into the connection and to store into
|
||||
* the timestamps database
|
||||
*
|
||||
* Updates the connection and timestamps database with the provided timestamp.
|
||||
**/
|
||||
void
|
||||
nm_settings_connection_update_timestamp (NMSettingsConnection *connection, guint64 timestamp)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
|
||||
const char *connection_uuid;
|
||||
GKeyFile *timestamps_file;
|
||||
char *data;
|
||||
gsize len;
|
||||
GError *error = NULL;
|
||||
|
||||
/* Update timestamp in private storage */
|
||||
priv->timestamp = timestamp;
|
||||
|
||||
/* Save timestamp to timestamps database file */
|
||||
timestamps_file = g_key_file_new ();
|
||||
if (!g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) {
|
||||
if (!(error->domain == G_FILE_ERROR && error->code == G_FILE_ERROR_NOENT))
|
||||
nm_log_warn (LOGD_SETTINGS, "error parsing timestamps file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message);
|
||||
g_clear_error (&error);
|
||||
}
|
||||
|
||||
connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection));
|
||||
g_key_file_set_uint64 (timestamps_file, "timestamps", connection_uuid, timestamp);
|
||||
|
||||
data = g_key_file_to_data (timestamps_file, &len, &error);
|
||||
if (data) {
|
||||
g_file_set_contents (SETTINGS_TIMESTAMPS_FILE, data, len, &error);
|
||||
g_free (data);
|
||||
}
|
||||
if (error) {
|
||||
nm_log_warn (LOGD_SETTINGS, "error saving timestamp to file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
g_key_file_free (timestamps_file);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_settings_connection_read_and_fill_timestamp:
|
||||
* @connection: the #NMSettingsConnection
|
||||
*
|
||||
* Retrieves timestamp of the connection's last usage from database file and
|
||||
* stores it into the connection private data.
|
||||
**/
|
||||
void
|
||||
nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection)
|
||||
{
|
||||
NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (connection);
|
||||
const char *connection_uuid;
|
||||
guint64 timestamp;
|
||||
GKeyFile *timestamps_file;
|
||||
GError *err = NULL;
|
||||
|
||||
/* Get timestamp from database file */
|
||||
timestamps_file = g_key_file_new ();
|
||||
g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL);
|
||||
connection_uuid = nm_connection_get_uuid (NM_CONNECTION (connection));
|
||||
timestamp = g_key_file_get_uint64 (timestamps_file, "timestamps", connection_uuid, &err);
|
||||
|
||||
/* Update connection's timestamp */
|
||||
if (!err)
|
||||
priv->timestamp = timestamp;
|
||||
else {
|
||||
nm_log_dbg (LOGD_SETTINGS, "failed to read connection timestamp for '%s': (%d) %s",
|
||||
connection_uuid, err->code, err->message);
|
||||
g_clear_error (&err);
|
||||
}
|
||||
g_key_file_free (timestamps_file);
|
||||
}
|
||||
|
||||
/**************************************************************/
|
||||
|
||||
static void
|
||||
|
|
|
|||
|
|
@ -116,6 +116,12 @@ void nm_settings_connection_recheck_visibility (NMSettingsConnection *self);
|
|||
|
||||
void nm_settings_connection_signal_remove (NMSettingsConnection *self);
|
||||
|
||||
guint64 nm_settings_connection_get_timestamp (NMSettingsConnection *connection);
|
||||
|
||||
void nm_settings_connection_update_timestamp (NMSettingsConnection *connection, guint64 timestamp);
|
||||
|
||||
void nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *connection);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* NM_SETTINGS_CONNECTION_H */
|
||||
|
|
|
|||
|
|
@ -19,7 +19,7 @@
|
|||
* with this program; if not, write to the Free Software Foundation, Inc.,
|
||||
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
|
||||
*
|
||||
* (C) Copyright 2007 - 2010 Red Hat, Inc.
|
||||
* (C) Copyright 2007 - 2011 Red Hat, Inc.
|
||||
* (C) Copyright 2008 Novell, Inc.
|
||||
*/
|
||||
|
||||
|
|
@ -227,6 +227,7 @@ connection_sort (gconstpointer pa, gconstpointer pb)
|
|||
NMSettingConnection *con_a;
|
||||
NMConnection *b = NM_CONNECTION (pb);
|
||||
NMSettingConnection *con_b;
|
||||
guint64 ts_a, ts_b;
|
||||
|
||||
con_a = (NMSettingConnection *) nm_connection_get_setting (a, NM_TYPE_SETTING_CONNECTION);
|
||||
g_assert (con_a);
|
||||
|
|
@ -239,9 +240,11 @@ connection_sort (gconstpointer pa, gconstpointer pb)
|
|||
return 1;
|
||||
}
|
||||
|
||||
if (nm_setting_connection_get_timestamp (con_a) > nm_setting_connection_get_timestamp (con_b))
|
||||
ts_a = nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pa));
|
||||
ts_b = nm_settings_connection_get_timestamp (NM_SETTINGS_CONNECTION (pb));
|
||||
if (ts_a > ts_b)
|
||||
return -1;
|
||||
else if (nm_setting_connection_get_timestamp (con_a) == nm_setting_connection_get_timestamp (con_b))
|
||||
else if (ts_a == ts_b)
|
||||
return 0;
|
||||
return 1;
|
||||
}
|
||||
|
|
@ -692,6 +695,9 @@ claim_connection (NMSettings *self,
|
|||
return;
|
||||
}
|
||||
|
||||
/* Read timestamp from look-aside file and put it into the connection's data */
|
||||
nm_settings_connection_read_and_fill_timestamp (connection);
|
||||
|
||||
/* Ensure it's initial visibility is up-to-date */
|
||||
nm_settings_connection_recheck_visibility (connection);
|
||||
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue