summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2021-07-01 11:32:48 +0200
committerThomas Haller <thaller@redhat.com>2021-07-01 11:33:57 +0200
commitba0e61840daa4cd6e1d11a4b19ef863ce0d950b9 (patch)
tree285e684210401e92e5951b7e7b930aaf2735cc93
parentdb744d2296c9e95ca51c8cea6d64fa8457e03987 (diff)
parent35402a7e909c9507698261478f97faf8592eebf3 (diff)
downloadNetworkManager-ba0e61840daa4cd6e1d11a4b19ef863ce0d950b9.tar.gz
core: merge branch 'th/keyfile-db-stale-entries'
https://gitlab.freedesktop.org/NetworkManager/NetworkManager/-/merge_requests/906 (cherry picked from commit 26f38b9ffafeab145150332f8a11eb94559c31bf)
-rw-r--r--src/core/main.c4
-rw-r--r--src/core/settings/nm-settings-connection.c227
-rw-r--r--src/core/settings/nm-settings-connection.h2
-rw-r--r--src/core/settings/nm-settings.c53
-rw-r--r--src/libnm-core-impl/nm-keyfile.c3
-rw-r--r--src/libnm-core-impl/nm-setting-wireless.c60
-rw-r--r--src/libnm-glib-aux/nm-io-utils.c64
-rw-r--r--src/libnm-glib-aux/nm-io-utils.h2
-rw-r--r--src/libnm-glib-aux/nm-keyfile-aux.c118
-rw-r--r--src/libnm-glib-aux/nm-keyfile-aux.h6
-rw-r--r--src/libnm-glib-aux/nm-macros-internal.h8
-rw-r--r--src/libnm-std-aux/nm-std-aux.h16
12 files changed, 449 insertions, 114 deletions
diff --git a/src/core/main.c b/src/core/main.c
index cfcdb860dd..3cb5c07f7f 100644
--- a/src/core/main.c
+++ b/src/core/main.c
@@ -304,14 +304,14 @@ main(int argc, char *argv[])
const char *const * warnings;
int errsv;
+ _nm_utils_is_manager_process = TRUE;
+
/* Known to cause a possible deadlock upon GDBus initialization:
* https://bugzilla.gnome.org/show_bug.cgi?id=674885 */
g_type_ensure(G_TYPE_SOCKET);
g_type_ensure(G_TYPE_DBUS_CONNECTION);
g_type_ensure(NM_TYPE_DBUS_MANAGER);
- _nm_utils_is_manager_process = TRUE;
-
main_loop = g_main_loop_new(NULL, FALSE);
/* we determine a first-start (contrary to a restart during the same boot)
diff --git a/src/core/settings/nm-settings-connection.c b/src/core/settings/nm-settings-connection.c
index 641f3297b8..36ef6acb2f 100644
--- a/src/core/settings/nm-settings-connection.c
+++ b/src/core/settings/nm-settings-connection.c
@@ -11,6 +11,7 @@
#include "c-list/src/c-list.h"
#include "libnm-glib-aux/nm-keyfile-aux.h"
+#include "libnm-glib-aux/nm-c-list.h"
#include "libnm-core-aux-intern/nm-common-macros.h"
#include "nm-config.h"
#include "nm-config-data.h"
@@ -30,6 +31,8 @@
#define AUTOCONNECT_RETRIES_FOREVER -1
#define AUTOCONNECT_RESET_RETRIES_TIMER 300
+#define SEEN_BSSIDS_MAX 30
+
#define _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES \
((NMSettingsUpdate2Flags) (NM_SETTINGS_UPDATE2_FLAG_TO_DISK \
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY \
@@ -59,6 +62,56 @@ nm_settings_connections_array_to_connections(NMSettingsConnection *const *connec
/*****************************************************************************/
+typedef struct {
+ char bssid[sizeof(NMEtherAddr) * 3];
+ CList seen_bssids_lst;
+} SeenBssidEntry;
+
+static inline SeenBssidEntry *
+_seen_bssid_entry_init_stale(SeenBssidEntry *entry, const NMEtherAddr *bssid_bin)
+{
+ _nm_utils_hwaddr_ntoa(bssid_bin, sizeof(NMEtherAddr), TRUE, entry->bssid, sizeof(entry->bssid));
+ return entry;
+}
+
+static inline SeenBssidEntry *
+_seen_bssid_entry_new_stale_bin(const NMEtherAddr *bssid_bin)
+{
+ return _seen_bssid_entry_init_stale(g_slice_new(SeenBssidEntry), bssid_bin);
+}
+
+static inline SeenBssidEntry *
+_seen_bssid_entry_new_stale_copy(const SeenBssidEntry *src)
+{
+ SeenBssidEntry *entry;
+
+ entry = g_slice_new(SeenBssidEntry);
+ memcpy(entry->bssid, src->bssid, sizeof(entry->bssid));
+ return entry;
+}
+
+static void
+_seen_bssid_entry_free(gpointer data)
+{
+ SeenBssidEntry *entry = data;
+
+ c_list_unlink_stale(&entry->seen_bssids_lst);
+ nm_g_slice_free(entry);
+}
+
+/*****************************************************************************/
+
+static GHashTable *
+_seen_bssids_hash_new(void)
+{
+ return g_hash_table_new_full(nm_str_hash,
+ g_str_equal,
+ (GDestroyNotify) _seen_bssid_entry_free,
+ NULL);
+}
+
+/*****************************************************************************/
+
NM_GOBJECT_PROPERTIES_DEFINE(NMSettingsConnection, PROP_UNSAVED, PROP_FLAGS, PROP_FILENAME, );
enum { UPDATED_INTERNAL, FLAGS_CHANGED, LAST_SIGNAL };
@@ -99,7 +152,8 @@ typedef struct _NMSettingsConnectionPrivate {
*/
GVariant *agent_secrets;
- GHashTable *seen_bssids; /* Up-to-date BSSIDs that's been seen for the connection */
+ CList seen_bssids_lst_head;
+ GHashTable *seen_bssids_hash;
guint64 timestamp; /* Up-to-date timestamp of connection use */
@@ -167,7 +221,9 @@ static const GDBusSignalInfo signal_info_updated;
static const GDBusSignalInfo signal_info_removed;
static const NMDBusInterfaceInfoExtended interface_info_settings_connection;
-static void update_agent_secrets_cache(NMSettingsConnection *self, NMConnection *new);
+static void update_agent_secrets_cache(NMSettingsConnection *self, NMConnection *new);
+static guint _get_seen_bssids(NMSettingsConnection *self,
+ const char * strv_buf[static(SEEN_BSSIDS_MAX + 1)]);
/*****************************************************************************/
@@ -246,14 +302,6 @@ nm_settings_connection_still_valid(NMSettingsConnection *self)
/*****************************************************************************/
-static GHashTable *
-_seen_bssids_hash_new(void)
-{
- return g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL);
-}
-
-/*****************************************************************************/
-
static void
_getsettings_cached_clear(NMSettingsConnectionPrivate *priv)
{
@@ -1300,8 +1348,8 @@ get_settings_auth_cb(NMSettingsConnection * self,
GError * error,
gpointer data)
{
- gs_free const char ** seen_bssids = NULL;
- NMConnectionSerializationOptions options = {};
+ const char * seen_bssids_strv[SEEN_BSSIDS_MAX + 1];
+ NMConnectionSerializationOptions options = {};
if (error) {
g_dbus_method_invocation_return_gerror(context, error);
@@ -1321,8 +1369,8 @@ get_settings_auth_cb(NMSettingsConnection * self,
* from the same reason as timestamp. Thus we put it here to GetSettings()
* return settings too.
*/
- seen_bssids = nm_settings_connection_get_seen_bssids(self);
- options.seen_bssids = seen_bssids;
+ _get_seen_bssids(self, seen_bssids_strv);
+ options.seen_bssids = seen_bssids_strv;
/* Secrets should *never* be returned by the GetSettings method, they
* get returned by the GetSecrets method which can be better
@@ -2304,68 +2352,66 @@ _nm_settings_connection_register_kf_dbs(NMSettingsConnection *self,
if (priv->kf_db_seen_bssids != kf_db_seen_bssids) {
gs_strfreev char **tmp_strv = NULL;
- gsize i, len;
+ gsize len;
+ gsize i;
+ guint result_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);
- nm_clear_pointer(&priv->seen_bssids, g_hash_table_unref);
+ if (priv->seen_bssids_hash)
+ g_hash_table_remove_all(priv->seen_bssids_hash);
- if (len > 0) {
- _LOGT("read %zu seen-bssids from keyfile database \"%s\"",
- len,
- nm_key_file_db_get_filename(priv->kf_db_seen_bssids));
- priv->seen_bssids = _seen_bssids_hash_new();
- for (i = len; i > 0;)
- g_hash_table_add(priv->seen_bssids, g_steal_pointer(&tmp_strv[--i]));
- nm_clear_g_free(&tmp_strv);
- } else {
- NMSettingWireless *s_wifi;
+ for (result_len = 0, i = 0; i < len; i++) {
+ NMEtherAddr addr_bin;
+ SeenBssidEntry *entry;
- _LOGT("no seen-bssids from keyfile database \"%s\"",
- nm_key_file_db_get_filename(priv->kf_db_seen_bssids));
+ nm_assert(result_len == nm_g_hash_table_size(priv->seen_bssids_hash));
+ if (result_len >= SEEN_BSSIDS_MAX)
+ break;
- /* 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);
- if (len > 0) {
- priv->seen_bssids = _seen_bssids_hash_new();
- 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));
- }
- }
+ if (!_nm_utils_hwaddr_aton_exact(tmp_strv[i], &addr_bin, sizeof(addr_bin)))
+ continue;
+
+ if (!priv->seen_bssids_hash)
+ priv->seen_bssids_hash = _seen_bssids_hash_new();
+
+ entry = _seen_bssid_entry_new_stale_bin(&addr_bin);
+ if (!g_hash_table_insert(priv->seen_bssids_hash, entry, entry)) {
+ /* duplicate detected! The @entry key was freed by g_hash_table_insert(). */
+ continue;
}
+ c_list_link_tail(&priv->seen_bssids_lst_head, &entry->seen_bssids_lst);
+ result_len++;
}
+ if (result_len > 0) {
+ _LOGT("read %u seen-bssids from keyfile database \"%s\"",
+ result_len,
+ nm_key_file_db_get_filename(priv->kf_db_seen_bssids));
+ } else
+ nm_clear_pointer(&priv->seen_bssids_hash, g_hash_table_destroy);
+
+ nm_assert(nm_g_hash_table_size(priv->seen_bssids_hash) == result_len);
+ nm_assert(result_len <= SEEN_BSSIDS_MAX);
}
}
-/**
- * nm_settings_connection_get_seen_bssids:
- * @self: the #NMSettingsConnection
- *
- * Returns current list of seen BSSIDs for the connection.
- *
- * Returns: (transfer container) list of seen BSSIDs (in the standard hex-digits-and-colons notation).
- * The caller is responsible for freeing the list, but not the content.
- **/
-const char **
-nm_settings_connection_get_seen_bssids(NMSettingsConnection *self)
+static guint
+_get_seen_bssids(NMSettingsConnection *self, const char *strv_buf[static(SEEN_BSSIDS_MAX + 1)])
{
- g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), NULL);
+ NMSettingsConnectionPrivate *priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self);
+ SeenBssidEntry * entry;
+ guint i;
- return nm_utils_strdict_get_keys(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->seen_bssids,
- TRUE,
- NULL);
+ i = 0;
+ c_list_for_each_entry (entry, &priv->seen_bssids_lst_head, seen_bssids_lst) {
+ nm_assert(i <= SEEN_BSSIDS_MAX);
+ strv_buf[i++] = entry->bssid;
+ }
+ strv_buf[i] = NULL;
+ return i;
}
/**
@@ -2379,14 +2425,17 @@ gboolean
nm_settings_connection_has_seen_bssid(NMSettingsConnection *self, const char *bssid)
{
NMSettingsConnectionPrivate *priv;
+ NMEtherAddr addr_bin;
g_return_val_if_fail(NM_IS_SETTINGS_CONNECTION(self), FALSE);
g_return_val_if_fail(bssid, FALSE);
+ nm_assert(_nm_utils_hwaddr_aton_exact(bssid, &addr_bin, sizeof(addr_bin)));
priv = NM_SETTINGS_CONNECTION_GET_PRIVATE(self);
- return priv->seen_bssids
- && g_hash_table_contains(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->seen_bssids, bssid);
+ return priv->seen_bssids_hash
+ && g_hash_table_contains(NM_SETTINGS_CONNECTION_GET_PRIVATE(self)->seen_bssids_hash,
+ bssid);
}
/**
@@ -2401,15 +2450,47 @@ void
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 * seen_bssids_strv[SEEN_BSSIDS_MAX + 1];
+ NMEtherAddr addr_bin;
const char * connection_uuid;
+ SeenBssidEntry entry_stack;
+ SeenBssidEntry * entry;
+ guint i;
+
+ g_return_if_fail(seen_bssid);
- g_return_if_fail(seen_bssid != NULL);
+ if (!_nm_utils_hwaddr_aton_exact(seen_bssid, &addr_bin, sizeof(addr_bin)))
+ g_return_if_reached();
- if (!priv->seen_bssids)
- priv->seen_bssids = _seen_bssids_hash_new();
+ _seen_bssid_entry_init_stale(&entry_stack, &addr_bin);
- g_hash_table_add(priv->seen_bssids, g_strdup(seen_bssid));
+ if (!priv->seen_bssids_hash) {
+ priv->seen_bssids_hash = _seen_bssids_hash_new();
+ entry = NULL;
+ } else
+ entry = g_hash_table_lookup(priv->seen_bssids_hash, &entry_stack);
+
+ if (entry) {
+ if (!nm_c_list_move_front(&priv->seen_bssids_lst_head, &entry->seen_bssids_lst)) {
+ /* no change. */
+ return;
+ }
+ } else {
+ entry = _seen_bssid_entry_new_stale_copy(&entry_stack);
+ c_list_link_front(&priv->seen_bssids_lst_head, &entry->seen_bssids_lst);
+ if (!g_hash_table_add(priv->seen_bssids_hash, entry))
+ nm_assert_not_reached();
+
+ if (g_hash_table_size(priv->seen_bssids_hash) > SEEN_BSSIDS_MAX) {
+ g_hash_table_remove(
+ priv->seen_bssids_hash,
+ c_list_last_entry(&priv->seen_bssids_lst_head, SeenBssidEntry, seen_bssids_lst));
+ }
+ }
+
+ nm_assert(g_hash_table_size(priv->seen_bssids_hash) <= SEEN_BSSIDS_MAX);
+ nm_assert(g_hash_table_size(priv->seen_bssids_hash)
+ == c_list_length(&priv->seen_bssids_lst_head));
if (!priv->kf_db_seen_bssids)
return;
@@ -2418,12 +2499,8 @@ nm_settings_connection_add_seen_bssid(NMSettingsConnection *self, const char *se
if (!connection_uuid)
return;
- strv = nm_utils_strdict_get_keys(priv->seen_bssids, TRUE, NULL);
-
- nm_key_file_db_set_string_list(priv->kf_db_seen_bssids,
- connection_uuid,
- strv ?: NM_PTRARRAY_EMPTY(const char *),
- -1);
+ i = _get_seen_bssids(self, seen_bssids_strv);
+ nm_key_file_db_set_string_list(priv->kf_db_seen_bssids, connection_uuid, seen_bssids_strv, i);
}
/*****************************************************************************/
@@ -2634,7 +2711,7 @@ nm_settings_connection_init(NMSettingsConnection *self)
self->_priv = priv;
c_list_init(&self->_connections_lst);
-
+ c_list_init(&priv->seen_bssids_lst_head);
c_list_init(&priv->call_ids_lst_head);
c_list_init(&priv->auth_lst_head);
@@ -2672,7 +2749,7 @@ dispose(GObject *object)
nm_clear_pointer(&priv->agent_secrets, g_variant_unref);
- nm_clear_pointer(&priv->seen_bssids, g_hash_table_destroy);
+ nm_clear_pointer(&priv->seen_bssids_hash, g_hash_table_destroy);
g_clear_object(&priv->agent_mgr);
diff --git a/src/core/settings/nm-settings-connection.h b/src/core/settings/nm-settings-connection.h
index 83a6a7f62b..fa3dbcfbcf 100644
--- a/src/core/settings/nm-settings-connection.h
+++ b/src/core/settings/nm-settings-connection.h
@@ -340,8 +340,6 @@ gboolean nm_settings_connection_get_timestamp(NMSettingsConnection *self, guint6
void nm_settings_connection_update_timestamp(NMSettingsConnection *self, guint64 timestamp);
-const char **nm_settings_connection_get_seen_bssids(NMSettingsConnection *self);
-
gboolean nm_settings_connection_has_seen_bssid(NMSettingsConnection *self, const char *bssid);
void nm_settings_connection_add_seen_bssid(NMSettingsConnection *self, const char *seen_bssid);
diff --git a/src/core/settings/nm-settings.c b/src/core/settings/nm-settings.c
index c876ea148c..a81f76b539 100644
--- a/src/core/settings/nm-settings.c
+++ b/src/core/settings/nm-settings.c
@@ -388,6 +388,9 @@ typedef struct {
guint kf_db_flush_idle_id_timestamps;
guint kf_db_flush_idle_id_seen_bssids;
+ bool kf_db_pruned_timestamps;
+ bool kf_db_pruned_seen_bssid;
+
bool started : 1;
/* Whether NMSettingsConnections changed in a way that affects the comparison
@@ -3684,6 +3687,41 @@ again:
/*****************************************************************************/
+static gboolean
+_kf_db_prune_predicate(const char *uuid, gpointer user_data)
+{
+ return !!nm_settings_get_connection_by_uuid(user_data, uuid);
+}
+
+static void
+_kf_db_to_file(NMSettings *self, gboolean is_timestamps, gboolean force_write)
+{
+ NMSettingsPrivate *priv = NM_SETTINGS_GET_PRIVATE(self);
+ NMKeyFileDB * kf_db;
+ bool * p_kf_db_pruned;
+
+ if (is_timestamps) {
+ kf_db = priv->kf_db_timestamps;
+ p_kf_db_pruned = &priv->kf_db_pruned_timestamps;
+ } else {
+ kf_db = priv->kf_db_seen_bssids;
+ p_kf_db_pruned = &priv->kf_db_pruned_seen_bssid;
+ }
+
+ if (!*p_kf_db_pruned) {
+ /* we only prune the DB once, because afterwards every
+ * add/remove of an connection will lead to a direct update. */
+ *p_kf_db_pruned = TRUE;
+ nm_key_file_db_prune(kf_db, _kf_db_prune_predicate, self);
+
+ /* once we also go over the directory, and see whether we
+ * have any left over temporary files to delete. */
+ nm_key_file_db_prune_tmp_files(kf_db);
+ }
+
+ nm_key_file_db_to_file(kf_db, force_write);
+}
+
G_GNUC_PRINTF(4, 5)
static void
_kf_db_log_fcn(NMKeyFileDB *kf_db, int syslog_level, gpointer user_data, const char *fmt, ...)
@@ -3732,7 +3770,7 @@ _kf_db_got_dirty_flush(NMSettings *self, gboolean is_timestamps)
}
if (nm_key_file_db_is_dirty(kf_db))
- nm_key_file_db_to_file(kf_db, FALSE);
+ _kf_db_to_file(self, is_timestamps, FALSE);
else {
_LOGT("[%s-keyfile]: skip saving changes to \"%s\"",
prefix,
@@ -3785,15 +3823,10 @@ _kf_db_got_dirty_fcn(NMKeyFileDB *kf_db, gpointer user_data)
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);
+ _kf_db_to_file(self, TRUE, TRUE);
+ _kf_db_to_file(self, FALSE, TRUE);
}
/*****************************************************************************/
@@ -4031,8 +4064,8 @@ finalize(GObject *object)
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);
+ _kf_db_to_file(self, TRUE, FALSE);
+ _kf_db_to_file(self, FALSE, FALSE);
nm_key_file_db_destroy(priv->kf_db_timestamps);
nm_key_file_db_destroy(priv->kf_db_seen_bssids);
diff --git a/src/libnm-core-impl/nm-keyfile.c b/src/libnm-core-impl/nm-keyfile.c
index 88aa0d46cd..c6c4a2eb57 100644
--- a/src/libnm-core-impl/nm-keyfile.c
+++ b/src/libnm-core-impl/nm-keyfile.c
@@ -2781,6 +2781,9 @@ static const ParseInfoSetting *const parse_infos[_NM_META_SETTING_TYPE_NUM] = {
.parser = mac_address_parser_ETHER_cloned, ),
PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_MAC_ADDRESS,
.parser = mac_address_parser_ETHER, ),
+ PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SEEN_BSSIDS,
+ .parser_skip = TRUE,
+ .writer_skip = TRUE, ),
PARSE_INFO_PROPERTY(NM_SETTING_WIRELESS_SSID,
.parser = ssid_parser,
.writer = ssid_writer, ), ), ),
diff --git a/src/libnm-core-impl/nm-setting-wireless.c b/src/libnm-core-impl/nm-setting-wireless.c
index 111116965a..5bdedf9bfb 100644
--- a/src/libnm-core-impl/nm-setting-wireless.c
+++ b/src/libnm-core-impl/nm-setting-wireless.c
@@ -750,19 +750,54 @@ _to_dbus_fcn_seen_bssids(const NMSettInfoSetting * sett_info,
NMConnectionSerializationFlags flags,
const NMConnectionSerializationOptions *options)
{
+ if (options && options->seen_bssids)
+ return options->seen_bssids[0] ? g_variant_new_strv(options->seen_bssids, -1) : NULL;
+
+ /* The seen-bssid property is special. It cannot be converted to D-Bus
+ * like regular properties, only via the "options".
+ *
+ * This basically means, that only the daemon can provide seen-bssids as GVariant,
+ * while when a client converts the property to GVariant, it gets lost.
+ *
+ * This has the odd effect, that when the client converts the setting to GVariant
+ * and back, the seen-bssids gets lost. That is kinda desired here, because the to_dbus_fcn()
+ * and from_dbus_fcn() have the meaning of how a setting gets transferred via D-Bus,
+ * and not necessarily a loss-less conversion into another format and back. And when
+ * transferring via D-Bus, then the option makes only sense when sending it from
+ * the daemon to the client, not otherwise. */
+ return NULL;
+}
+
+static gboolean
+_from_dbus_fcn_seen_bssids(NMSetting * setting,
+ GVariant * connection_dict,
+ const char * property,
+ GVariant * value,
+ NMSettingParseFlags parse_flags,
+ GError ** error)
+{
NMSettingWirelessPrivate *priv;
+ gs_free const char ** s = NULL;
+ gsize len;
+ gsize i;
- if (options && options->seen_bssids) {
- return options->seen_bssids[0] ? g_variant_new_strv(options->seen_bssids, -1) : NULL;
+ if (_nm_utils_is_manager_process) {
+ /* in the manager process, we don't accept seen-bssid from the client.
+ * Do nothing. */
+ return TRUE;
}
priv = NM_SETTING_WIRELESS_GET_PRIVATE(setting);
- if (!priv->seen_bssids || priv->seen_bssids->len == 0)
- return NULL;
+ nm_clear_pointer(&priv->seen_bssids, g_ptr_array_unref);
- return g_variant_new_strv((const char *const *) priv->seen_bssids->pdata,
- priv->seen_bssids->len);
+ s = g_variant_get_strv(value, &len);
+ if (len > 0) {
+ priv->seen_bssids = g_ptr_array_new_full(len, g_free);
+ for (i = 0; i < len; i++)
+ g_ptr_array_add(priv->seen_bssids, g_strdup(s[i]));
+ }
+ return TRUE;
}
/**
@@ -1075,12 +1110,18 @@ compare_property(const NMSettInfoSetting *sett_info,
NMSetting * set_b,
NMSettingCompareFlags flags)
{
- if (nm_streq(sett_info->property_infos[property_idx].name,
- NM_SETTING_WIRELESS_CLONED_MAC_ADDRESS)) {
+ if (sett_info->property_infos[property_idx].param_spec
+ == obj_properties[PROP_CLONED_MAC_ADDRESS]) {
return !set_b
|| nm_streq0(NM_SETTING_WIRELESS_GET_PRIVATE(set_a)->cloned_mac_address,
NM_SETTING_WIRELESS_GET_PRIVATE(set_b)->cloned_mac_address);
}
+ if (sett_info->property_infos[property_idx].param_spec == obj_properties[PROP_SEEN_BSSIDS]) {
+ return !set_b
+ || (nm_strv_ptrarray_cmp(NM_SETTING_WIRELESS_GET_PRIVATE(set_a)->seen_bssids,
+ NM_SETTING_WIRELESS_GET_PRIVATE(set_b)->seen_bssids)
+ == 0);
+ }
return NM_SETTING_CLASS(nm_setting_wireless_parent_class)
->compare_property(sett_info, property_idx, con_a, set_a, con_b, set_b, flags);
@@ -1744,7 +1785,8 @@ nm_setting_wireless_class_init(NMSettingWirelessClass *klass)
properties_override,
obj_properties[PROP_SEEN_BSSIDS],
NM_SETT_INFO_PROPERT_TYPE_DBUS(G_VARIANT_TYPE_STRING_ARRAY,
- .to_dbus_fcn = _to_dbus_fcn_seen_bssids, ));
+ .to_dbus_fcn = _to_dbus_fcn_seen_bssids,
+ .from_dbus_fcn = _from_dbus_fcn_seen_bssids, ));
/**
* NMSettingWireless:mtu:
diff --git a/src/libnm-glib-aux/nm-io-utils.c b/src/libnm-glib-aux/nm-io-utils.c
index 894c8726c0..87478a2dc2 100644
--- a/src/libnm-glib-aux/nm-io-utils.c
+++ b/src/libnm-glib-aux/nm-io-utils.c
@@ -564,3 +564,67 @@ nm_g_subprocess_terminate_in_background(GSubprocess *subprocess, int timeout_mse
NULL),
main_context);
}
+
+/*****************************************************************************/
+
+char **
+nm_utils_find_mkstemp_files(const char *dirname, const char *filename)
+{
+ static const char letters[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
+ DIR * dir;
+ struct dirent * entry;
+ GPtrArray * arr = NULL;
+ gsize l;
+
+ /* We write files with g_file_set_contents() and nm_utils_file_set_contents().
+ * These create temporary files using g_mkstemp_full(), with a random .XXXXXX suffix.
+ *
+ * If NetworkManager crashes while writing the file, then those temporary files are
+ * left over. We might want to find and delete such files.
+ *
+ * Beware: only delete such files if you are in full control about which files are
+ * supposed to be in the directory. For example, NetworkManager controls
+ * /var/lib/NetworkManager/timestamps files, and it thus takes the right to delete
+ * all files /var/lib/NetworkManager/timestamps.XXXXXX. That may not be appropriate
+ * in other cases! */
+
+ if (!dirname || !filename || !filename[0])
+ return NULL;
+
+ dir = opendir(dirname);
+ if (!dir)
+ return NULL;
+
+ l = strlen(filename);
+
+ while ((entry = readdir(dir))) {
+ const char *f = entry->d_name;
+ guint i;
+
+ if (strncmp(f, filename, l) != 0)
+ goto next;
+ if (f[l] != '.')
+ goto next;
+ for (i = 1; i <= 6; i++) {
+ /* @letters is also what g_mkstemp_full() does! */
+ if (!memchr(letters, f[l + i], G_N_ELEMENTS(letters)))
+ goto next;
+ }
+ if (f[l + 7] != '\0')
+ goto next;
+
+ if (!arr)
+ arr = g_ptr_array_new();
+
+ g_ptr_array_add(arr, g_strdup(f));
+next:;
+ }
+
+ closedir(dir);
+
+ if (!arr)
+ return NULL;
+
+ g_ptr_array_add(arr, NULL);
+ return (char **) g_ptr_array_free(arr, FALSE);
+}
diff --git a/src/libnm-glib-aux/nm-io-utils.h b/src/libnm-glib-aux/nm-io-utils.h
index 98e63ac01e..31ff6d0569 100644
--- a/src/libnm-glib-aux/nm-io-utils.h
+++ b/src/libnm-glib-aux/nm-io-utils.h
@@ -58,4 +58,6 @@ int nm_utils_file_stat(const char *filename, struct stat *out_st);
void nm_g_subprocess_terminate_in_background(GSubprocess *subprocess, int timeout_msec_before_kill);
+char **nm_utils_find_mkstemp_files(const char *dirname, const char *filename);
+
#endif /* __NM_IO_UTILS_H__ */
diff --git a/src/libnm-glib-aux/nm-keyfile-aux.c b/src/libnm-glib-aux/nm-keyfile-aux.c
index 75abe53848..9cda1cf714 100644
--- a/src/libnm-glib-aux/nm-keyfile-aux.c
+++ b/src/libnm-glib-aux/nm-keyfile-aux.c
@@ -27,6 +27,8 @@ struct _NMKeyFileDB {
bool dirty : 1;
bool destroyed : 1;
+ bool groups_pruned : 1;
+
char filename[];
};
@@ -62,6 +64,16 @@ _IS_KEY_FILE_DB(NMKeyFileDB *self, gboolean require_is_started, gboolean allow_d
return TRUE;
}
+static GKeyFile *
+_key_file_new(void)
+{
+ GKeyFile *kf;
+
+ kf = g_key_file_new();
+ g_key_file_set_list_separator(kf, ',');
+ return kf;
+}
+
/*****************************************************************************/
NMKeyFileDB *
@@ -86,8 +98,7 @@ nm_key_file_db_new(const char * filename,
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, ',');
+ self->kf = _key_file_new();
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);
@@ -371,3 +382,106 @@ nm_key_file_db_to_file(NMKeyFileDB *self, gboolean force)
} else
_LOGD("write keyfile: \"%s\"", self->filename);
}
+
+/*****************************************************************************/
+
+void
+nm_key_file_db_prune_tmp_files(NMKeyFileDB *self)
+{
+ gs_free char * n_file = NULL;
+ gs_free char * n_dir = NULL;
+ gs_strfreev char **tmpfiles = NULL;
+ gsize i;
+
+ n_file = g_path_get_basename(self->filename);
+ n_dir = g_path_get_dirname(self->filename);
+
+ tmpfiles = nm_utils_find_mkstemp_files(n_dir, n_file);
+ if (!tmpfiles)
+ return;
+
+ for (i = 0; tmpfiles[i]; i++) {
+ const char * tmpfile = tmpfiles[i];
+ gs_free char *full_file = NULL;
+ int r;
+
+ full_file = g_strdup_printf("%s/%s", n_dir, tmpfile);
+
+ r = unlink(full_file);
+ if (r != 0) {
+ int errsv = errno;
+
+ if (errsv != ENOENT) {
+ _LOGD("prune left over temp file %s failed: %s",
+ full_file,
+ nm_strerror_native(errsv));
+ }
+ continue;
+ }
+
+ _LOGD("prune left over temp file %s", full_file);
+ }
+}
+
+/*****************************************************************************/
+
+void
+nm_key_file_db_prune(NMKeyFileDB *self,
+ gboolean (*predicate)(const char *key, gpointer user_data),
+ gpointer user_data)
+{
+ gs_strfreev char ** keys = NULL;
+ nm_auto_unref_keyfile GKeyFile *kf_to_free = NULL;
+ GKeyFile * kf_src = NULL;
+ GKeyFile * kf_dst = NULL;
+ guint k;
+
+ g_return_if_fail(_IS_KEY_FILE_DB(self, TRUE, FALSE));
+ nm_assert(predicate);
+
+ _LOGD("prune keyfile of old entries: \"%s\"", self->filename);
+
+ if (!self->groups_pruned) {
+ /* When we prune the first time, we swap the GKeyfile instance.
+ * The instance loaded from disk might have unrelated groups and
+ * comments. Let's get rid of them by creating a new instance.
+ *
+ * Otherwise, we know that self->kf only contains good keys,
+ * and at most we need to remove some of them. */
+ kf_to_free = g_steal_pointer(&self->kf);
+ self->kf = _key_file_new();
+ kf_src = kf_to_free;
+ self->groups_pruned = TRUE;
+ self->dirty = TRUE;
+ } else
+ kf_src = self->kf;
+ kf_dst = self->kf;
+
+ keys = g_key_file_get_keys(kf_src, self->group_name, NULL, NULL);
+ if (keys) {
+ for (k = 0; keys[k]; k++) {
+ const char *key = keys[k];
+ gboolean keep;
+
+ keep = predicate(key, user_data);
+
+ if (!keep) {
+ if (kf_dst == kf_src) {
+ g_key_file_remove_key(kf_dst, self->group_name, key, NULL);
+ self->dirty = TRUE;
+ }
+ continue;
+ }
+
+ if (kf_dst != kf_src) {
+ gs_free char *value = NULL;
+
+ value = g_key_file_get_value(kf_src, self->group_name, key, NULL);
+ if (value)
+ g_key_file_set_value(kf_dst, self->group_name, key, value);
+ else
+ self->dirty = TRUE;
+ }
+ }
+ }
+}
diff --git a/src/libnm-glib-aux/nm-keyfile-aux.h b/src/libnm-glib-aux/nm-keyfile-aux.h
index 72d2f418f9..e756c57a84 100644
--- a/src/libnm-glib-aux/nm-keyfile-aux.h
+++ b/src/libnm-glib-aux/nm-keyfile-aux.h
@@ -50,6 +50,12 @@ void nm_key_file_db_set_string_list(NMKeyFileDB * self,
void nm_key_file_db_to_file(NMKeyFileDB *self, gboolean force);
+void nm_key_file_db_prune_tmp_files(NMKeyFileDB *self);
+
+void nm_key_file_db_prune(NMKeyFileDB *self,
+ gboolean (*predicate)(const char *key, gpointer user_data),
+ gpointer user_data);
+
/*****************************************************************************/
#endif /* __NM_KEYFILE_AUX_H__ */
diff --git a/src/libnm-glib-aux/nm-macros-internal.h b/src/libnm-glib-aux/nm-macros-internal.h
index 39197ecf3a..f2d81e1ccf 100644
--- a/src/libnm-glib-aux/nm-macros-internal.h
+++ b/src/libnm-glib-aux/nm-macros-internal.h
@@ -121,14 +121,6 @@ _nm_auto_free_gstring(GString **str)
}
#define nm_auto_free_gstring nm_auto(_nm_auto_free_gstring)
-static inline void
-_nm_auto_protect_errno(const int *p_saved_errno)
-{
- errno = *p_saved_errno;
-}
-#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \
- nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
-
NM_AUTO_DEFINE_FCN0(GSource *, _nm_auto_unref_gsource, g_source_unref);
#define nm_auto_unref_gsource nm_auto(_nm_auto_unref_gsource)
diff --git a/src/libnm-std-aux/nm-std-aux.h b/src/libnm-std-aux/nm-std-aux.h
index b153866fd8..17b268816d 100644
--- a/src/libnm-std-aux/nm-std-aux.h
+++ b/src/libnm-std-aux/nm-std-aux.h
@@ -695,16 +695,22 @@ nm_close(int fd)
NM_AUTO_DEFINE_FCN_VOID0(void *, _nm_auto_free_impl, free);
#define nm_auto_free nm_auto(_nm_auto_free_impl)
+static inline void
+_nm_auto_protect_errno(const int *p_saved_errno)
+{
+ errno = *p_saved_errno;
+}
+#define NM_AUTO_PROTECT_ERRNO(errsv_saved) \
+ nm_auto(_nm_auto_protect_errno) _nm_unused const int errsv_saved = (errno)
+
/*****************************************************************************/
static inline void
_nm_auto_close(int *pfd)
{
if (*pfd >= 0) {
- int errsv = errno;
-
+ NM_AUTO_PROTECT_ERRNO(errsv);
(void) nm_close(*pfd);
- errno = errsv;
}
}
#define nm_auto_close nm_auto(_nm_auto_close)
@@ -713,10 +719,8 @@ static inline void
_nm_auto_fclose(FILE **pfd)
{
if (*pfd) {
- int errsv = errno;
-
+ NM_AUTO_PROTECT_ERRNO(errsv);
(void) fclose(*pfd);
- errno = errsv;
}
}
#define nm_auto_fclose nm_auto(_nm_auto_fclose)