settings: support storing "shadowed-storage" to [.nmmeta] section for keyfiles in /run

When we make runtime only changes, we may leave the profile in persistent
storage and store a overlay profile in /run. However, in various cases we need
to remember the original path.

Add code to store and retrieve that path from the keyfile.

Note that this data is written inside the keyfile in /run. That is because
this piece of information really depends on that particular keyfile, and not
on the profile/UUID. That is why we write it to the [.nmmeta] section of the
keyfile and not to the .nmmeta file (which is per-UUID).

This patch only adds the backend to write and load the setting from
disk. It's not yet used.
This commit is contained in:
Thomas Haller
2019-07-19 16:55:47 +02:00
parent aade7e5317
commit e3b5b1e64b
11 changed files with 193 additions and 12 deletions

View File

@@ -174,6 +174,8 @@ gboolean _nm_keyfile_has_values (GKeyFile *keyfile);
#define NM_KEYFILE_GROUP_NMMETA ".nmmeta"
#define NM_KEYFILE_KEY_NMMETA_NM_GENERATED "nm-generated"
#define NM_KEYFILE_KEY_NMMETA_VOLATILE "volatile"
#define NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE "shadowed-storage"
#define NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED "shadowed-owned"
#define NM_KEYFILE_PATH_NAME_LIB NMLIBDIR "/system-connections"
#define NM_KEYFILE_PATH_NAME_ETC_DEFAULT NMCONFDIR "/system-connections"

View File

@@ -1284,6 +1284,8 @@ _add_connection_to_first_plugin (NMSettings *self,
gboolean in_memory,
gboolean is_nm_generated,
gboolean is_volatile,
const char *shadowed_storage,
gboolean shadowed_owned,
NMSettingsStorage **out_new_storage,
NMConnection **out_new_connection,
GError **error)
@@ -1311,9 +1313,11 @@ _add_connection_to_first_plugin (NMSettings *self,
if (plugin == (NMSettingsPlugin *) priv->keyfile_plugin) {
success = nms_keyfile_plugin_add_connection (priv->keyfile_plugin,
new_connection,
in_memory,
is_nm_generated,
is_volatile,
in_memory,
shadowed_storage,
shadowed_owned,
&storage,
&connection_to_add,
&add_error);
@@ -1457,6 +1461,8 @@ nm_settings_add_connection (NMSettings *self,
| NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED)),
NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED),
NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE),
NULL,
FALSE,
&new_storage,
&new_connection,
&local)) {
@@ -1538,6 +1544,8 @@ nm_settings_update_connection (NMSettings *self,
gboolean cur_in_memory;
gboolean new_in_memory;
const char *uuid;
const char *shadowed_storage;
gboolean shadowed_owned;
g_return_val_if_fail (NM_IS_SETTINGS (self), FALSE);
g_return_val_if_fail (NM_IS_SETTINGS_CONNECTION (sett_conn), FALSE);
@@ -1659,6 +1667,9 @@ nm_settings_update_connection (NMSettings *self,
| NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE);
}
/* TODO: set and handle shadowed-storages. */
shadowed_storage = NULL;
shadowed_owned = FALSE;
if (persist_mode == NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST) {
new_storage = g_object_ref (cur_storage);
@@ -1688,6 +1699,8 @@ nm_settings_update_connection (NMSettings *self,
new_in_memory,
NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED),
NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE),
shadowed_storage,
shadowed_owned,
&new_storage,
&new_connection,
&local);
@@ -1701,6 +1714,8 @@ nm_settings_update_connection (NMSettings *self,
connection,
NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_NM_GENERATED),
NM_FLAGS_HAS (sett_flags, NM_SETTINGS_CONNECTION_INT_FLAGS_VOLATILE),
shadowed_storage,
shadowed_owned,
NM_FLAGS_HAS (update_reason, NM_SETTINGS_CONNECTION_UPDATE_REASON_FORCE_RENAME),
&new_storage,
&new_connection,

