From 4aba7d46968fa442f34abb6e7caed43e7f242e7b Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 May 2019 16:45:59 +0200 Subject: [PATCH 1/5] core: use NM_SETTINGS_GET for singlton instead of nm_settings_get() We have it, so use it. Also, we use a similar macro for other singletons. --- src/devices/wifi/nm-iwd-manager.c | 2 +- src/nm-checkpoint.c | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) 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/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))); } From 8decdf22258f678897bb0d37ca0872d10bbd1c9e Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 May 2019 15:08:04 +0200 Subject: [PATCH 2/5] shared: add nm_log_level_from_syslog() helper to convert from syslog levels --- shared/nm-glib-aux/nm-logging-fwd.h | 17 ++++++++++++++++ .../sd-adapt-shared/nm-sd-adapt-shared.h | 20 ++----------------- src/nm-logging.c | 9 +++++++++ 3 files changed, 28 insertions(+), 18 deletions(-) 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 - #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/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)); From 8c2fda7ca09e0fb5119e5ba15b242aa6a93fde99 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 May 2019 11:57:35 +0200 Subject: [PATCH 3/5] shared: add "shared/nm-glib-aux/nm-keyfile-aux.h" --- Makefile.am | 2 ++ libnm-core/nm-keyfile-utils.c | 2 +- shared/meson.build | 1 + shared/nm-glib-aux/nm-keyfile-aux.c | 24 ++++++++++++++++++++++++ shared/nm-glib-aux/nm-keyfile-aux.h | 24 ++++++++++++++++++++++++ 5 files changed, 52 insertions(+), 1 deletion(-) create mode 100644 shared/nm-glib-aux/nm-keyfile-aux.c create mode 100644 shared/nm-glib-aux/nm-keyfile-aux.h 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..a0d8186d8d --- /dev/null +++ b/shared/nm-glib-aux/nm-keyfile-aux.c @@ -0,0 +1,24 @@ +/* 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" + 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..f7ef866c92 --- /dev/null +++ b/shared/nm-glib-aux/nm-keyfile-aux.h @@ -0,0 +1,24 @@ +/* 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__ + +#endif /* __NM_KEYFILE_AUX_H__ */ From b0693863c1f6c6bf31033499e222a6f6135411eb Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 May 2019 12:07:37 +0200 Subject: [PATCH 4/5] shared: add NMKeyFileDB API It will be used for "/var/lib/NetworkManager/seen-bssids" and "/var/lib/NetworkManager/timestamps" which currently is implemented in NMSettingConnection. --- shared/nm-glib-aux/nm-keyfile-aux.c | 389 ++++++++++++++++++++++++++++ shared/nm-glib-aux/nm-keyfile-aux.h | 54 ++++ 2 files changed, 443 insertions(+) diff --git a/shared/nm-glib-aux/nm-keyfile-aux.c b/shared/nm-glib-aux/nm-keyfile-aux.c index a0d8186d8d..0257bcca7f 100644 --- a/shared/nm-glib-aux/nm-keyfile-aux.c +++ b/shared/nm-glib-aux/nm-keyfile-aux.c @@ -22,3 +22,392 @@ #include "nm-keyfile-aux.h" +#include +#include +#include + +#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 index f7ef866c92..8563f4d186 100644 --- a/shared/nm-glib-aux/nm-keyfile-aux.h +++ b/shared/nm-glib-aux/nm-keyfile-aux.h @@ -21,4 +21,58 @@ #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__ */ From 8a78493de1c33d879082e55edca1ee6e672efc40 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Fri, 3 May 2019 14:33:23 +0200 Subject: [PATCH 5/5] settings: cache keyfile databases for "timestamps" and "seen-bssids" Only read the keyfile databases once and cache them for the remainder of the program. - this avoids the overhead of opening the file over and over again. - it also avoids the data changing without us expecting it. The state files are internal and we don't support changing it outside of NetworkManager. So in the base case we read the same data over and over. In the worst case, we read different data but are not interested in handling the changes. - only write the file when the content changes or before exiting (normally). - better log what is happening. - our state files tend to grow as we don't garbage collect old entries. Keeping this all in memory might be problematic. However, the right solution for this is that we come up with some form of garbage collection so that the state files are reaonsably small to begin with. --- src/devices/nm-device.c | 2 +- src/main.c | 2 + src/nm-active-connection.c | 2 +- src/nm-manager.c | 2 +- src/settings/nm-settings-connection.c | 293 +++++++++----------------- src/settings/nm-settings-connection.h | 13 +- src/settings/nm-settings.c | 157 +++++++++++++- src/settings/nm-settings.h | 2 + 8 files changed, 266 insertions(+), 207 deletions(-) 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/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-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); - /* Remove connection from seen-bssids database file */ - remove_entry_from_db (self, "seen-bssids"); + if (priv->kf_db_timestamps) + nm_key_file_db_remove_key (priv->kf_db_timestamps, connection_uuid); + + 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) + if (!priv->kf_db_timestamps) return; - if (nm_config_get_configure_and_quit (nm_config_get ()) == NM_CONFIG_CONFIGURE_AND_QUIT_INITRD) - 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; + + 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)); } - 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_seen_bssids != kf_db_seen_bssids) { + gs_strfreev char **tmp_strv = NULL; + gsize i, len; - priv->timestamp = timestamp; - priv->timestamp_set = TRUE; + 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 */ + g_hash_table_add (priv->seen_bssids, g_strdup (seen_bssid)); - /* 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); - - /* 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__ */