// 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;
}