diff options
author | Beniamino Galvani <bgalvani@redhat.com> | 2016-07-01 12:11:01 +0200 |
---|---|---|
committer | Beniamino Galvani <bgalvani@redhat.com> | 2016-07-14 14:30:14 +0200 |
commit | 05c2c389bc4f331b037648fea49212b479fe02ea (patch) | |
tree | 5d8acb74eef8ece60945dec39435c3e11f18d27c | |
parent | df73cf4f64c9391592f92488df019387672003b3 (diff) | |
download | NetworkManager-05c2c389bc4f331b037648fea49212b479fe02ea.tar.gz |
checkpoint: add create, rollback and destroy D-Bus API
Co-authored-by: Thomas Haller <thaller@redhat.com>
-rw-r--r-- | introspection/nm-manager.xml | 40 | ||||
-rw-r--r-- | libnm-core/nm-dbus-interface.h | 16 | ||||
-rw-r--r-- | src/Makefile.am | 4 | ||||
-rw-r--r-- | src/nm-checkpoint-manager.c | 476 | ||||
-rw-r--r-- | src/nm-checkpoint-manager.h | 48 | ||||
-rw-r--r-- | src/nm-manager.c | 109 | ||||
-rw-r--r-- | src/nm-manager.h | 2 |
7 files changed, 693 insertions, 2 deletions
diff --git a/introspection/nm-manager.xml b/introspection/nm-manager.xml index ea368ba331..01e946a38c 100644 --- a/introspection/nm-manager.xml +++ b/introspection/nm-manager.xml @@ -206,6 +206,46 @@ </method> <!-- + CheckpointCreate: + + @devices: a list of device paths for which a checkpoint should be created. An empty list means all managed devices. + @rollback_timeout: the time in seconds until NetworkManager will automatically rollback to the checkpoint. Set to zero for infinite. + @flags: optional flags that influence the creation + @checkpoint_id: on success, returns the ID of the checkpoint. This ID can be used to rollback or destroy the checkpoint later. + + Create a checkpoint of the current networking configuration + for given interfaces. If @rollback_timeout is not zero, a + rollback is automatically performed after the given timeout. + --> + <method name="CheckpointCreate"> + <arg name="devices" type="ao" direction="in"/> + <arg name="rollback_timeout" type="u" direction="in"/> + <arg name="flags" type="u" direction="in"/> + + <arg name="checkpoint_id" type="s" direction="out"/> + </method> + + <!-- + CheckpointDestroy: + @checkpoint_id: ID of the checkpoint. Set to an empty string to cancel all pending checkpoints. + + Destroy a previously created checkpoint. + --> + <method name="CheckpointDestroy"> + <arg name="checkpoint_id" type="s" direction="in"/> + </method> + + <!-- + CheckpointRollback: + @checkpoint_id: ID of the checkpoint. + + Rollback a checkpoint before the timeout is reached. + --> + <method name="CheckpointRollback"> + <arg name="checkpoint_id" type="s" direction="in"/> + </method> + + <!-- Devices: The list of realized network devices. Realized devices are those which diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h index 1e0fbe68b6..a4a1e4ad64 100644 --- a/libnm-core/nm-dbus-interface.h +++ b/libnm-core/nm-dbus-interface.h @@ -689,4 +689,20 @@ typedef enum { NM_IP_TUNNEL_MODE_VTI6 = 9, } NMIPTunnelMode; + +/** + * NMCheckpointCreateFlags: + * @NM_CHECKPOINT_CREATE_FLAG_NONE: no flags + * @NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL: when creating + * a new checkpoint, destroy all existing ones. + * + * The flags for CheckpointCreate call + * + * Since: 1.4 + */ +typedef enum { /*< skip >*/ + NM_CHECKPOINT_CREATE_FLAG_NONE = 0, + NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL = 0x01, +} NMCheckpointCreateFlags; + #endif /* __NM_DBUS_INTERFACE_H__ */ diff --git a/src/Makefile.am b/src/Makefile.am index 84ef1346c0..389ca0a7a6 100644 --- a/src/Makefile.am +++ b/src/Makefile.am @@ -292,6 +292,10 @@ libNetworkManager_la_SOURCES = \ \ dhcp-manager/nm-dhcp-dhclient-utils.c \ dhcp-manager/nm-dhcp-dhclient-utils.h \ + \ + nm-checkpoint-manager.c \ + nm-checkpoint-manager.h \ + \ devices/nm-device.c \ devices/nm-device.h \ devices/nm-lldp-listener.c \ diff --git a/src/nm-checkpoint-manager.c b/src/nm-checkpoint-manager.c new file mode 100644 index 0000000000..186e540ed4 --- /dev/null +++ b/src/nm-checkpoint-manager.c @@ -0,0 +1,476 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2016 Red Hat, Inc. + */ + +#include "nm-default.h" + +#include "nm-checkpoint-manager.h" + +#include "nm-auth-subject.h" +#include "nm-connection.h" +#include "nm-core-utils.h" +#include "nm-device.h" +#include "nm-manager.h" +#include "nm-exported-object.h" +#include "nm-settings.h" +#include "nm-simple-connection.h" +#include "nm-utils.h" + +/*****************************************************************************/ + +struct _NMCheckpointManager { + NMManager *_manager; + GHashTable *checkpoints; + guint rollback_timeout_id; +}; + +#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_PREFIX_NAME "checkpoint" +#define _NMLOG_DOMAIN LOGD_CORE + +#define _NMLOG(level, ...) \ + nm_log (level, _NMLOG_DOMAIN, \ + "%s: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)) + +/*****************************************************************************/ + +typedef struct { + char *dev_path; + NMConnection *connection; +} DeviceCheckpoint; + +typedef struct { + char *id; + gint64 rollback_ts; + GHashTable *devices; +} Checkpoint; + +static void update_rollback_timeout (NMCheckpointManager *self); + +static void +device_checkpoint_destroy (gpointer data) +{ + DeviceCheckpoint *dev_cp = data; + + g_free (dev_cp->dev_path); + g_clear_object (&dev_cp->connection); + g_slice_free (DeviceCheckpoint, dev_cp); +} + +static void +checkpoint_destroy (gpointer data) +{ + Checkpoint *cp = data; + + g_free (cp->id); + g_hash_table_destroy (cp->devices); + g_slice_free (Checkpoint, cp); +} + +static gboolean +do_rollback (NMCheckpointManager *self, Checkpoint *cp, GError **error) +{ + DeviceCheckpoint *dev_cp; + GHashTableIter iter; + const char *path; + NMSettingsConnection *connection; + NMDevice *device; + GError *local_error = NULL; + gboolean success = TRUE; + + _LOGI ("rollback of checkpoint %s", cp->id); + + /* Start rolling-back each device */ + g_hash_table_iter_init (&iter, cp->devices); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &dev_cp)) { + gs_unref_object NMAuthSubject *subject = NULL; + + device = nm_manager_get_device_by_path (self->_manager, dev_cp->dev_path); + if (!device) { + _LOGD ("device %s no longer exists", dev_cp->dev_path); + success = FALSE; + } + + _LOGD ("restoring state of device %s", nm_device_get_iface (device)); + + if (dev_cp->connection) { + /* The device had an active connection, check if the + * connection still exists + * */ + path = nm_connection_get_path (dev_cp->connection); + connection = nm_settings_get_connection_by_path (nm_settings_get(), path); + + if (connection) { + /* If the connection is still there, restore its content + * and save it + * */ + _LOGD ("connection %s still exists", path); + + nm_connection_replace_settings_from_connection (NM_CONNECTION (connection), + dev_cp->connection); + nm_settings_connection_commit_changes (connection, + NM_SETTINGS_CONNECTION_COMMIT_REASON_NONE, + NULL, + NULL); + } else { + /* The connection was deleted, recreate it */ + + _LOGD ("adding connection %s again", path); + + connection = nm_settings_add_connection (nm_settings_get (), + dev_cp->connection, + TRUE, + &local_error); + if (!connection) { + _LOGW ("connection add failure: %s", local_error->message); + g_clear_error (&local_error); + success = FALSE; + continue; + } + } + + /* Now re-activate the connection */ + subject = nm_auth_subject_new_internal (); + if (!nm_manager_activate_connection (self->_manager, + connection, + NULL, + device, + subject, + &local_error)) { + _LOGW ("reactivation of connection %s/%s failed: %s", + nm_connection_get_id ((NMConnection *) connection), + nm_connection_get_uuid ((NMConnection * ) connection), + local_error->message); + g_clear_error (&local_error); + success = FALSE; + continue; + } + } else { + + /* The device was disconnected, deactivate any existing connection */ + + _LOGD ("disconnecting device %s", nm_device_get_iface (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); + } + } + } + + return success; +} + + +static gboolean +rollback_timeout_cb (NMCheckpointManager *self) +{ + GHashTableIter iter; + Checkpoint *cp; + gint64 now; + + now = nm_utils_get_monotonic_timestamp_ms (); + + g_hash_table_iter_init (&iter, self->checkpoints); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cp)) { + if (cp->rollback_ts <= now) { + do_rollback (self, cp, NULL); + g_hash_table_iter_remove (&iter); + } + } + + self->rollback_timeout_id = 0; + update_rollback_timeout (self); + + return FALSE; +} + +static void +update_rollback_timeout (NMCheckpointManager *self) +{ + GHashTableIter iter; + Checkpoint *cp; + gint64 delta, next = G_MAXINT64; + + g_hash_table_iter_init (&iter, self->checkpoints); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cp)) { + if (cp->rollback_ts && cp->rollback_ts < next) + next = cp->rollback_ts; + } + + nm_clear_g_source (&self->rollback_timeout_id); + + if (next != G_MAXINT64) { + delta = MAX (next - nm_utils_get_monotonic_timestamp_ms (), 0); + self->rollback_timeout_id = g_timeout_add (delta, + (GSourceFunc) rollback_timeout_cb, + self); + _LOGT ("update timeout: next check in %" G_GINT64_FORMAT " ms", delta); + } +} + +static Checkpoint * +find_checkpoint_for_device (NMCheckpointManager *self, const char *dev_path) +{ + GHashTableIter iter; + Checkpoint *cp; + DeviceCheckpoint *dev_cp; + + g_hash_table_iter_init (&iter, self->checkpoints); + while (g_hash_table_iter_next (&iter, NULL, (gpointer *) &cp)) { + dev_cp = g_hash_table_lookup (cp->devices, dev_path); + if (dev_cp) + return cp; + } + + return NULL; +} + +static DeviceCheckpoint * +device_checkpoint_create (NMCheckpointManager *self, + const char *dev_path, + GError **error) +{ + NMDevice *device; + NMConnection *connection; + DeviceCheckpoint *cp; + + device = nm_manager_get_device_by_path (self->_manager, dev_path); + if (!device) { + g_set_error (error, + NM_MANAGER_ERROR, + NM_MANAGER_ERROR_UNKNOWN_DEVICE, + "unknown device '%s'", dev_path); + return NULL; + } + + cp = g_slice_new0 (DeviceCheckpoint); + cp->dev_path = g_strdup (dev_path); + + connection = nm_device_get_applied_connection (device); + if (connection) + cp->connection = nm_simple_connection_new_clone (connection); + + return cp; +} + +static const char ** +get_all_device_paths (NMCheckpointManager *self) +{ + const GSList *devices, *iter; + NMDevice *dev; + GPtrArray *paths; + const char *path; + + devices = nm_manager_get_devices (self->_manager); + paths = g_ptr_array_new (); + + for (iter = devices; iter; iter = g_slist_next (iter)) { + dev = iter->data; + + if (!nm_device_is_real (dev)) + continue; + if (nm_device_get_state (dev) == NM_DEVICE_STATE_UNMANAGED) + continue; + /* We never touch assumed connections, unless told explicitly */ + if (nm_device_uses_assumed_connection (dev)) + continue; + + path = nm_exported_object_get_path (NM_EXPORTED_OBJECT (dev)); + g_ptr_array_add (paths, (gpointer) path); + } + + g_ptr_array_add (paths, NULL); + + return (const char **) g_ptr_array_free (paths, FALSE); +} + +char * +nm_checkpoint_manager_create (NMCheckpointManager *self, + const char *const *device_paths, + guint32 rollback_timeout, + NMCheckpointCreateFlags flags, + GError **error) +{ + Checkpoint *cp; + DeviceCheckpoint *dev_cp; + const char * const *path; + gs_free const char **device_paths_free = NULL; + + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + if (!device_paths || !device_paths[0]) { + device_paths_free = get_all_device_paths (self); + device_paths = (const char *const *) device_paths_free; + } + + if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) { + for (path = device_paths; *path; path++) { + if (find_checkpoint_for_device (self, *path)) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_INVALID_ARGUMENTS, + "a checkpoint for device '%s' already exists", + *path); + return NULL; + } + } + } + + cp = g_slice_new0 (Checkpoint); + cp->rollback_ts = rollback_timeout ? + (nm_utils_get_monotonic_timestamp_ms () + (gint64) 1000 * rollback_timeout) : + 0; + cp->devices = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, device_checkpoint_destroy); + + for (path = device_paths; *path; path++) { + dev_cp = device_checkpoint_create (self, *path, error); + if (!dev_cp) { + checkpoint_destroy (cp); + return NULL; + } + g_hash_table_insert (cp->devices, dev_cp->dev_path, dev_cp); + } + + if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) + g_hash_table_remove_all (self->checkpoints); + + cp->id = nm_utils_uuid_generate (); + if (!nm_g_hash_table_insert (self->checkpoints, cp->id, cp)) + g_return_val_if_reached (NULL); + + _LOGI ("created checkpoint %s", cp->id); + + update_rollback_timeout (self); + + return cp->id; +} + +gboolean +nm_checkpoint_manager_destroy_all (NMCheckpointManager *self, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + g_hash_table_remove_all (self->checkpoints); + + return TRUE; +} + +gboolean +nm_checkpoint_manager_destroy (NMCheckpointManager *self, + const char *checkpoint_id, + GError **error) +{ + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + if (checkpoint_id && checkpoint_id[0]) { + _LOGI ("destroy checkpoint %s", checkpoint_id); + return g_hash_table_remove (self->checkpoints, checkpoint_id); + } else { + _LOGI ("destroy all checkpoints"); + g_hash_table_remove_all (self->checkpoints); + return TRUE; + } +} + +gboolean +nm_checkpoint_manager_rollback (NMCheckpointManager *self, + const char *checkpoint_id, + GError **error) +{ + Checkpoint *cp; + gboolean ret; + + g_return_val_if_fail (self, FALSE); + g_return_val_if_fail (checkpoint_id && *checkpoint_id, FALSE); + g_return_val_if_fail (!error || !*error, FALSE); + + cp = g_hash_table_lookup (self->checkpoints, checkpoint_id); + if (!cp) { + g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, + "checkpoint '%s' does not exist", checkpoint_id); + return FALSE; + } + + ret = do_rollback (self, cp, error); + + g_hash_table_remove (self->checkpoints, cp->id); + + return ret; +} + +/*****************************************************************************/ + +NMCheckpointManager * +nm_checkpoint_manager_new (NMManager *manager) +{ + 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->checkpoints = g_hash_table_new_full (g_str_hash, g_str_equal, + NULL, checkpoint_destroy); + + return self; +} + +void +nm_checkpoint_manager_unref (NMCheckpointManager *self) +{ + /* proper ref-counting is not yet implemented, and maybe not needed. */ + + if (!self) + return; + + GET_MANAGER (self); + + nm_clear_g_source (&self->rollback_timeout_id); + g_hash_table_destroy (self->checkpoints); + + g_slice_free (NMCheckpointManager, self); +} + diff --git a/src/nm-checkpoint-manager.h b/src/nm-checkpoint-manager.h new file mode 100644 index 0000000000..9428d249fc --- /dev/null +++ b/src/nm-checkpoint-manager.h @@ -0,0 +1,48 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* NetworkManager + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2016 Red Hat, Inc. + */ + +#ifndef __NM_CHECKPOINT_MANAGER_H__ +#define __NM_CHECKPOINT_MANAGER_H__ + +#include "nm-dbus-interface.h" + +typedef struct _NMCheckpointManager NMCheckpointManager; + +NMCheckpointManager *nm_checkpoint_manager_new (NMManager *manager); +void nm_checkpoint_manager_unref (NMCheckpointManager *self); + +char *nm_checkpoint_manager_create (NMCheckpointManager *self, + const char *const*device_names, + guint32 rollback_timeout, + NMCheckpointCreateFlags flags, + GError **error); + +gboolean nm_checkpoint_manager_destroy_all (NMCheckpointManager *self, + GError **error); + +gboolean nm_checkpoint_manager_destroy (NMCheckpointManager *self, + const char *checkpoint_id, + GError **error); +gboolean nm_checkpoint_manager_rollback (NMCheckpointManager *self, + const char *checkpoint_id, + GError **error); + +#endif /* __NM_CHECKPOINT_MANAGER_H__ */ + diff --git a/src/nm-manager.c b/src/nm-manager.c index b3576b02fd..38629fec6c 100644 --- a/src/nm-manager.c +++ b/src/nm-manager.c @@ -53,6 +53,7 @@ #include "nm-config.h" #include "nm-audit-manager.h" #include "nm-dbus-compat.h" +#include "nm-checkpoint-manager.h" #include "NetworkManagerUtils.h" #include "nmdbus-manager.h" @@ -119,6 +120,8 @@ typedef struct { } prop_filter; NMRfkillManager *rfkill_mgr; + NMCheckpointManager *checkpoint_mgr; + NMSettings *settings; char *hostname; @@ -578,7 +581,7 @@ impl_manager_reload (NMManager *self, /************************************************************************/ -static NMDevice * +NMDevice * nm_manager_get_device_by_path (NMManager *manager, const char *path) { GSList *iter; @@ -5122,6 +5125,101 @@ _set_prop_filter (NMManager *self, GDBusConnection *connection) /******************************************************************************/ +static NMCheckpointManager * +_checkpoint_mgr_get (NMManager *self, gboolean create_as_needed) +{ + NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self); + + if (G_UNLIKELY (!priv->checkpoint_mgr) && create_as_needed) + priv->checkpoint_mgr = nm_checkpoint_manager_new (self); + return priv->checkpoint_mgr; +} + +static void +impl_manager_checkpoint_create (NMManager *self, + GDBusMethodInvocation *context, + const char *const*devices, + guint32 rollback_timeout, + guint32 flags) +{ + NMManagerPrivate *priv; + GError *error = NULL; + char *checkpoint_id; + + g_return_if_fail (NM_IS_MANAGER (self)); + priv = NM_MANAGER_GET_PRIVATE (self); + + if (!nm_bus_manager_ensure_root (priv->dbus_mgr, context, + NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED)) + return; + + G_STATIC_ASSERT_EXPR (sizeof (flags) <= sizeof (NMCheckpointCreateFlags)); + + checkpoint_id = nm_checkpoint_manager_create (_checkpoint_mgr_get (self, TRUE), + devices, + rollback_timeout, + (NMCheckpointCreateFlags) flags, + &error); + if (!checkpoint_id) { + g_dbus_method_invocation_take_error (context, error); + return; + } + g_dbus_method_invocation_return_value (context, + g_variant_new ("(s)", checkpoint_id)); +} + +static void +impl_manager_checkpoint_destroy (NMManager *self, + GDBusMethodInvocation *context, + const char *checkpoint_id) +{ + NMManagerPrivate *priv; + GError *error = NULL; + gboolean r; + + g_return_if_fail (NM_IS_MANAGER (self)); + priv = NM_MANAGER_GET_PRIVATE (self); + + if (!nm_bus_manager_ensure_root (priv->dbus_mgr, context, + NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED)) + return; + + r = nm_checkpoint_manager_destroy (_checkpoint_mgr_get (self, TRUE), + checkpoint_id, &error); + if (!r) { + g_dbus_method_invocation_take_error (context, error); + return; + } + g_dbus_method_invocation_return_value (context, NULL); +} + +static void +impl_manager_checkpoint_rollback (NMManager *self, + GDBusMethodInvocation *context, + const char *checkpoint_id) +{ + NMManagerPrivate *priv; + GError *error = NULL; + gboolean r; + + g_return_if_fail (NM_IS_MANAGER (self)); + priv = NM_MANAGER_GET_PRIVATE (self); + + if (!nm_bus_manager_ensure_root (priv->dbus_mgr, context, + NM_SETTINGS_ERROR, NM_SETTINGS_ERROR_PERMISSION_DENIED)) + return; + + r = nm_checkpoint_manager_rollback (_checkpoint_mgr_get (self, TRUE), + checkpoint_id, &error); + if (!r) { + g_dbus_method_invocation_take_error (context, error); + return; + } + g_dbus_method_invocation_return_value (context, NULL); +} + +/******************************************************************************/ + static void auth_mgr_changed (NMAuthManager *auth_manager, gpointer user_data) { @@ -5424,7 +5522,6 @@ nm_manager_init (NMManager *self) G_CALLBACK (auth_mgr_changed), self); - /* Monitor the firmware directory */ if (strlen (KERNEL_FIRMWARE_DIR)) { file = g_file_new_for_path (KERNEL_FIRMWARE_DIR "/"); @@ -5603,6 +5700,11 @@ dispose (GObject *object) g_slist_free_full (priv->auth_chains, (GDestroyNotify) nm_auth_chain_unref); priv->auth_chains = NULL; + if (priv->checkpoint_mgr) { + nm_checkpoint_manager_destroy_all (priv->checkpoint_mgr, NULL); + g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_unref); + } + if (priv->auth_mgr) { g_signal_handlers_disconnect_by_func (priv->auth_mgr, G_CALLBACK (auth_mgr_changed), @@ -5936,6 +6038,9 @@ nm_manager_class_init (NMManagerClass *manager_class) "GetLogging", impl_manager_get_logging, "CheckConnectivity", impl_manager_check_connectivity, "state", impl_manager_get_state, + "CheckpointCreate", impl_manager_checkpoint_create, + "CheckpointDestroy", impl_manager_checkpoint_destroy, + "CheckpointRollback", impl_manager_checkpoint_rollback, NULL); } diff --git a/src/nm-manager.h b/src/nm-manager.h index d436f0516b..d7aabff16b 100644 --- a/src/nm-manager.h +++ b/src/nm-manager.h @@ -91,6 +91,8 @@ const GSList * nm_manager_get_devices (NMManager *manager); NMDevice * nm_manager_get_device_by_ifindex (NMManager *manager, int ifindex); +NMDevice * nm_manager_get_device_by_path (NMManager *manager, + const char *path); char * nm_manager_get_connection_iface (NMManager *self, NMConnection *connection, |