summaryrefslogtreecommitdiff
path: root/src/nm-checkpoint-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/nm-checkpoint-manager.c')
-rw-r--r--src/nm-checkpoint-manager.c138
1 files changed, 105 insertions, 33 deletions
diff --git a/src/nm-checkpoint-manager.c b/src/nm-checkpoint-manager.c
index 033c11cc43..a205854be4 100644
--- a/src/nm-checkpoint-manager.c
+++ b/src/nm-checkpoint-manager.c
@@ -29,12 +29,15 @@
#include "nm-exported-object.h"
#include "nm-manager.h"
#include "nm-utils.h"
+#include "nm-utils/c-list.h"
/*****************************************************************************/
struct _NMCheckpointManager {
NMManager *_manager;
+ GParamSpec *property_spec;
GHashTable *checkpoints;
+ CList list;
guint rollback_timeout_id;
};
@@ -56,52 +59,71 @@ struct _NMCheckpointManager {
/*****************************************************************************/
+typedef struct {
+ CList list;
+ NMCheckpoint *checkpoint;
+} CheckpointItem;
+
static void update_rollback_timeout (NMCheckpointManager *self);
static void
-checkpoint_destroy (gpointer checkpoint)
+notify_checkpoints (NMCheckpointManager *self) {
+ g_object_notify_by_pspec ((GObject *) GET_MANAGER (self),
+ self->property_spec);
+}
+
+static void
+item_destroy (gpointer data)
{
- nm_exported_object_unexport (NM_EXPORTED_OBJECT (checkpoint));
- g_object_unref (G_OBJECT (checkpoint));
+ CheckpointItem *item = data;
+
+ c_list_unlink (&item->list);
+ nm_exported_object_unexport (NM_EXPORTED_OBJECT (item->checkpoint));
+ g_object_unref (G_OBJECT (item->checkpoint));
+ g_slice_free (CheckpointItem, item);
}
static gboolean
rollback_timeout_cb (NMCheckpointManager *self)
{
- NMCheckpoint *checkpoint;
- GHashTableIter iter;
+ CheckpointItem *item, *safe;
GVariant *result;
gint64 ts, now;
+ const char *path;
+ gboolean removed = FALSE;
now = nm_utils_get_monotonic_timestamp_ms ();
- g_hash_table_iter_init (&iter, self->checkpoints);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) {
- ts = nm_checkpoint_get_rollback_ts (checkpoint);
+ c_list_for_each_entry_safe (item, safe, &self->list, list) {
+ ts = nm_checkpoint_get_rollback_ts (item->checkpoint);
if (ts && ts <= now) {
- result = nm_checkpoint_rollback (checkpoint);
+ result = nm_checkpoint_rollback (item->checkpoint);
if (result)
g_variant_unref (result);
- g_hash_table_iter_remove (&iter);
+ path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (item->checkpoint));
+ if (!g_hash_table_remove (self->checkpoints, path))
+ nm_assert_not_reached();
+ removed = TRUE;
}
}
self->rollback_timeout_id = 0;
update_rollback_timeout (self);
+ if (removed)
+ notify_checkpoints (self);
+
return G_SOURCE_REMOVE;
}
static void
update_rollback_timeout (NMCheckpointManager *self)
{
- NMCheckpoint *checkpoint;
- GHashTableIter iter;
+ CheckpointItem *item;
gint64 ts, delta, next = G_MAXINT64;
- g_hash_table_iter_init (&iter, self->checkpoints);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) {
- ts = nm_checkpoint_get_rollback_ts (checkpoint);
+ c_list_for_each_entry (item, &self->list, list) {
+ ts = nm_checkpoint_get_rollback_ts (item->checkpoint);
if (ts && ts < next)
next = ts;
}
@@ -120,13 +142,11 @@ update_rollback_timeout (NMCheckpointManager *self)
static NMCheckpoint *
find_checkpoint_for_device (NMCheckpointManager *self, NMDevice *device)
{
- GHashTableIter iter;
- NMCheckpoint *checkpoint;
+ CheckpointItem *item;
- g_hash_table_iter_init (&iter, self->checkpoints);
- while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &checkpoint)) {
- if (nm_checkpoint_includes_device (checkpoint, device))
- return checkpoint;
+ c_list_for_each_entry (item, &self->list, list) {
+ if (nm_checkpoint_includes_device (item->checkpoint, device))
+ return item->checkpoint;
}
return NULL;
@@ -141,6 +161,7 @@ nm_checkpoint_manager_create (NMCheckpointManager *self,
{
NMManager *manager;
NMCheckpoint *checkpoint;
+ CheckpointItem *item;
const char * const *path;
gs_unref_ptrarray GPtrArray *devices = NULL;
NMDevice *device;
@@ -153,7 +174,23 @@ nm_checkpoint_manager_create (NMCheckpointManager *self,
manager = GET_MANAGER (self);
if (!device_paths || !device_paths[0]) {
- device_paths_free = nm_manager_get_device_paths (manager);
+ const char *device_path;
+ const GSList *iter;
+ GPtrArray *paths;
+
+ paths = g_ptr_array_new ();
+ for (iter = nm_manager_get_devices (manager);
+ iter;
+ iter = g_slist_next (iter)) {
+ device = NM_DEVICE (iter->data);
+ if (!nm_device_is_real (device))
+ continue;
+ device_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (device));
+ if (device_path)
+ g_ptr_array_add (paths, (gpointer) device_path);
+ }
+ g_ptr_array_add (paths, NULL);
+ device_paths_free = (const char **) g_ptr_array_free (paths, FALSE);
device_paths = (const char *const *) device_paths_free;
} 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,
@@ -175,10 +212,12 @@ nm_checkpoint_manager_create (NMCheckpointManager *self,
if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) {
for (i = 0; i < devices->len; i++) {
device = devices->pdata[i];
- if (find_checkpoint_for_device (self, device)) {
+ checkpoint = find_checkpoint_for_device (self, device);
+ if (checkpoint) {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS,
- "a checkpoint for device '%s' already exists",
- nm_device_get_iface (device));
+ "device '%s' is already included in checkpoint %s",
+ nm_device_get_iface (device),
+ nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint)));
return NULL;
}
}
@@ -194,11 +233,16 @@ nm_checkpoint_manager_create (NMCheckpointManager *self,
nm_exported_object_export (NM_EXPORTED_OBJECT (checkpoint));
checkpoint_path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (checkpoint));
+ item = g_slice_new0 (CheckpointItem);
+ item->checkpoint = checkpoint;
+ c_list_link_tail (&self->list, &item->list);
+
if (!nm_g_hash_table_insert (self->checkpoints,
(gpointer) checkpoint_path,
- checkpoint))
+ item))
g_return_val_if_reached (NULL);
+ notify_checkpoints (self);
update_rollback_timeout (self);
return checkpoint;
@@ -211,6 +255,7 @@ nm_checkpoint_manager_destroy_all (NMCheckpointManager *self,
g_return_val_if_fail (self, FALSE);
g_hash_table_remove_all (self->checkpoints);
+ notify_checkpoints (self);
return TRUE;
}
@@ -228,7 +273,9 @@ nm_checkpoint_manager_destroy (NMCheckpointManager *self,
if (!nm_streq (checkpoint_path, "/")) {
ret = g_hash_table_remove (self->checkpoints, checkpoint_path);
- if (!ret) {
+ if (ret) {
+ notify_checkpoints (self);
+ } else {
g_set_error (error,
NM_MANAGER_ERROR,
NM_MANAGER_ERROR_INVALID_ARGUMENTS,
@@ -245,30 +292,53 @@ nm_checkpoint_manager_rollback (NMCheckpointManager *self,
GVariant **results,
GError **error)
{
- NMCheckpoint *cp;
+ CheckpointItem *item;
g_return_val_if_fail (self, FALSE);
g_return_val_if_fail (checkpoint_path && checkpoint_path[0] == '/', FALSE);
g_return_val_if_fail (results, FALSE);
g_return_val_if_fail (!error || !*error, FALSE);
- cp = g_hash_table_lookup (self->checkpoints, checkpoint_path);
- if (!cp) {
+ item = g_hash_table_lookup (self->checkpoints, checkpoint_path);
+ if (!item) {
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
"checkpoint %s does not exist", checkpoint_path);
return FALSE;
}
- *results = nm_checkpoint_rollback (cp);
+ *results = nm_checkpoint_rollback (item->checkpoint);
g_hash_table_remove (self->checkpoints, checkpoint_path);
+ notify_checkpoints (self);
return TRUE;
}
+char **
+nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self)
+{
+ CheckpointItem *item;
+ char **strv;
+ guint num, i = 0;
+
+ num = g_hash_table_size (self->checkpoints);
+ if (!num) {
+ nm_assert (c_list_is_empty (&self->list));
+ return NULL;
+ }
+
+ strv = g_new (char *, num + 1);
+ c_list_for_each_entry (item, &self->list, list)
+ strv[i++] = g_strdup (nm_exported_object_get_path (NM_EXPORTED_OBJECT (item->checkpoint)));
+ nm_assert (i == num);
+ strv[i] = NULL;
+
+ return strv;
+}
+
/*****************************************************************************/
NMCheckpointManager *
-nm_checkpoint_manager_new (NMManager *manager)
+nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec)
{
NMCheckpointManager *self;
@@ -284,7 +354,9 @@ nm_checkpoint_manager_new (NMManager *manager)
* instance. */
self->_manager = manager;
self->checkpoints = g_hash_table_new_full (nm_str_hash, g_str_equal,
- NULL, checkpoint_destroy);
+ NULL, item_destroy);
+ self->property_spec = spec;
+ c_list_init (&self->list);
return self;
}