diff options
| author | Michael Biebl <biebl@debian.org> | 2021-02-11 18:11:46 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2021-02-11 18:11:46 +0100 |
| commit | 80ec1decc49c72efec2a8b87c06245c92c0ab807 (patch) | |
| tree | e3b229aa94e8dcf0590f2317664176e7b8f7607b /src/nm-checkpoint.c | |
| parent | 65f86e8f56267192d42f2b629fc6b0c99fb9cd0c (diff) | |
New upstream version 1.29.90 upstream/1.29.90
Diffstat (limited to 'src/nm-checkpoint.c')
| -rw-r--r-- | src/nm-checkpoint.c | 790 |
1 files changed, 0 insertions, 790 deletions
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c deleted file mode 100644 index b26f7e80..00000000 --- a/src/nm-checkpoint.c +++ /dev/null @@ -1,790 +0,0 @@ -/* SPDX-License-Identifier: GPL-2.0+ */ -/* - * Copyright (C) 2016 Red Hat, Inc. - */ - -#include "nm-default.h" - -#include "nm-checkpoint.h" - -#include "nm-active-connection.h" -#include "nm-act-request.h" -#include "nm-libnm-core-intern/nm-auth-subject.h" -#include "nm-core-utils.h" -#include "nm-dbus-interface.h" -#include "devices/nm-device.h" -#include "nm-manager.h" -#include "settings/nm-settings.h" -#include "settings/nm-settings-connection.h" -#include "nm-simple-connection.h" -#include "nm-utils.h" - -/*****************************************************************************/ - -typedef struct { - char * original_dev_path; - char * original_dev_name; - NMDeviceType dev_type; - NMDevice * device; - NMConnection * applied_connection; - NMConnection * settings_connection; - guint64 ac_version_id; - NMDeviceState state; - bool is_software : 1; - bool realized : 1; - bool activation_lifetime_bound_to_profile_visibility : 1; - NMUnmanFlagOp unmanaged_explicit; - NMActivationReason activation_reason; - gulong dev_exported_change_id; -} DeviceCheckpoint; - -NM_GOBJECT_PROPERTIES_DEFINE(NMCheckpoint, PROP_DEVICES, PROP_CREATED, PROP_ROLLBACK_TIMEOUT, ); - -struct _NMCheckpointPrivate { - /* properties */ - GHashTable *devices; - GPtrArray * removed_devices; - gint64 created_at_ms; - guint32 rollback_timeout_s; - guint timeout_id; - /* private members */ - NMManager * manager; - NMCheckpointCreateFlags flags; - GHashTable * connection_uuids; - gulong dev_removed_id; - - NMCheckpointTimeoutCallback timeout_cb; - gpointer timeout_data; -}; - -struct _NMCheckpointClass { - NMDBusObjectClass parent; -}; - -G_DEFINE_TYPE(NMCheckpoint, nm_checkpoint, NM_TYPE_DBUS_OBJECT) - -#define NM_CHECKPOINT_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR(self, NMCheckpoint, NM_IS_CHECKPOINT) - -/*****************************************************************************/ - -#define _NMLOG_PREFIX_NAME "checkpoint" -#define _NMLOG_DOMAIN LOGD_CORE - -#define _NMLOG(level, ...) \ - G_STMT_START \ - { \ - if (nm_logging_enabled(level, _NMLOG_DOMAIN)) { \ - char __prefix[32]; \ - \ - if (self) \ - g_snprintf(__prefix, \ - sizeof(__prefix), \ - "%s[%p]", \ - ""_NMLOG_PREFIX_NAME \ - "", \ - (self)); \ - else \ - g_strlcpy(__prefix, _NMLOG_PREFIX_NAME, sizeof(__prefix)); \ - _nm_log((level), \ - (_NMLOG_DOMAIN), \ - 0, \ - NULL, \ - NULL, \ - "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ - __prefix _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ - } \ - } \ - G_STMT_END - -/*****************************************************************************/ - -void -nm_checkpoint_log_destroy(NMCheckpoint *self) -{ - _LOGI("destroy %s", nm_dbus_object_get_path(NM_DBUS_OBJECT(self))); -} - -void -nm_checkpoint_set_timeout_callback(NMCheckpoint * self, - NMCheckpointTimeoutCallback callback, - gpointer user_data) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - - /* in glib world, we would have a GSignal for this. But as there - * is only one subscriber, it's simpler to just set and unset(!) - * the callback this way. */ - priv->timeout_cb = callback; - priv->timeout_data = user_data; -} - -NMDevice * -nm_checkpoint_includes_devices(NMCheckpoint *self, NMDevice *const *devices, guint n_devices) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - guint i; - - for (i = 0; i < n_devices; i++) { - if (g_hash_table_contains(priv->devices, devices[i])) - return devices[i]; - } - return NULL; -} - -NMDevice * -nm_checkpoint_includes_devices_of(NMCheckpoint *self, NMCheckpoint *cp_for_devices) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - NMCheckpointPrivate *priv2 = NM_CHECKPOINT_GET_PRIVATE(cp_for_devices); - GHashTableIter iter; - NMDevice * device; - - g_hash_table_iter_init(&iter, priv2->devices); - while (g_hash_table_iter_next(&iter, (gpointer *) &device, NULL)) { - if (g_hash_table_contains(priv->devices, device)) - return device; - } - return NULL; -} - -static NMSettingsConnection * -find_settings_connection(NMCheckpoint * self, - DeviceCheckpoint *dev_checkpoint, - gboolean * need_update, - gboolean * need_activation) -{ - NMCheckpointPrivate * priv = NM_CHECKPOINT_GET_PRIVATE(self); - NMActiveConnection * active; - NMSettingsConnection *sett_conn; - const char * uuid, *ac_uuid; - const CList * tmp_clist; - - *need_activation = FALSE; - *need_update = FALSE; - - uuid = nm_connection_get_uuid(dev_checkpoint->settings_connection); - sett_conn = nm_settings_get_connection_by_uuid(NM_SETTINGS_GET, uuid); - - if (!sett_conn) - return NULL; - - /* Now check if the connection changed, ... */ - if (!nm_connection_compare(dev_checkpoint->settings_connection, - nm_settings_connection_get_connection(sett_conn), - NM_SETTING_COMPARE_FLAG_EXACT)) { - _LOGT("rollback: settings connection %s changed", uuid); - *need_update = TRUE; - *need_activation = TRUE; - } - - /* ... is active, ... */ - nm_manager_for_each_active_connection (priv->manager, active, tmp_clist) { - ac_uuid = - nm_settings_connection_get_uuid(nm_active_connection_get_settings_connection(active)); - if (nm_streq(uuid, ac_uuid)) { - _LOGT("rollback: connection %s is active", uuid); - break; - } - } - - if (!active) { - _LOGT("rollback: connection %s is not active", uuid); - *need_activation = TRUE; - return sett_conn; - } - - /* ... or if the connection was reactivated/reapplied */ - if (nm_active_connection_version_id_get(active) != dev_checkpoint->ac_version_id) { - _LOGT("rollback: active connection version id of %s changed", uuid); - *need_activation = TRUE; - } - - return sett_conn; -} - -static gboolean -restore_and_activate_connection(NMCheckpoint *self, DeviceCheckpoint *dev_checkpoint) -{ - NMCheckpointPrivate * priv = NM_CHECKPOINT_GET_PRIVATE(self); - NMSettingsConnection *connection; - gs_unref_object NMAuthSubject * subject = NULL; - GError * local_error = NULL; - gboolean need_update, need_activation; - NMSettingsConnectionPersistMode persist_mode; - NMSettingsConnectionIntFlags sett_flags; - NMSettingsConnectionIntFlags sett_mask; - - connection = find_settings_connection(self, dev_checkpoint, &need_update, &need_activation); - - /* FIXME: we need to ensure to re-create/update the profile for the - * same settings plugin. E.g. if it was a keyfile in /run or /etc, - * it must be again. If it was previously handled by a certain settings plugin, - * so it must again. - * - * FIXME: preserve and restore the right settings flags (volatile, nm-generated). */ - sett_flags = NM_SETTINGS_CONNECTION_INT_FLAGS_NONE; - sett_mask = NM_SETTINGS_CONNECTION_INT_FLAGS_NONE; - - if (connection) { - if (need_update) { - _LOGD("rollback: updating connection %s", nm_settings_connection_get_uuid(connection)); - persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_KEEP; - nm_settings_connection_update(connection, - dev_checkpoint->settings_connection, - persist_mode, - sett_flags, - sett_mask, - NM_SETTINGS_CONNECTION_UPDATE_REASON_NONE, - "checkpoint-rollback", - NULL); - } - } else { - /* The connection was deleted, recreate it */ - _LOGD("rollback: adding connection %s again", - nm_connection_get_uuid(dev_checkpoint->settings_connection)); - - persist_mode = NM_SETTINGS_CONNECTION_PERSIST_MODE_TO_DISK; - if (!nm_settings_add_connection(NM_SETTINGS_GET, - dev_checkpoint->settings_connection, - persist_mode, - NM_SETTINGS_CONNECTION_ADD_REASON_NONE, - sett_flags, - &connection, - &local_error)) { - _LOGD("rollback: connection add failure: %s", local_error->message); - g_clear_error(&local_error); - return FALSE; - } - - /* If the device is software, a brand new NMDevice may have been created */ - if (dev_checkpoint->is_software && !dev_checkpoint->device) { - dev_checkpoint->device = nm_manager_get_device(priv->manager, - dev_checkpoint->original_dev_name, - dev_checkpoint->dev_type); - nm_g_object_ref(dev_checkpoint->device); - } - need_activation = TRUE; - } - - if (!dev_checkpoint->device) { - _LOGD("rollback: device cannot be restored"); - return FALSE; - } - - if (need_activation) { - _LOGD("rollback: reactivating connection %s", nm_settings_connection_get_uuid(connection)); - subject = nm_auth_subject_new_internal(); - - /* Disconnect the device if needed. This necessary because now - * the manager prevents the reactivation of the same connection by - * an internal subject. */ - if (nm_device_get_state(dev_checkpoint->device) > NM_DEVICE_STATE_DISCONNECTED - && nm_device_get_state(dev_checkpoint->device) < NM_DEVICE_STATE_DEACTIVATING) { - nm_device_state_changed(dev_checkpoint->device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_NEW_ACTIVATION); - } - - if (!nm_manager_activate_connection( - priv->manager, - connection, - dev_checkpoint->applied_connection, - NULL, - dev_checkpoint->device, - subject, - NM_ACTIVATION_TYPE_MANAGED, - dev_checkpoint->activation_reason, - dev_checkpoint->activation_lifetime_bound_to_profile_visibility - ? NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY - : NM_ACTIVATION_STATE_FLAG_NONE, - &local_error)) { - _LOGW("rollback: reactivation of connection %s/%s failed: %s", - nm_settings_connection_get_id(connection), - nm_settings_connection_get_uuid(connection), - local_error->message); - g_clear_error(&local_error); - return FALSE; - } - } - return TRUE; -} - -GVariant * -nm_checkpoint_rollback(NMCheckpoint *self) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - DeviceCheckpoint * dev_checkpoint; - GHashTableIter iter; - NMDevice * device; - GVariantBuilder builder; - uint i; - - _LOGI("rollback of %s", nm_dbus_object_get_path(NM_DBUS_OBJECT(self))); - g_variant_builder_init(&builder, G_VARIANT_TYPE("a{su}")); - - /* Start creating removed devices (if any and if possible) */ - if (priv->removed_devices) { - for (i = 0; i < priv->removed_devices->len; i++) { - guint32 result = NM_ROLLBACK_RESULT_OK; - - dev_checkpoint = priv->removed_devices->pdata[i]; - _LOGD("rollback: restoring removed device %s (state %d, realized %d, explicitly " - "unmanaged %d)", - dev_checkpoint->original_dev_name, - (int) dev_checkpoint->state, - dev_checkpoint->realized, - dev_checkpoint->unmanaged_explicit); - - if (dev_checkpoint->applied_connection) { - if (!restore_and_activate_connection(self, dev_checkpoint)) - result = NM_ROLLBACK_RESULT_ERR_FAILED; - } - g_variant_builder_add(&builder, "{su}", dev_checkpoint->original_dev_path, result); - } - } - - /* Start rolling-back each device */ - g_hash_table_iter_init(&iter, priv->devices); - while (g_hash_table_iter_next(&iter, (gpointer *) &device, (gpointer *) &dev_checkpoint)) { - guint32 result = NM_ROLLBACK_RESULT_OK; - - _LOGD("rollback: restoring device %s (state %d, realized %d, explicitly unmanaged %d)", - dev_checkpoint->original_dev_name, - (int) dev_checkpoint->state, - dev_checkpoint->realized, - dev_checkpoint->unmanaged_explicit); - - if (nm_device_is_real(device)) { - if (!dev_checkpoint->realized) { - _LOGD("rollback: device was not realized, unmanage it"); - nm_device_set_unmanaged_by_flags_queue(device, - NM_UNMANAGED_USER_EXPLICIT, - TRUE, - NM_DEVICE_STATE_REASON_NOW_UNMANAGED); - goto next_dev; - } - } else { - if (dev_checkpoint->realized) { - if (dev_checkpoint->is_software) { - /* try to recreate software device */ - _LOGD("rollback: software device not realized, will re-activate"); - goto activate; - } else { - _LOGD("rollback: device is not realized"); - result = NM_ROLLBACK_RESULT_ERR_FAILED; - } - } - goto next_dev; - } - - /* Manage the device again if needed */ - if (nm_device_get_unmanaged_flags(device, NM_UNMANAGED_USER_EXPLICIT) - && dev_checkpoint->unmanaged_explicit != NM_UNMAN_FLAG_OP_SET_UNMANAGED) { - _LOGD("rollback: restore unmanaged user-explicit"); - nm_device_set_unmanaged_by_flags_queue(device, - NM_UNMANAGED_USER_EXPLICIT, - dev_checkpoint->unmanaged_explicit, - NM_DEVICE_STATE_REASON_NOW_MANAGED); - } - - if (dev_checkpoint->state == NM_DEVICE_STATE_UNMANAGED) { - if (nm_device_get_state(device) != NM_DEVICE_STATE_UNMANAGED - || dev_checkpoint->unmanaged_explicit == NM_UNMAN_FLAG_OP_SET_UNMANAGED) { - _LOGD("rollback: explicitly unmanage device"); - nm_device_set_unmanaged_by_flags_queue(device, - NM_UNMANAGED_USER_EXPLICIT, - TRUE, - NM_DEVICE_STATE_REASON_NOW_UNMANAGED); - } - goto next_dev; - } - -activate: - if (dev_checkpoint->applied_connection) { - if (!restore_and_activate_connection(self, dev_checkpoint)) { - result = NM_ROLLBACK_RESULT_ERR_FAILED; - goto next_dev; - } - } else { - /* The device was initially disconnected, deactivate any existing connection */ - _LOGD("rollback: disconnecting device"); - - if (nm_device_get_state(device) > NM_DEVICE_STATE_DISCONNECTED - && nm_device_get_state(device) < NM_DEVICE_STATE_DEACTIVATING) { - nm_device_state_changed(device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - } - } - -next_dev: - g_variant_builder_add(&builder, "{su}", dev_checkpoint->original_dev_path, result); - } - - if (NM_FLAGS_HAS(priv->flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) { - NMSettingsConnection *con; - gs_free NMSettingsConnection **list = NULL; - - g_return_val_if_fail(priv->connection_uuids, NULL); - list = nm_settings_get_connections_clone( - NM_SETTINGS_GET, - NULL, - NULL, - NULL, - nm_settings_connection_cmp_autoconnect_priority_p_with_data, - NULL); - - for (i = 0; list[i]; i++) { - con = list[i]; - if (!g_hash_table_contains(priv->connection_uuids, - nm_settings_connection_get_uuid(con))) { - _LOGD("rollback: deleting new connection %s", nm_settings_connection_get_uuid(con)); - nm_settings_connection_delete(con, FALSE); - } - } - } - - if (NM_FLAGS_HAS(priv->flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { - const CList * tmp_lst; - NMDeviceState state; - - nm_manager_for_each_device (priv->manager, device, tmp_lst) { - if (g_hash_table_contains(priv->devices, device)) - continue; - state = nm_device_get_state(device); - if (state > NM_DEVICE_STATE_DISCONNECTED && state < NM_DEVICE_STATE_DEACTIVATING) { - _LOGD("rollback: disconnecting new device %s", nm_device_get_iface(device)); - nm_device_state_changed(device, - NM_DEVICE_STATE_DEACTIVATING, - NM_DEVICE_STATE_REASON_USER_REQUESTED); - } - } - } - - return g_variant_new("(a{su})", &builder); -} - -static void -device_checkpoint_destroy(gpointer data) -{ - DeviceCheckpoint *dev_checkpoint = data; - - nm_clear_g_signal_handler(dev_checkpoint->device, &dev_checkpoint->dev_exported_change_id); - g_clear_object(&dev_checkpoint->applied_connection); - g_clear_object(&dev_checkpoint->settings_connection); - g_clear_object(&dev_checkpoint->device); - g_free(dev_checkpoint->original_dev_path); - g_free(dev_checkpoint->original_dev_name); - - g_slice_free(DeviceCheckpoint, dev_checkpoint); -} - -static void -_move_dev_to_removed_devices(NMDevice *device, NMCheckpoint *checkpoint) -{ - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(checkpoint); - DeviceCheckpoint * dev_checkpoint; - - g_return_if_fail(device); - - dev_checkpoint = g_hash_table_lookup(priv->devices, device); - if (!dev_checkpoint) - return; - - g_hash_table_steal(priv->devices, dev_checkpoint->device); - nm_clear_g_signal_handler(dev_checkpoint->device, &dev_checkpoint->dev_exported_change_id); - g_clear_object(&dev_checkpoint->device); - - if (!priv->removed_devices) - priv->removed_devices = - g_ptr_array_new_with_free_func((GDestroyNotify) device_checkpoint_destroy); - g_ptr_array_add(priv->removed_devices, dev_checkpoint); - - _notify(checkpoint, PROP_DEVICES); -} - -static void -_dev_exported_changed(NMDBusObject *obj, NMCheckpoint *checkpoint) -{ - _move_dev_to_removed_devices(NM_DEVICE(obj), checkpoint); -} - -static DeviceCheckpoint * -device_checkpoint_create(NMCheckpoint *checkpoint, NMDevice *device) -{ - DeviceCheckpoint * dev_checkpoint; - NMConnection * applied_connection; - NMSettingsConnection *settings_connection; - const char * path; - NMActRequest * act_request; - - nm_assert(NM_IS_DEVICE(device)); - nm_assert(nm_device_is_real(device)); - - path = nm_dbus_object_get_path(NM_DBUS_OBJECT(device)); - - dev_checkpoint = g_slice_new0(DeviceCheckpoint); - dev_checkpoint->device = g_object_ref(device); - dev_checkpoint->original_dev_path = g_strdup(path); - dev_checkpoint->original_dev_name = g_strdup(nm_device_get_iface(device)); - dev_checkpoint->dev_type = nm_device_get_device_type(device); - dev_checkpoint->state = nm_device_get_state(device); - dev_checkpoint->is_software = nm_device_is_software(device); - dev_checkpoint->realized = nm_device_is_real(device); - dev_checkpoint->dev_exported_change_id = g_signal_connect(device, - NM_DBUS_OBJECT_EXPORTED_CHANGED, - G_CALLBACK(_dev_exported_changed), - checkpoint); - - if (nm_device_get_unmanaged_mask(device, NM_UNMANAGED_USER_EXPLICIT)) { - dev_checkpoint->unmanaged_explicit = - !!nm_device_get_unmanaged_flags(device, NM_UNMANAGED_USER_EXPLICIT); - } else - dev_checkpoint->unmanaged_explicit = NM_UNMAN_FLAG_OP_FORGET; - - act_request = nm_device_get_act_request(device); - if (act_request) { - settings_connection = nm_act_request_get_settings_connection(act_request); - applied_connection = nm_act_request_get_applied_connection(act_request); - - dev_checkpoint->applied_connection = nm_simple_connection_new_clone(applied_connection); - dev_checkpoint->settings_connection = nm_simple_connection_new_clone( - nm_settings_connection_get_connection(settings_connection)); - dev_checkpoint->ac_version_id = - nm_active_connection_version_id_get(NM_ACTIVE_CONNECTION(act_request)); - dev_checkpoint->activation_reason = - nm_active_connection_get_activation_reason(NM_ACTIVE_CONNECTION(act_request)); - dev_checkpoint->activation_lifetime_bound_to_profile_visibility = - NM_FLAGS_HAS(nm_active_connection_get_state_flags(NM_ACTIVE_CONNECTION(act_request)), - NM_ACTIVATION_STATE_FLAG_LIFETIME_BOUND_TO_PROFILE_VISIBILITY); - } - - return dev_checkpoint; -} - -static gboolean -_timeout_cb(gpointer user_data) -{ - NMCheckpoint * self = user_data; - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - - priv->timeout_id = 0; - - if (priv->timeout_cb) - priv->timeout_cb(self, priv->timeout_data); - - /* beware, @self likely got destroyed! */ - return G_SOURCE_REMOVE; -} - -void -nm_checkpoint_adjust_rollback_timeout(NMCheckpoint *self, guint32 add_timeout) -{ - guint32 rollback_timeout_s; - gint64 now_ms, add_timeout_ms, rollback_timeout_ms; - - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - - nm_clear_g_source(&priv->timeout_id); - - if (add_timeout == 0) - rollback_timeout_s = 0; - else { - now_ms = nm_utils_get_monotonic_timestamp_msec(); - add_timeout_ms = ((gint64) add_timeout) * 1000; - rollback_timeout_ms = (now_ms - priv->created_at_ms) + add_timeout_ms; - - /* round to nearest integer second. Since NM_CHECKPOINT_ROLLBACK_TIMEOUT is - * in units seconds, it will be able to exactly express the timeout. */ - rollback_timeout_s = NM_MIN((rollback_timeout_ms + 500) / 1000, (gint64) G_MAXUINT32); - - /* we expect the timeout to be positive, because add_timeout_ms is positive. - * We cannot accept a zero, because it means "infinity". */ - nm_assert(rollback_timeout_s > 0); - - priv->timeout_id = - g_timeout_add(NM_MIN(add_timeout_ms, (gint64) G_MAXUINT32), _timeout_cb, self); - } - - if (rollback_timeout_s != priv->rollback_timeout_s) { - priv->rollback_timeout_s = rollback_timeout_s; - _notify(self, PROP_ROLLBACK_TIMEOUT); - } -} - -/*****************************************************************************/ - -static void -get_property(GObject *object, guint prop_id, GValue *value, GParamSpec *pspec) -{ - NMCheckpoint * self = NM_CHECKPOINT(object); - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - - switch (prop_id) { - case PROP_DEVICES: - nm_dbus_utils_g_value_set_object_path_from_hash(value, priv->devices, FALSE); - break; - case PROP_CREATED: - g_value_set_int64( - value, - nm_utils_monotonic_timestamp_as_boottime(priv->created_at_ms, NM_UTILS_NSEC_PER_MSEC)); - break; - case PROP_ROLLBACK_TIMEOUT: - g_value_set_uint(value, priv->rollback_timeout_s); - break; - default: - G_OBJECT_WARN_INVALID_PROPERTY_ID(object, prop_id, pspec); - break; - } -} - -/*****************************************************************************/ - -static void -nm_checkpoint_init(NMCheckpoint *self) -{ - NMCheckpointPrivate *priv; - - priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_CHECKPOINT, NMCheckpointPrivate); - - self->_priv = priv; - - c_list_init(&self->checkpoints_lst); - - priv->devices = g_hash_table_new_full(nm_direct_hash, NULL, NULL, device_checkpoint_destroy); -} - -static void -_device_removed(NMManager *manager, NMDevice *device, gpointer user_data) -{ - _move_dev_to_removed_devices(device, NM_CHECKPOINT(user_data)); -} - -NMCheckpoint * -nm_checkpoint_new(NMManager * manager, - GPtrArray * devices, - guint32 rollback_timeout_s, - NMCheckpointCreateFlags flags) -{ - NMCheckpoint * self; - NMCheckpointPrivate * priv; - NMSettingsConnection *const *con; - gint64 rollback_timeout_ms; - guint i; - - g_return_val_if_fail(manager, NULL); - g_return_val_if_fail(devices, NULL); - g_return_val_if_fail(devices->len > 0, NULL); - - self = g_object_new(NM_TYPE_CHECKPOINT, NULL); - - priv = NM_CHECKPOINT_GET_PRIVATE(self); - priv->manager = g_object_ref(manager); - priv->rollback_timeout_s = rollback_timeout_s; - priv->created_at_ms = nm_utils_get_monotonic_timestamp_msec(); - priv->flags = flags; - - if (rollback_timeout_s != 0) { - rollback_timeout_ms = ((gint64) rollback_timeout_s) * 1000; - priv->timeout_id = - g_timeout_add(NM_MIN(rollback_timeout_ms, (gint64) G_MAXUINT32), _timeout_cb, self); - } - - if (NM_FLAGS_HAS(flags, NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS)) { - priv->connection_uuids = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, NULL); - for (con = nm_settings_get_connections(NM_SETTINGS_GET, NULL); *con; con++) { - g_hash_table_add(priv->connection_uuids, - g_strdup(nm_settings_connection_get_uuid(*con))); - } - } - - for (i = 0; i < devices->len; i++) { - NMDevice *device = devices->pdata[i]; - - /* As long as the check point instance exists, it will keep a reference - * to the device also if the device gets removed (by rmmod or by deleting - * a connection profile for a software device). */ - g_hash_table_insert(priv->devices, device, device_checkpoint_create(self, device)); - } - - priv->dev_removed_id = g_signal_connect(priv->manager, - NM_MANAGER_DEVICE_REMOVED, - G_CALLBACK(_device_removed), - self); - return self; -} - -static void -dispose(GObject *object) -{ - NMCheckpoint * self = NM_CHECKPOINT(object); - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - - nm_assert(c_list_is_empty(&self->checkpoints_lst)); - - nm_clear_pointer(&priv->devices, g_hash_table_unref); - nm_clear_pointer(&priv->connection_uuids, g_hash_table_unref); - nm_clear_pointer(&priv->removed_devices, g_ptr_array_unref); - - nm_clear_g_signal_handler(priv->manager, &priv->dev_removed_id); - g_clear_object(&priv->manager); - - nm_clear_g_source(&priv->timeout_id); - - G_OBJECT_CLASS(nm_checkpoint_parent_class)->dispose(object); -} - -static const NMDBusInterfaceInfoExtended interface_info_checkpoint = { - .parent = NM_DEFINE_GDBUS_INTERFACE_INFO_INIT( - NM_DBUS_INTERFACE_CHECKPOINT, - .signals = NM_DEFINE_GDBUS_SIGNAL_INFOS(&nm_signal_info_property_changed_legacy, ), - .properties = NM_DEFINE_GDBUS_PROPERTY_INFOS( - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Devices", - "ao", - NM_CHECKPOINT_DEVICES), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("Created", "x", NM_CHECKPOINT_CREATED), - NM_DEFINE_DBUS_PROPERTY_INFO_EXTENDED_READABLE_L("RollbackTimeout", - "u", - NM_CHECKPOINT_ROLLBACK_TIMEOUT), ), ), - .legacy_property_changed = TRUE, -}; - -static void -nm_checkpoint_class_init(NMCheckpointClass *checkpoint_class) -{ - GObjectClass * object_class = G_OBJECT_CLASS(checkpoint_class); - NMDBusObjectClass *dbus_object_class = NM_DBUS_OBJECT_CLASS(checkpoint_class); - - g_type_class_add_private(object_class, sizeof(NMCheckpointPrivate)); - - dbus_object_class->export_path = NM_DBUS_EXPORT_PATH_NUMBERED(NM_DBUS_PATH "/Checkpoint"); - dbus_object_class->interface_infos = NM_DBUS_INTERFACE_INFOS(&interface_info_checkpoint); - - object_class->dispose = dispose; - object_class->get_property = get_property; - - obj_properties[PROP_DEVICES] = g_param_spec_boxed(NM_CHECKPOINT_DEVICES, - "", - "", - G_TYPE_STRV, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_CREATED] = g_param_spec_int64(NM_CHECKPOINT_CREATED, - "", - "", - G_MININT64, - G_MAXINT64, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - obj_properties[PROP_ROLLBACK_TIMEOUT] = - g_param_spec_uint(NM_CHECKPOINT_ROLLBACK_TIMEOUT, - "", - "", - 0, - G_MAXUINT32, - 0, - G_PARAM_READABLE | G_PARAM_STATIC_STRINGS); - - g_object_class_install_properties(object_class, _PROPERTY_ENUMS_LAST, obj_properties); -} |