Commit 7bd16e85 authored by Thomas Haller's avatar Thomas Haller

settings: merge branch 'th/settings-shadowed-storage'

!211
parents 40355d03 df252a62
Pipeline #51408 passed with stages
in 61 minutes and 9 seconds
......@@ -178,6 +178,7 @@ EXTRA_DIST += \
examples/python/gi/list-connections.py \
examples/python/gi/nm-add-connection2.py \
examples/python/gi/nm-connection-update-stable-id.py \
examples/python/gi/nm-update2.py \
examples/python/gi/nm-wg-set \
examples/python/gi/setting-user-data.py \
examples/python/gi/show-wifi-networks.py \
......
#!/usr/bin/env python
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License along
# with this program; if not, write to the Free Software Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
#
# Copyright 2019 Red Hat, Inc.
#
import sys
import re
import gi
gi.require_version('NM', '1.0')
from gi.repository import GLib, NM
def find_connections(nm_client, arg_type, arg_id):
for c in nm_client.get_connections():
if arg_type in [None, 'id'] and c.get_id() == arg_id:
yield c
if arg_type in [None, 'uuid'] and c.get_uuid() == arg_id:
yield c
def find_connection_first(nm_client, arg_type, arg_id):
for f in find_connections(nm_client, arg_type, arg_id):
return f
def con_to_str(con):
s_con = con.get_setting_connection()
return '"%s" (%s)' % (s_con.get_id(), s_con.get_uuid())
def usage():
print('Usage: %s [[id] <id>]' % (sys.argv[0]))
print(' %s [[uuid] <uuid>]' % (sys.argv[0]))
return 1
def die(msg, print_usage=False):
print(msg)
if print_usage:
usage()
sys.exit(1)
def main():
main_loop = GLib.MainLoop()
nm_client = NM.Client.new(None)
arg_mode = None
arg_block_autoconnect = NM.SettingsUpdate2Flags.NONE
arg_volatile = NM.SettingsUpdate2Flags.NONE
arg_no_reapply = NM.SettingsUpdate2Flags.NONE
cons = []
argv = list(sys.argv[1:])
while argv:
if argv[0] in ['id', 'uuid']:
if cons:
die('cannot specify multiple connections')
if len(argv) < 2:
die('missing argument for "%s" specifier' % (argv[0]))
cons.extend(find_connections(nm_client, argv[0], argv[1]))
if len(cons) == 0:
die('could not find connection for "%s %s"' % (argv[0], argv[1]))
if len(cons) != 1:
die('could not find unique connection for "%s %s"' % (argv[0], argv[1]))
argv = argv[2:]
continue
if argv[0] in ['--block-autoconnect']:
arg_block_autoconnect = NM.SettingsUpdate2Flags.BLOCK_AUTOCONNECT
argv = argv[1:]
continue
if argv[0] in ['--volatile']:
arg_volatile = NM.SettingsUpdate2Flags.VOLATILE
argv = argv[1:]
continue
if argv[0] in ['--no-reapply']:
arg_no_reapply = NM.SettingsUpdate2Flags.NO_REAPPLY
argv = argv[1:]
continue
if argv[0] in ['--to-disk', '--in-memory', '--in-memory-detached', '--in-memory-only']:
if argv[0] == '--to-disk':
v = NM.SettingsUpdate2Flags.TO_DISK
elif argv[0] == '--in-memory':
v = NM.SettingsUpdate2Flags.IN_MEMORY
elif argv[0] == '--in-memory-detached':
v = NM.SettingsUpdate2Flags.IN_MEMORY_DETACHED
elif argv[0] == '--in-memory-only':
v = NM.SettingsUpdate2Flags.IN_MEMORY_ONLY
elif argv[0] == '--keep':
v = NM.SettingsUpdate2Flags.NONE
else:
assert(False)
if arg_mode is not None:
die('duplicate storage modes ("%s")' % (argv[0]))
arg_mode = v
argv = argv[1:]
continue
if cons:
die('unknown argument "%s"' % (argv[0]))
cons.extend(find_connections(nm_client, None, argv[0]))
if len(cons) == 0:
die('could not find connection for "%s"' % (argv[0]))
if len(cons) != 1:
die('could not find unique connection for "%s"' % (argv[0]))
argv = argv[1:]
continue
if len(cons) != 1:
die('missing connection argument', True)
con = cons[0]
con2 = NM.SimpleConnection.new_clone(con)
result = {}
def _update2_cb(con, async_result, user_data):
try:
r = con.update2_finish(async_result)
except Exception as e:
result['error'] = e
else:
result['result'] = r
main_loop.quit()
con.update2(con2.to_dbus(NM.ConnectionSerializationFlags.ALL),
(arg_mode if arg_mode is not None else NM.SettingsUpdate2Flags.NONE)
| arg_block_autoconnect
| arg_volatile
| arg_no_reapply,
None,
None,
_update2_cb,
None)
main_loop.run()
if 'error' in result:
die('update connection %s failed [%s]: %s' % (con_to_str(con2), ' '.join(sys.argv), result['error']))
print('update connection %s succeeded [%s]: %s' % (con_to_str(con2), ' '.join(sys.argv), result['result']))
if __name__ == '__main__':
main()
......@@ -1030,26 +1030,31 @@ typedef enum { /*< flags >*/
* NMSettingsUpdate2Flags:
* @NM_SETTINGS_UPDATE2_FLAG_NONE: an alias for numeric zero, no flags set.
* @NM_SETTINGS_UPDATE2_FLAG_TO_DISK: to persist the connection to disk.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY: to make the connection in-memory only.
* If the connection was previously persistent, the corresponding file on disk
* is not deleted but merely the connection is decoupled from the file
* on disk. If you later delete an in-memory connection, the connection
* on disk will be deleted as well.
* Note: with 1.20, this flag is no longer implemented because in-memory connections
* are also persisted under /run. For the moment, this behaves the same as
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED: this is like @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY,
* but if the connection has a corresponding file on disk, the association between
* the connection and the file is forgotten but the file is not modified.
* The difference to %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY is if you later
* save the connection again to disk, a new file name will be chosen without
* overwriting the remaining file on disk. Also, if you delete the connection
* later, the file on disk will not be deleted.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY: makes the profile in-memory.
* Note that such profiles are stored in keyfile format under /run.
* If the file is already in-memory, the file in /run is updated in-place.
* Otherwise, the previous storage for the profile is left unchanged
* on disk, and the in-memory copy shadows it.
* Note that the original filename of the previous persistent storage (if any)
* is remembered. That means, when later persisting the profile again to disk,
* the file on disk will be overwritten again.
* Likewise, when finally deleting the profile, both the storage from /run
* and persistent storage are deleted (or if the persistent storage does not
* allow deletion, and nmmeta file is written to mark the UUID as deleted).
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED: this is almost the same as
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY, with one difference: when later deleting
* the profile, the original profile will not be deleted. Instead a nmmeta
* file is written to /run to indicate that the profile is gone.
* Note that if such a nmmeta tombstone file exists and hides a file in persistant
* storage, then when re-adding the profile with the same UUID, then the original
* storage is taken over again.
* @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY: this is like @NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY,
* but if the connection has a corresponding file on disk, the file on
* disk will be deleted.
* but if the connection has a corresponding file on persistent storage, the file
* will be deleted right away. If the profile is later again persisted to disk,
* a new, unused filename will be chosen.
* @NM_SETTINGS_UPDATE2_FLAG_VOLATILE: This can be specified with either
* %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED or %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY.
* %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY, %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED
* or %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY.
* After making the connection in-memory only, the connection is marked
* as volatile. That means, if the connection is currently not active
* it will be deleted right away. Otherwise, it is marked to for deletion
......
......@@ -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"
......
......@@ -12420,7 +12420,7 @@ nm_device_set_ip_config (NMDevice *self,
nm_settings_connection_update (settings_connection,
new_connection,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED,
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,
NM_SETTINGS_CONNECTION_INT_FLAGS_NONE,
NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE,
......
......@@ -436,7 +436,6 @@ mirror_8021x_connection (NMIwdManager *self,
NM_SETTING_CONNECTION_TYPE, NM_SETTING_WIRELESS_SETTING_NAME,
NM_SETTING_CONNECTION_ID, name,
NM_SETTING_CONNECTION_UUID, nm_utils_uuid_generate_buf (uuid),
NM_SETTING_CONNECTION_READ_ONLY, TRUE,
NULL));
nm_connection_add_setting (connection, setting);
......
......@@ -254,7 +254,7 @@ restore_and_activate_connection (NMCheckpoint *self,
_LOGD ("rollback: adding connection %s again",
nm_connection_get_uuid (dev_checkpoint->settings_connection));
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
if (!nm_settings_add_connection (NM_SETTINGS_GET,
dev_checkpoint->settings_connection,
persist_mode,
......
......@@ -5454,7 +5454,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
const char *device_path;
const char *specific_object_path;
gs_free NMConnection **conns = NULL;
NMSettingsConnectionPersistMode persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
NMSettingsConnectionPersistMode persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
gboolean is_volatile = FALSE;
gboolean bind_dbus_client = FALSE;
AsyncOpType async_op_type;
......@@ -5485,7 +5485,7 @@ impl_manager_add_and_activate_connection (NMDBusObject *obj,
s = g_variant_get_string (option_value, NULL);
is_volatile = FALSE;
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
if (nm_streq (s, "volatile")) {
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY;
......
......@@ -44,6 +44,11 @@
#define AUTOCONNECT_RETRIES_FOREVER -1
#define AUTOCONNECT_RESET_RETRIES_TIMER 300
#define _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES ((NMSettingsUpdate2Flags) ( NM_SETTINGS_UPDATE2_FLAG_TO_DISK \
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY \
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED \
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY))
/*****************************************************************************/
NMConnection **
......@@ -1319,37 +1324,6 @@ auth_start (NMSettingsConnection *self,
/**** DBus method handlers ************************************/
static gboolean
check_writable (NMConnection *self, GError **error)
{
NMSettingConnection *s_con;
g_return_val_if_fail (NM_IS_CONNECTION (self), FALSE);
s_con = nm_connection_get_setting_connection (self);
if (!s_con) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_CONNECTION,
"Connection did not have required 'connection' setting");
return FALSE;
}
/* If the connection is read-only, that has to be changed at the source of
* the problem (ex a system settings plugin that can't write connections out)
* instead of over D-Bus.
*/
if (nm_setting_connection_get_read_only (s_con)) {
g_set_error_literal (error,
NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_READ_ONLY_CONNECTION,
"Connection is read-only");
return FALSE;
}
return TRUE;
}
static void
get_settings_auth_cb (NMSettingsConnection *self,
GDBusMethodInvocation *context,
......@@ -1504,10 +1478,14 @@ update_auth_cb (NMSettingsConnection *self,
}
}
nm_assert ( !NM_FLAGS_ANY (info->flags, _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES)
|| nm_utils_is_power_of_two (info->flags & _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES));
if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_TO_DISK))
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK;
else if (NM_FLAGS_ANY (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED))
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK;
else if (NM_FLAGS_ANY (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY))
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY;
else if (NM_FLAGS_ANY (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED))
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED;
else if (NM_FLAGS_HAS (info->flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY)) {
persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY;
......@@ -1594,13 +1572,6 @@ settings_connection_update (NMSettingsConnection *self,
UpdateInfo *info;
const char *permission;
/* If the connection is read-only, that has to be changed at the source of
* the problem (ex a system settings plugin that can't write connections out)
* instead of over D-Bus.
*/
if (!check_writable (nm_settings_connection_get_connection (self), &error))
goto error;
/* Check if the settings are valid first */
if (new_settings) {
if (!g_variant_is_of_type (new_settings, NM_VARIANT_TYPE_CONNECTION)) {
......@@ -1725,14 +1696,10 @@ impl_settings_connection_update2 (NMDBusObject *obj,
GVariantIter iter;
const char *args_name;
NMSettingsUpdate2Flags flags;
const NMSettingsUpdate2Flags ALL_PERSIST_MODES = NM_SETTINGS_UPDATE2_FLAG_TO_DISK
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY;
g_variant_get (parameters, "(@a{sa{sv}}u@a{sv})", &settings, &flags_u, &args);
if (NM_FLAGS_ANY (flags_u, ~((guint32) ( ALL_PERSIST_MODES
if (NM_FLAGS_ANY (flags_u, ~((guint32) ( _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES
| NM_SETTINGS_UPDATE2_FLAG_VOLATILE
| NM_SETTINGS_UPDATE2_FLAG_BLOCK_AUTOCONNECT
| NM_SETTINGS_UPDATE2_FLAG_NO_REAPPLY)))) {
......@@ -1745,11 +1712,12 @@ impl_settings_connection_update2 (NMDBusObject *obj,
flags = (NMSettingsUpdate2Flags) flags_u;
if ( ( NM_FLAGS_ANY (flags, ALL_PERSIST_MODES)
&& !nm_utils_is_power_of_two (flags & ALL_PERSIST_MODES))
if ( ( NM_FLAGS_ANY (flags, _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES)
&& !nm_utils_is_power_of_two (flags & _NM_SETTINGS_UPDATE2_FLAG_ALL_PERSIST_MODES))
|| ( NM_FLAGS_HAS (flags, NM_SETTINGS_UPDATE2_FLAG_VOLATILE)
&& !NM_FLAGS_ANY (flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED |
NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY))) {
&& !NM_FLAGS_ANY (flags, NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED
| NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY))) {
error = g_error_new_literal (NM_SETTINGS_ERROR,
NM_SETTINGS_ERROR_INVALID_ARGUMENTS,
"Conflicting flags");
......@@ -1831,9 +1799,6 @@ impl_settings_connection_delete (NMDBusObject *obj,
nm_assert (nm_settings_connection_still_valid (self));
if (!check_writable (nm_settings_connection_get_connection (self), &error))
goto err;
subject = _new_auth_subject (invocation, &error);
if (!subject)
goto err;
......
......@@ -85,21 +85,46 @@ typedef enum {
* if the profile is on-disk, update it on-disk, and keep it. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP,
/* persist to disk. If the profile is currenly in-memory, remove
* it from /run. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_DISK,
/* persist to disk. If the profile is currently in-memory, remove
* it from /run. Depending on the shadowed-storage, the pre-existing
* file is reused when moving the storage.
*
* Corresponds to %NM_SETTINGS_UPDATE2_FLAG_TO_DISK. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK,
/* Update in-memory (i.e. persist to /run). If the profile is currently on disk,
* then a reference to the profile is remembered as "shadowed-storage".
* Later, when storing again to persistant storage, the shawowed-storage is
* updated. When deleting the profile, the shadowed-storage is also deleted
* from disk.
*
* Corresponds to %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY,
/* Update in-memory (i.e. persist to /run). This is almost like
* %NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY, except the in-memory profile
* remembers not to own the shadowed-storage ("shadowed-owned").
* The diffrence is that when deleting the in-memory profile, the original
* profile is not deleted but instead the nmmeta tombstone remembers the
* shadowed-storage and re-used it when re-adding the profile.
*
* Corresponds to %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_DETACHED. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED,
/* persist to /run (in-memory). If the profile is currently on disk,
* delete it from disk. */
/* Update in-memory (i.e. persist to /run). If the profile is currently on disk,
* delete it from disk.
*
* If the profile is in-memory and has a shadowed-storage, the original profile
* will be deleted from disk.
*
* Corresponds to %NM_SETTINGS_UPDATE2_FLAG_IN_MEMORY_ONLY. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_ONLY,
/* persist to /run (in-memory). If the profile is currently on disk,
* forget about it, but don't delete it from disk. */
NM_SETTINGS_CONNECTION_PERSIST_MODE_IN_MEMORY_DETACHED,
/* this only updates the connection in-memory. Note that "in-memory" above
* means to write to keyfile in /run. This really means to not notify the
* settings plugin about the change. */
/* This only updates the connection in-memory. Note that "in-memory" above
* means to write to keyfile in /run. This mode really means to not notify the
* settings plugin about the change. This should be only used for updating
* secrets.
*/
NM_SETTINGS_CONNECTION_PERSIST_MODE_NO_PERSIST,
} NMSettingsConnectionPersistMode;
......
This diff is collapsed.
......@@ -676,7 +676,6 @@ ifupdown_new_connection_from_if_block (if_block *block,
NM_SETTING_CONNECTION_INTERFACE_NAME, block->name,
NM_SETTING_CONNECTION_ID, idstr,
NM_SETTING_CONNECTION_UUID, uuid,
NM_SETTING_CONNECTION_READ_ONLY, TRUE,
NM_SETTING_CONNECTION_AUTOCONNECT, (gboolean) (!!autoconnect),
NULL);
......
......@@ -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,
......@@ -64,6 +68,7 @@ gboolean nms_keyfile_plugin_set_nmmeta_tombstone (NMSKeyfilePlugin *self,
const char *uuid,
gboolean in_memory,
gboolean set,
const char *shadowed_storage,
NMSettingsStorage **out_storage,
gboolean *out_hard_failure);
......
......@@ -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;
}
......@@ -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__ */
......@@ -41,24 +41,39 @@ nms_keyfile_storage_copy_content (NMSKeyfileStorage *dst,
{
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_g_object_ref_set (&dst->connection, src->connection);
dst->storage_type = src->storage_type;
dst->stat_mtime = src->stat_mtime;
dst->is_nm_generated = src->is_nm_generated;
dst->is_volatile = src->is_volatile;
dst->is_tombstone = src->is_tombstone;
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->connection && self->is_tombstone)
|| NM_IS_CONNECTION (self->connection));
nm_assert ( self->is_meta_data
|| NM_IS_CONNECTION (self->u.conn_data.connection));
return g_steal_pointer (&self->connection);
return self->is_meta_data
? NULL
: g_steal_pointer (&self->u.conn_data.connection);
}
/*****************************************************************************/
......@@ -75,16 +90,19 @@ cmp_fcn (const NMSKeyfileStorage *a,
* (inverse) priority. */
NM_CMP_FIELD_UNSAFE (b, a, storage_type);
/* tombstones are more important. */
nm_assert (a->is_tombstone == nm_settings_storage_is_keyfile_tombstone (NM_SETTINGS_STORAGE (a)));
nm_assert (b->is_tombstone == nm_settings_storage_is_keyfile_tombstone (NM_SETTINGS_STORAGE (b)));
NM_CMP_FIELD_UNSAFE (a, b, is_tombstone);
/* meta-data is more important. */
NM_CMP_FIELD_UNSAFE (a, b, is_meta_data);
/* newer files are more important. */
NM_CMP_FIELD (a, b, stat_mtime.tv_sec);
NM_CMP_FIELD (a, b, stat_mtime.tv_nsec);
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));
NM_CMP_DIRECT_STRCMP (nms_keyfile_storage_get_filename (a), nms_keyfile_storage_get_filename (b));
}
return 0;
}
......@@ -99,24 +117,35 @@ nms_keyfile_storage_init (NMSKeyfileStorage *self)
static NMSKeyfileStorage *
_storage_new (NMSKeyfilePlugin *plugin,
const char *uuid,
const char *filename)
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] == '/');
return g_object_new (NMS_TYPE_KEYFILE_STORAGE,
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)
NMSKeyfileStorageType storage_type,
const char *shadowed_storage)
{
NMSKeyfileStorage *self;
......@@ -126,12 +155,10 @@ nms_keyfile_storage_new_tombstone (NMSKeyfilePlugin *plugin,
nm_assert (NM_IN_SET (storage_type, NMS_KEYFILE_STORAGE_TYPE_ETC,
NMS_KEYFILE_STORAGE_TYPE_RUN));
self = _storage_new (plugin, uuid, filename);
self->is_tombstone = TRUE;
self->storage_type = storage_type;
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;
}
......@@ -142,6 +169,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;
......@@ -154,19 +183,21 @@ nms_keyfile_storage_new_connection (NMSKeyfilePlugin *plugin,
&& 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);
self = _storage_new (plugin, nm_connection_get_uuid (connection_take), filename, FALSE, storage_type);
self->connection = connection_take; /* take reference. */
self->u.conn_data.connection = connection_take; /* take reference. */
if (storage_type == NMS_KEYFILE_STORAGE_TYPE_RUN) {
self->is_nm_generated = (is_nm_generated_opt == NM_TERNARY_TRUE);
self->is_volatile = (is_volatile_opt == NM_TERNARY_TRUE);
}
self->u.conn_data.shadowed_storage = g_strdup (shadowed_storage);
if (stat_mtime)
self->stat_mtime = *stat_mtime;
self->u.conn_data.stat_mtime = *stat_mtime;
self->storage_type = storage_type;
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;
}
......@@ -176,7 +207,13 @@ _storage_clear (NMSKeyfileStorage *self)
{
c_list_unlink (&self->parent._storage_lst);
c_list_unlink (&self->parent._storage_by_uuid_lst);
g_clear_object (&self->connection);
if (self->is_meta_data)