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