mirror of
https://gitlab.freedesktop.org/NetworkManager/NetworkManager.git
synced 2026-01-05 22:00:32 +01:00
checkpoint: merge branch 'th/checkpoint'
https://github.com/NetworkManager/NetworkManager/pull/83
This commit is contained in:
commit
aefb66d547
23 changed files with 1021 additions and 519 deletions
|
|
@ -1466,10 +1466,10 @@ src_libNetworkManager_la_CPPFLAGS = $(src_cppflags)
|
|||
|
||||
src_libNetworkManager_la_SOURCES = \
|
||||
\
|
||||
src/nm-checkpoint-manager.c \
|
||||
src/nm-checkpoint-manager.h \
|
||||
src/nm-checkpoint.c \
|
||||
src/nm-checkpoint.h \
|
||||
src/nm-checkpoint-manager.c \
|
||||
src/nm-checkpoint-manager.h \
|
||||
\
|
||||
src/devices/nm-device.c \
|
||||
src/devices/nm-device.h \
|
||||
|
|
|
|||
|
|
@ -150,6 +150,8 @@ EXTRA_DIST += \
|
|||
examples/nm-conf.d/30-anon.conf \
|
||||
examples/nm-conf.d/31-mac-addr-change.conf \
|
||||
\
|
||||
examples/python/nmex.py \
|
||||
\
|
||||
examples/python/dbus/nm-state.py \
|
||||
examples/python/dbus/add-connection.py \
|
||||
examples/python/dbus/add-connection-compat.py \
|
||||
|
|
|
|||
193
examples/python/gi/checkpoint.py
Normal file → Executable file
193
examples/python/gi/checkpoint.py
Normal file → Executable file
|
|
@ -18,98 +18,153 @@ import gi
|
|||
gi.require_version('NM', '1.0')
|
||||
from gi.repository import GLib, NM
|
||||
|
||||
import os
|
||||
os.sys.path.append(os.path.abspath(os.path.join(os.path.dirname(__file__), '..')))
|
||||
import nmex
|
||||
|
||||
###############################################################################
|
||||
|
||||
def usage():
|
||||
print "Usage: %s [COMMAND [ARG]...]" % sys.argv[0]
|
||||
print ""
|
||||
print " COMMANDS: show"
|
||||
print " create TIMEOUT [DEV]..."
|
||||
print " destroy PATH|NUMBER"
|
||||
print " rollback PATH|NUMBER"
|
||||
print
|
||||
print("Usage: %s [COMMAND [ARG]...]" % sys.argv[0])
|
||||
print("")
|
||||
print(" COMMANDS: [show]")
|
||||
print(" create TIMEOUT [--destroy-all|--delete-new-connections|--disconnect-new-devices|--allow-overlapping|DEV]...")
|
||||
print(" destroy PATH|NUMBER")
|
||||
print(" rollback PATH|NUMBER")
|
||||
print(" adjust-rollback-timeout PATH|NUMBER TIMEOUT")
|
||||
print("")
|
||||
sys.exit(1)
|
||||
|
||||
def create_cb(client, result, data):
|
||||
try:
|
||||
checkpoint = client.checkpoint_create_finish(result)
|
||||
print("%s" % checkpoint.get_path())
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
|
||||
def do_create(client):
|
||||
if len(sys.argv) < 3:
|
||||
sys.exit("Failed: %s\n" % e.message)
|
||||
|
||||
timeout = int(sys.argv[2])
|
||||
devices = []
|
||||
for arg in sys.argv[3:]:
|
||||
d = client.get_device_by_iface(arg)
|
||||
if d is None:
|
||||
sys.exit("Unknown device %s" % arg)
|
||||
devices.append(d)
|
||||
|
||||
client.checkpoint_create_async(devices, timeout, 0, None, create_cb, None)
|
||||
|
||||
def destroy_cb(client, result, data):
|
||||
try:
|
||||
if client.checkpoint_destroy_finish(result) == True:
|
||||
print "Success"
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
|
||||
def find_checkpoint(client, arg):
|
||||
try:
|
||||
num = int(arg)
|
||||
path = "/org/freedesktop/NetworkManager/Checkpoint/%u" % num
|
||||
except Exception, e:
|
||||
path = arg
|
||||
def show(c, ts = None):
|
||||
cr = c.get_created()
|
||||
rt = c.get_rollback_timeout()
|
||||
print("%s:" % c.get_path())
|
||||
print(" created: %u%s" % (cr, "" if ts is None else (" (%s sec ago)" % ((ts - cr) / 1000.0))))
|
||||
if rt == 0:
|
||||
print(" timeout: infinity")
|
||||
else:
|
||||
print(" timeout: %u seconds%s" % (rt, "" if ts is None else (" (circa %s sec left)" % ((cr + (rt * 1000) - ts) / 1000.0))))
|
||||
print(" devices: %s" % (' '.join(sorted(map(lambda x: x.get_iface(), c.get_devices())))))
|
||||
|
||||
def find_checkpoint(client, path):
|
||||
for c in client.get_checkpoints():
|
||||
if c.get_path() == path:
|
||||
return c
|
||||
return None
|
||||
|
||||
def validate_path(path, client):
|
||||
try:
|
||||
num = int(path)
|
||||
path = "/org/freedesktop/NetworkManager/Checkpoint/%u" % (num)
|
||||
except Exception as e:
|
||||
pass
|
||||
|
||||
if not path or path[0] != '/':
|
||||
sys.exit('Invalid checkpoint path \"%s\"' % (path))
|
||||
|
||||
if client is not None:
|
||||
checkpoint = find_checkpoint(client, path)
|
||||
if checkpoint is None:
|
||||
print('WARNING: no checkpoint with path "%s" found' % (path))
|
||||
|
||||
return path
|
||||
|
||||
def do_create(client):
|
||||
flags = NM.CheckpointCreateFlags.NONE
|
||||
if len(sys.argv) < 3:
|
||||
sys.exit("Failed: missing argument timeout")
|
||||
|
||||
timeout = int(sys.argv[2])
|
||||
devices = []
|
||||
for arg in sys.argv[3:]:
|
||||
if arg == '--destroy-all':
|
||||
flags |= NM.CheckpointCreateFlags.DESTROY_ALL
|
||||
elif arg == '--delete-new-connections':
|
||||
flags |= NM.CheckpointCreateFlags.DELETE_NEW_CONNECTIONS
|
||||
elif arg == '--disconnect-new-devices':
|
||||
flags |= NM.CheckpointCreateFlags.DISCONNECT_NEW_DEVICES
|
||||
elif arg == '--allow-overlapping':
|
||||
flags |= NM.CheckpointCreateFlags.ALLOW_OVERLAPPING
|
||||
else:
|
||||
d = client.get_device_by_iface(arg)
|
||||
if d is None:
|
||||
sys.exit("Unknown device %s" % arg)
|
||||
devices.append(d)
|
||||
|
||||
def create_cb(client, result, data):
|
||||
try:
|
||||
checkpoint = client.checkpoint_create_finish(result)
|
||||
print("%s" % checkpoint.get_path())
|
||||
except Exception as e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
|
||||
client.checkpoint_create(devices, timeout, flags, None, create_cb, None)
|
||||
|
||||
def do_destroy(client):
|
||||
if len(sys.argv) < 3:
|
||||
sys.exit("Missing checkpoint path")
|
||||
|
||||
checkpoint = find_checkpoint(client, sys.argv[2])
|
||||
if checkpoint is None:
|
||||
sys.exit("Uknown checkpoint %s" % sys.argv[2])
|
||||
path = validate_path(sys.argv[2], client)
|
||||
|
||||
client.checkpoint_destroy_async(checkpoint, None, destroy_cb, None)
|
||||
def destroy_cb(client, result, data):
|
||||
try:
|
||||
if client.checkpoint_destroy_finish(result) == True:
|
||||
print("Success")
|
||||
except Exception as e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
|
||||
def rollback_cb(client, result, data):
|
||||
try:
|
||||
res = client.checkpoint_rollback_finish(result)
|
||||
for path in res:
|
||||
d = client.get_device_by_path(path)
|
||||
if d is None:
|
||||
iface = path
|
||||
else:
|
||||
iface = d.get_iface()
|
||||
print "%s => %s" % (iface, "OK" if res[path] == 0 else "ERROR")
|
||||
except Exception, e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
client.checkpoint_destroy(path, None, destroy_cb, None)
|
||||
|
||||
def do_rollback(client):
|
||||
if len(sys.argv) < 3:
|
||||
sys.exit("Missing checkpoint path")
|
||||
|
||||
checkpoint = find_checkpoint(client, sys.argv[2])
|
||||
if checkpoint is None:
|
||||
sys.exit("Uknown checkpoint %s" % sys.argv[2])
|
||||
path = validate_path(sys.argv[2], client)
|
||||
|
||||
client.checkpoint_rollback_async(checkpoint, None, rollback_cb, None)
|
||||
def rollback_cb(client, result, data):
|
||||
try:
|
||||
res = client.checkpoint_rollback_finish(result)
|
||||
for path in res:
|
||||
d = client.get_device_by_path(path)
|
||||
if d is None:
|
||||
iface = path
|
||||
else:
|
||||
iface = d.get_iface()
|
||||
print("%s => %s" % (iface, "OK" if res[path] == 0 else "ERROR"))
|
||||
except Exception as e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
|
||||
client.checkpoint_rollback(path, None, rollback_cb, None)
|
||||
|
||||
def do_adjust_rollback_timeout(client):
|
||||
if len(sys.argv) < 3:
|
||||
sys.exit("Missing checkpoint path")
|
||||
if len(sys.argv) < 4:
|
||||
sys.exit("Missing timeout")
|
||||
try:
|
||||
add_timeout = int(sys.argv[3])
|
||||
except:
|
||||
sys.exit("Invalid timeout")
|
||||
|
||||
path = validate_path(sys.argv[2], client)
|
||||
|
||||
def adjust_rollback_timeout_cb(client, result, data):
|
||||
try:
|
||||
client.checkpoint_adjust_rollback_timeout_finish(result)
|
||||
print("Success")
|
||||
except Exception as e:
|
||||
sys.stderr.write("Failed: %s\n" % e.message)
|
||||
main_loop.quit()
|
||||
|
||||
client.checkpoint_adjust_rollback_timeout(path, add_timeout, None, adjust_rollback_timeout_cb, None)
|
||||
|
||||
def do_show(client):
|
||||
ts = nmex.nm_boot_time_ms()
|
||||
for c in client.get_checkpoints():
|
||||
print "%s:" % c.get_path()
|
||||
print " created: %u" % c.get_created()
|
||||
print " timeout: %u seconds" % c.get_rollback_timeout()
|
||||
print " devices:", ' '.join(sorted(map(lambda x: x.get_iface(), c.get_devices())))
|
||||
show(c, ts)
|
||||
|
||||
if __name__ == '__main__':
|
||||
nm_client = NM.Client.new(None)
|
||||
|
|
@ -124,6 +179,8 @@ if __name__ == '__main__':
|
|||
do_destroy(nm_client)
|
||||
elif sys.argv[1] == 'rollback':
|
||||
do_rollback(nm_client)
|
||||
elif sys.argv[1] == 'adjust-rollback-timeout':
|
||||
do_adjust_rollback_timeout(nm_client)
|
||||
else:
|
||||
usage()
|
||||
|
||||
|
|
|
|||
72
examples/python/nmex.py
Normal file
72
examples/python/nmex.py
Normal file
|
|
@ -0,0 +1,72 @@
|
|||
#!/usr/bin/env python
|
||||
# -*- Mode: Python; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*-
|
||||
# vim: ft=python ts=4 sts=4 sw=4 et ai
|
||||
|
||||
# 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.
|
||||
#
|
||||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
#
|
||||
# Copyright 2018 Red Hat, Inc.
|
||||
|
||||
###############################################################################
|
||||
# nmex.py contains helper functions used by some examples. The helper functions
|
||||
# should be simple and independent, so that the user can extract them easily
|
||||
# when modifying the example to his needs.
|
||||
###############################################################################
|
||||
|
||||
def _sys_clock_gettime_ns_lazy():
|
||||
import ctypes
|
||||
|
||||
class timespec(ctypes.Structure):
|
||||
_fields_ = [
|
||||
('tv_sec', ctypes.c_long),
|
||||
('tv_nsec', ctypes.c_long)
|
||||
]
|
||||
|
||||
librt = ctypes.CDLL('librt.so.1', use_errno=True)
|
||||
clock_gettime = librt.clock_gettime
|
||||
clock_gettime.argtypes = [ctypes.c_int, ctypes.POINTER(timespec)]
|
||||
|
||||
t = timespec()
|
||||
def f(clock_id):
|
||||
if clock_gettime(clock_id, ctypes.pointer(t)) != 0:
|
||||
import os
|
||||
errno_ = ctypes.get_errno()
|
||||
raise OSError(errno_, os.strerror(errno_))
|
||||
return (t.tv_sec * 1000000000) + t.tv_nsec
|
||||
return f
|
||||
|
||||
_sys_clock_gettime_ns = None
|
||||
|
||||
# call POSIX clock_gettime() and return it as integer (in nanoseconds)
|
||||
def sys_clock_gettime_ns(clock_id):
|
||||
global _sys_clock_gettime_ns
|
||||
if _sys_clock_gettime_ns is None:
|
||||
_sys_clock_gettime_ns = _sys_clock_gettime_ns_lazy()
|
||||
return _sys_clock_gettime_ns(clock_id)
|
||||
|
||||
def nm_boot_time_ns():
|
||||
# NetworkManager exposes some timestamps as CLOCK_BOOTTIME.
|
||||
# Try that first (number 7).
|
||||
try:
|
||||
return sys_clock_gettime_ns(7)
|
||||
except OSError as e:
|
||||
# On systems, where this is not available, fallback to
|
||||
# CLOCK_MONOTONIC (numeric 1).
|
||||
# That is what NetworkManager does as well.
|
||||
import errno
|
||||
if e.errno == errno.EINVAL:
|
||||
return sys_clock_gettime_ns(1)
|
||||
raise
|
||||
def nm_boot_time_us():
|
||||
return nm_boot_time_ns() / 1000
|
||||
def nm_boot_time_ms():
|
||||
return nm_boot_time_ns() / 1000000
|
||||
def nm_boot_time_s():
|
||||
return nm_boot_time_ns() / 1000000000
|
||||
|
||||
###############################################################################
|
||||
|
|
@ -251,6 +251,27 @@
|
|||
<arg name="result" type="a{su}" direction="out" />
|
||||
</method>
|
||||
|
||||
<!--
|
||||
CheckpointAdjustRollbackTimeout:
|
||||
@add_timeout: number of seconds from ~now~ in which the
|
||||
timeout will expire. Set to 0 to disable the timeout.
|
||||
Note that the added seconds start counting from now,
|
||||
not "Created" timestamp or the previous expiration
|
||||
time. Note that the "Created" property of the checkpoint
|
||||
will stay unchanged by this call. However, the "RollbackTimeout"
|
||||
will be recalculated to give the approximate new expiration time.
|
||||
The new "RollbackTimeout" property will be approximate up to
|
||||
one second precision, which is the accuracy of the property.
|
||||
|
||||
Reset the timeout for rollback for the checkpoint.
|
||||
|
||||
Since: 1.12
|
||||
-->
|
||||
<method name="CheckpointAdjustRollbackTimeout">
|
||||
<arg name="checkpoint" type="o" direction="in"/>
|
||||
<arg name="add_timeout" type="u" direction="in"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Devices:
|
||||
|
||||
|
|
|
|||
|
|
@ -842,16 +842,29 @@ typedef enum {
|
|||
* delete any new connection added after the checkpoint (Since: 1.6)
|
||||
* @NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES: upon rollback,
|
||||
* disconnect any new device appeared after the checkpoint (Since: 1.6)
|
||||
* @NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING: by default, creating
|
||||
* a checkpoint fails if there are already existing checkoints that
|
||||
* reference the same devices. With this flag, creation of such
|
||||
* checkpoints is allowed, however, if an older checkpoint
|
||||
* that references overlapping devices gets rolled back, it will
|
||||
* automatically destroy this checkpoint during rollback. This
|
||||
* allows to create several overlapping checkpoints in parallel,
|
||||
* and rollback to them at will. With the special case that
|
||||
* rolling back to an older checkpoint will invalidate all
|
||||
* overlapping younger checkpoints. This opts-in that the
|
||||
* checkpoint can be automatically destroyed by the rollback
|
||||
* of an older checkpoint. (Since: 1.12)
|
||||
*
|
||||
* The flags for CheckpointCreate call
|
||||
*
|
||||
* Since: 1.4
|
||||
* Since: 1.4 (gi flags generated since 1.12)
|
||||
*/
|
||||
typedef enum { /*< skip >*/
|
||||
typedef enum { /*< flags >*/
|
||||
NM_CHECKPOINT_CREATE_FLAG_NONE = 0,
|
||||
NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL = 0x01,
|
||||
NM_CHECKPOINT_CREATE_FLAG_DELETE_NEW_CONNECTIONS = 0x02,
|
||||
NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES = 0x04,
|
||||
NM_CHECKPOINT_CREATE_FLAG_ALLOW_OVERLAPPING = 0x08,
|
||||
} NMCheckpointCreateFlags;
|
||||
|
||||
/**
|
||||
|
|
|
|||
|
|
@ -1334,15 +1334,18 @@ global:
|
|||
|
||||
libnm_1_12_0 {
|
||||
global:
|
||||
nm_checkpoint_create_flags_get_type;
|
||||
nm_checkpoint_get_created;
|
||||
nm_checkpoint_get_devices;
|
||||
nm_checkpoint_get_rollback_timeout;
|
||||
nm_checkpoint_get_type;
|
||||
nm_client_checkpoint_create_async;
|
||||
nm_client_checkpoint_adjust_rollback_timeout;
|
||||
nm_client_checkpoint_adjust_rollback_timeout_finish;
|
||||
nm_client_checkpoint_create;
|
||||
nm_client_checkpoint_create_finish;
|
||||
nm_client_checkpoint_destroy_async;
|
||||
nm_client_checkpoint_destroy;
|
||||
nm_client_checkpoint_destroy_finish;
|
||||
nm_client_checkpoint_rollback_async;
|
||||
nm_client_checkpoint_rollback;
|
||||
nm_client_checkpoint_rollback_finish;
|
||||
nm_client_get_checkpoints;
|
||||
nm_device_ip_tunnel_get_flags;
|
||||
|
|
|
|||
|
|
@ -2121,7 +2121,7 @@ nm_client_get_checkpoints (NMClient *client)
|
|||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_create_async:
|
||||
* nm_client_checkpoint_create:
|
||||
* @client: the %NMClient
|
||||
* @devices: (element-type NMDevice): a list of devices for which a
|
||||
* checkpoint should be created.
|
||||
|
|
@ -2139,13 +2139,13 @@ nm_client_get_checkpoints (NMClient *client)
|
|||
* Since: 1.12
|
||||
**/
|
||||
void
|
||||
nm_client_checkpoint_create_async (NMClient *client,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
nm_client_checkpoint_create (NMClient *client,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
|
@ -2158,12 +2158,12 @@ nm_client_checkpoint_create_async (NMClient *client,
|
|||
}
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
|
||||
nm_client_checkpoint_create_async);
|
||||
nm_client_checkpoint_create);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
nm_manager_checkpoint_create_async (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
devices, rollback_timeout, flags,
|
||||
cancellable, checkpoint_create_cb, simple);
|
||||
nm_manager_checkpoint_create (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
devices, rollback_timeout, flags,
|
||||
cancellable, checkpoint_create_cb, simple);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2172,7 +2172,7 @@ nm_client_checkpoint_create_async (NMClient *client,
|
|||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_client_checkpoint_create_async().
|
||||
* Gets the result of a call to nm_client_checkpoint_create().
|
||||
*
|
||||
* Returns: (transfer full): the new #NMCheckpoint on success, %NULL on
|
||||
* failure, in which case @error will be set.
|
||||
|
|
@ -2214,9 +2214,9 @@ checkpoint_destroy_cb (GObject *object,
|
|||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_destroy_async:
|
||||
* nm_client_checkpoint_destroy:
|
||||
* @client: the %NMClient
|
||||
* @checkpoint: a checkpoint
|
||||
* @checkpoint_path: the D-Bus path for the checkpoint
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: (scope async): callback to be called when the add operation completes
|
||||
* @user_data: (closure): caller-specific data passed to @callback
|
||||
|
|
@ -2226,16 +2226,17 @@ checkpoint_destroy_cb (GObject *object,
|
|||
* Since: 1.12
|
||||
**/
|
||||
void
|
||||
nm_client_checkpoint_destroy_async (NMClient *client,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
nm_client_checkpoint_destroy (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (NM_IS_CLIENT (client));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
if (!_nm_client_check_nm_running (client, &error)) {
|
||||
g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
|
||||
|
|
@ -2243,12 +2244,12 @@ nm_client_checkpoint_destroy_async (NMClient *client,
|
|||
}
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
|
||||
nm_client_checkpoint_destroy_async);
|
||||
nm_client_checkpoint_destroy);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
nm_manager_checkpoint_destroy_async (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
checkpoint,
|
||||
cancellable, checkpoint_destroy_cb, simple);
|
||||
nm_manager_checkpoint_destroy (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
checkpoint_path,
|
||||
cancellable, checkpoint_destroy_cb, simple);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2257,7 +2258,7 @@ nm_client_checkpoint_destroy_async (NMClient *client,
|
|||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_client_checkpoint_destroy_async().
|
||||
* Gets the result of a call to nm_client_checkpoint_destroy().
|
||||
*
|
||||
* Returns: %TRUE on success or %FALSE on failure, in which case
|
||||
* @error will be set.
|
||||
|
|
@ -2301,9 +2302,9 @@ checkpoint_rollback_cb (GObject *object,
|
|||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_rollback_async:
|
||||
* nm_client_checkpoint_rollback:
|
||||
* @client: the %NMClient
|
||||
* @checkpoint: a checkpoint
|
||||
* @checkpoint_path: the D-Bus path to the checkpoint
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: (scope async): callback to be called when the add operation completes
|
||||
* @user_data: (closure): caller-specific data passed to @callback
|
||||
|
|
@ -2313,16 +2314,17 @@ checkpoint_rollback_cb (GObject *object,
|
|||
* Since: 1.12
|
||||
**/
|
||||
void
|
||||
nm_client_checkpoint_rollback_async (NMClient *client,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
nm_client_checkpoint_rollback (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (NM_IS_CLIENT (client));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
if (!_nm_client_check_nm_running (client, &error)) {
|
||||
g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
|
||||
|
|
@ -2330,12 +2332,12 @@ nm_client_checkpoint_rollback_async (NMClient *client,
|
|||
}
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
|
||||
nm_client_checkpoint_rollback_async);
|
||||
nm_client_checkpoint_rollback);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
nm_manager_checkpoint_rollback_async (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
checkpoint,
|
||||
cancellable, checkpoint_rollback_cb, simple);
|
||||
nm_manager_checkpoint_rollback (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
checkpoint_path,
|
||||
cancellable, checkpoint_rollback_cb, simple);
|
||||
}
|
||||
|
||||
/**
|
||||
|
|
@ -2344,7 +2346,7 @@ nm_client_checkpoint_rollback_async (NMClient *client,
|
|||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_client_checkpoint_rollback_async().
|
||||
* Gets the result of a call to nm_client_checkpoint_rollback().
|
||||
*
|
||||
* Returns: (transfer full) (element-type utf8 guint32): an hash table of
|
||||
* devices and results. Devices are represented by their original
|
||||
|
|
@ -2372,6 +2374,89 @@ nm_client_checkpoint_rollback_finish (NMClient *client,
|
|||
}
|
||||
}
|
||||
|
||||
static void
|
||||
checkpoint_adjust_rollback_timeout_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
gs_unref_object GSimpleAsyncResult *simple = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (nm_manager_checkpoint_adjust_rollback_timeout_finish (NM_MANAGER (object), result, &error))
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
else
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
|
||||
g_simple_async_result_complete (simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_adjust_rollback_timeout:
|
||||
* @client: the %NMClient
|
||||
* @checkpoint_path: a D-Bus path to a checkpoint
|
||||
* @add_timeout: the timeout in seconds counting from now.
|
||||
* Set to zero, to disable the timeout.
|
||||
* @cancellable: a #GCancellable, or %NULL
|
||||
* @callback: (scope async): callback to be called when the add operation completes
|
||||
* @user_data: (closure): caller-specific data passed to @callback
|
||||
*
|
||||
* Resets the timeout for the checkpoint with path @checkpoint_path
|
||||
* to @timeout_add.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
void
|
||||
nm_client_checkpoint_adjust_rollback_timeout (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
GError *error = NULL;
|
||||
|
||||
g_return_if_fail (NM_IS_CLIENT (client));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
if (!_nm_client_check_nm_running (client, &error)) {
|
||||
g_simple_async_report_take_gerror_in_idle (G_OBJECT (client), callback, user_data, error);
|
||||
return;
|
||||
}
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (client), callback, user_data,
|
||||
nm_client_checkpoint_rollback);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
nm_manager_checkpoint_adjust_rollback_timeout (NM_CLIENT_GET_PRIVATE (client)->manager,
|
||||
checkpoint_path, add_timeout,
|
||||
cancellable, checkpoint_adjust_rollback_timeout_cb, simple);
|
||||
}
|
||||
|
||||
/**
|
||||
* nm_client_checkpoint_adjust_rollback_timeout_finish:
|
||||
* @client: an #NMClient
|
||||
* @result: the result passed to the #GAsyncReadyCallback
|
||||
* @error: location for a #GError, or %NULL
|
||||
*
|
||||
* Gets the result of a call to nm_client_checkpoint_adjust_rollback_timeout().
|
||||
*
|
||||
* Returns: %TRUE on success or %FALSE on failure.
|
||||
*
|
||||
* Since: 1.12
|
||||
**/
|
||||
gboolean
|
||||
nm_client_checkpoint_adjust_rollback_timeout_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CLIENT (client), FALSE);
|
||||
g_return_val_if_fail (G_IS_SIMPLE_ASYNC_RESULT (result), FALSE);
|
||||
|
||||
return !g_simple_async_result_propagate_error (G_SIMPLE_ASYNC_RESULT (result),
|
||||
error);
|
||||
}
|
||||
|
||||
/****************************************************************/
|
||||
/* Object Initialization */
|
||||
/****************************************************************/
|
||||
|
|
|
|||
|
|
@ -408,40 +408,53 @@ NM_AVAILABLE_IN_1_12
|
|||
const GPtrArray *nm_client_get_checkpoints (NMClient *client);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
void nm_client_checkpoint_create_async (NMClient *client,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
void nm_client_checkpoint_create (NMClient *client,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
NM_AVAILABLE_IN_1_12
|
||||
NMCheckpoint *nm_client_checkpoint_create_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
void nm_client_checkpoint_destroy_async (NMClient *client,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
void nm_client_checkpoint_destroy (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
NM_AVAILABLE_IN_1_12
|
||||
gboolean nm_client_checkpoint_destroy_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
void nm_client_checkpoint_rollback_async (NMClient *client,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
void nm_client_checkpoint_rollback (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
NM_AVAILABLE_IN_1_12
|
||||
GHashTable *nm_client_checkpoint_rollback_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
void nm_client_checkpoint_adjust_rollback_timeout (NMClient *client,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
NM_AVAILABLE_IN_1_12
|
||||
gboolean nm_client_checkpoint_adjust_rollback_timeout_finish (NMClient *client,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
G_END_DECLS
|
||||
|
||||
#endif /* __NM_CLIENT_H__ */
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ find_checkpoint_info (NMManager *manager, const char *path)
|
|||
|
||||
for (iter = priv->added_checkpoints; iter; iter = g_slist_next (iter)) {
|
||||
info = iter->data;
|
||||
if (nm_streq (path, info->path))
|
||||
if (nm_streq0 (path, info->path))
|
||||
return info;
|
||||
}
|
||||
|
||||
|
|
@ -790,8 +790,7 @@ NMDevice *
|
|||
nm_manager_get_device_by_path (NMManager *manager, const char *object_path)
|
||||
{
|
||||
const GPtrArray *devices;
|
||||
int i;
|
||||
NMDevice *device = NULL;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (NM_IS_MANAGER (manager), NULL);
|
||||
g_return_val_if_fail (object_path, NULL);
|
||||
|
|
@ -800,12 +799,25 @@ nm_manager_get_device_by_path (NMManager *manager, const char *object_path)
|
|||
for (i = 0; i < devices->len; i++) {
|
||||
NMDevice *candidate = g_ptr_array_index (devices, i);
|
||||
if (!strcmp (nm_object_get_path (NM_OBJECT (candidate)), object_path)) {
|
||||
device = candidate;
|
||||
break;
|
||||
return candidate;
|
||||
}
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return device;
|
||||
static NMCheckpoint *
|
||||
get_checkpoint_by_path (NMManager *manager, const char *object_path)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||
NMCheckpoint *candidate;
|
||||
guint i;
|
||||
|
||||
for (i = 0; i < priv->checkpoints->len; i++) {
|
||||
candidate = priv->checkpoints->pdata[i];
|
||||
if (nm_streq (nm_object_get_path (NM_OBJECT (candidate)), object_path))
|
||||
return candidate;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
NMDevice *
|
||||
|
|
@ -1196,11 +1208,6 @@ checkpoint_added (NMManager *manager, NMCheckpoint *checkpoint)
|
|||
checkpoint_info_complete (manager, info, checkpoint, NULL);
|
||||
}
|
||||
|
||||
static void
|
||||
checkpoint_removed (NMManager *manager, NMCheckpoint *checkpoint)
|
||||
{
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_manager_deactivate_connection (NMManager *manager,
|
||||
NMActiveConnection *active,
|
||||
|
|
@ -1331,25 +1338,37 @@ checkpoint_created_cb (GObject *object,
|
|||
gpointer user_data)
|
||||
{
|
||||
CheckpointInfo *info = user_data;
|
||||
GError *error = NULL;
|
||||
NMManager *self = info->manager;
|
||||
gs_free_error GError *error = NULL;
|
||||
NMCheckpoint *checkpoint;
|
||||
|
||||
nmdbus_manager_call_checkpoint_create_finish (NMDBUS_MANAGER (object),
|
||||
&info->path, result, &error);
|
||||
if (error) {
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
checkpoint_info_complete (info->manager, info, NULL, error);
|
||||
g_clear_error (&error);
|
||||
checkpoint_info_complete (self, info, NULL, error);
|
||||
return;
|
||||
}
|
||||
|
||||
checkpoint = get_checkpoint_by_path (self, info->path);
|
||||
if (!checkpoint) {
|
||||
/* this is really problematic. The async request returned, but
|
||||
* we don't yet have a visible (fully initialized) NMCheckpoint instance
|
||||
* to return. Wait longer for it to appear. However, it's ugly. */
|
||||
return;
|
||||
}
|
||||
|
||||
checkpoint_info_complete (self, info, checkpoint, NULL);
|
||||
}
|
||||
|
||||
void
|
||||
nm_manager_checkpoint_create_async (NMManager *manager,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
nm_manager_checkpoint_create (NMManager *manager,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (manager);
|
||||
gs_free const char **paths = NULL;
|
||||
|
|
@ -1360,7 +1379,7 @@ nm_manager_checkpoint_create_async (NMManager *manager,
|
|||
info = g_slice_new0 (CheckpointInfo);
|
||||
info->manager = manager;
|
||||
info->simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
|
||||
nm_manager_checkpoint_create_async);
|
||||
nm_manager_checkpoint_create);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (info->simple, cancellable);
|
||||
paths = get_device_paths (devices);
|
||||
|
|
@ -1411,26 +1430,24 @@ checkpoint_destroy_cb (GObject *object,
|
|||
}
|
||||
|
||||
void
|
||||
nm_manager_checkpoint_destroy_async (NMManager *manager,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
nm_manager_checkpoint_destroy (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
const char *path;
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_if_fail (NM_IS_MANAGER (manager));
|
||||
g_return_if_fail (NM_IS_CHECKPOINT (checkpoint));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
|
||||
nm_manager_checkpoint_destroy_async);
|
||||
nm_manager_checkpoint_destroy);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
|
||||
path = nm_object_get_path (NM_OBJECT (checkpoint));
|
||||
nmdbus_manager_call_checkpoint_destroy (NM_MANAGER_GET_PRIVATE (manager)->proxy,
|
||||
path,
|
||||
checkpoint_path,
|
||||
cancellable,
|
||||
checkpoint_destroy_cb, simple);
|
||||
}
|
||||
|
|
@ -1443,7 +1460,7 @@ nm_manager_checkpoint_destroy_finish (NMManager *manager,
|
|||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager),
|
||||
nm_manager_checkpoint_destroy_async),
|
||||
nm_manager_checkpoint_destroy),
|
||||
FALSE);
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
|
|
@ -1484,26 +1501,24 @@ checkpoint_rollback_cb (GObject *object,
|
|||
}
|
||||
|
||||
void
|
||||
nm_manager_checkpoint_rollback_async (NMManager *manager,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
nm_manager_checkpoint_rollback (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
const char *path;
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_if_fail (NM_IS_MANAGER (manager));
|
||||
g_return_if_fail (NM_IS_CHECKPOINT (checkpoint));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
|
||||
nm_manager_checkpoint_rollback_async);
|
||||
nm_manager_checkpoint_rollback);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
|
||||
path = nm_object_get_path (NM_OBJECT (checkpoint));
|
||||
nmdbus_manager_call_checkpoint_rollback (NM_MANAGER_GET_PRIVATE (manager)->proxy,
|
||||
path,
|
||||
checkpoint_path,
|
||||
cancellable,
|
||||
checkpoint_rollback_cb, simple);
|
||||
}
|
||||
|
|
@ -1516,7 +1531,7 @@ nm_manager_checkpoint_rollback_finish (NMManager *manager,
|
|||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager),
|
||||
nm_manager_checkpoint_rollback_async),
|
||||
nm_manager_checkpoint_rollback),
|
||||
NULL);
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
|
|
@ -1526,6 +1541,66 @@ nm_manager_checkpoint_rollback_finish (NMManager *manager,
|
|||
return g_simple_async_result_get_op_res_gpointer (simple);
|
||||
}
|
||||
|
||||
static void
|
||||
checkpoint_adjust_rollback_timeout_cb (GObject *object,
|
||||
GAsyncResult *result,
|
||||
gpointer user_data)
|
||||
{
|
||||
gs_unref_object GSimpleAsyncResult *simple = user_data;
|
||||
GError *error = NULL;
|
||||
|
||||
if (nmdbus_manager_call_checkpoint_adjust_rollback_timeout_finish (NMDBUS_MANAGER (object),
|
||||
result,
|
||||
&error))
|
||||
g_simple_async_result_set_op_res_gboolean (simple, TRUE);
|
||||
else {
|
||||
g_dbus_error_strip_remote_error (error);
|
||||
g_simple_async_result_take_error (simple, error);
|
||||
}
|
||||
g_simple_async_result_complete (simple);
|
||||
}
|
||||
|
||||
void
|
||||
nm_manager_checkpoint_adjust_rollback_timeout (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_if_fail (NM_IS_MANAGER (manager));
|
||||
g_return_if_fail (checkpoint_path && checkpoint_path[0] == '/');
|
||||
|
||||
simple = g_simple_async_result_new (G_OBJECT (manager), callback, user_data,
|
||||
nm_manager_checkpoint_adjust_rollback_timeout);
|
||||
if (cancellable)
|
||||
g_simple_async_result_set_check_cancellable (simple, cancellable);
|
||||
|
||||
nmdbus_manager_call_checkpoint_adjust_rollback_timeout (NM_MANAGER_GET_PRIVATE (manager)->proxy,
|
||||
checkpoint_path,
|
||||
add_timeout,
|
||||
cancellable,
|
||||
checkpoint_adjust_rollback_timeout_cb,
|
||||
simple);
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_manager_checkpoint_adjust_rollback_timeout_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error)
|
||||
{
|
||||
GSimpleAsyncResult *simple;
|
||||
|
||||
g_return_val_if_fail (g_simple_async_result_is_valid (result, G_OBJECT (manager),
|
||||
nm_manager_checkpoint_adjust_rollback_timeout),
|
||||
FALSE);
|
||||
|
||||
simple = G_SIMPLE_ASYNC_RESULT (result);
|
||||
return !g_simple_async_result_propagate_error (simple, error);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -1832,7 +1907,6 @@ nm_manager_class_init (NMManagerClass *manager_class)
|
|||
manager_class->active_connection_added = active_connection_added;
|
||||
manager_class->active_connection_removed = active_connection_removed;
|
||||
manager_class->checkpoint_added = checkpoint_added;
|
||||
manager_class->checkpoint_removed = checkpoint_removed;
|
||||
|
||||
/* properties */
|
||||
|
||||
|
|
|
|||
|
|
@ -184,31 +184,40 @@ gboolean nm_manager_deactivate_connection_finish (NMManager *manager,
|
|||
GError **error);
|
||||
|
||||
const GPtrArray *nm_manager_get_checkpoints (NMManager *manager);
|
||||
void nm_manager_checkpoint_create_async (NMManager *manager,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
void nm_manager_checkpoint_create (NMManager *manager,
|
||||
const GPtrArray *devices,
|
||||
guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
NMCheckpoint *nm_manager_checkpoint_create_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
void nm_manager_checkpoint_destroy_async (NMManager *manager,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
void nm_manager_checkpoint_destroy (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean nm_manager_checkpoint_destroy_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
void nm_manager_checkpoint_rollback_async (NMManager *manager,
|
||||
NMCheckpoint *checkpoint,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
void nm_manager_checkpoint_rollback (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
GHashTable *nm_manager_checkpoint_rollback_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
void nm_manager_checkpoint_adjust_rollback_timeout (NMManager *manager,
|
||||
const char *checkpoint_path,
|
||||
guint32 add_timeout,
|
||||
GCancellable *cancellable,
|
||||
GAsyncReadyCallback callback,
|
||||
gpointer user_data);
|
||||
gboolean nm_manager_checkpoint_adjust_rollback_timeout_finish (NMManager *manager,
|
||||
GAsyncResult *result,
|
||||
GError **error);
|
||||
|
||||
#endif /* __NM_MANAGER_H__ */
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ static void
|
|||
find_companion (NMDeviceOlpcMesh *self)
|
||||
{
|
||||
NMDeviceOlpcMeshPrivate *priv = NM_DEVICE_OLPC_MESH_GET_PRIVATE (self);
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *candidate;
|
||||
|
||||
if (priv->companion)
|
||||
|
|
@ -396,8 +396,7 @@ find_companion (NMDeviceOlpcMesh *self)
|
|||
nm_device_add_pending_action (NM_DEVICE (self), NM_PENDING_ACTION_WAITING_FOR_COMPANION, TRUE);
|
||||
|
||||
/* Try to find the companion if it's already known to the NMManager */
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (candidate, all_devices, devices_lst) {
|
||||
nm_manager_for_each_device (priv->manager, candidate, tmp_lst) {
|
||||
if (check_companion (self, candidate)) {
|
||||
nm_device_queue_recheck_available (NM_DEVICE (self),
|
||||
NM_DEVICE_STATE_REASON_NONE,
|
||||
|
|
|
|||
|
|
@ -39,7 +39,7 @@ typedef struct {
|
|||
} KnownNetworkData;
|
||||
|
||||
typedef struct {
|
||||
NMManager *nm_manager;
|
||||
NMManager *manager;
|
||||
GCancellable *cancellable;
|
||||
gboolean running;
|
||||
GDBusObjectManager *object_manager;
|
||||
|
|
@ -138,7 +138,7 @@ psk_agent_dbus_method_cb (GDBusConnection *connection,
|
|||
goto return_error;
|
||||
}
|
||||
|
||||
device = nm_manager_get_device_by_ifindex (priv->nm_manager, ifindex);
|
||||
device = nm_manager_get_device_by_ifindex (priv->manager, ifindex);
|
||||
if (!NM_IS_DEVICE_IWD (device)) {
|
||||
_LOGE ("IWD device named %s is not a Wifi device in IWD Agent request",
|
||||
ifname);
|
||||
|
|
@ -291,7 +291,7 @@ set_device_dbus_object (NMIwdManager *self, GDBusInterface *interface,
|
|||
return;
|
||||
}
|
||||
|
||||
device = nm_manager_get_device_by_ifindex (priv->nm_manager, ifindex);
|
||||
device = nm_manager_get_device_by_ifindex (priv->manager, ifindex);
|
||||
if (!NM_IS_DEVICE_IWD (device)) {
|
||||
_LOGE ("IWD device named %s is not a Wifi device", ifname);
|
||||
return;
|
||||
|
|
@ -460,7 +460,7 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
|
|||
g_clear_object (&priv->object_manager);
|
||||
prepare_object_manager (self);
|
||||
} else {
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *device;
|
||||
|
||||
if (!priv->running)
|
||||
|
|
@ -468,13 +468,11 @@ name_owner_changed (GObject *object, GParamSpec *pspec, gpointer user_data)
|
|||
|
||||
priv->running = false;
|
||||
|
||||
all_devices = nm_manager_get_devices (priv->nm_manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst) {
|
||||
if (!NM_IS_DEVICE_IWD (device))
|
||||
continue;
|
||||
|
||||
nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device),
|
||||
NULL);
|
||||
nm_manager_for_each_device (priv->manager, device, tmp_lst) {
|
||||
if (NM_IS_DEVICE_IWD (device)) {
|
||||
nm_device_iwd_set_dbus_object (NM_DEVICE_IWD (device),
|
||||
NULL);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -639,8 +637,8 @@ nm_iwd_manager_init (NMIwdManager *self)
|
|||
{
|
||||
NMIwdManagerPrivate *priv = NM_IWD_MANAGER_GET_PRIVATE (self);
|
||||
|
||||
priv->nm_manager = g_object_ref (nm_manager_get ());
|
||||
g_signal_connect (priv->nm_manager, NM_MANAGER_DEVICE_ADDED,
|
||||
priv->manager = g_object_ref (nm_manager_get ());
|
||||
g_signal_connect (priv->manager, NM_MANAGER_DEVICE_ADDED,
|
||||
G_CALLBACK (device_added), self);
|
||||
|
||||
priv->cancellable = g_cancellable_new ();
|
||||
|
|
@ -679,9 +677,9 @@ dispose (GObject *object)
|
|||
g_slist_free_full (priv->known_networks, (GDestroyNotify) known_network_free);
|
||||
priv->known_networks = NULL;
|
||||
|
||||
if (priv->nm_manager) {
|
||||
g_signal_handlers_disconnect_by_data (priv->nm_manager, self);
|
||||
g_clear_object (&priv->nm_manager);
|
||||
if (priv->manager) {
|
||||
g_signal_handlers_disconnect_by_data (priv->manager, self);
|
||||
g_clear_object (&priv->manager);
|
||||
}
|
||||
|
||||
G_OBJECT_CLASS (nm_iwd_manager_parent_class)->dispose (object);
|
||||
|
|
|
|||
|
|
@ -57,6 +57,7 @@ typedef struct _NMAuditManagerClass NMAuditManagerClass;
|
|||
#define NM_AUDIT_OP_CHECKPOINT_CREATE "checkpoint-create"
|
||||
#define NM_AUDIT_OP_CHECKPOINT_ROLLBACK "checkpoint-rollback"
|
||||
#define NM_AUDIT_OP_CHECKPOINT_DESTROY "checkpoint-destroy"
|
||||
#define NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT "checkpoint-adjust-rollback-timeout"
|
||||
|
||||
GType nm_audit_manager_get_type (void);
|
||||
NMAuditManager *nm_audit_manager_get (void);
|
||||
|
|
|
|||
|
|
@ -35,9 +35,7 @@
|
|||
struct _NMCheckpointManager {
|
||||
NMManager *_manager;
|
||||
GParamSpec *property_spec;
|
||||
GHashTable *checkpoints;
|
||||
CList list;
|
||||
guint rollback_timeout_id;
|
||||
CList checkpoints_lst_head;
|
||||
};
|
||||
|
||||
#define GET_MANAGER(self) \
|
||||
|
|
@ -58,13 +56,6 @@ struct _NMCheckpointManager {
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
typedef struct {
|
||||
CList list;
|
||||
NMCheckpoint *checkpoint;
|
||||
} CheckpointItem;
|
||||
|
||||
static void update_rollback_timeout (NMCheckpointManager *self);
|
||||
|
||||
static void
|
||||
notify_checkpoints (NMCheckpointManager *self) {
|
||||
g_object_notify_by_pspec ((GObject *) GET_MANAGER (self),
|
||||
|
|
@ -72,83 +63,60 @@ notify_checkpoints (NMCheckpointManager *self) {
|
|||
}
|
||||
|
||||
static void
|
||||
item_destroy (gpointer data)
|
||||
destroy_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint, gboolean log_destroy)
|
||||
{
|
||||
CheckpointItem *item = data;
|
||||
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));
|
||||
|
||||
c_list_unlink_stale (&item->list);
|
||||
nm_dbus_object_unexport (NM_DBUS_OBJECT (item->checkpoint));
|
||||
g_object_unref (G_OBJECT (item->checkpoint));
|
||||
g_slice_free (CheckpointItem, item);
|
||||
nm_checkpoint_set_timeout_callback (checkpoint, NULL, NULL);
|
||||
|
||||
c_list_unlink (&checkpoint->checkpoints_lst);
|
||||
|
||||
if (log_destroy)
|
||||
nm_checkpoint_log_destroy (checkpoint);
|
||||
|
||||
notify_checkpoints (self);
|
||||
|
||||
nm_dbus_object_unexport (NM_DBUS_OBJECT (checkpoint));
|
||||
g_object_unref (checkpoint);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
rollback_timeout_cb (NMCheckpointManager *self)
|
||||
static GVariant *
|
||||
rollback_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint)
|
||||
{
|
||||
CheckpointItem *item, *safe;
|
||||
GVariant *result;
|
||||
gint64 ts, now;
|
||||
const char *path;
|
||||
gboolean removed = FALSE;
|
||||
const CList *iter;
|
||||
|
||||
now = nm_utils_get_monotonic_timestamp_ms ();
|
||||
nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst));
|
||||
|
||||
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 (item->checkpoint);
|
||||
if (result)
|
||||
g_variant_unref (result);
|
||||
path = nm_dbus_object_get_path (NM_DBUS_OBJECT (item->checkpoint));
|
||||
if (!g_hash_table_remove (self->checkpoints, path))
|
||||
nm_assert_not_reached();
|
||||
removed = TRUE;
|
||||
/* 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);
|
||||
}
|
||||
}
|
||||
|
||||
self->rollback_timeout_id = 0;
|
||||
update_rollback_timeout (self);
|
||||
|
||||
if (removed)
|
||||
notify_checkpoints (self);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
result = nm_checkpoint_rollback (checkpoint);
|
||||
destroy_checkpoint (self, checkpoint, FALSE);
|
||||
return result;
|
||||
}
|
||||
|
||||
static void
|
||||
update_rollback_timeout (NMCheckpointManager *self)
|
||||
rollback_timeout_cb (NMCheckpoint *checkpoint,
|
||||
gpointer user_data)
|
||||
{
|
||||
CheckpointItem *item;
|
||||
gint64 ts, delta, next = G_MAXINT64;
|
||||
NMCheckpointManager *self = user_data;
|
||||
gs_unref_variant GVariant *result = NULL;
|
||||
|
||||
c_list_for_each_entry (item, &self->list, list) {
|
||||
ts = nm_checkpoint_get_rollback_ts (item->checkpoint);
|
||||
if (ts && ts < next)
|
||||
next = 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 NMCheckpoint *
|
||||
find_checkpoint_for_device (NMCheckpointManager *self, NMDevice *device)
|
||||
{
|
||||
CheckpointItem *item;
|
||||
|
||||
c_list_for_each_entry (item, &self->list, list) {
|
||||
if (nm_checkpoint_includes_device (item->checkpoint, device))
|
||||
return item->checkpoint;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
result = rollback_checkpoint (self, checkpoint);
|
||||
}
|
||||
|
||||
NMCheckpoint *
|
||||
|
|
@ -160,57 +128,61 @@ nm_checkpoint_manager_create (NMCheckpointManager *self,
|
|||
{
|
||||
NMManager *manager;
|
||||
NMCheckpoint *checkpoint;
|
||||
CheckpointItem *item;
|
||||
const char * const *path;
|
||||
gs_unref_ptrarray GPtrArray *devices = NULL;
|
||||
NMDevice *device;
|
||||
const char *checkpoint_path;
|
||||
gs_free const char **device_paths_free = NULL;
|
||||
guint i;
|
||||
|
||||
g_return_val_if_fail (self, FALSE);
|
||||
g_return_val_if_fail (!error || !*error, FALSE);
|
||||
manager = GET_MANAGER (self);
|
||||
|
||||
if (!device_paths || !device_paths[0]) {
|
||||
const char *device_path;
|
||||
const CList *all_devices;
|
||||
GPtrArray *paths;
|
||||
devices = g_ptr_array_new ();
|
||||
|
||||
paths = g_ptr_array_new ();
|
||||
all_devices = nm_manager_get_devices (manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst) {
|
||||
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;
|
||||
device_path = nm_dbus_object_get_path (NM_DBUS_OBJECT (device));
|
||||
if (device_path)
|
||||
g_ptr_array_add (paths, (gpointer) device_path);
|
||||
nm_assert (nm_dbus_object_get_path (NM_DBUS_OBJECT (device)));
|
||||
g_ptr_array_add (devices, device);
|
||||
}
|
||||
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,
|
||||
"the DISCONNECT_NEW_DEVICES flag can only be used with an empty device list");
|
||||
return NULL;
|
||||
}
|
||||
|
||||
devices = g_ptr_array_new ();
|
||||
for (path = device_paths; *path; path++) {
|
||||
device = nm_manager_get_device_by_path (manager, *path);
|
||||
if (!device) {
|
||||
g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_UNKNOWN_DEVICE,
|
||||
"device %s does not exist", *path);
|
||||
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);
|
||||
}
|
||||
g_ptr_array_add (devices, device);
|
||||
}
|
||||
|
||||
if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) {
|
||||
for (i = 0; i < devices->len; i++) {
|
||||
device = devices->pdata[i];
|
||||
checkpoint = find_checkpoint_for_device (self, device);
|
||||
if (checkpoint) {
|
||||
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),
|
||||
|
|
@ -220,115 +192,132 @@ nm_checkpoint_manager_create (NMCheckpointManager *self,
|
|||
}
|
||||
}
|
||||
|
||||
checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags, error);
|
||||
if (!checkpoint)
|
||||
return NULL;
|
||||
checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags);
|
||||
|
||||
if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL))
|
||||
g_hash_table_remove_all (self->checkpoints);
|
||||
|
||||
checkpoint_path = nm_dbus_object_export (NM_DBUS_OBJECT (checkpoint));
|
||||
|
||||
item = g_slice_new0 (CheckpointItem);
|
||||
item->checkpoint = checkpoint;
|
||||
c_list_link_tail (&self->list, &item->list);
|
||||
|
||||
if (!g_hash_table_insert (self->checkpoints, (gpointer) checkpoint_path, item))
|
||||
g_return_val_if_reached (NULL);
|
||||
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);
|
||||
update_rollback_timeout (self);
|
||||
|
||||
return checkpoint;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_checkpoint_manager_destroy_all (NMCheckpointManager *self,
|
||||
GError **error)
|
||||
void
|
||||
nm_checkpoint_manager_destroy_all (NMCheckpointManager *self)
|
||||
{
|
||||
g_return_val_if_fail (self, FALSE);
|
||||
NMCheckpoint *checkpoint;
|
||||
|
||||
g_hash_table_remove_all (self->checkpoints);
|
||||
notify_checkpoints (self);
|
||||
g_return_if_fail (self);
|
||||
|
||||
return 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 *checkpoint_path,
|
||||
const char *path,
|
||||
GError **error)
|
||||
{
|
||||
gboolean ret;
|
||||
NMCheckpoint *checkpoint;
|
||||
|
||||
g_return_val_if_fail (self, FALSE);
|
||||
g_return_val_if_fail (checkpoint_path && checkpoint_path[0] == '/', FALSE);
|
||||
g_return_val_if_fail (path && path[0] == '/', FALSE);
|
||||
g_return_val_if_fail (!error || !*error, FALSE);
|
||||
|
||||
if (!nm_streq (checkpoint_path, "/")) {
|
||||
ret = g_hash_table_remove (self->checkpoints, checkpoint_path);
|
||||
if (ret) {
|
||||
notify_checkpoints (self);
|
||||
} else {
|
||||
g_set_error (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_INVALID_ARGUMENTS,
|
||||
"checkpoint %s does not exist", checkpoint_path);
|
||||
}
|
||||
return ret;
|
||||
} else
|
||||
return nm_checkpoint_manager_destroy_all (self, error);
|
||||
if (!nm_streq (path, "/")) {
|
||||
nm_checkpoint_manager_destroy_all (self);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error);
|
||||
if (!checkpoint)
|
||||
return FALSE;
|
||||
|
||||
destroy_checkpoint (self, checkpoint, TRUE);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_checkpoint_manager_rollback (NMCheckpointManager *self,
|
||||
const char *checkpoint_path,
|
||||
const char *path,
|
||||
GVariant **results,
|
||||
GError **error)
|
||||
{
|
||||
CheckpointItem *item;
|
||||
NMCheckpoint *checkpoint;
|
||||
|
||||
g_return_val_if_fail (self, FALSE);
|
||||
g_return_val_if_fail (checkpoint_path && checkpoint_path[0] == '/', 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);
|
||||
|
||||
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);
|
||||
checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error);
|
||||
if (!checkpoint)
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
*results = nm_checkpoint_rollback (item->checkpoint);
|
||||
g_hash_table_remove (self->checkpoints, checkpoint_path);
|
||||
notify_checkpoints (self);
|
||||
|
||||
*results = rollback_checkpoint (self, checkpoint);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
char **
|
||||
nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self)
|
||||
NMCheckpoint *
|
||||
nm_checkpoint_manager_lookup_by_path (NMCheckpointManager *self, const char *path, GError **error)
|
||||
{
|
||||
CheckpointItem *item;
|
||||
char **strv;
|
||||
guint num, i = 0;
|
||||
NMCheckpoint *checkpoint;
|
||||
|
||||
num = g_hash_table_size (self->checkpoints);
|
||||
if (!num) {
|
||||
nm_assert (c_list_is_empty (&self->list));
|
||||
g_return_val_if_fail (self, NULL);
|
||||
|
||||
checkpoint = (NMCheckpoint *) 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;
|
||||
}
|
||||
|
||||
strv = g_new (char *, num + 1);
|
||||
c_list_for_each_entry (item, &self->list, list)
|
||||
strv[i++] = g_strdup (nm_dbus_object_get_path (NM_DBUS_OBJECT (item->checkpoint)));
|
||||
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)
|
||||
{
|
||||
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)
|
||||
{
|
||||
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);
|
||||
|
||||
checkpoint = nm_checkpoint_manager_lookup_by_path (self, path, error);
|
||||
if (!checkpoint)
|
||||
return FALSE;
|
||||
|
||||
nm_checkpoint_adjust_rollback_timeout (checkpoint, add_timeout);
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
NMCheckpointManager *
|
||||
|
|
@ -347,22 +336,17 @@ nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec)
|
|||
* of NMManager shall surpass the lifetime of the NMCheckpointManager
|
||||
* instance. */
|
||||
self->_manager = manager;
|
||||
self->checkpoints = g_hash_table_new_full (nm_str_hash, g_str_equal,
|
||||
NULL, item_destroy);
|
||||
self->property_spec = spec;
|
||||
c_list_init (&self->list);
|
||||
|
||||
c_list_init (&self->checkpoints_lst_head);
|
||||
return self;
|
||||
}
|
||||
|
||||
void
|
||||
nm_checkpoint_manager_unref (NMCheckpointManager *self)
|
||||
nm_checkpoint_manager_free (NMCheckpointManager *self)
|
||||
{
|
||||
if (!self)
|
||||
return;
|
||||
|
||||
nm_clear_g_source (&self->rollback_timeout_id);
|
||||
g_hash_table_destroy (self->checkpoints);
|
||||
|
||||
nm_checkpoint_manager_destroy_all (self);
|
||||
g_slice_free (NMCheckpointManager, self);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -28,7 +28,12 @@
|
|||
typedef struct _NMCheckpointManager NMCheckpointManager;
|
||||
|
||||
NMCheckpointManager *nm_checkpoint_manager_new (NMManager *manager, GParamSpec *spec);
|
||||
void nm_checkpoint_manager_unref (NMCheckpointManager *self);
|
||||
|
||||
void nm_checkpoint_manager_free (NMCheckpointManager *self);
|
||||
|
||||
NMCheckpoint *nm_checkpoint_manager_lookup_by_path (NMCheckpointManager *self,
|
||||
const char *path,
|
||||
GError **error);
|
||||
|
||||
NMCheckpoint *nm_checkpoint_manager_create (NMCheckpointManager *self,
|
||||
const char *const*device_names,
|
||||
|
|
@ -36,17 +41,22 @@ NMCheckpoint *nm_checkpoint_manager_create (NMCheckpointManager *self,
|
|||
NMCheckpointCreateFlags flags,
|
||||
GError **error);
|
||||
|
||||
gboolean nm_checkpoint_manager_destroy_all (NMCheckpointManager *self,
|
||||
GError **error);
|
||||
void nm_checkpoint_manager_destroy_all (NMCheckpointManager *self);
|
||||
|
||||
gboolean nm_checkpoint_manager_destroy (NMCheckpointManager *self,
|
||||
const char *checkpoint_path,
|
||||
const char *path,
|
||||
GError **error);
|
||||
gboolean nm_checkpoint_manager_rollback (NMCheckpointManager *self,
|
||||
const char *checkpoint_path,
|
||||
const char *path,
|
||||
GVariant **results,
|
||||
GError **error);
|
||||
|
||||
char **nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self);
|
||||
gboolean nm_checkpoint_manager_adjust_rollback_timeout (NMCheckpointManager *self,
|
||||
const char *path,
|
||||
guint32 add_timeout,
|
||||
GError **error);
|
||||
|
||||
const char **nm_checkpoint_manager_get_checkpoint_paths (NMCheckpointManager *self,
|
||||
guint *out_length);
|
||||
|
||||
#endif /* __NM_CHECKPOINT_MANAGER_H__ */
|
||||
|
|
|
|||
|
|
@ -25,6 +25,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include "nm-active-connection.h"
|
||||
#include "nm-act-request.h"
|
||||
#include "nm-auth-subject.h"
|
||||
#include "nm-core-utils.h"
|
||||
#include "nm-dbus-interface.h"
|
||||
|
|
@ -48,27 +49,26 @@ typedef struct {
|
|||
NMUnmanFlagOp unmanaged_explicit;
|
||||
} DeviceCheckpoint;
|
||||
|
||||
NM_GOBJECT_PROPERTIES_DEFINE_BASE (
|
||||
NM_GOBJECT_PROPERTIES_DEFINE (NMCheckpoint,
|
||||
PROP_DEVICES,
|
||||
PROP_CREATED,
|
||||
PROP_ROLLBACK_TIMEOUT,
|
||||
);
|
||||
|
||||
typedef struct {
|
||||
struct _NMCheckpointPrivate {
|
||||
/* properties */
|
||||
GHashTable *devices;
|
||||
gint64 created;
|
||||
guint32 rollback_timeout;
|
||||
gint64 created_at_ms;
|
||||
guint32 rollback_timeout_s;
|
||||
guint timeout_id;
|
||||
/* private members */
|
||||
/* private members */
|
||||
NMManager *manager;
|
||||
gint64 rollback_ts;
|
||||
NMCheckpointCreateFlags flags;
|
||||
GHashTable *connection_uuids;
|
||||
} NMCheckpointPrivate;
|
||||
|
||||
struct _NMCheckpoint {
|
||||
NMDBusObject parent;
|
||||
NMCheckpointPrivate _priv;
|
||||
NMCheckpointTimeoutCallback timeout_cb;
|
||||
gpointer timeout_data;
|
||||
};
|
||||
|
||||
struct _NMCheckpointClass {
|
||||
|
|
@ -77,7 +77,7 @@ struct _NMCheckpointClass {
|
|||
|
||||
G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_DBUS_OBJECT)
|
||||
|
||||
#define NM_CHECKPOINT_GET_PRIVATE(self) _NM_GET_PRIVATE (self, NMCheckpoint, NM_IS_CHECKPOINT)
|
||||
#define NM_CHECKPOINT_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMCheckpoint, NM_IS_CHECKPOINT)
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
|
@ -101,20 +101,53 @@ G_DEFINE_TYPE (NMCheckpoint, nm_checkpoint, NM_TYPE_DBUS_OBJECT)
|
|||
|
||||
/*****************************************************************************/
|
||||
|
||||
guint64
|
||||
nm_checkpoint_get_rollback_ts (NMCheckpoint *self)
|
||||
void
|
||||
nm_checkpoint_log_destroy (NMCheckpoint *self)
|
||||
{
|
||||
g_return_val_if_fail (NM_IS_CHECKPOINT (self), 0);
|
||||
|
||||
return NM_CHECKPOINT_GET_PRIVATE (self)->rollback_ts;
|
||||
_LOGI ("destroy %s", nm_dbus_object_get_path (NM_DBUS_OBJECT (self)));
|
||||
}
|
||||
|
||||
gboolean
|
||||
nm_checkpoint_includes_device (NMCheckpoint *self, NMDevice *device)
|
||||
void
|
||||
nm_checkpoint_set_timeout_callback (NMCheckpoint *self,
|
||||
NMCheckpointTimeoutCallback callback,
|
||||
gpointer user_data)
|
||||
{
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
|
||||
return g_hash_table_contains (priv->devices, device);
|
||||
/* 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;
|
||||
}
|
||||
|
||||
NMDevice *
|
||||
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;
|
||||
}
|
||||
|
||||
NMDevice *
|
||||
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;
|
||||
}
|
||||
|
||||
static NMSettingsConnection *
|
||||
|
|
@ -348,11 +381,10 @@ next_dev:
|
|||
}
|
||||
|
||||
if (NM_FLAGS_HAS (priv->flags, NM_CHECKPOINT_CREATE_FLAG_DISCONNECT_NEW_DEVICES)) {
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDeviceState state;
|
||||
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst) {
|
||||
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);
|
||||
|
|
@ -371,8 +403,7 @@ next_dev:
|
|||
}
|
||||
|
||||
static DeviceCheckpoint *
|
||||
device_checkpoint_create (NMDevice *device,
|
||||
GError **error)
|
||||
device_checkpoint_create (NMDevice *device)
|
||||
{
|
||||
DeviceCheckpoint *dev_checkpoint;
|
||||
NMConnection *applied_connection;
|
||||
|
|
@ -380,6 +411,9 @@ device_checkpoint_create (NMDevice *device,
|
|||
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);
|
||||
|
|
@ -389,25 +423,21 @@ device_checkpoint_create (NMDevice *device,
|
|||
dev_checkpoint->realized = nm_device_is_real (device);
|
||||
|
||||
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);
|
||||
dev_checkpoint->unmanaged_explicit = !!nm_device_get_unmanaged_flags (device,
|
||||
NM_UNMANAGED_USER_EXPLICIT);
|
||||
} else
|
||||
dev_checkpoint->unmanaged_explicit = NM_UNMAN_FLAG_OP_FORGET;
|
||||
|
||||
applied_connection = nm_device_get_applied_connection (device);
|
||||
if (applied_connection) {
|
||||
dev_checkpoint->applied_connection =
|
||||
nm_simple_connection_new_clone (applied_connection);
|
||||
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);
|
||||
|
||||
settings_connection = nm_device_get_settings_connection (device);
|
||||
g_return_val_if_fail (settings_connection, NULL);
|
||||
dev_checkpoint->applied_connection = nm_simple_connection_new_clone (applied_connection);
|
||||
dev_checkpoint->settings_connection =
|
||||
nm_simple_connection_new_clone (NM_CONNECTION (settings_connection));
|
||||
|
||||
act_request = nm_device_get_act_request (device);
|
||||
g_return_val_if_fail (act_request, NULL);
|
||||
nm_simple_connection_new_clone (NM_CONNECTION (settings_connection));
|
||||
dev_checkpoint->ac_version_id =
|
||||
nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request));
|
||||
nm_active_connection_version_id_get (NM_ACTIVE_CONNECTION (act_request));
|
||||
}
|
||||
|
||||
return dev_checkpoint;
|
||||
|
|
@ -426,6 +456,57 @@ device_checkpoint_destroy (gpointer data)
|
|||
g_slice_free (DeviceCheckpoint, dev_checkpoint);
|
||||
}
|
||||
|
||||
static gboolean
|
||||
_timeout_cb (gpointer user_data)
|
||||
{
|
||||
NMCheckpoint *self = user_data;
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
|
||||
priv->timeout_id = 0;
|
||||
|
||||
if (priv->timeout_cb)
|
||||
priv->timeout_cb (self, priv->timeout_data);
|
||||
|
||||
/* beware, @self likely got destroyed! */
|
||||
return G_SOURCE_REMOVE;
|
||||
}
|
||||
|
||||
void
|
||||
nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout)
|
||||
{
|
||||
guint32 rollback_timeout_s;
|
||||
gint64 now_ms, add_timeout_ms, rollback_timeout_ms;
|
||||
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
|
||||
nm_clear_g_source (&priv->timeout_id);
|
||||
|
||||
if (add_timeout == 0)
|
||||
rollback_timeout_s = 0;
|
||||
else {
|
||||
now_ms = nm_utils_get_monotonic_timestamp_ms ();
|
||||
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
|
||||
* 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);
|
||||
|
||||
/* 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);
|
||||
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -434,22 +515,20 @@ get_property (GObject *object, guint prop_id,
|
|||
{
|
||||
NMCheckpoint *self = NM_CHECKPOINT (object);
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
gs_free_slist GSList *devices = NULL;
|
||||
GHashTableIter iter;
|
||||
NMDevice *device;
|
||||
|
||||
switch (prop_id) {
|
||||
case PROP_DEVICES:
|
||||
g_hash_table_iter_init (&iter, priv->devices);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &device, NULL))
|
||||
devices = g_slist_append (devices, device);
|
||||
nm_dbus_utils_g_value_set_object_path_array (value, devices, NULL, NULL);
|
||||
nm_dbus_utils_g_value_set_object_path_from_hash (value,
|
||||
priv->devices,
|
||||
FALSE);
|
||||
break;
|
||||
case PROP_CREATED:
|
||||
g_value_set_int64 (value, priv->created);
|
||||
g_value_set_int64 (value,
|
||||
nm_utils_monotonic_timestamp_as_boottime (priv->created_at_ms,
|
||||
NM_UTILS_NS_PER_MSEC));
|
||||
break;
|
||||
case PROP_ROLLBACK_TIMEOUT:
|
||||
g_value_set_uint (value, priv->rollback_timeout);
|
||||
g_value_set_uint (value, priv->rollback_timeout_s);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
@ -462,47 +541,47 @@ get_property (GObject *object, guint prop_id,
|
|||
static void
|
||||
nm_checkpoint_init (NMCheckpoint *self)
|
||||
{
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
NMCheckpointPrivate *priv;
|
||||
|
||||
priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_CHECKPOINT, NMCheckpointPrivate);
|
||||
|
||||
self->_priv = priv;
|
||||
|
||||
c_list_init (&self->checkpoints_lst);
|
||||
|
||||
priv->devices = g_hash_table_new_full (nm_direct_hash, NULL,
|
||||
NULL, device_checkpoint_destroy);
|
||||
}
|
||||
|
||||
NMCheckpoint *
|
||||
nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags, GError **error)
|
||||
nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_timeout_s,
|
||||
NMCheckpointCreateFlags flags)
|
||||
{
|
||||
NMCheckpoint *self;
|
||||
NMCheckpointPrivate *priv;
|
||||
NMSettingsConnection *const *con;
|
||||
DeviceCheckpoint *dev_checkpoint;
|
||||
NMDevice *device;
|
||||
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 (!error || !*error, NULL);
|
||||
|
||||
if (!devices->len) {
|
||||
g_set_error_literal (error,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_INVALID_ARGUMENTS,
|
||||
"no device available");
|
||||
return 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 = manager;
|
||||
priv->created = nm_utils_monotonic_timestamp_as_boottime (nm_utils_get_monotonic_timestamp_ms (),
|
||||
NM_UTILS_NS_PER_MSEC);
|
||||
priv->rollback_timeout = rollback_timeout;
|
||||
priv->rollback_ts = rollback_timeout ?
|
||||
(nm_utils_get_monotonic_timestamp_ms () + ((gint64) rollback_timeout * 1000)) :
|
||||
0;
|
||||
priv->rollback_timeout_s = rollback_timeout_s;
|
||||
priv->created_at_ms = nm_utils_get_monotonic_timestamp_ms ();
|
||||
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++) {
|
||||
|
|
@ -512,13 +591,15 @@ nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_time
|
|||
}
|
||||
|
||||
for (i = 0; i < devices->len; i++) {
|
||||
device = (NMDevice *) devices->pdata[i];
|
||||
dev_checkpoint = device_checkpoint_create (device, error);
|
||||
if (!dev_checkpoint) {
|
||||
g_object_unref (self);
|
||||
return NULL;
|
||||
}
|
||||
g_hash_table_insert (priv->devices, device, dev_checkpoint);
|
||||
NMDevice *device = devices->pdata[i];
|
||||
|
||||
/* FIXME: as long as the check point instance exists, it won't let go
|
||||
* of the device. That is a bug, for example, if you have a ethernet
|
||||
* device that gets removed (rmmod), the checkpoint will reference
|
||||
* a non-existing D-Bus path of a device. */
|
||||
g_hash_table_insert (priv->devices,
|
||||
device,
|
||||
device_checkpoint_create (device));
|
||||
}
|
||||
|
||||
return self;
|
||||
|
|
@ -530,9 +611,13 @@ dispose (GObject *object)
|
|||
NMCheckpoint *self = NM_CHECKPOINT (object);
|
||||
NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
|
||||
|
||||
nm_assert (c_list_is_empty (&self->checkpoints_lst));
|
||||
|
||||
g_clear_pointer (&priv->devices, g_hash_table_unref);
|
||||
g_clear_pointer (&priv->connection_uuids, g_hash_table_unref);
|
||||
|
||||
nm_clear_g_source (&priv->timeout_id);
|
||||
|
||||
G_OBJECT_CLASS (nm_checkpoint_parent_class)->dispose (object);
|
||||
}
|
||||
|
||||
|
|
@ -557,6 +642,8 @@ 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);
|
||||
|
||||
|
|
|
|||
|
|
@ -35,16 +35,35 @@
|
|||
#define NM_CHECKPOINT_CREATED "created"
|
||||
#define NM_CHECKPOINT_ROLLBACK_TIMEOUT "rollback-timeout"
|
||||
|
||||
typedef struct _NMCheckpoint NMCheckpoint;
|
||||
typedef struct _NMCheckpointPrivate NMCheckpointPrivate;
|
||||
|
||||
typedef struct {
|
||||
NMDBusObject parent;
|
||||
NMCheckpointPrivate *_priv;
|
||||
CList checkpoints_lst;
|
||||
} NMCheckpoint;
|
||||
|
||||
typedef struct _NMCheckpointClass NMCheckpointClass;
|
||||
|
||||
GType nm_checkpoint_get_type (void);
|
||||
|
||||
NMCheckpoint *nm_checkpoint_new (NMManager *manager, GPtrArray *devices, guint32 rollback_timeout,
|
||||
NMCheckpointCreateFlags flags, GError **error);
|
||||
NMCheckpointCreateFlags flags);
|
||||
|
||||
typedef void (*NMCheckpointTimeoutCallback) (NMCheckpoint *self,
|
||||
gpointer user_data);
|
||||
|
||||
void nm_checkpoint_log_destroy (NMCheckpoint *self);
|
||||
|
||||
void nm_checkpoint_set_timeout_callback (NMCheckpoint *self,
|
||||
NMCheckpointTimeoutCallback callback,
|
||||
gpointer user_data);
|
||||
|
||||
guint64 nm_checkpoint_get_rollback_ts (NMCheckpoint *checkpoint);
|
||||
gboolean nm_checkpoint_includes_device (NMCheckpoint *checkpoint, NMDevice *device);
|
||||
GVariant *nm_checkpoint_rollback (NMCheckpoint *self);
|
||||
|
||||
void nm_checkpoint_adjust_rollback_timeout (NMCheckpoint *self, guint32 add_timeout);
|
||||
|
||||
NMDevice *nm_checkpoint_includes_devices (NMCheckpoint *self, NMDevice *const*devices, guint n_devices);
|
||||
NMDevice *nm_checkpoint_includes_devices_of (NMCheckpoint *self, NMCheckpoint *cp_for_devices);
|
||||
|
||||
#endif /* __NETWORKMANAGER_CHECKPOINT_H__ */
|
||||
|
|
|
|||
|
|
@ -121,32 +121,35 @@ nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object)
|
|||
}
|
||||
|
||||
void
|
||||
nm_dbus_utils_g_value_set_object_path_array (GValue *value,
|
||||
GSList *objects,
|
||||
gboolean (*filter_func) (GObject *object, gpointer user_data),
|
||||
gpointer user_data)
|
||||
nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value,
|
||||
GHashTable *hash /* has keys of NMDBusObject type. */,
|
||||
gboolean expect_all_exported)
|
||||
{
|
||||
char **paths;
|
||||
guint i;
|
||||
GSList *iter;
|
||||
NMDBusObject *obj;
|
||||
char **strv;
|
||||
guint i, n;
|
||||
GHashTableIter iter;
|
||||
|
||||
paths = g_new (char *, g_slist_length (objects) + 1);
|
||||
for (i = 0, iter = objects; iter; iter = iter->next) {
|
||||
NMDBusObject *object = iter->data;
|
||||
nm_assert (value);
|
||||
nm_assert (hash);
|
||||
|
||||
n = g_hash_table_size (hash);
|
||||
strv = g_new (char *, n + 1);
|
||||
i = 0;
|
||||
g_hash_table_iter_init (&iter, hash);
|
||||
while (g_hash_table_iter_next (&iter, (gpointer *) &obj, NULL)) {
|
||||
const char *path;
|
||||
|
||||
path = nm_dbus_object_get_path (object);
|
||||
if (!path)
|
||||
path = nm_dbus_object_get_path (obj);
|
||||
if (!path) {
|
||||
nm_assert (!expect_all_exported);
|
||||
continue;
|
||||
if ( filter_func
|
||||
&& !filter_func ((GObject *) object, user_data))
|
||||
continue;
|
||||
paths[i++] = g_strdup (path);
|
||||
}
|
||||
strv[i++] = g_strdup (path);
|
||||
}
|
||||
paths[i] = NULL;
|
||||
g_value_take_boxed (value, paths);
|
||||
nm_assert (i <= n);
|
||||
strv[i] = NULL;
|
||||
g_value_take_boxed (value, strv);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -166,9 +166,8 @@ GVariant *nm_dbus_utils_get_property (GObject *obj,
|
|||
|
||||
void nm_dbus_utils_g_value_set_object_path (GValue *value, gpointer object);
|
||||
|
||||
void nm_dbus_utils_g_value_set_object_path_array (GValue *value,
|
||||
GSList *objects,
|
||||
gboolean (*filter_func) (GObject *object, gpointer user_data),
|
||||
gpointer user_data);
|
||||
void nm_dbus_utils_g_value_set_object_path_from_hash (GValue *value,
|
||||
GHashTable *hash,
|
||||
gboolean expect_all_exported);
|
||||
|
||||
#endif /* __NM_DBUS_UTILS_H__ */
|
||||
|
|
|
|||
|
|
@ -5956,13 +5956,15 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
|
|||
GVariant *variant = NULL;
|
||||
GError *error = NULL;
|
||||
const char *arg = NULL;
|
||||
guint32 add_timeout;
|
||||
|
||||
op = nm_auth_chain_get_data (chain, "audit-op");
|
||||
priv->auth_chains = g_slist_remove (priv->auth_chains, chain);
|
||||
result = nm_auth_chain_get_result (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK);
|
||||
|
||||
if ( nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_DESTROY)
|
||||
|| nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK))
|
||||
if (NM_IN_STRSET (op, NM_AUDIT_OP_CHECKPOINT_DESTROY,
|
||||
NM_AUDIT_OP_CHECKPOINT_ROLLBACK,
|
||||
NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT))
|
||||
arg = checkpoint_path = nm_auth_chain_get_data (chain, "checkpoint_path");
|
||||
|
||||
if (auth_error) {
|
||||
|
|
@ -5995,6 +5997,10 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
|
|||
} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ROLLBACK)) {
|
||||
nm_checkpoint_manager_rollback (_checkpoint_mgr_get (self, TRUE),
|
||||
checkpoint_path, &variant, &error);
|
||||
} else if (nm_streq0 (op, NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT)) {
|
||||
add_timeout = GPOINTER_TO_UINT (nm_auth_chain_get_data (chain, "add_timeout"));
|
||||
nm_checkpoint_manager_adjust_rollback_timeout (_checkpoint_mgr_get (self, TRUE),
|
||||
checkpoint_path, add_timeout, &error);
|
||||
} else
|
||||
g_return_if_reached ();
|
||||
}
|
||||
|
|
@ -6007,7 +6013,6 @@ checkpoint_auth_done_cb (NMAuthChain *chain,
|
|||
else
|
||||
g_dbus_method_invocation_return_value (context, variant);
|
||||
|
||||
|
||||
nm_auth_chain_unref (chain);
|
||||
}
|
||||
|
||||
|
|
@ -6110,6 +6115,39 @@ impl_manager_checkpoint_rollback (NMDBusObject *obj,
|
|||
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
|
||||
}
|
||||
|
||||
static void
|
||||
impl_manager_checkpoint_adjust_rollback_timeout (NMDBusObject *obj,
|
||||
const NMDBusInterfaceInfoExtended *interface_info,
|
||||
const NMDBusMethodInfoExtended *method_info,
|
||||
GDBusConnection *connection,
|
||||
const char *sender,
|
||||
GDBusMethodInvocation *invocation,
|
||||
GVariant *parameters)
|
||||
{
|
||||
NMManager *self = NM_MANAGER (obj);
|
||||
NMManagerPrivate *priv = NM_MANAGER_GET_PRIVATE (self);
|
||||
NMAuthChain *chain;
|
||||
const char *checkpoint_path;
|
||||
guint32 add_timeout;
|
||||
|
||||
chain = nm_auth_chain_new_context (invocation, checkpoint_auth_done_cb, self);
|
||||
if (!chain) {
|
||||
g_dbus_method_invocation_return_error_literal (invocation,
|
||||
NM_MANAGER_ERROR,
|
||||
NM_MANAGER_ERROR_PERMISSION_DENIED,
|
||||
"Unable to authenticate request.");
|
||||
return;
|
||||
}
|
||||
|
||||
g_variant_get (parameters, "(&ou)", &checkpoint_path, &add_timeout);
|
||||
|
||||
priv->auth_chains = g_slist_append (priv->auth_chains, chain);
|
||||
nm_auth_chain_set_data (chain, "audit-op", NM_AUDIT_OP_CHECKPOINT_ADJUST_ROLLBACK_TIMEOUT, NULL);
|
||||
nm_auth_chain_set_data (chain, "checkpoint_path", g_strdup (checkpoint_path), g_free);
|
||||
nm_auth_chain_set_data (chain, "add_timeout", GUINT_TO_POINTER (add_timeout), NULL);
|
||||
nm_auth_chain_add_call (chain, NM_AUTH_PERMISSION_CHECKPOINT_ROLLBACK, TRUE);
|
||||
}
|
||||
|
||||
/*****************************************************************************/
|
||||
|
||||
static void
|
||||
|
|
@ -6471,7 +6509,6 @@ get_property (GObject *object, guint prop_id,
|
|||
NMConfigData *config_data;
|
||||
const NMGlobalDnsConfig *dns_config;
|
||||
const char *type;
|
||||
char **strv;
|
||||
const char *path;
|
||||
NMActiveConnection *ac;
|
||||
GPtrArray *ptrarr;
|
||||
|
|
@ -6578,10 +6615,11 @@ get_property (GObject *object, guint prop_id,
|
|||
TRUE)));
|
||||
break;
|
||||
case PROP_CHECKPOINTS:
|
||||
strv = NULL;
|
||||
if (priv->checkpoint_mgr)
|
||||
strv = nm_checkpoint_manager_get_checkpoint_paths (priv->checkpoint_mgr);
|
||||
g_value_take_boxed (value, strv);
|
||||
g_value_take_boxed (value,
|
||||
priv->checkpoint_mgr
|
||||
? nm_utils_strv_make_deep_copied (nm_checkpoint_manager_get_checkpoint_paths (priv->checkpoint_mgr,
|
||||
NULL))
|
||||
: NULL);
|
||||
break;
|
||||
default:
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
||||
|
|
@ -6664,10 +6702,7 @@ dispose (GObject *object)
|
|||
|
||||
nm_clear_g_source (&priv->devices_inited_id);
|
||||
|
||||
if (priv->checkpoint_mgr) {
|
||||
nm_checkpoint_manager_destroy_all (priv->checkpoint_mgr, NULL);
|
||||
g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_unref);
|
||||
}
|
||||
g_clear_pointer (&priv->checkpoint_mgr, nm_checkpoint_manager_free);
|
||||
|
||||
if (priv->auth_mgr) {
|
||||
g_signal_handlers_disconnect_by_func (priv->auth_mgr,
|
||||
|
|
@ -6967,6 +7002,16 @@ static const NMDBusInterfaceInfoExtended interface_info_manager = {
|
|||
),
|
||||
.handle = impl_manager_checkpoint_rollback,
|
||||
),
|
||||
NM_DEFINE_DBUS_METHOD_INFO_EXTENDED (
|
||||
NM_DEFINE_GDBUS_METHOD_INFO_INIT (
|
||||
"CheckpointAdjustRollbackTimeout",
|
||||
.in_args = NM_DEFINE_GDBUS_ARG_INFOS (
|
||||
NM_DEFINE_GDBUS_ARG_INFO ("checkpoint", "o"),
|
||||
NM_DEFINE_GDBUS_ARG_INFO ("add_timeout", "u"),
|
||||
),
|
||||
),
|
||||
.handle = impl_manager_checkpoint_adjust_rollback_timeout,
|
||||
),
|
||||
),
|
||||
.signals = NM_DEFINE_GDBUS_SIGNAL_INFOS (
|
||||
&nm_signal_info_property_changed_legacy,
|
||||
|
|
|
|||
|
|
@ -83,13 +83,14 @@ gboolean nm_manager_start (NMManager *manager,
|
|||
GError **error);
|
||||
void nm_manager_stop (NMManager *manager);
|
||||
NMState nm_manager_get_state (NMManager *manager);
|
||||
|
||||
const CList * nm_manager_get_active_connections (NMManager *manager);
|
||||
|
||||
#define nm_manager_for_each_active_connection(manager, iter, tmp_list) \
|
||||
for (tmp_list = nm_manager_get_active_connections (manager), \
|
||||
iter = c_list_entry (tmp_list->next, NMActiveConnection, active_connections_lst); \
|
||||
({ \
|
||||
gboolean _has_next = (&iter->active_connections_lst != tmp_list); \
|
||||
const gboolean _has_next = (&iter->active_connections_lst != tmp_list); \
|
||||
\
|
||||
if (!_has_next) \
|
||||
iter = NULL; \
|
||||
|
|
@ -107,6 +108,18 @@ void nm_manager_write_device_state (NMManager *manager);
|
|||
|
||||
const CList * nm_manager_get_devices (NMManager *manager);
|
||||
|
||||
#define nm_manager_for_each_device(manager, iter, tmp_list) \
|
||||
for (tmp_list = nm_manager_get_devices (manager), \
|
||||
iter = c_list_entry (tmp_list->next, NMDevice, devices_lst); \
|
||||
({ \
|
||||
const gboolean _has_next = (&iter->devices_lst != tmp_list); \
|
||||
\
|
||||
if (!_has_next) \
|
||||
iter = NULL; \
|
||||
_has_next; \
|
||||
}); \
|
||||
iter = c_list_entry (iter->devices_lst.next, NMDevice, devices_lst))
|
||||
|
||||
NMDevice * nm_manager_get_device_by_ifindex (NMManager *manager,
|
||||
int ifindex);
|
||||
NMDevice * nm_manager_get_device_by_path (NMManager *manager,
|
||||
|
|
|
|||
|
|
@ -385,7 +385,7 @@ get_best_ip_device (NMPolicy *self,
|
|||
gboolean fully_activated)
|
||||
{
|
||||
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *device;
|
||||
NMDevice *best_device;
|
||||
NMDevice *prev_device;
|
||||
|
|
@ -401,8 +401,7 @@ get_best_ip_device (NMPolicy *self,
|
|||
? (fully_activated ? priv->default_device4 : priv->activating_device4)
|
||||
: (fully_activated ? priv->default_device6 : priv->activating_device6);
|
||||
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst) {
|
||||
nm_manager_for_each_device (priv->manager, device, tmp_lst) {
|
||||
NMDeviceState state;
|
||||
const NMPObject *r;
|
||||
NMConnection *connection;
|
||||
|
|
@ -462,11 +461,10 @@ static gboolean
|
|||
all_devices_not_active (NMPolicy *self)
|
||||
{
|
||||
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *device;
|
||||
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst) {
|
||||
nm_manager_for_each_device (priv->manager, device, tmp_lst) {
|
||||
NMDeviceState state;
|
||||
|
||||
state = nm_device_get_state (device);
|
||||
|
|
@ -2186,13 +2184,12 @@ schedule_activate_all_cb (gpointer user_data)
|
|||
{
|
||||
NMPolicy *self = user_data;
|
||||
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *device;
|
||||
|
||||
priv->schedule_activate_all_id = 0;
|
||||
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst)
|
||||
nm_manager_for_each_device (priv->manager, device, tmp_lst)
|
||||
schedule_activate_check (self, device);
|
||||
|
||||
return G_SOURCE_REMOVE;
|
||||
|
|
@ -2227,7 +2224,7 @@ firewall_state_changed (NMFirewallManager *manager,
|
|||
{
|
||||
NMPolicy *self = (NMPolicy *) user_data;
|
||||
NMPolicyPrivate *priv = NM_POLICY_GET_PRIVATE (self);
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *device;
|
||||
|
||||
if (initialized_now) {
|
||||
|
|
@ -2241,8 +2238,7 @@ firewall_state_changed (NMFirewallManager *manager,
|
|||
return;
|
||||
|
||||
/* add interface of each device to correct zone */
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (device, all_devices, devices_lst)
|
||||
nm_manager_for_each_device (priv->manager, device, tmp_lst)
|
||||
nm_device_update_firewall_zone (device);
|
||||
}
|
||||
|
||||
|
|
@ -2288,14 +2284,13 @@ connection_updated (NMSettings *settings,
|
|||
{
|
||||
NMPolicyPrivate *priv = user_data;
|
||||
NMPolicy *self = _PRIV_TO_SELF (priv);
|
||||
const CList *all_devices;
|
||||
const CList *tmp_lst;
|
||||
NMDevice *device = NULL;
|
||||
NMDevice *dev;
|
||||
|
||||
if (by_user) {
|
||||
/* find device with given connection */
|
||||
all_devices = nm_manager_get_devices (priv->manager);
|
||||
c_list_for_each_entry (dev, all_devices, devices_lst) {
|
||||
nm_manager_for_each_device (priv->manager, dev, tmp_lst) {
|
||||
if (nm_device_get_settings_connection (dev) == connection) {
|
||||
device = dev;
|
||||
break;
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue