diff options
Diffstat (limited to 'src/nm-checkpoint.c')
-rw-r--r-- | src/nm-checkpoint.c | 1244 |
1 files changed, 624 insertions, 620 deletions
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c index 6851710c54..7706dddf9b 100644 --- a/src/nm-checkpoint.c +++ b/src/nm-checkpoint.c @@ -22,765 +22,769 @@ /*****************************************************************************/ 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; + 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, -); +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; + /* 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; + NMDBusObjectClass parent; }; -G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_DBUS_OBJECT) +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 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 +#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) +nm_checkpoint_log_destroy(NMCheckpoint *self) { - _LOGI ("destroy %s", nm_dbus_object_get_path (NM_DBUS_OBJECT (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) +nm_checkpoint_set_timeout_callback(NMCheckpoint * self, + NMCheckpointTimeoutCallback callback, + gpointer user_data) { - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - /* in glib world, we would have a GSignal for this. But as there + /* 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; + priv->timeout_cb = callback; + priv->timeout_data = user_data; } NMDevice * -nm_checkpoint_includes_devices (NMCheckpoint *self, NMDevice *const*devices, guint n_devices) +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; + 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) +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; + 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) +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; + 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) +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 + 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 + 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; + 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) +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; - } + 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); - } - } + 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); + 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) +device_checkpoint_destroy(gpointer data) { - DeviceCheckpoint *dev_checkpoint = 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); + 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); + g_slice_free(DeviceCheckpoint, dev_checkpoint); } static void -_move_dev_to_removed_devices (NMDevice *device, - NMCheckpoint *checkpoint) +_move_dev_to_removed_devices(NMDevice *device, NMCheckpoint *checkpoint) { - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (checkpoint); - DeviceCheckpoint *dev_checkpoint; + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(checkpoint); + DeviceCheckpoint * dev_checkpoint; - g_return_if_fail (device); + g_return_if_fail(device); - dev_checkpoint = g_hash_table_lookup (priv->devices, device); - if (!dev_checkpoint) - return; + 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); + 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); + 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); + _notify(checkpoint, PROP_DEVICES); } static void -_dev_exported_changed (NMDBusObject *obj, - NMCheckpoint *checkpoint) +_dev_exported_changed(NMDBusObject *obj, NMCheckpoint *checkpoint) { - - _move_dev_to_removed_devices (NM_DEVICE (obj), checkpoint); + _move_dev_to_removed_devices(NM_DEVICE(obj), checkpoint); } static DeviceCheckpoint * -device_checkpoint_create (NMCheckpoint *checkpoint, NMDevice *device) +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; + 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) +_timeout_cb(gpointer user_data) { - NMCheckpoint *self = user_data; - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); + NMCheckpoint * self = user_data; + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - priv->timeout_id = 0; + priv->timeout_id = 0; - if (priv->timeout_cb) - priv->timeout_cb (self, priv->timeout_data); + if (priv->timeout_cb) + priv->timeout_cb(self, priv->timeout_data); - /* beware, @self likely got destroyed! */ - return G_SOURCE_REMOVE; + /* beware, @self likely got destroyed! */ + return G_SOURCE_REMOVE; } void -nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout) +nm_checkpoint_adjust_rollback_timeout(NMCheckpoint *self, guint32 add_timeout) { - guint32 rollback_timeout_s; - gint64 now_ms, add_timeout_ms, rollback_timeout_ms; + guint32 rollback_timeout_s; + gint64 now_ms, add_timeout_ms, rollback_timeout_ms; - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - nm_clear_g_source (&priv->timeout_id); + 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; + 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 + /* 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); + 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 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); + nm_assert(rollback_timeout_s > 0); - priv->timeout_id = g_timeout_add (NM_MIN (add_timeout_ms, (gint64) G_MAXUINT32), - _timeout_cb, - self); - } + 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); - } + 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) +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; - } + 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) +nm_checkpoint_init(NMCheckpoint *self) { - NMCheckpointPrivate *priv; + NMCheckpointPrivate *priv; - priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_CHECKPOINT, NMCheckpointPrivate); + priv = G_TYPE_INSTANCE_GET_PRIVATE(self, NM_TYPE_CHECKPOINT, NMCheckpointPrivate); - self->_priv = priv; + self->_priv = priv; - c_list_init (&self->checkpoints_lst); + c_list_init(&self->checkpoints_lst); - priv->devices = g_hash_table_new_full (nm_direct_hash, NULL, - NULL, device_checkpoint_destroy); + 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) +_device_removed(NMManager *manager, NMDevice *device, gpointer user_data) { - _move_dev_to_removed_devices (device, NM_CHECKPOINT (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) +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 + 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; + 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) +dispose(GObject *object) { - NMCheckpoint *self = NM_CHECKPOINT (object); - NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self); + NMCheckpoint * self = NM_CHECKPOINT(object); + NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE(self); - nm_assert (c_list_is_empty (&self->checkpoints_lst)); + 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_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_signal_handler(priv->manager, &priv->dev_removed_id); + g_clear_object(&priv->manager); - nm_clear_g_source (&priv->timeout_id); + nm_clear_g_source(&priv->timeout_id); - G_OBJECT_CLASS (nm_checkpoint_parent_class)->dispose (object); + 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, + .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) +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); + 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); } |