diff options
author | Thomas Haller <thaller@redhat.com> | 2019-05-07 16:42:15 +0200 |
---|---|---|
committer | Thomas Haller <thaller@redhat.com> | 2019-05-07 16:42:15 +0200 |
commit | 7a5bf59e5f5133cedc8d06080cc47392e2e7afc4 (patch) | |
tree | fd4283279e5f0daf66de8c7e2e0b7ed21f98692d | |
parent | 4a078d5065b7c771bf71f79432a645798e5536e3 (diff) | |
parent | 8a78493de1c33d879082e55edca1ee6e672efc40 (diff) | |
download | NetworkManager-7a5bf59e5f5133cedc8d06080cc47392e2e7afc4.tar.gz |
core: merge branch 'th/cache-state-keyfiles'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/merge_requests/134
-rw-r--r-- | Makefile.am | 2 | ||||
-rw-r--r-- | libnm-core/nm-keyfile-utils.c | 2 | ||||
-rw-r--r-- | shared/meson.build | 1 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-keyfile-aux.c | 413 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-keyfile-aux.h | 78 | ||||
-rw-r--r-- | shared/nm-glib-aux/nm-logging-fwd.h | 17 | ||||
-rw-r--r-- | shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h | 20 | ||||
-rw-r--r-- | src/devices/nm-device.c | 2 | ||||
-rw-r--r-- | src/devices/wifi/nm-iwd-manager.c | 2 | ||||
-rw-r--r-- | src/main.c | 2 | ||||
-rw-r--r-- | src/nm-active-connection.c | 2 | ||||
-rw-r--r-- | src/nm-checkpoint.c | 8 | ||||
-rw-r--r-- | src/nm-logging.c | 9 | ||||
-rw-r--r-- | src/nm-manager.c | 2 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.c | 293 | ||||
-rw-r--r-- | src/settings/nm-settings-connection.h | 13 | ||||
-rw-r--r-- | src/settings/nm-settings.c | 157 | ||||
-rw-r--r-- | src/settings/nm-settings.h | 2 |
18 files changed, 794 insertions, 231 deletions
diff --git a/Makefile.am b/Makefile.am index 993ee9781d..1de743030f 100644 --- a/Makefile.am +++ b/Makefile.am @@ -347,6 +347,8 @@ shared_nm_glib_aux_libnm_glib_aux_la_SOURCES = \ shared/nm-glib-aux/nm-io-utils.c \ shared/nm-glib-aux/nm-io-utils.h \ shared/nm-glib-aux/nm-jansson.h \ + shared/nm-glib-aux/nm-keyfile-aux.c \ + shared/nm-glib-aux/nm-keyfile-aux.h \ shared/nm-glib-aux/nm-logging-fwd.h \ shared/nm-glib-aux/nm-macros-internal.h \ shared/nm-glib-aux/nm-obj.h \ diff --git a/libnm-core/nm-keyfile-utils.c b/libnm-core/nm-keyfile-utils.c index e243150d02..a7d50e2216 100644 --- a/libnm-core/nm-keyfile-utils.c +++ b/libnm-core/nm-keyfile-utils.c @@ -415,7 +415,7 @@ _keyfile_key_encode (const char *name, /* See g_key_file_is_key_name(). * - * GKeyfile allows all UTF-8 characters (even non-well formed sequences), + * GKeyFile allows all UTF-8 characters (even non-well formed sequences), * except: * - no empty keys * - no leading/trailing ' ' diff --git a/shared/meson.build b/shared/meson.build index ba4c28c3fd..a63068eca5 100644 --- a/shared/meson.build +++ b/shared/meson.build @@ -144,6 +144,7 @@ shared_nm_glib_aux = static_library( 'nm-glib-aux/nm-errno.c', 'nm-glib-aux/nm-hash-utils.c', 'nm-glib-aux/nm-io-utils.c', + 'nm-glib-aux/nm-keyfile-aux.c', 'nm-glib-aux/nm-random-utils.c', 'nm-glib-aux/nm-secret-utils.c', 'nm-glib-aux/nm-shared-utils.c', diff --git a/shared/nm-glib-aux/nm-keyfile-aux.c b/shared/nm-glib-aux/nm-keyfile-aux.c new file mode 100644 index 0000000000..0257bcca7f --- /dev/null +++ b/shared/nm-glib-aux/nm-keyfile-aux.c @@ -0,0 +1,413 @@ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2019 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-keyfile-aux.h" + +#include <syslog.h> +#include <sys/stat.h> +#include <fcntl.h> + +#include "nm-io-utils.h" + +/*****************************************************************************/ + +struct _NMKeyFileDB { + NMKeyFileDBLogFcn log_fcn; + NMKeyFileDBGotDirtyFcn got_dirty_fcn; + gpointer user_data; + const char *group_name; + GKeyFile *kf; + guint ref_count; + + bool is_started:1; + bool dirty:1; + bool destroyed:1; + + char filename[]; +}; + +#define _NMLOG(self, \ + syslog_level, \ + fmt, \ + ...) \ + G_STMT_START { \ + NMKeyFileDB *_self = (self); \ + \ + nm_assert (_self); \ + nm_assert (!_self->destroyed); \ + \ + if (_self->log_fcn) { \ + _self->log_fcn (_self, \ + (syslog_level), \ + _self->user_data, \ + ""fmt"", \ + ##__VA_ARGS__); \ + }; \ + } G_STMT_END + +#define _LOGD(...) _NMLOG (self, LOG_DEBUG, __VA_ARGS__) + +static gboolean +_IS_KEY_FILE_DB (NMKeyFileDB *self, gboolean require_is_started, gboolean allow_destroyed) +{ + if (self == NULL) + return FALSE; + if (self->ref_count <= 0) { + nm_assert_not_reached (); + return FALSE; + } + if ( require_is_started + && !self->is_started) + return FALSE; + if ( !allow_destroyed + && self->destroyed) + return FALSE; + return TRUE; +} + +/*****************************************************************************/ + +NMKeyFileDB * +nm_key_file_db_new (const char *filename, + const char *group_name, + NMKeyFileDBLogFcn log_fcn, + NMKeyFileDBGotDirtyFcn got_dirty_fcn, + gpointer user_data) +{ + NMKeyFileDB *self; + gsize l_filename; + gsize l_group; + + g_return_val_if_fail (filename && filename[0], NULL); + g_return_val_if_fail (group_name && group_name[0], NULL); + + l_filename = strlen (filename); + l_group = strlen (group_name); + + self = g_malloc0 (sizeof (NMKeyFileDB) + l_filename + 1 + l_group + 1); + self->ref_count = 1; + self->log_fcn = log_fcn; + self->got_dirty_fcn = got_dirty_fcn; + self->user_data = user_data; + self->kf = g_key_file_new (); + g_key_file_set_list_separator (self->kf, ','); + memcpy (self->filename, filename, l_filename + 1); + self->group_name = &self->filename[l_filename + 1]; + memcpy ((char *) self->group_name, group_name, l_group + 1); + + return self; +} + +NMKeyFileDB * +nm_key_file_db_ref (NMKeyFileDB *self) +{ + if (!self) + return NULL; + + g_return_val_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE), NULL); + + nm_assert (self->ref_count <= G_MAXUINT); + self->ref_count++; + return self; +} + +void +nm_key_file_db_unref (NMKeyFileDB *self) +{ + if (!self) + return; + + g_return_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE)); + + if (--self->ref_count > 0) + return; + + g_key_file_unref (self->kf); + + g_free (self); +} + +/* destroy() is like unref, but it also makes the instance unusable. + * All changes afterwards fail with an assertion. + * + * The point is that NMKeyFileDB is ref-counted in principle. But there + * is a primary owner who also provides the log_fcn(). + * + * When the primary owner goes out of scope and gives up the reference, it does + * not want to receive any log notifications anymore. + * + * The way NMKeyFileDB is intended to be used is in a very strict context: + * NMSettings owns the NMKeyFileDB instance and receives logging notifications. + * It's also the last one to persist the data to disk. Afterwards, no other user + * is supposed to be around and do anything with NMKeyFileDB. But since NMKeyFileDB + * is ref-counted it's hard to ensure that this is truly honored. So we start + * asserting at that point. + */ +void +nm_key_file_db_destroy (NMKeyFileDB *self) +{ + if (!self) + return; + + g_return_if_fail (_IS_KEY_FILE_DB (self, FALSE, FALSE)); + g_return_if_fail (!self->destroyed); + + self->destroyed = TRUE; + nm_key_file_db_unref (self); +} + +/*****************************************************************************/ + +/* nm_key_file_db_start() is supposed to be called right away, after creating the + * instance. + * + * It's not done as separate step after nm_key_file_db_new(), because we want to log, + * and the log_fcn returns the self pointer (which we should not expose before + * nm_key_file_db_new() returns. */ +void +nm_key_file_db_start (NMKeyFileDB *self) +{ + int r; + gs_free char *contents = NULL; + gsize contents_len; + gs_free_error GError *error = NULL; + + g_return_if_fail (_IS_KEY_FILE_DB (self, FALSE, FALSE)); + g_return_if_fail (!self->is_started); + + self->is_started = TRUE; + + r = nm_utils_file_get_contents (-1, + self->filename, + 20*1024*1024, + NM_UTILS_FILE_GET_CONTENTS_FLAG_NONE, + &contents, + &contents_len, + &error); + if (r < 0) { + _LOGD ("failed to read \"%s\": %s", self->filename, error->message); + return; + } + + if (!g_key_file_load_from_data (self->kf, + contents, + contents_len, + G_KEY_FILE_KEEP_COMMENTS, + &error)) { + _LOGD ("failed to load keyfile \"%s\": %s", self->filename, error->message); + return; + } + + _LOGD ("loaded keyfile-db for \"%s\"", self->filename); +} + +/*****************************************************************************/ + +const char * +nm_key_file_db_get_filename (NMKeyFileDB *self) +{ + g_return_val_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE), NULL); + + return self->filename; +} + +gboolean +nm_key_file_db_is_dirty (NMKeyFileDB *self) +{ + g_return_val_if_fail (_IS_KEY_FILE_DB (self, FALSE, TRUE), FALSE); + + return self->dirty; +} + +/*****************************************************************************/ + +char * +nm_key_file_db_get_value (NMKeyFileDB *self, + const char *key) +{ + g_return_val_if_fail (_IS_KEY_FILE_DB (self, TRUE, TRUE), NULL); + + return g_key_file_get_value (self->kf, self->group_name, key, NULL); +} + +char ** +nm_key_file_db_get_string_list (NMKeyFileDB *self, + const char *key, + gsize *out_len) +{ + g_return_val_if_fail (_IS_KEY_FILE_DB (self, TRUE, TRUE), NULL); + + return g_key_file_get_string_list (self->kf, self->group_name, key, out_len, NULL); +} + +/*****************************************************************************/ + +static void +_got_dirty (NMKeyFileDB *self, + const char *key) +{ + nm_assert (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + nm_assert (!self->dirty); + + _LOGD ("updated entry for %s.%s", self->group_name, key); + + self->dirty = TRUE; + if (self->got_dirty_fcn) + self->got_dirty_fcn (self, self->user_data); +} + +/*****************************************************************************/ + +void +nm_key_file_db_remove_key (NMKeyFileDB *self, + const char *key) +{ + gboolean got_dirty = FALSE; + + g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + + if (!key) + return; + + if (!self->dirty) { + gs_free_error GError *error = NULL; + + g_key_file_has_key (self->kf, self->group_name, key, &error); + got_dirty = (error != NULL); + } + g_key_file_remove_key (self->kf, self->group_name, key, NULL); + + if (got_dirty) + _got_dirty (self, key); +} + +void +nm_key_file_db_set_value (NMKeyFileDB *self, + const char *key, + const char *value) +{ + gs_free char *old_value = NULL; + gboolean got_dirty = FALSE; + + g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + g_return_if_fail (key); + + if (!value) { + nm_key_file_db_remove_key (self, key); + return; + } + + if (!self->dirty) { + gs_free_error GError *error = NULL; + + old_value = g_key_file_get_value (self->kf, self->group_name, key, &error); + if (error) + got_dirty = TRUE; + } + + g_key_file_set_value (self->kf, self->group_name, key, value); + + if ( !self->dirty + && !got_dirty) { + gs_free_error GError *error = NULL; + gs_free char *new_value = NULL; + + new_value = g_key_file_get_value (self->kf, self->group_name, key, &error); + if ( error + || !new_value + || !nm_streq0 (old_value, new_value)) + got_dirty = TRUE; + } + + if (got_dirty) + _got_dirty (self, key); +} + +void +nm_key_file_db_set_string_list (NMKeyFileDB *self, + const char *key, + const char *const*value, + gssize len) +{ + gs_free char *old_value = NULL; + gboolean got_dirty = FALSE;; + + g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + g_return_if_fail (key); + + if (!value) { + nm_key_file_db_remove_key (self, key); + return; + } + + if (!self->dirty) { + gs_free_error GError *error = NULL; + + old_value = g_key_file_get_value (self->kf, self->group_name, key, &error); + if (error) + got_dirty = TRUE; + } + + if (len < 0) + len = NM_PTRARRAY_LEN (value); + + g_key_file_set_string_list (self->kf, self->group_name, key, value, len); + + if ( !self->dirty + && !got_dirty) { + gs_free_error GError *error = NULL; + gs_free char *new_value = NULL; + + new_value = g_key_file_get_value (self->kf, self->group_name, key, &error); + if ( error + || !new_value + || !nm_streq0 (old_value, new_value)) + got_dirty = TRUE; + } + + if (got_dirty) + _got_dirty (self, key); +} + +/*****************************************************************************/ + +void +nm_key_file_db_to_file (NMKeyFileDB *self, + gboolean force) +{ + gs_free_error GError *error = NULL; + + g_return_if_fail (_IS_KEY_FILE_DB (self, TRUE, FALSE)); + + if ( !force + && !self->dirty) + return; + + self->dirty = FALSE; + + if (!g_key_file_save_to_file (self->kf, + self->filename, + &error)) { + _LOGD ("failure to write keyfile \"%s\": %s", self->filename, error->message); + } else + _LOGD ("write keyfile: \"%s\"", self->filename); +} diff --git a/shared/nm-glib-aux/nm-keyfile-aux.h b/shared/nm-glib-aux/nm-keyfile-aux.h new file mode 100644 index 0000000000..8563f4d186 --- /dev/null +++ b/shared/nm-glib-aux/nm-keyfile-aux.h @@ -0,0 +1,78 @@ +/* NetworkManager -- Network link manager + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the + * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, + * Boston, MA 02110-1301 USA. + * + * (C) Copyright 2019 Red Hat, Inc. + */ + +#ifndef __NM_KEYFILE_AUX_H__ +#define __NM_KEYFILE_AUX_H__ + +/*****************************************************************************/ + +typedef struct _NMKeyFileDB NMKeyFileDB; + +typedef void (*NMKeyFileDBLogFcn) (NMKeyFileDB *self, + int syslog_level, + gpointer user_data, + const char *fmt, + ...) G_GNUC_PRINTF (4, 5); + +typedef void (*NMKeyFileDBGotDirtyFcn) (NMKeyFileDB *self, + gpointer user_data); + +NMKeyFileDB *nm_key_file_db_new (const char *filename, + const char *group, + NMKeyFileDBLogFcn log_fcn, + NMKeyFileDBGotDirtyFcn got_dirty_fcn, + gpointer user_data); + +void nm_key_file_db_start (NMKeyFileDB *self); + +NMKeyFileDB *nm_key_file_db_ref (NMKeyFileDB *self); +void nm_key_file_db_unref (NMKeyFileDB *self); + +void nm_key_file_db_destroy (NMKeyFileDB *self); + +const char *nm_key_file_db_get_filename (NMKeyFileDB *self); + +gboolean nm_key_file_db_is_dirty (NMKeyFileDB *self); + +char *nm_key_file_db_get_value (NMKeyFileDB *self, + const char *key); + +char **nm_key_file_db_get_string_list (NMKeyFileDB *self, + const char *key, + gsize *out_len); + +void nm_key_file_db_remove_key (NMKeyFileDB *self, + const char *key); + +void nm_key_file_db_set_value (NMKeyFileDB *self, + const char *key, + const char *value); + +void nm_key_file_db_set_string_list (NMKeyFileDB *self, + const char *key, + const char *const*value, + gssize len); + +void nm_key_file_db_to_file (NMKeyFileDB *self, + gboolean force); + +/*****************************************************************************/ + +#endif /* __NM_KEYFILE_AUX_H__ */ diff --git a/shared/nm-glib-aux/nm-logging-fwd.h b/shared/nm-glib-aux/nm-logging-fwd.h index 900dfff812..693803f9d4 100644 --- a/shared/nm-glib-aux/nm-logging-fwd.h +++ b/shared/nm-glib-aux/nm-logging-fwd.h @@ -110,4 +110,21 @@ void _nm_log_impl (const char *file, const char *fmt, ...) _nm_printf (10, 11); +static inline NMLogLevel +nm_log_level_from_syslog (int syslog_level) +{ + switch (syslog_level) { + case 0 /* LOG_EMERG */ : return LOGL_ERR; + case 1 /* LOG_ALERT */ : return LOGL_ERR; + case 2 /* LOG_CRIT */ : return LOGL_ERR; + case 3 /* LOG_ERR */ : return LOGL_ERR; + case 4 /* LOG_WARNING */ : return LOGL_WARN; + case 5 /* LOG_NOTICE */ : return LOGL_INFO; + case 6 /* LOG_INFO */ : return LOGL_DEBUG; + case 7 /* LOG_DEBUG */ : return LOGL_TRACE; + default: + return syslog_level >= 0 ? LOGL_TRACE : LOGL_ERR; + } +} + #endif /* __NM_LOGGING_DEFINES_H__ */ diff --git a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h index a285c3cdc5..d38a39b15a 100644 --- a/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h +++ b/shared/systemd/sd-adapt-shared/nm-sd-adapt-shared.h @@ -21,8 +21,6 @@ #include "nm-default.h" -#include <syslog.h> - #include "nm-glib-aux/nm-logging-fwd.h" /*****************************************************************************/ @@ -32,32 +30,18 @@ /*****************************************************************************/ -static inline NMLogLevel -_slog_level_to_nm (int slevel) -{ - switch (LOG_PRI (slevel)) { - case LOG_DEBUG: return LOGL_DEBUG; - case LOG_WARNING: return LOGL_WARN; - case LOG_CRIT: - case LOG_ERR: return LOGL_ERR; - case LOG_INFO: - case LOG_NOTICE: - default: return LOGL_INFO; - } -} - static inline int _nm_log_get_max_level_realm (void) { /* inline function, to avoid coverity warning about constant expression. */ - return LOG_DEBUG; + return 7 /* LOG_DEBUG */; } #define log_get_max_level_realm(realm) _nm_log_get_max_level_realm () #define log_internal_realm(level, error, file, line, func, format, ...) \ ({ \ const int _nm_e = (error); \ - const NMLogLevel _nm_l = _slog_level_to_nm ((level)); \ + const NMLogLevel _nm_l = nm_log_level_from_syslog (LOG_PRI (level)); \ \ if (_nm_log_enabled_impl (!(NM_THREAD_SAFE_ON_MAIN_THREAD), _nm_l, LOGD_SYSTEMD)) { \ const char *_nm_location = strrchr ((""file), '/'); \ diff --git a/src/devices/nm-device.c b/src/devices/nm-device.c index 62d2e57836..26bcc2c840 100644 --- a/src/devices/nm-device.c +++ b/src/devices/nm-device.c @@ -15121,7 +15121,7 @@ _set_state_full (NMDevice *self, * and those we haven't tried yet (no timestamp). */ if (sett_conn && !nm_settings_connection_get_timestamp (sett_conn, NULL)) - nm_settings_connection_update_timestamp (sett_conn, (guint64) 0, TRUE); + nm_settings_connection_update_timestamp (sett_conn, (guint64) 0); /* Schedule the transition to DISCONNECTED. The device can't transition * immediately because we can't change states again from the state diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c index 494fca321f..3f973090f3 100644 --- a/src/devices/wifi/nm-iwd-manager.c +++ b/src/devices/wifi/nm-iwd-manager.c @@ -900,7 +900,7 @@ nm_iwd_manager_init (NMIwdManager *self) g_signal_connect (priv->manager, NM_MANAGER_DEVICE_ADDED, G_CALLBACK (device_added), self); - priv->settings = g_object_ref (nm_settings_get ()); + priv->settings = g_object_ref (NM_SETTINGS_GET); g_signal_connect (priv->settings, NM_SETTINGS_SIGNAL_CONNECTION_REMOVED, G_CALLBACK (connection_removed), self); diff --git a/src/main.c b/src/main.c index 9f979cf4dc..02a4210532 100644 --- a/src/main.c +++ b/src/main.c @@ -458,6 +458,8 @@ done: nm_dns_manager_stop (nm_dns_manager_get ()); + nm_settings_kf_db_write (NM_SETTINGS_GET); + done_no_manager: if (global_opt.pidfile && wrote_pidfile) unlink (global_opt.pidfile); diff --git a/src/nm-active-connection.c b/src/nm-active-connection.c index 17568c30b5..d28588c989 100644 --- a/src/nm-active-connection.c +++ b/src/nm-active-connection.c @@ -285,7 +285,7 @@ nm_active_connection_set_state (NMActiveConnection *self, if ( new_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED || old_state == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { nm_settings_connection_update_timestamp (priv->settings_connection.obj, - (guint64) time (NULL), TRUE); + (guint64) time (NULL)); } if (priv->device) { diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index f715eea611..3a1693d26e 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -171,7 +171,7 @@ find_settings_connection (NMCheckpoint *self, *need_update = FALSE; uuid = nm_connection_get_uuid (dev_checkpoint->settings_connection); - sett_conn = nm_settings_get_connection_by_uuid (nm_settings_get (), uuid); + sett_conn = nm_settings_get_connection_by_uuid (NM_SETTINGS_GET, uuid); if (!sett_conn) return NULL; @@ -239,7 +239,7 @@ restore_and_activate_connection (NMCheckpoint *self, _LOGD ("rollback: adding connection %s again", nm_connection_get_uuid (dev_checkpoint->settings_connection)); - connection = nm_settings_add_connection (nm_settings_get (), + connection = nm_settings_add_connection (NM_SETTINGS_GET, dev_checkpoint->settings_connection, TRUE, &local_error); @@ -419,7 +419,7 @@ next_dev: gs_free NMSettingsConnection **list = NULL; g_return_val_if_fail (priv->connection_uuids, NULL); - list = nm_settings_get_connections_clone (nm_settings_get (), NULL, + list = nm_settings_get_connections_clone (NM_SETTINGS_GET, NULL, NULL, NULL, nm_settings_connection_cmp_autoconnect_priority_p_with_data, NULL); @@ -687,7 +687,7 @@ nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_time if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) { priv->connection_uuids = g_hash_table_new_full (nm_str_hash, g_str_equal, g_free, NULL); - for (con = nm_settings_get_connections (nm_settings_get (), NULL); *con; con++) { + for (con = nm_settings_get_connections (NM_SETTINGS_GET, NULL); *con; con++) { g_hash_table_add (priv->connection_uuids, g_strdup (nm_settings_connection_get_uuid (*con))); } diff --git a/src/nm-logging.c b/src/nm-logging.c index 48e51421b9..79e3658ab4 100644 --- a/src/nm-logging.c +++ b/src/nm-logging.c @@ -68,6 +68,15 @@ /*****************************************************************************/ +G_STATIC_ASSERT (LOG_EMERG == 0); +G_STATIC_ASSERT (LOG_ALERT == 1); +G_STATIC_ASSERT (LOG_CRIT == 2); +G_STATIC_ASSERT (LOG_ERR == 3); +G_STATIC_ASSERT (LOG_WARNING == 4); +G_STATIC_ASSERT (LOG_NOTICE == 5); +G_STATIC_ASSERT (LOG_INFO == 6); +G_STATIC_ASSERT (LOG_DEBUG == 7); + /* We have more then 32 logging domains. Assert that it compiles to a 64 bit sized enum */ G_STATIC_ASSERT (sizeof (NMLogDomain) >= sizeof (guint64)); diff --git a/src/nm-manager.c b/src/nm-manager.c index c0cd15c0cd..3622a0a5ad 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -7313,7 +7313,7 @@ periodic_update_active_connection_timestamps (gpointer user_data) c_list_for_each_entry (ac, &priv->active_connections_lst_head, active_connections_lst) { if (nm_active_connection_get_state (ac) == NM_ACTIVE_CONNECTION_STATE_ACTIVATED) { nm_settings_connection_update_timestamp (nm_active_connection_get_settings_connection (ac), - (guint64) time (NULL), FALSE); + (guint64) time (NULL)); } } return G_SOURCE_CONTINUE; diff --git a/src/settings/nm-settings-connection.c b/src/settings/nm-settings-connection.c index 3fdaa59814..3bb30cbe57 100644 --- a/src/settings/nm-settings-connection.c +++ b/src/settings/nm-settings-connection.c @@ -25,6 +25,7 @@ #include "c-list/src/c-list.h" +#include "nm-glib-aux/nm-keyfile-aux.h" #include "nm-libnm-core-intern/nm-common-macros.h" #include "nm-config.h" #include "nm-config-data.h" @@ -38,9 +39,6 @@ #include "nm-core-internal.h" #include "nm-audit-manager.h" -#define SETTINGS_TIMESTAMPS_FILE NMSTATEDIR "/timestamps" -#define SETTINGS_SEEN_BSSIDS_FILE NMSTATEDIR "/seen-bssids" - #define AUTOCONNECT_RETRIES_UNSET -2 #define AUTOCONNECT_RETRIES_FOREVER -1 #define AUTOCONNECT_RESET_RETRIES_TIMER 300 @@ -86,6 +84,9 @@ static guint signals[LAST_SIGNAL] = { 0 }; typedef struct _NMSettingsConnectionPrivate { + NMKeyFileDB *kf_db_timestamps; + NMKeyFileDB *kf_db_seen_bssids; + NMAgentManager *agent_mgr; NMSessionMonitor *session_monitor; gulong session_changed_id; @@ -658,42 +659,6 @@ out: return TRUE; } -static void -remove_entry_from_db (NMSettingsConnection *self, const char* db_name) -{ - GKeyFile *key_file; - const char *db_file; - - if (strcmp (db_name, "timestamps") == 0) - db_file = SETTINGS_TIMESTAMPS_FILE; - else if (strcmp (db_name, "seen-bssids") == 0) - db_file = SETTINGS_SEEN_BSSIDS_FILE; - else - return; - - key_file = g_key_file_new (); - if (g_key_file_load_from_file (key_file, db_file, G_KEY_FILE_KEEP_COMMENTS, NULL)) { - const char *connection_uuid; - char *data; - gsize len; - GError *error = NULL; - - connection_uuid = nm_settings_connection_get_uuid (self); - - g_key_file_remove_key (key_file, db_name, connection_uuid, NULL); - data = g_key_file_to_data (key_file, &len, &error); - if (data) { - g_file_set_contents (db_file, data, len, &error); - g_free (data); - } - if (error) { - _LOGW ("error writing %s file '%s': %s", db_name, db_file, error->message); - g_error_free (error); - } - } - g_key_file_free (key_file); -} - gboolean nm_settings_connection_delete (NMSettingsConnection *self, GError **error) @@ -701,6 +666,7 @@ nm_settings_connection_delete (NMSettingsConnection *self, gs_unref_object NMSettingsConnection *self_keep_alive = NULL; NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); NMConnection *for_agents; + const char *connection_uuid; g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); @@ -719,11 +685,13 @@ nm_settings_connection_delete (NMSettingsConnection *self, for_agents); g_object_unref (for_agents); - /* Remove timestamp from timestamps database file */ - remove_entry_from_db (self, "timestamps"); + connection_uuid = nm_settings_connection_get_uuid (self); + + if (priv->kf_db_timestamps) + nm_key_file_db_remove_key (priv->kf_db_timestamps, connection_uuid); - /* Remove connection from seen-bssids database file */ - remove_entry_from_db (self, "seen-bssids"); + if (priv->kf_db_seen_bssids) + nm_key_file_db_remove_key (priv->kf_db_seen_bssids, connection_uuid); nm_settings_connection_signal_remove (self); return TRUE; @@ -2338,11 +2306,13 @@ gboolean nm_settings_connection_get_timestamp (NMSettingsConnection *self, guint64 *out_timestamp) { + NMSettingsConnectionPrivate *priv; + g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (self), FALSE); - if (out_timestamp) - *out_timestamp = NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->timestamp; - return NM_SETTINGS_CONNECTION_GET_PRIVATE (self)->timestamp_set; + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + NM_SET_OUT (out_timestamp, priv->timestamp); + return priv->timestamp_set; } /** @@ -2350,56 +2320,31 @@ nm_settings_connection_get_timestamp (NMSettingsConnection *self, * @self: the #NMSettingsConnection * @timestamp: timestamp to set into the connection and to store into * the timestamps database - * @flush_to_disk: if %TRUE, commit timestamp update to persistent storage * * Updates the connection and timestamps database with the provided timestamp. **/ void nm_settings_connection_update_timestamp (NMSettingsConnection *self, - guint64 timestamp, - gboolean flush_to_disk) + guint64 timestamp) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); const char *connection_uuid; - GKeyFile *timestamps_file; - char *data, *tmp; - gsize len; - GError *error = NULL; + char sbuf[60]; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); - /* Update timestamp in private storage */ priv->timestamp = timestamp; priv->timestamp_set = TRUE; - if (flush_to_disk == FALSE) - return; - if (nm_config_get_configure_and_quit (nm_config_get ()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) + if (!priv->kf_db_timestamps) return; - /* 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 (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) - _LOGW ("error parsing timestamps file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message); - g_clear_error (&error); - } - connection_uuid = nm_settings_connection_get_uuid (self); - tmp = g_strdup_printf ("%" G_GUINT64_FORMAT, timestamp); - g_key_file_set_value (timestamps_file, "timestamps", connection_uuid, tmp); - g_free (tmp); - - 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 (connection_uuid) { + nm_key_file_db_set_value (priv->kf_db_timestamps, + connection_uuid, + nm_sprintf_buf (sbuf, "%" G_GUINT64_FORMAT, timestamp)); } - if (error) { - _LOGW ("error saving timestamp to file '%s': %s", SETTINGS_TIMESTAMPS_FILE, error->message); - g_error_free (error); - } - g_key_file_free (timestamps_file); } /** @@ -2410,38 +2355,79 @@ nm_settings_connection_update_timestamp (NMSettingsConnection *self, * stores it into the connection private data. **/ void -nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *self) +nm_settings_connection_register_kf_dbs (NMSettingsConnection *self, + NMKeyFileDB *kf_db_timestamps, + NMKeyFileDB *kf_db_seen_bssids) { - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - gs_unref_keyfile GKeyFile *timestamps_file = NULL; - gs_free_error GError *error = NULL; - gs_free char *tmp_str = NULL; + NMSettingsConnectionPrivate *priv; const char *connection_uuid; - gint64 timestamp; g_return_if_fail (NM_IS_SETTINGS_CONNECTION (self)); + g_return_if_fail (kf_db_timestamps); + g_return_if_fail (kf_db_seen_bssids); - timestamps_file = g_key_file_new (); - if (!g_key_file_load_from_file (timestamps_file, SETTINGS_TIMESTAMPS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) { - _LOGD ("failed to read connection timestamp: %s", error->message); - return; - } + priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); connection_uuid = nm_settings_connection_get_uuid (self); - tmp_str = g_key_file_get_value (timestamps_file, "timestamps", connection_uuid, &error); - if (!tmp_str) { - _LOGD ("failed to read connection timestamp: %s", error->message); - return; - } - timestamp = _nm_utils_ascii_str_to_int64 (tmp_str, 10, 0, G_MAXINT64, -1); - if (timestamp < 0) { - _LOGD ("failed to read connection timestamp: %s", "invalid number"); - return; + if (priv->kf_db_timestamps != kf_db_timestamps) { + gs_free char *tmp_str = NULL; + guint64 timestamp; + + nm_key_file_db_unref (priv->kf_db_timestamps); + priv->kf_db_timestamps = nm_key_file_db_ref (kf_db_timestamps); + + tmp_str = nm_key_file_db_get_value (priv->kf_db_timestamps, connection_uuid); + + timestamp = _nm_utils_ascii_str_to_uint64 (tmp_str, 10, 0, G_MAXUINT64, G_MAXUINT64); + if (timestamp != G_MAXUINT64) { + priv->timestamp = timestamp; + priv->timestamp_set = TRUE; + _LOGT ("read timestamp %"G_GUINT64_FORMAT" from keyfile database \"%s\"", + timestamp, nm_key_file_db_get_filename (priv->kf_db_timestamps)); + } else + _LOGT ("no timestamp from keyfile database \"%s\"", + nm_key_file_db_get_filename (priv->kf_db_timestamps)); } - priv->timestamp = timestamp; - priv->timestamp_set = TRUE; + if (priv->kf_db_seen_bssids != kf_db_seen_bssids) { + gs_strfreev char **tmp_strv = NULL; + gsize i, len; + + nm_key_file_db_unref (priv->kf_db_seen_bssids); + priv->kf_db_seen_bssids = nm_key_file_db_ref (kf_db_seen_bssids); + + tmp_strv = nm_key_file_db_get_string_list (priv->kf_db_seen_bssids, connection_uuid, &len); + + if (tmp_strv) { + _LOGT ("read %zu seen-bssids from keyfile database \"%s\"", + NM_PTRARRAY_LEN (tmp_strv), + nm_key_file_db_get_filename (priv->kf_db_seen_bssids)); + g_hash_table_remove_all (priv->seen_bssids); + for (i = len; i > 0; ) + g_hash_table_add (priv->seen_bssids, g_steal_pointer (&tmp_strv[--i])); + } else { + NMSettingWireless *s_wifi; + + _LOGT ("no seen-bssids from keyfile database \"%s\"", + nm_key_file_db_get_filename (priv->kf_db_seen_bssids)); + + /* If this connection didn't have an entry in the seen-bssids database, + * maybe this is the first time we've read it in, so populate the + * seen-bssids list from the deprecated seen-bssids property of the + * wifi setting. + */ + s_wifi = nm_connection_get_setting_wireless (nm_settings_connection_get_connection (self)); + if (s_wifi) { + len = nm_setting_wireless_get_num_seen_bssids (s_wifi); + for (i = 0; i < len; i++) { + const char *bssid = nm_setting_wireless_get_seen_bssid (s_wifi, i); + + g_hash_table_add (priv->seen_bssids, g_strdup (bssid)); + } + } + } + } } /** @@ -2504,108 +2490,26 @@ nm_settings_connection_add_seen_bssid (NMSettingsConnection *self, const char *seen_bssid) { NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); + gs_free const char **strv = NULL; const char *connection_uuid; - GKeyFile *seen_bssids_file; - char *data, *bssid_str; - const char **list; - gsize len; - GError *error = NULL; - GHashTableIter iter; - guint n; g_return_if_fail (seen_bssid != NULL); - if (g_hash_table_lookup (priv->seen_bssids, seen_bssid)) - return; /* Already in the list */ - - /* Add the new BSSID; let the hash take ownership of the allocated BSSID string */ - bssid_str = g_strdup (seen_bssid); - g_hash_table_insert (priv->seen_bssids, bssid_str, bssid_str); + g_hash_table_add (priv->seen_bssids, g_strdup (seen_bssid)); - /* Build up a list of all the BSSIDs in string form */ - n = 0; - list = g_malloc0 (g_hash_table_size (priv->seen_bssids) * sizeof (char *)); - g_hash_table_iter_init (&iter, priv->seen_bssids); - while (g_hash_table_iter_next (&iter, NULL, (gpointer) &bssid_str)) - list[n++] = bssid_str; - - /* Save BSSID to seen-bssids file */ - seen_bssids_file = g_key_file_new (); - g_key_file_set_list_separator (seen_bssids_file, ','); - if (!g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, &error)) { - if (!g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) { - _LOGW ("error parsing seen-bssids file '%s': %s", - SETTINGS_SEEN_BSSIDS_FILE, error->message); - } - g_clear_error (&error); - } + if (!priv->kf_db_seen_bssids) + return; connection_uuid = nm_settings_connection_get_uuid (self); - g_key_file_set_string_list (seen_bssids_file, "seen-bssids", connection_uuid, list, n); - g_free (list); + if (!connection_uuid) + return; - data = g_key_file_to_data (seen_bssids_file, &len, &error); - if (data) { - g_file_set_contents (SETTINGS_SEEN_BSSIDS_FILE, data, len, &error); - g_free (data); - } - g_key_file_free (seen_bssids_file); + strv = nm_utils_strdict_get_keys (priv->seen_bssids, TRUE, NULL); - if (error) { - _LOGW ("error saving seen-bssids to file '%s': %s", - SETTINGS_SEEN_BSSIDS_FILE, error->message); - g_error_free (error); - } -} - -/** - * nm_settings_connection_read_and_fill_seen_bssids: - * @self: the #NMSettingsConnection - * - * Retrieves seen BSSIDs of the connection from database file and stores then into the - * connection private data. - **/ -void -nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self) -{ - NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE (self); - const char *connection_uuid; - GKeyFile *seen_bssids_file; - char **tmp_strv = NULL; - gsize i, len = 0; - NMSettingWireless *s_wifi; - - /* Get seen BSSIDs from database file */ - seen_bssids_file = g_key_file_new (); - g_key_file_set_list_separator (seen_bssids_file, ','); - if (g_key_file_load_from_file (seen_bssids_file, SETTINGS_SEEN_BSSIDS_FILE, G_KEY_FILE_KEEP_COMMENTS, NULL)) { - connection_uuid = nm_settings_connection_get_uuid (self); - tmp_strv = g_key_file_get_string_list (seen_bssids_file, "seen-bssids", connection_uuid, &len, NULL); - } - g_key_file_free (seen_bssids_file); - - /* Update connection's seen-bssids */ - if (tmp_strv) { - g_hash_table_remove_all (priv->seen_bssids); - for (i = 0; i < len; i++) - g_hash_table_insert (priv->seen_bssids, tmp_strv[i], tmp_strv[i]); - g_free (tmp_strv); - } else { - /* If this connection didn't have an entry in the seen-bssids database, - * maybe this is the first time we've read it in, so populate the - * seen-bssids list from the deprecated seen-bssids property of the - * wifi setting. - */ - s_wifi = nm_connection_get_setting_wireless (nm_settings_connection_get_connection (self)); - if (s_wifi) { - len = nm_setting_wireless_get_num_seen_bssids (s_wifi); - for (i = 0; i < len; i++) { - char *bssid_dup = g_strdup (nm_setting_wireless_get_seen_bssid (s_wifi, i)); - - g_hash_table_insert (priv->seen_bssids, bssid_dup, bssid_dup); - } - } - } + nm_key_file_db_set_string_list (priv->kf_db_seen_bssids, + connection_uuid, + strv ?: NM_PTRARRAY_EMPTY (const char *), + -1); } /*****************************************************************************/ @@ -2932,6 +2836,9 @@ dispose (GObject *object) g_clear_pointer (&priv->filename, g_free); + g_clear_pointer (&priv->kf_db_timestamps, nm_key_file_db_unref); + g_clear_pointer (&priv->kf_db_seen_bssids, nm_key_file_db_unref); + G_OBJECT_CLASS (nm_settings_connection_parent_class)->dispose (object); } diff --git a/src/settings/nm-settings-connection.h b/src/settings/nm-settings-connection.h index e796b71645..c23f68fcdc 100644 --- a/src/settings/nm-settings-connection.h +++ b/src/settings/nm-settings-connection.h @@ -220,14 +220,17 @@ int nm_settings_connection_cmp_timestamp_p_with_data (gconstpointer pa, gconstpo int nm_settings_connection_cmp_autoconnect_priority (NMSettingsConnection *a, NMSettingsConnection *b); int nm_settings_connection_cmp_autoconnect_priority_p_with_data (gconstpointer pa, gconstpointer pb, gpointer user_data); +struct _NMKeyFileDB; + +void nm_settings_connection_register_kf_dbs (NMSettingsConnection *self, + struct _NMKeyFileDB *kf_db_timestamps, + struct _NMKeyFileDB *kf_db_seen_bssids); + gboolean nm_settings_connection_get_timestamp (NMSettingsConnection *self, guint64 *out_timestamp); void nm_settings_connection_update_timestamp (NMSettingsConnection *self, - guint64 timestamp, - gboolean flush_to_disk); - -void nm_settings_connection_read_and_fill_timestamp (NMSettingsConnection *self); + guint64 timestamp); char **nm_settings_connection_get_seen_bssids (NMSettingsConnection *self); @@ -237,8 +240,6 @@ gboolean nm_settings_connection_has_seen_bssid (NMSettingsConnection *self, void nm_settings_connection_add_seen_bssid (NMSettingsConnection *self, const char *seen_bssid); -void nm_settings_connection_read_and_fill_seen_bssids (NMSettingsConnection *self); - int nm_settings_connection_autoconnect_retries_get (NMSettingsConnection *self); void nm_settings_connection_autoconnect_retries_set (NMSettingsConnection *self, int retries); diff --git a/src/settings/nm-settings.c b/src/settings/nm-settings.c index e594860bcb..9bc3bce95f 100644 --- a/src/settings/nm-settings.c +++ b/src/settings/nm-settings.c @@ -37,6 +37,7 @@ #endif #include "nm-libnm-core-intern/nm-common-macros.h" +#include "nm-glib-aux/nm-keyfile-aux.h" #include "nm-dbus-interface.h" #include "nm-connection.h" #include "nm-setting-8021x.h" @@ -119,6 +120,9 @@ typedef struct { GSList *plugins; + NMKeyFileDB *kf_db_timestamps; + NMKeyFileDB *kf_db_seen_bssids; + CList connections_lst_head; NMSettingsConnection **connections_cached_list; @@ -131,6 +135,9 @@ typedef struct { guint connections_len; + guint kf_db_flush_idle_id_timestamps; + guint kf_db_flush_idle_id_seen_bssids; + bool started:1; bool startup_complete:1; bool connections_loaded:1; @@ -935,11 +942,9 @@ claim_connection (NMSettings *self, NMSettingsConnection *sett_conn) return; } - /* Read timestamp from look-aside file and put it into the connection's data */ - nm_settings_connection_read_and_fill_timestamp (sett_conn); - - /* Read seen-bssids from look-aside file and put it into the connection's data */ - nm_settings_connection_read_and_fill_seen_bssids (sett_conn); + nm_settings_connection_register_kf_dbs (sett_conn, + priv->kf_db_timestamps, + priv->kf_db_seen_bssids); /* Ensure its initial visibility is up-to-date */ nm_settings_connection_recheck_visibility (sett_conn); @@ -1764,6 +1769,128 @@ nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean quittin /*****************************************************************************/ +G_GNUC_PRINTF (4, 5) +static void +_kf_db_log_fcn (NMKeyFileDB *kf_db, + int syslog_level, + gpointer user_data, + const char *fmt, + ...) +{ + NMSettings *self = user_data; + NMLogLevel level = nm_log_level_from_syslog (syslog_level); + + if (_NMLOG_ENABLED (level)) { + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + gs_free char *msg = NULL; + va_list ap; + const char *prefix; + + va_start (ap, fmt); + msg = g_strdup_vprintf (fmt, ap); + va_end (ap); + + if (priv->kf_db_timestamps == kf_db) + prefix = "timestamps"; + else if (priv->kf_db_seen_bssids == kf_db) + prefix = "seen-bssids"; + else { + nm_assert_not_reached (); + prefix = "???"; + } + + _NMLOG (level, "[%s-keyfile]: %s", prefix, msg); + } +} + +static gboolean +_kf_db_got_dirty_flush (NMSettings *self, + gboolean is_timestamps) +{ + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + const char *prefix; + NMKeyFileDB *kf_db; + + if (is_timestamps) { + prefix = "timestamps"; + kf_db = priv->kf_db_timestamps; + priv->kf_db_flush_idle_id_timestamps = 0; + } else { + prefix = "seen-bssids"; + kf_db = priv->kf_db_seen_bssids; + priv->kf_db_flush_idle_id_seen_bssids = 0; + } + + if (nm_key_file_db_is_dirty (kf_db)) + nm_key_file_db_to_file (kf_db, FALSE); + else { + _LOGT ("[%s-keyfile]: skip saving changes to \"%s\"", + prefix, + nm_key_file_db_get_filename (kf_db)); + } + + return G_SOURCE_REMOVE; +} + +static gboolean +_kf_db_got_dirty_flush_timestamps_cb (gpointer user_data) +{ + return _kf_db_got_dirty_flush (user_data, + TRUE); +} + +static gboolean +_kf_db_got_dirty_flush_seen_bssids_cb (gpointer user_data) +{ + return _kf_db_got_dirty_flush (user_data, + FALSE); +} + +static void +_kf_db_got_dirty_fcn (NMKeyFileDB *kf_db, + gpointer user_data) +{ + NMSettings *self = user_data; + NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE (self); + GSourceFunc idle_func; + guint *p_id; + const char *prefix; + + if (priv->kf_db_timestamps == kf_db) { + prefix = "timestamps"; + p_id = &priv->kf_db_flush_idle_id_timestamps; + idle_func = _kf_db_got_dirty_flush_timestamps_cb; + } else if (priv->kf_db_seen_bssids == kf_db) { + prefix = "seen-bssids"; + p_id = &priv->kf_db_flush_idle_id_seen_bssids; + idle_func = _kf_db_got_dirty_flush_seen_bssids_cb; + } else { + nm_assert_not_reached (); + return; + } + + if (*p_id != 0) + return; + _LOGT ("[%s-keyfile]: schedule flushing changes to disk", prefix); + *p_id = g_idle_add_full (G_PRIORITY_LOW, idle_func, self, NULL); +} + +void +nm_settings_kf_db_write (NMSettings *self) +{ + NMSettingsPrivate *priv; + + g_return_if_fail (NM_IS_SETTINGS (self)); + + priv = NM_SETTINGS_GET_PRIVATE (self); + if (priv->kf_db_timestamps) + nm_key_file_db_to_file (priv->kf_db_timestamps, TRUE); + if (priv->kf_db_seen_bssids) + nm_key_file_db_to_file (priv->kf_db_seen_bssids, TRUE); +} + +/*****************************************************************************/ + const char * nm_settings_get_startup_complete_blocked_reason (NMSettings *self) { @@ -1797,6 +1924,19 @@ nm_settings_start (NMSettings *self, GError **error) priv = NM_SETTINGS_GET_PRIVATE (self); + priv->kf_db_timestamps = nm_key_file_db_new (NMSTATEDIR "/timestamps", + "timestamps", + _kf_db_log_fcn, + _kf_db_got_dirty_fcn, + self); + priv->kf_db_seen_bssids = nm_key_file_db_new (NMSTATEDIR "/seen-bssids", + "seen-bssids", + _kf_db_log_fcn, + _kf_db_got_dirty_fcn, + self); + nm_key_file_db_start (priv->kf_db_timestamps); + nm_key_file_db_start (priv->kf_db_seen_bssids); + /* Load the plugins; fail if a plugin is not found. */ plugins = nm_config_data_get_plugins (nm_config_get_data_orig (priv->config), TRUE); @@ -1933,6 +2073,13 @@ finalize (GObject *object) g_clear_object (&priv->config); + nm_clear_g_source (&priv->kf_db_flush_idle_id_timestamps); + nm_clear_g_source (&priv->kf_db_flush_idle_id_seen_bssids); + nm_key_file_db_to_file (priv->kf_db_timestamps, FALSE); + nm_key_file_db_to_file (priv->kf_db_seen_bssids, FALSE); + nm_key_file_db_destroy (priv->kf_db_timestamps); + nm_key_file_db_destroy (priv->kf_db_seen_bssids); + G_OBJECT_CLASS (nm_settings_parent_class)->finalize (object); } diff --git a/src/settings/nm-settings.h b/src/settings/nm-settings.h index eb74c09c4a..a3bd26a938 100644 --- a/src/settings/nm-settings.h +++ b/src/settings/nm-settings.h @@ -114,4 +114,6 @@ void nm_settings_device_removed (NMSettings *self, NMDevice *device, gboolean qu const char *nm_settings_get_startup_complete_blocked_reason (NMSettings *self); +void nm_settings_kf_db_write (NMSettings *settings); + #endif /* __NM_SETTINGS_H__ */ |