// SPDX-License-Identifier: GPL-2.0+ /* * Copyright (C) 2018 Red Hat, Inc. */ #include "nm-default.h" #include "nms-keyfile-storage.h" #include "nm-utils.h" #include "nm-core-internal.h" #include "nms-keyfile-plugin.h" /*****************************************************************************/ struct _NMSKeyfileStorageClass { NMSettingsStorageClass parent; }; G_DEFINE_TYPE (NMSKeyfileStorage, nms_keyfile_storage, NM_TYPE_SETTINGS_STORAGE) /*****************************************************************************/ void nms_keyfile_storage_copy_content (NMSKeyfileStorage *dst, const NMSKeyfileStorage *src) { nm_assert (src != dst); nm_assert (nm_streq (nms_keyfile_storage_get_uuid (dst), nms_keyfile_storage_get_uuid (src))); nm_assert ( nms_keyfile_storage_get_filename (dst) && nm_streq (nms_keyfile_storage_get_filename (dst), nms_keyfile_storage_get_filename (src))); nm_assert (dst->storage_type == src->storage_type); nm_assert (dst->is_meta_data == src->is_meta_data); if (dst->is_meta_data) { gs_free char *shadowed_storage_to_free = NULL; shadowed_storage_to_free = g_steal_pointer (&dst->u.meta_data.shadowed_storage); dst->u.meta_data = src->u.meta_data; dst->u.meta_data.shadowed_storage = g_strdup (dst->u.meta_data.shadowed_storage); } else { gs_unref_object NMConnection *connection_to_free = NULL; gs_free char *shadowed_storage_to_free = NULL; connection_to_free = g_steal_pointer (&dst->u.conn_data.connection); shadowed_storage_to_free = g_steal_pointer (&dst->u.conn_data.shadowed_storage); dst->u.conn_data = src->u.conn_data; nm_g_object_ref (dst->u.conn_data.connection); dst->u.conn_data.shadowed_storage = g_strdup (dst->u.conn_data.shadowed_storage); } } NMConnection * nms_keyfile_storage_steal_connection (NMSKeyfileStorage *self) { nm_assert (NMS_IS_KEYFILE_STORAGE (self)); nm_assert ( self->is_meta_data || NM_IS_CONNECTION (self->u.conn_data.connection)); return self->is_meta_data ? NULL : g_steal_pointer (&self->u.conn_data.connection); } /*****************************************************************************/ static int cmp_fcn (const NMSKeyfileStorage *a, const NMSKeyfileStorage *b) { nm_assert (NMS_IS_KEYFILE_STORAGE (a)); nm_assert (NMS_IS_KEYFILE_STORAGE (b)); nm_assert (a != b); /* sort by storage-type, which also has a numeric value according to their * (inverse) priority. */ NM_CMP_FIELD_UNSAFE (b, a, storage_type); /* meta-data is more important. */ NM_CMP_FIELD_UNSAFE (a, b, is_meta_data); if (a->is_meta_data) { nm_assert (nm_streq (nms_keyfile_storage_get_filename (a), nms_keyfile_storage_get_filename (b))); NM_CMP_FIELD_UNSAFE (a, b, u.meta_data.is_tombstone); } else { /* newer files are more important. */ NM_CMP_FIELD (a, b, u.conn_data.stat_mtime.tv_sec); NM_CMP_FIELD (a, b, u.conn_data.stat_mtime.tv_nsec); NM_CMP_DIRECT_STRCMP (nms_keyfile_storage_get_filename (a), nms_keyfile_storage_get_filename (b)); } return 0; } /*****************************************************************************/ static void nms_keyfile_storage_init (NMSKeyfileStorage *self) { } static NMSKeyfileStorage * _storage_new (NMSKeyfilePlugin *plugin, const char *uuid, const char *filename, gboolean is_meta_data, NMSKeyfileStorageType storage_type) { NMSKeyfileStorage *self; nm_assert (NMS_IS_KEYFILE_PLUGIN (plugin)); nm_assert (nm_utils_is_uuid (uuid)); nm_assert (filename && filename[0] == '/'); self = g_object_new (NMS_TYPE_KEYFILE_STORAGE, NM_SETTINGS_STORAGE_PLUGIN, plugin, NM_SETTINGS_STORAGE_UUID, uuid, NM_SETTINGS_STORAGE_FILENAME, filename, NULL); *((bool *) &self->is_meta_data) = is_meta_data; *((NMSKeyfileStorageType *) &self->storage_type) = storage_type; return self; } NMSKeyfileStorage * nms_keyfile_storage_new_tombstone (NMSKeyfilePlugin *plugin, const char *uuid, const char *filename, NMSKeyfileStorageType storage_type, const char *shadowed_storage) { NMSKeyfileStorage *self; nm_assert (nm_utils_is_uuid (uuid)); nm_assert (filename && filename[0] == '/'); nm_assert (nms_keyfile_nmmeta_check_filename (filename, NULL)); nm_assert (NM_IN_SET (storage_type, NMS_KEYFILE_STORAGE_TYPE_ETC, NMS_KEYFILE_STORAGE_TYPE_RUN)); self = _storage_new (plugin, uuid, filename, TRUE, storage_type); self->u.meta_data.is_tombstone = TRUE; if (storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN) self->u.meta_data.shadowed_storage = g_strdup (shadowed_storage); return self; } NMSKeyfileStorage * nms_keyfile_storage_new_connection (NMSKeyfilePlugin *plugin, NMConnection *connection_take /* pass reference */, const char *filename, NMSKeyfileStorageType storage_type, NMTernary is_nm_generated_opt, NMTernary is_volatile_opt, NMTernary is_external_opt, const char *shadowed_storage, NMTernary shadowed_owned_opt, const struct timespec *stat_mtime) { NMSKeyfileStorage *self; nm_assert (NMS_IS_KEYFILE_PLUGIN (plugin)); nm_assert (NM_IS_CONNECTION (connection_take)); nm_assert (_nm_connection_verify (connection_take, NULL) == NM_SETTING_VERIFY_SUCCESS); nm_assert (filename && filename[0] == '/'); nm_assert ( storage_type >= NMS_KEYFILE_STORAGE_TYPE_RUN && storage_type <= _NMS_KEYFILE_STORAGE_TYPE_LIB_LAST); nmtst_connection_assert_unchanging (connection_take); self = _storage_new (plugin, nm_connection_get_uuid (connection_take), filename, FALSE, storage_type); self->u.conn_data.connection = connection_take; /* take reference. */ self->u.conn_data.shadowed_storage = g_strdup (shadowed_storage); if (stat_mtime) self->u.conn_data.stat_mtime = *stat_mtime; if (storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN) { self->u.conn_data.is_nm_generated = (is_nm_generated_opt == NM_TERNARY_TRUE); self->u.conn_data.is_volatile = (is_volatile_opt == NM_TERNARY_TRUE); self->u.conn_data.is_external = (is_external_opt == NM_TERNARY_TRUE); self->u.conn_data.shadowed_owned = shadowed_storage && (shadowed_owned_opt == NM_TERNARY_TRUE); } return self; } static void _storage_clear (NMSKeyfileStorage *self) { c_list_unlink (&self->parent._storage_lst); c_list_unlink (&self->parent._storage_by_uuid_lst); if (self->is_meta_data) nm_clear_g_free (&self->u.meta_data.shadowed_storage); else { g_clear_object (&self->u.conn_data.connection); nm_clear_g_free (&self->u.conn_data.shadowed_storage); self->u.conn_data.shadowed_owned = FALSE; } } static void dispose (GObject *object) { NMSKeyfileStorage *self = NMS_KEYFILE_STORAGE (object); _storage_clear (self); G_OBJECT_CLASS (nms_keyfile_storage_parent_class)->dispose (object); } void nms_keyfile_storage_destroy (NMSKeyfileStorage *self) { _storage_clear (self); g_object_unref (self); } static void nms_keyfile_storage_class_init (NMSKeyfileStorageClass *klass) { GObjectClass *object_class = G_OBJECT_CLASS (klass); NMSettingsStorageClass *storage_class = NM_SETTINGS_STORAGE_CLASS (klass); object_class->dispose = dispose; storage_class->cmp_fcn = (int (*) (NMSettingsStorage *, NMSettingsStorage *)) cmp_fcn; } /*****************************************************************************/ #include "settings/nm-settings-connection.h" void nm_settings_storage_load_sett_flags (NMSettingsStorage *self, NMSettingsConnectionIntFlags *sett_flags, NMSettingsConnectionIntFlags *sett_mask) { NMSKeyfileStorage *s; *sett_flags = NM_SETTINGS_CONNECTION_INT_FLAGS_NONE; *sett_mask = NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED | NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE | NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL; if (!NMS_IS_KEYFILE_STORAGE (self)) return; s = NMS_KEYFILE_STORAGE (self); if (s->is_meta_data) return; if (s->storage_type != NMS_KEYFILE_STORAGE_TYPE_RUN) return; if (s->u.conn_data.is_nm_generated) *sett_flags |= NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED; if (s->u.conn_data.is_volatile) *sett_flags |= NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE; if (s->u.conn_data.is_external) *sett_flags |= NM_SETTINGS_CONNECTION_INT_FLAGS_EXTERNAL; }