View File

@@ -216,13 +216,22 @@ _read_from_file (const char *full_filename,
struct stat *out_stat,
NMTernary *out_is_nm_generated,
NMTernary *out_is_volatile,
char **out_shadowed_storage,
NMTernary *out_shadowed_owned,
GError **error)
{
NMConnection *connection;
nm_assert (full_filename && full_filename[0] == '/');
connection = nms_keyfile_reader_from_file (full_filename, plugin_dir, out_stat, out_is_nm_generated, out_is_volatile, error);
connection = nms_keyfile_reader_from_file (full_filename,
plugin_dir,
out_stat,
out_is_nm_generated,
out_is_volatile,
out_shadowed_storage,
out_shadowed_owned,
error);
nm_assert (!connection || (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS));
nm_assert (!connection || nm_utils_is_uuid (nm_connection_get_uuid (connection)));
@@ -291,6 +300,8 @@ _load_file (NMSKeyfilePlugin *self,
gs_unref_object NMConnection *connection = NULL;
NMTernary is_volatile_opt;
NMTernary is_nm_generated_opt;
NMTernary shadowed_owned_opt;
gs_free char *shadowed_storage = NULL;
gs_free_error GError *local = NULL;
gs_free char *full_filename = NULL;
struct stat st;
@@ -350,6 +361,8 @@ _load_file (NMSKeyfilePlugin *self,
&st,
&is_nm_generated_opt,
&is_volatile_opt,
&shadowed_storage,
&shadowed_owned_opt,
&local);
if (!connection) {
if (error)
@@ -365,6 +378,8 @@ _load_file (NMSKeyfilePlugin *self,
storage_type,
is_nm_generated_opt,
is_volatile_opt,
shadowed_storage,
shadowed_owned_opt,
&st.st_mtim);
}
@@ -725,9 +740,11 @@ load_connections (NMSettingsPlugin *plugin,
gboolean
nms_keyfile_plugin_add_connection (NMSKeyfilePlugin *self,
NMConnection *connection,
gboolean in_memory,
gboolean is_nm_generated,
gboolean is_volatile,
gboolean in_memory,
const char *shadowed_storage,
gboolean shadowed_owned,
NMSettingsStorage **out_storage,
NMConnection **out_connection,
GError **error)
@@ -747,8 +764,16 @@ nms_keyfile_plugin_add_connection (NMSKeyfilePlugin *self,
nm_assert (out_storage && !*out_storage);
nm_assert (out_connection && !*out_connection);
nm_assert ( in_memory
|| ( !is_nm_generated
&& !is_volatile
&& !shadowed_storage
&& !shadowed_owned));
uuid = nm_connection_get_uuid (connection);
/* Note that even if the caller requests persistent storage, we may switch to in-memory, if
* no /etc directory is configured. */
storage_type = !in_memory && priv->dirname_etc
? NMS_KEYFILE_STORAGE_TYPE_ETC
: NMS_KEYFILE_STORAGE_TYPE_RUN;
@@ -756,6 +781,8 @@ nms_keyfile_plugin_add_connection (NMSKeyfilePlugin *self,
if (!nms_keyfile_writer_connection (connection,
is_nm_generated,
is_volatile,
shadowed_storage,
shadowed_owned,
storage_type == NMS_KEYFILE_STORAGE_TYPE_ETC
? priv->dirname_etc
: priv->dirname_run,
@@ -787,11 +814,12 @@ nms_keyfile_plugin_add_connection (NMSKeyfilePlugin *self,
nm_assert (full_filename && full_filename[0] == '/');
nm_assert (!nm_sett_util_storages_lookup_by_filename (&priv->storages, full_filename));
_LOGT ("commit: %s (%s) added as \"%s\"%s",
_LOGT ("commit: %s (%s) added as \"%s\"%s%s%s%s",
uuid,
nm_connection_get_id (connection),
full_filename,
_extra_flags_to_string (strbuf, sizeof (strbuf), is_nm_generated, is_volatile));
_extra_flags_to_string (strbuf, sizeof (strbuf), is_nm_generated, is_volatile),
NM_PRINT_FMT_QUOTED (shadowed_storage, " (shadows \"", shadowed_storage, shadowed_owned ? "\", owned)" : "\")", ""));
storage = nms_keyfile_storage_new_connection (self,
g_steal_pointer (&reread),
@@ -799,6 +827,8 @@ nms_keyfile_plugin_add_connection (NMSKeyfilePlugin *self,
storage_type,
is_nm_generated ? NM_TERNARY_TRUE : NM_TERNARY_FALSE,
is_volatile ? NM_TERNARY_TRUE : NM_TERNARY_FALSE,
shadowed_storage,
shadowed_owned ? NM_TERNARY_TRUE : NM_TERNARY_FALSE,
nm_sett_util_stat_mtime (full_filename, FALSE, &mtime));
nm_sett_util_storages_add_take (&priv->storages, g_object_ref (storage));
@@ -821,6 +851,8 @@ add_connection (NMSettingsPlugin *plugin,
FALSE,
FALSE,
FALSE,
NULL,
FALSE,
out_storage,
out_connection,
error);
@@ -832,6 +864,8 @@ nms_keyfile_plugin_update_connection (NMSKeyfilePlugin *self,
NMConnection *connection,
gboolean is_nm_generated,
gboolean is_volatile,
const char *shadowed_storage,
gboolean shadowed_owned,
gboolean force_rename,
NMSettingsStorage **out_storage,
NMConnection **out_connection,
@@ -847,6 +881,7 @@ nms_keyfile_plugin_update_connection (NMSKeyfilePlugin *self,
const char *previous_filename;
gboolean reread_same;
const char *uuid;
char strbuf[100];
_nm_assert_storage (self, storage, TRUE);
nm_assert (NM_IS_CONNECTION (connection));
@@ -855,11 +890,15 @@ nms_keyfile_plugin_update_connection (NMSKeyfilePlugin *self,
nm_assert (!error || !*error);
nm_assert (NM_IN_SET (storage->storage_type, NMS_KEYFILE_STORAGE_TYPE_ETC,
NMS_KEYFILE_STORAGE_TYPE_RUN));
nm_assert ( (!is_nm_generated && !is_volatile)
|| storage->storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN);
nm_assert (!storage->is_meta_data);
nm_assert ( storage->storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN
|| ( !is_nm_generated
&& !is_volatile
&& !shadowed_storage
&& !shadowed_owned));
nm_assert (!shadowed_owned || shadowed_storage);
nm_assert ( priv->dirname_etc
|| storage->storage_type != NMS_KEYFILE_STORAGE_TYPE_ETC);
nm_assert (!storage->is_meta_data);
previous_filename = nms_keyfile_storage_get_filename (storage);
uuid = nms_keyfile_storage_get_uuid (storage);
@@ -867,6 +906,8 @@ nms_keyfile_plugin_update_connection (NMSKeyfilePlugin *self,
if (!nms_keyfile_writer_connection (connection,
is_nm_generated,
is_volatile,
shadowed_storage,
shadowed_owned,
storage->storage_type == NMS_KEYFILE_STORAGE_TYPE_ETC
? priv->dirname_etc
: priv->dirname_run,
@@ -899,14 +940,17 @@ nms_keyfile_plugin_update_connection (NMSKeyfilePlugin *self,
nm_assert (_nm_connection_verify (reread, NULL) == NM_SETTING_VERIFY_SUCCESS);
nm_assert (nm_streq (nm_connection_get_uuid (reread), uuid));
_LOGT ("commit: \"%s\": profile %s (%s) written",
_LOGT ("commit: \"%s\": profile %s (%s) written%s%s%s%s",
full_filename,
uuid,
nm_connection_get_id (connection));
nm_connection_get_id (connection),
_extra_flags_to_string (strbuf, sizeof (strbuf), is_nm_generated, is_volatile),
NM_PRINT_FMT_QUOTED (shadowed_storage, shadowed_owned ? " (owns \"" : " (shadows \"", shadowed_storage, "\")", ""));
storage->u.conn_data.is_nm_generated = is_nm_generated;
storage->u.conn_data.is_volatile = is_volatile;
storage->u.conn_data.stat_mtime = *nm_sett_util_stat_mtime (full_filename, FALSE, &mtime);
storage->u.conn_data.shadowed_owned = shadowed_owned;
*out_storage = g_object_ref (NM_SETTINGS_STORAGE (storage));
*out_connection = g_steal_pointer (&reread);
@@ -926,6 +970,8 @@ update_connection (NMSettingsPlugin *plugin,
connection,
FALSE,
FALSE,
NULL,
FALSE,
FALSE,
out_storage,
out_connection,

View File

@@ -42,9 +42,11 @@ NMSKeyfilePlugin *nms_keyfile_plugin_new (void);
gboolean nms_keyfile_plugin_add_connection (NMSKeyfilePlugin *self,
NMConnection *connection,
gboolean in_memory,
gboolean is_nm_generated,
gboolean is_volatile,
gboolean in_memory,
const char *shadowed_storage,
gboolean shadowed_owned,
NMSettingsStorage **out_storage,
NMConnection **out_connection,
GError **error);
@@ -54,6 +56,8 @@ gboolean nms_keyfile_plugin_update_connection (NMSKeyfilePlugin *self,
NMConnection *connection,
gboolean is_nm_generated,
gboolean is_volatile,
const char *shadowed_storage,
gboolean shadowed_owned,
gboolean force_rename,
NMSettingsStorage **out_storage,
NMConnection **out_connection,

View File

@@ -164,6 +164,8 @@ nms_keyfile_reader_from_file (const char *full_filename,
struct stat *out_stat,
NMTernary *out_is_nm_generated,
NMTernary *out_is_volatile,
char **out_shadowed_storage,
NMTernary *out_shadowed_owned,
GError **error)
{
gs_unref_keyfile GKeyFile *key_file = NULL;
@@ -210,6 +212,16 @@ nms_keyfile_reader_from_file (const char *full_filename,
NM_KEYFILE_KEY_NMMETA_VOLATILE,
NM_TERNARY_DEFAULT));
NM_SET_OUT (out_shadowed_storage, g_key_file_get_string (key_file,
NM_KEYFILE_GROUP_NMMETA,
NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE,
NULL));
NM_SET_OUT (out_shadowed_owned, nm_key_file_get_boolean (key_file,
NM_KEYFILE_GROUP_NMMETA,
NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED,
NM_TERNARY_DEFAULT));
return connection;
}

View File

@@ -37,6 +37,8 @@ NMConnection *nms_keyfile_reader_from_file (const char *full_filename,
struct stat *out_stat,
NMTernary *out_is_nm_generated,
NMTernary *out_is_volatile,
char **out_shadowed_storage,
NMTernary *out_shadowed_owned,
GError **error);
#endif /* __NMS_KEYFILE_READER_H__ */

View File

@@ -50,10 +50,13 @@ nms_keyfile_storage_copy_content (NMSKeyfileStorage *dst,
dst->u.meta_data = src->u.meta_data;
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);
}
}
@@ -159,6 +162,8 @@ nms_keyfile_storage_new_connection (NMSKeyfilePlugin *plugin,
NMSKeyfileStorageType storage_type,
NMTernary is_nm_generated_opt,
NMTernary is_volatile_opt,
const char *shadowed_storage,
NMTernary shadowed_owned_opt,
const struct timespec *stat_mtime)
{
NMSKeyfileStorage *self;
@@ -175,12 +180,16 @@ nms_keyfile_storage_new_connection (NMSKeyfilePlugin *plugin,
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.shadowed_owned = shadowed_storage
&& (shadowed_owned_opt == NM_TERNARY_TRUE);
}
return self;
@@ -191,8 +200,11 @@ _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)
if (!self->is_meta_data) {
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

View File

@@ -51,6 +51,19 @@ typedef struct {
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. */
@@ -66,6 +79,11 @@ typedef struct {
bool is_nm_generated:1;
bool is_volatile: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
@@ -106,6 +124,8 @@ NMSKeyfileStorage *nms_keyfile_storage_new_connection (struct _NMSKeyfilePlugin
NMSKeyfileStorageType storage_type,
NMTernary is_nm_generated_opt,
NMTernary is_volatile_opt,
const char *shadowed_storage,
NMTernary shadowed_owned_opt,
const struct timespec *stat_mtime);
void nms_keyfile_storage_destroy (NMSKeyfileStorage *storage);
@@ -188,6 +208,46 @@ nm_settings_storage_is_meta_data_alive (const NMSettingsStorage *storage)
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;
}
}
}
}
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;

View File

@@ -170,6 +170,8 @@ static gboolean
_internal_write_connection (NMConnection *connection,
gboolean is_nm_generated,
gboolean is_volatile,
const char *shadowed_storage,
gboolean shadowed_owned,
const char *keyfile_dir,
const char *profile_dir,
gboolean with_extension,
@@ -201,6 +203,8 @@ _internal_write_connection (NMConnection *connection,
nm_assert (_nm_connection_verify (connection, NULL) == NM_SETTING_VERIFY_SUCCESS);
nm_assert (!shadowed_owned || shadowed_storage);
rename = force_rename
|| existing_path_read_only
|| ( existing_path
@@ -229,6 +233,20 @@ _internal_write_connection (NMConnection *connection,
TRUE);
}
if (shadowed_storage) {
g_key_file_set_string (kf_file,
NM_KEYFILE_GROUP_NMMETA,
NM_KEYFILE_KEY_NMMETA_SHADOWED_STORAGE,
shadowed_storage);
}
if (shadowed_owned) {
g_key_file_set_boolean (kf_file,
NM_KEYFILE_GROUP_NMMETA,
NM_KEYFILE_KEY_NMMETA_SHADOWED_OWNED,
TRUE);
}
kf_content_buf = g_key_file_to_data (kf_file, &kf_content_len, error);
if (!kf_content_buf)
return FALSE;
@@ -356,6 +374,8 @@ gboolean
nms_keyfile_writer_connection (NMConnection *connection,
gboolean is_nm_generated,
gboolean is_volatile,
const char *shadowed_storage,
gboolean shadowed_owned,
const char *keyfile_dir,
const char *profile_dir,
const char *existing_path,
@@ -371,6 +391,8 @@ nms_keyfile_writer_connection (NMConnection *connection,
return _internal_write_connection (connection,
is_nm_generated,
is_volatile,
shadowed_storage,
shadowed_owned,
keyfile_dir,
profile_dir,
TRUE,
@@ -400,6 +422,8 @@ nms_keyfile_writer_test_connection (NMConnection *connection,
return _internal_write_connection (connection,
FALSE,
FALSE,
NULL,
FALSE,
keyfile_dir,
keyfile_dir,
FALSE,

View File

@@ -29,6 +29,8 @@ typedef gboolean (*NMSKeyfileWriterAllowFilenameCb) (const char *check_filename,
gboolean nms_keyfile_writer_connection (NMConnection *connection,
gboolean is_nm_generated,
gboolean is_volatile,
const char *shadowed_storage,
gboolean shadowed_owned,
const char *keyfile_dir,
const char *profile_dir,
const char *existing_path,

View File

@@ -75,6 +75,8 @@ check_ip_route (NMSettingIPConfig *config, int idx, const char *destination, int
NULL, \
NULL, \
NULL, \
NULL, \
NULL, \
(nmtst_get_rand_uint32 () % 2) ? &_error : NULL); \
nmtst_assert_success (_connection, _error); \
nmtst_assert_connection_verifies_without_normalization (_connection); \