/* SPDX-License-Identifier: GPL-2.0-or-later */
/*
* Copyright (C) 2018 Red Hat, Inc.
*/
#ifndef __NMS_KEYFILE_STORAGE_H__
#define __NMS_KEYFILE_STORAGE_H__
#include "c-list/src/c-list.h"
#include "settings/nm-settings-storage.h"
#include "nms-keyfile-utils.h"
/*****************************************************************************/
#define NMS_TYPE_KEYFILE_STORAGE (nms_keyfile_storage_get_type())
#define NMS_KEYFILE_STORAGE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST((obj), NMS_TYPE_KEYFILE_STORAGE, NMSKeyfileStorage))
#define NMS_KEYFILE_STORAGE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST((klass), NMS_TYPE_KEYFILE_STORAGE, NMSKeyfileStorageClass))
#define NMS_IS_KEYFILE_STORAGE(obj) (G_TYPE_CHECK_INSTANCE_TYPE((obj), NMS_TYPE_KEYFILE_STORAGE))
#define NMS_IS_KEYFILE_STORAGE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE((klass), NMS_TYPE_KEYFILE_STORAGE))
#define NMS_KEYFILE_STORAGE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS((obj), NMS_TYPE_KEYFILE_STORAGE, NMSKeyfileStorageClass))
typedef struct {
/* whether this is a tombstone to hide a UUID (via symlink to /dev/null). */
char *shadowed_storage;
bool is_tombstone : 1;
} NMSettingsMetaData;
typedef struct {
NMSettingsStorage parent;
/* The connection. Note that there are tombstones (loaded-uuid files to /dev/null)
* that don't have a connection.
*
* Also, we don't actually remember the loaded connection after returning it
* to NMSettings. So, also for regular storages (non-tombstones) this field
* is often cleared. */
union {
struct {
NMConnection *connection;
/* when we move a profile from permanent storage to unsaved (/run), then
* we may leave the profile on disk (depending on options for Update2()).
*
* Later, when we save the profile again to disk, we want to re-use that filename.
* Likewise, we delete the (now in-memory) profile, we may want to also delete
* the original filename.
*
* This is the original filename, and we store it inside [.nmmeta] in the
* keyfile in /run. Note that we don't store this in the .nmmeta file, because
* the information is tied to the particular keyfile in /run, not to all UUIDs
* in general. */
char *shadowed_storage;
/* the timestamp (stat's mtime) of the keyfile. For meta-data this
* is irrelevant. The purpose is that if the same storage type (directory) has
* multiple files with the same UUID, then the newer file gets preferred. */
struct timespec stat_mtime;
/* these flags are only relevant for storages with %NMS_KEYFILE_STORAGE_TYPE_RUN
* (and non-metadata). This is to persist and reload these settings flags to
* /run.
*
* Note that these flags are not stored in as meta-data. The reason is that meta-data
* is per UUID. But these flags are only relevant for a particular keyfile on disk.
* That is, it must be tied to the actual keyfile, and not to the UUID. */
bool is_nm_generated : 1;
bool is_volatile : 1;
bool is_external : 1;
/* if shadowed_storage is set, then this flag indicates whether the file
* is owned. The difference comes into play when deleting the in-memory,
* shadowing profile: a owned profile will also be deleted. */
bool shadowed_owned : 1;
} conn_data;
/* the content from the .nmmeta file. Note that the nmmeta file has the UUID
* in the filename, that means there can be only two variants of this file:
* in /etc and in /run. As such, this is really meta-data about the entire profile
* (the UUID), and not about the individual keyfile. */
NMSettingsMetaData meta_data;
} u;
/* The storage type. This is directly related to the filename. Since
* the filename cannot change, this value is unchanging. */
const NMSKeyfileStorageType storage_type;
/* whether union "u" has meta_data or conn_data. Since the type of the storage
* depends on the (immutable) filename, this is also const. */
const bool is_meta_data;
/* this flag is only used during reload to mark and prune old entries. */
bool is_dirty : 1;
} NMSKeyfileStorage;
typedef struct _NMSKeyfileStorageClass NMSKeyfileStorageClass;
GType nms_keyfile_storage_get_type(void);
struct _NMSKeyfilePlugin;
NMSKeyfileStorage *nms_keyfile_storage_new_tombstone(struct _NMSKeyfilePlugin *self,
const char * uuid,
const char * filename,
NMSKeyfileStorageType storage_type,
const char * shadowed_storage);
NMSKeyfileStorage *
nms_keyfile_storage_new_connection(struct _NMSKeyfilePlugin *self,
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);
void nms_keyfile_storage_destroy(NMSKeyfileStorage *storage);
/*****************************************************************************/
void nms_keyfile_storage_copy_content(NMSKeyfileStorage *dst, const NMSKeyfileStorage *src);
NMConnection *nms_keyfile_storage_steal_connection(NMSKeyfileStorage *storage);
/*****************************************************************************/
static inline const char *
nms_keyfile_storage_get_uuid(const NMSKeyfileStorage *self)
{
return nm_settings_storage_get_uuid((const NMSettingsStorage *) self);
}
static inline const char *
nms_keyfile_storage_get_filename(const NMSKeyfileStorage *self)
{
return nm_settings_storage_get_filename((const NMSettingsStorage *) self);
}
/*****************************************************************************/
static inline gboolean
nm_settings_storage_is_keyfile_run(const NMSettingsStorage *self)
{
return NMS_IS_KEYFILE_STORAGE(self)
&& (((NMSKeyfileStorage *) self)->storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN);
}
static inline gboolean
nm_settings_storage_is_keyfile_lib(const NMSettingsStorage *self)
{
return NMS_IS_KEYFILE_STORAGE(self)
&& (((NMSKeyfileStorage *) self)->storage_type >= NMS_KEYFILE_STORAGE_TYPE_LIB_BASE);
}
static inline const NMSettingsMetaData *
nm_settings_storage_is_meta_data(const NMSettingsStorage *storage)
{
const NMSKeyfileStorage *self;
if (!NMS_IS_KEYFILE_STORAGE(storage))
return NULL;
self = (NMSKeyfileStorage *) storage;
if (!self->is_meta_data)
return NULL;
return &self->u.meta_data;
}
static inline const NMSettingsMetaData *
nm_settings_storage_is_meta_data_alive(const NMSettingsStorage *storage)
{
const NMSettingsMetaData *meta_data;
meta_data = nm_settings_storage_is_meta_data(storage);
if (!meta_data)
return NULL;
/* Regular (all other) storages are alive as long as they report a NMConnection, and
* they will be dropped, once they have no more connection.
*
* Meta-data storages are special: they never report a NMConnection.
* So, a meta-data storage is alive as long as it is tracked by the
* settings plugin.
*
* This function is used to ckeck for that. */
if (c_list_is_empty(&storage->_storage_lst))
return NULL;
return meta_data;
}
static inline const char *
nm_settings_storage_get_shadowed_storage(const NMSettingsStorage *storage,
gboolean * out_shadowed_owned)
{
if (NMS_IS_KEYFILE_STORAGE(storage)) {
const NMSKeyfileStorage *self = (const NMSKeyfileStorage *) storage;
if (self->storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN) {
if (!self->is_meta_data) {
if (self->u.conn_data.shadowed_storage) {
NM_SET_OUT(out_shadowed_owned, self->u.conn_data.shadowed_owned);
return self->u.conn_data.shadowed_storage;
}
} else {
NM_SET_OUT(out_shadowed_owned, FALSE);
return self->u.meta_data.shadowed_storage;
}
}
}
NM_SET_OUT(out_shadowed_owned, FALSE);
return NULL;
}
static inline const char *
nm_settings_storage_get_filename_for_shadowed_storage(const NMSettingsStorage *storage)
{
g_return_val_if_fail(NM_IS_SETTINGS_STORAGE(storage), NULL);
if (!storage->_filename)
return NULL;
if (NMS_IS_KEYFILE_STORAGE(storage)) {
const NMSKeyfileStorage *self = (const NMSKeyfileStorage *) storage;
if (self->is_meta_data || self->storage_type != NMS_KEYFILE_STORAGE_TYPE_ETC)
return NULL;
}
return storage->_filename;
}
/*****************************************************************************/
enum _NMSettingsConnectionIntFlags;
void nm_settings_storage_load_sett_flags(NMSettingsStorage * self,
enum _NMSettingsConnectionIntFlags *sett_flags,
enum _NMSettingsConnectionIntFlags *sett_mask);
#endif /* __NMS_KEYFILE_STORAGE_H__ */