diff options
Diffstat (limited to 'src/nm-checkpoint-manager.c')
| -rw-r--r-- | src/nm-checkpoint-manager.c | 488 |
1 files changed, 250 insertions, 238 deletions
diff --git a/src/nm-checkpoint-manager.c b/src/nm-checkpoint-manager.c index 8cc8e609..5d36213b 100644 --- a/src/nm-checkpoint-manager.c +++ b/src/nm-checkpoint-manager.c @@ -1,4 +1,4 @@ -// SPDX-License-Identifier: GPL-2.0+ +/* SPDX-License-Identifier: GPL-2.0+ */ /* * Copyright (C) 2016 Red Hat, Inc. */ @@ -18,320 +18,332 @@ /*****************************************************************************/ struct _NMCheckpointManager { - NMManager *_manager; - GParamSpec *property_spec; - CList checkpoints_lst_head; + NMManager * _manager; + GParamSpec *property_spec; + CList checkpoints_lst_head; }; -#define GET_MANAGER(self) \ - ({ \ - typeof (self) _self = (self); \ - \ - _nm_unused NMCheckpointManager *_self2 = _self; \ - \ - nm_assert (_self); \ - nm_assert (NM_IS_MANAGER (_self->_manager)); \ - _self->_manager; \ - }) +#define GET_MANAGER(self) \ + ({ \ + typeof(self) _self = (self); \ + \ + _nm_unused NMCheckpointManager *_self2 = _self; \ + \ + nm_assert(_self); \ + nm_assert(NM_IS_MANAGER(_self->_manager)); \ + _self->_manager; \ + }) /*****************************************************************************/ #define _NMLOG_DOMAIN LOGD_CORE -#define _NMLOG(level, ...) __NMLOG_DEFAULT (level, _NMLOG_DOMAIN, "checkpoint", __VA_ARGS__) +#define _NMLOG(level, ...) __NMLOG_DEFAULT(level, _NMLOG_DOMAIN, "checkpoint", __VA_ARGS__) /*****************************************************************************/ static void -notify_checkpoints (NMCheckpointManager *self) { - g_object_notify_by_pspec ((GObject *) GET_MANAGER (self), - self->property_spec); +notify_checkpoints(NMCheckpointManager *self) +{ + g_object_notify_by_pspec((GObject *) GET_MANAGER(self), self->property_spec); } static void -destroy_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint, gboolean log_destroy) +destroy_checkpoint(NMCheckpointManager *self, NMCheckpoint *checkpoint, gboolean log_destroy) { - nm_assert (NM_IS_CHECKPOINT (checkpoint)); - nm_assert (nm_dbus_object_is_exported (NM_DBUS_OBJECT (checkpoint))); - nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); + nm_assert(NM_IS_CHECKPOINT(checkpoint)); + nm_assert(nm_dbus_object_is_exported(NM_DBUS_OBJECT(checkpoint))); + nm_assert(c_list_contains(&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); - nm_checkpoint_set_timeout_callback (checkpoint, NULL, NULL); + nm_checkpoint_set_timeout_callback(checkpoint, NULL, NULL); - c_list_unlink (&checkpoint->checkpoints_lst); + c_list_unlink(&checkpoint->checkpoints_lst); - if (log_destroy) - nm_checkpoint_log_destroy (checkpoint); + if (log_destroy) + nm_checkpoint_log_destroy(checkpoint); - notify_checkpoints (self); + notify_checkpoints(self); - nm_dbus_object_unexport (NM_DBUS_OBJECT (checkpoint)); - g_object_unref (checkpoint); + nm_dbus_object_unexport(NM_DBUS_OBJECT(checkpoint)); + g_object_unref(checkpoint); } static GVariant * -rollback_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint) +rollback_checkpoint(NMCheckpointManager *self, NMCheckpoint *checkpoint) { - GVariant *result; - const CList *iter; - - nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); - - /* we destroy first all overlapping checkpoints that are younger/newer. */ - for (iter = checkpoint->checkpoints_lst.next; - iter != &self->checkpoints_lst_head; - ) { - NMCheckpoint *cp = c_list_entry (iter, NMCheckpoint, checkpoints_lst); - - iter = iter->next; - if (nm_checkpoint_includes_devices_of (cp, checkpoint)) { - /* the younger checkpoint has overlapping devices and gets obsoleted. - * Destroy it. */ - destroy_checkpoint (self, cp, TRUE); - } - } - - result = nm_checkpoint_rollback (checkpoint); - destroy_checkpoint (self, checkpoint, FALSE); - return result; + GVariant * result; + const CList *iter; + + nm_assert(c_list_contains(&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); + + /* we destroy first all overlapping checkpoints that are younger/newer. */ + for (iter = checkpoint->checkpoints_lst.next; iter != &self->checkpoints_lst_head;) { + NMCheckpoint *cp = c_list_entry(iter, NMCheckpoint, checkpoints_lst); + + iter = iter->next; + if (nm_checkpoint_includes_devices_of(cp, checkpoint)) { + /* the younger checkpoint has overlapping devices and gets obsoleted. + * Destroy it. */ + destroy_checkpoint(self, cp, TRUE); + } + } + + result = nm_checkpoint_rollback(checkpoint); + destroy_checkpoint(self, checkpoint, FALSE); + return result; } static void -rollback_timeout_cb (NMCheckpoint *checkpoint, - gpointer user_data) +rollback_timeout_cb(NMCheckpoint *checkpoint, gpointer user_data) { - NMCheckpointManager *self = user_data; - gs_unref_variant GVariant *result = NULL; + NMCheckpointManager *self = user_data; + gs_unref_variant GVariant *result = NULL; - result = rollback_checkpoint (self, checkpoint); + result = rollback_checkpoint(self, checkpoint); } NMCheckpoint * -nm_checkpoint_manager_create (NMCheckpointManager *self, - const char *const *device_paths, - guint32 rollback_timeout, - NMCheckpointCreateFlags flags, - GError **error) +nm_checkpoint_manager_create(NMCheckpointManager * self, + const char *const * device_paths, + guint32 rollback_timeout, + NMCheckpointCreateFlags flags, + GError ** error) { - NMManager *manager; - NMCheckpoint *checkpoint; - gs_unref_ptrarray GPtrArray *devices = NULL; - NMDevice *device; - - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); - manager = GET_MANAGER (self); - - devices = g_ptr_array_new (); - - if (!device_paths || !device_paths[0]) { - const CList *tmp_lst; - - nm_manager_for_each_device (manager, device, tmp_lst) { - /* FIXME: there is no strong reason to skip over unrealized devices. - * Also, NMCheckpoint anticipates to handle them (in parts). */ - if (!nm_device_is_real (device)) - continue; - nm_assert (nm_dbus_object_get_path (NM_DBUS_OBJECT (device))); - g_ptr_array_add (devices, device); - } - } else if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { - g_set_error_literal (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, - "the DISCONNECT_NEW_DEVICES flag can only be used with an empty device list"); - return NULL; - } else { - for (; *device_paths; device_paths++) { - device = nm_manager_get_device_by_path (manager, *device_paths); - if (!device) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "device %s does not exist", *device_paths); - return NULL; - } - if (!nm_device_is_real (device)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE, - "device %s is not realized", *device_paths); - return NULL; - } - g_ptr_array_add (devices, device); - } - } - - if (!devices->len) { - g_set_error_literal (error, - NM_MANAGER_ERROR, - NM_MANAGER_ERROR_INVALID_ARGUMENTS, - "no device available"); - return NULL; - } - - if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) - nm_checkpoint_manager_destroy_all (self); - else if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING)) { - c_list_for_each_entry (checkpoint, &self->checkpoints_lst_head, checkpoints_lst) { - device = nm_checkpoint_includes_devices (checkpoint, (NMDevice *const*) devices->pdata, devices->len); - if (device) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, - "device '%s' is already included in checkpoint %s", - nm_device_get_iface (device), - nm_dbus_object_get_path (NM_DBUS_OBJECT (checkpoint))); - return NULL; - } - } - } - - checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags); - - nm_dbus_object_export (NM_DBUS_OBJECT (checkpoint)); - - nm_checkpoint_set_timeout_callback (checkpoint, rollback_timeout_cb, self); - c_list_link_tail (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst); - notify_checkpoints (self); - return checkpoint; + NMManager * manager; + NMCheckpoint * checkpoint; + gs_unref_ptrarray GPtrArray *devices = NULL; + NMDevice * device; + + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); + manager = GET_MANAGER(self); + + devices = g_ptr_array_new(); + + if (!device_paths || !device_paths[0]) { + const CList *tmp_lst; + + nm_manager_for_each_device (manager, device, tmp_lst) { + /* FIXME: there is no strong reason to skip over unrealized devices. + * Also, NMCheckpoint anticipates to handle them (in parts). */ + if (!nm_device_is_real(device)) + continue; + nm_assert(nm_dbus_object_get_path(NM_DBUS_OBJECT(device))); + g_ptr_array_add(devices, device); + } + } else if (NM_FLAGS_HAS(flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) { + g_set_error_literal( + error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "the DISCONNECT_NEW_DEVICES flag can only be used with an empty device list"); + return NULL; + } else { + for (; *device_paths; device_paths++) { + device = nm_manager_get_device_by_path(manager, *device_paths); + if (!device) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "device %s does not exist", + *device_paths); + return NULL; + } + if (!nm_device_is_real(device)) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "device %s is not realized", + *device_paths); + return NULL; + } + g_ptr_array_add(devices, device); + } + } + + if (!devices->len) { + g_set_error_literal(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "no device available"); + return NULL; + } + + if (NM_FLAGS_HAS(flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) + nm_checkpoint_manager_destroy_all(self); + else if (!NM_FLAGS_HAS(flags, NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING)) { + c_list_for_each_entry (checkpoint, &self->checkpoints_lst_head, checkpoints_lst) { + device = nm_checkpoint_includes_devices(checkpoint, + (NMDevice *const *) devices->pdata, + devices->len); + if (device) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "device '%s' is already included in checkpoint %s", + nm_device_get_iface(device), + nm_dbus_object_get_path(NM_DBUS_OBJECT(checkpoint))); + return NULL; + } + } + } + + checkpoint = nm_checkpoint_new(manager, devices, rollback_timeout, flags); + + nm_dbus_object_export(NM_DBUS_OBJECT(checkpoint)); + + nm_checkpoint_set_timeout_callback(checkpoint, rollback_timeout_cb, self); + c_list_link_tail(&self->checkpoints_lst_head, &checkpoint->checkpoints_lst); + notify_checkpoints(self); + return checkpoint; } void -nm_checkpoint_manager_destroy_all (NMCheckpointManager *self) +nm_checkpoint_manager_destroy_all(NMCheckpointManager *self) { - NMCheckpoint *checkpoint; + NMCheckpoint *checkpoint; - g_return_if_fail (self); + g_return_if_fail(self); - while ((checkpoint = c_list_first_entry (&self->checkpoints_lst_head, NMCheckpoint, checkpoints_lst))) - destroy_checkpoint (self, checkpoint, TRUE); + while ((checkpoint = + c_list_first_entry(&self->checkpoints_lst_head, NMCheckpoint, checkpoints_lst))) + destroy_checkpoint(self, checkpoint, TRUE); } gboolean -nm_checkpoint_manager_destroy (NMCheckpointManager *self, - const char *path, - GError **error) +nm_checkpoint_manager_destroy(NMCheckpointManager *self, const char *path, GError **error) { - NMCheckpoint *checkpoint; + NMCheckpoint *checkpoint; - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (path && path[0] == '/', FALSE); - g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(path && path[0] == '/', FALSE); + g_return_val_if_fail(!error || !*error, FALSE); - if (!nm_dbus_path_not_empty (path)) { - nm_checkpoint_manager_destroy_all (self); - return TRUE; - } + if (!nm_dbus_path_not_empty(path)) { + nm_checkpoint_manager_destroy_all(self); + return TRUE; + } - checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error); - if (!checkpoint) - return FALSE; + checkpoint = nm_checkpoint_manager_lookup_by_path(self, path, error); + if (!checkpoint) + return FALSE; - destroy_checkpoint (self, checkpoint, TRUE); - return TRUE; + destroy_checkpoint(self, checkpoint, TRUE); + return TRUE; } gboolean -nm_checkpoint_manager_rollback (NMCheckpointManager *self, - const char *path, - GVariant **results, - GError **error) +nm_checkpoint_manager_rollback(NMCheckpointManager *self, + const char * path, + GVariant ** results, + GError ** error) { - NMCheckpoint *checkpoint; + NMCheckpoint *checkpoint; - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (path && path[0] == '/', FALSE); - g_return_val_if_fail (results, FALSE); - g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(path && path[0] == '/', FALSE); + g_return_val_if_fail(results, FALSE); + g_return_val_if_fail(!error || !*error, FALSE); - checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error); - if (!checkpoint) - return FALSE; + checkpoint = nm_checkpoint_manager_lookup_by_path(self, path, error); + if (!checkpoint) + return FALSE; - *results = rollback_checkpoint (self, checkpoint); - return TRUE; + *results = rollback_checkpoint(self, checkpoint); + return TRUE; } NMCheckpoint * -nm_checkpoint_manager_lookup_by_path (NMCheckpointManager *self, const char *path, GError **error) +nm_checkpoint_manager_lookup_by_path(NMCheckpointManager *self, const char *path, GError **error) { - NMCheckpoint *checkpoint; - - g_return_val_if_fail (self, NULL); - - checkpoint = nm_dbus_manager_lookup_object (nm_dbus_object_get_manager (NM_DBUS_OBJECT (GET_MANAGER (self))), - path); - if ( !checkpoint - || !NM_IS_CHECKPOINT (checkpoint)) { - g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, - "checkpoint %s does not exist", path); - return NULL; - } - - nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); - return checkpoint; + NMCheckpoint *checkpoint; + + g_return_val_if_fail(self, NULL); + + checkpoint = + nm_dbus_manager_lookup_object(nm_dbus_object_get_manager(NM_DBUS_OBJECT(GET_MANAGER(self))), + path); + if (!checkpoint || !NM_IS_CHECKPOINT(checkpoint)) { + g_set_error(error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "checkpoint %s does not exist", + path); + return NULL; + } + + nm_assert(c_list_contains(&self->checkpoints_lst_head, &checkpoint->checkpoints_lst)); + return checkpoint; } const char ** -nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self, guint *out_length) +nm_checkpoint_manager_get_checkpoint_paths(NMCheckpointManager *self, guint *out_length) { - NMCheckpoint *checkpoint; - const char **strv; - guint num, i = 0; - - num = c_list_length (&self->checkpoints_lst_head); - NM_SET_OUT (out_length, num); - if (!num) - return NULL; - - strv = g_new (const char *, num + 1); - c_list_for_each_entry (checkpoint, &self->checkpoints_lst_head, checkpoints_lst) - strv[i++] = nm_dbus_object_get_path (NM_DBUS_OBJECT (checkpoint)); - nm_assert (i == num); - strv[i] = NULL; - return strv; + NMCheckpoint *checkpoint; + const char ** strv; + guint num, i = 0; + + num = c_list_length(&self->checkpoints_lst_head); + NM_SET_OUT(out_length, num); + if (!num) + return NULL; + + strv = g_new(const char *, num + 1); + c_list_for_each_entry (checkpoint, &self->checkpoints_lst_head, checkpoints_lst) + strv[i++] = nm_dbus_object_get_path(NM_DBUS_OBJECT(checkpoint)); + nm_assert(i == num); + strv[i] = NULL; + return strv; } gboolean -nm_checkpoint_manager_adjust_rollback_timeout (NMCheckpointManager *self, - const char *path, - guint32 add_timeout, - GError **error) +nm_checkpoint_manager_adjust_rollback_timeout(NMCheckpointManager *self, + const char * path, + guint32 add_timeout, + GError ** error) { - NMCheckpoint *checkpoint; + NMCheckpoint *checkpoint; - g_return_val_if_fail (self, FALSE); - g_return_val_if_fail (path && path[0] == '/', FALSE); - g_return_val_if_fail (!error || !*error, FALSE); + g_return_val_if_fail(self, FALSE); + g_return_val_if_fail(path && path[0] == '/', FALSE); + g_return_val_if_fail(!error || !*error, FALSE); - checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error); - if (!checkpoint) - return FALSE; + checkpoint = nm_checkpoint_manager_lookup_by_path(self, path, error); + if (!checkpoint) + return FALSE; - nm_checkpoint_adjust_rollback_timeout (checkpoint, add_timeout); - return TRUE; + nm_checkpoint_adjust_rollback_timeout(checkpoint, add_timeout); + return TRUE; } /*****************************************************************************/ NMCheckpointManager * -nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec) +nm_checkpoint_manager_new(NMManager *manager, GParamSpec *spec) { - NMCheckpointManager *self; - - g_return_val_if_fail (NM_IS_MANAGER (manager), FALSE); - - self = g_slice_new0 (NMCheckpointManager); - - /* the NMCheckpointManager instance is actually owned by NMManager. - * Thus, we cannot take a reference to it, and we also don't bother - * taking a weak-reference. Instead let GET_MANAGER() assert that - * self->_manager is alive -- which we always expect as the lifetime - * of NMManager shall surpass the lifetime of the NMCheckpointManager - * instance. */ - self->_manager = manager; - self->property_spec = spec; - c_list_init (&self->checkpoints_lst_head); - return self; + NMCheckpointManager *self; + + g_return_val_if_fail(NM_IS_MANAGER(manager), FALSE); + + self = g_slice_new0(NMCheckpointManager); + + /* the NMCheckpointManager instance is actually owned by NMManager. + * Thus, we cannot take a reference to it, and we also don't bother + * taking a weak-reference. Instead let GET_MANAGER() assert that + * self->_manager is alive -- which we always expect as the lifetime + * of NMManager shall surpass the lifetime of the NMCheckpointManager + * instance. */ + self->_manager = manager; + self->property_spec = spec; + c_list_init(&self->checkpoints_lst_head); + return self; } void -nm_checkpoint_manager_free (NMCheckpointManager *self) +nm_checkpoint_manager_free(NMCheckpointManager *self) { - if (!self) - return; + if (!self) + return; - nm_checkpoint_manager_destroy_all (self); - g_slice_free (NMCheckpointManager, self); + nm_checkpoint_manager_destroy_all(self); + g_slice_free(NMCheckpointManager, self); } |