summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThomas Haller <thaller@redhat.com>2018-04-04 14:02:31 +0200
committerThomas Haller <thaller@redhat.com>2018-04-04 14:02:31 +0200
commitaefb66d547a6ac041d54bfb5e02ae0a9b5665b4c (patch)
tree12e85bc69a2e86711d07f3a5d7187002093783d5
parentcc1920d71470042c4e0837848da9183526b663d0 (diff)
parent617bf418707a286896245c4a5a79040639e876ba (diff)
downloadNetworkManager-aefb66d547a6ac041d54bfb5e02ae0a9b5665b4c.tar.gz
checkpoint: merge branch 'th/checkpoint'
https://github.com/NetworkManager/NetworkManager/pull/83
-rw-r--r--Makefile.am4
-rw-r--r--Makefile.examples2
-rwxr-xr-x[-rw-r--r--]examples/python/gi/checkpoint.py183
-rw-r--r--examples/python/nmex.py72
-rw-r--r--introspection/org.freedesktop.NetworkManager.xml21
-rw-r--r--libnm-core/nm-dbus-interface.h17
-rw-r--r--libnm/libnm.ver9
-rw-r--r--libnm/nm-client.c159
-rw-r--r--libnm/nm-client.h47
-rw-r--r--libnm/nm-manager.c164
-rw-r--r--libnm/nm-manager.h43
-rw-r--r--src/devices/wifi/nm-device-olpc-mesh.c5
-rw-r--r--src/devices/wifi/nm-iwd-manager.c30
-rw-r--r--src/nm-audit-manager.h1
-rw-r--r--src/nm-checkpoint-manager.c328
-rw-r--r--src/nm-checkpoint-manager.h22
-rw-r--r--src/nm-checkpoint.c229
-rw-r--r--src/nm-checkpoint.h27
-rw-r--r--src/nm-dbus-utils.c45
-rw-r--r--src/nm-dbus-utils.h7
-rw-r--r--src/nm-manager.c69
-rw-r--r--src/nm-manager.h15
-rw-r--r--src/nm-policy.c25
23 files changed, 1013 insertions, 511 deletions
diff --git a/Makefile.am b/Makefile.am
index f52e1f0248..61b89bd9f8 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -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 \
diff --git a/Makefile.examples b/Makefile.examples
index d49db6ce86..d5433395c3 100644
--- a/Makefile.examples
+++ b/Makefile.examples
@@ -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 \
diff --git a/examples/python/gi/checkpoint.py b/examples/python/gi/checkpoint.py
index 513e6c3a0a..7c36cdba57 100644..100755
--- a/examples/python/gi/checkpoint.py
+++ b/examples/python/gi/checkpoint.py
@@ -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):
+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:
- 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()
+ 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: %s\n" % e.message)
+ sys.exit("Failed: missing argument timeout")
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()
+ 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 find_checkpoint(client, arg):
- try:
- num = int(arg)
- path = "/org/freedesktop/NetworkManager/Checkpoint/%u" % num
- except Exception, e:
- path = arg
+ 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()
- for c in client.get_checkpoints():
- if c.get_path() == path:
- return c
- return None
+ 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)
+
+ 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_rollback_async(checkpoint, None, rollback_cb, None)
+ 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()
diff --git a/examples/python/nmex.py b/examples/python/nmex.py
new file mode 100644
index 0000000000..a85eecaf87
--- /dev/null
+++ b/examples/python/nmex.py
@@ -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
+
+###############################################################################
diff --git a/introspection/org.freedesktop.NetworkManager.xml b/introspection/org.freedesktop.NetworkManager.xml
index 26a618c1bf..b8ad5911f2 100644
--- a/introspection/org.freedesktop.NetworkManager.xml
+++ b/introspection/org.freedesktop.NetworkManager.xml
@@ -252,6 +252,27 @@
</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:
The list of realized network devices. Realized devices are those which
diff --git a/libnm-core/nm-dbus-interface.h b/libnm-core/nm-dbus-interface.h
index b2e448dfa3..ec9c7f1aee 100644
--- a/libnm-core/nm-dbus-interface.h
+++ b/libnm-core/nm-dbus-interface.h
@@ -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;
/**
diff --git a/libnm/libnm.ver b/libnm/libnm.ver
index b475dcf7ee..386216184e 100644
--- a/libnm/libnm.ver
+++ b/libnm/libnm.ver
@@ -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;
diff --git a/libnm/nm-client.c b/libnm/nm-client.c
index da0c100804..a31a0845e5 100644
--- a/libnm/nm-client.c
+++ b/libnm/nm-client.c
@@ -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 */
/****************************************************************/
diff --git a/libnm/nm-client.h b/libnm/nm-client.h
index 9833f48294..6f4a86c957 100644
--- a/libnm/nm-client.h
+++ b/libnm/nm-client.h
@@ -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__ */
diff --git a/libnm/nm-manager.c b/libnm/nm-manager.c
index 6ad5ad9d38..52b2e13510 100644
--- a/libnm/nm-manager.c
+++ b/libnm/nm-manager.c
@@ -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 */
diff --git a/libnm/nm-manager.h b/libnm/nm-manager.h
index ac0630ccf4..0a278aee58 100644
--- a/libnm/nm-manager.h
+++ b/libnm/nm-manager.h
@@ -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__ */
diff --git a/src/devices/wifi/nm-device-olpc-mesh.c b/src/devices/wifi/nm-device-olpc-mesh.c
index d655406437..cd2c68af86 100644
--- a/src/devices/wifi/nm-device-olpc-mesh.c
+++ b/src/devices/wifi/nm-device-olpc-mesh.c
@@ -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,
diff --git a/src/devices/wifi/nm-iwd-manager.c b/src/devices/wifi/nm-iwd-manager.c
index ea903bc724..450009f0c6 100644
--- a/src/devices/wifi/nm-iwd-manager.c
+++ b/src/devices/wifi/nm-iwd-manager.c
@@ -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);
diff --git a/src/nm-audit-manager.h b/src/nm-audit-manager.h
index 56e26584e5..59b8048f5a 100644
--- a/src/nm-audit-manager.h
+++ b/src/nm-audit-manager.h
@@ -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);
diff --git a/src/nm-checkpoint-manager.c b/src/nm-checkpoint-manager.c
index 7345f9a41d..e55d632b91 100644
--- a/src/nm-checkpoint-manager.c
+++ b/src/nm-checkpoint-manager.c
@@ -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);
-static gboolean
-rollback_timeout_cb (NMCheckpointManager *self)
-{
- CheckpointItem *item, *safe;
- GVariant *result;
- gint64 ts, now;
- const char *path;
- gboolean removed = FALSE;
-
- now = nm_utils_get_monotonic_timestamp_ms ();
-
- 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;
- }
- }
+ c_list_unlink (&checkpoint->checkpoints_lst);
- self->rollback_timeout_id = 0;
- update_rollback_timeout (self);
+ if (log_destroy)
+ nm_checkpoint_log_destroy (checkpoint);
- if (removed)
- notify_checkpoints (self);
+ notify_checkpoints (self);
- return G_SOURCE_REMOVE;
+ nm_dbus_object_unexport (NM_DBUS_OBJECT (checkpoint));
+ g_object_unref (checkpoint);
}
-static void
-update_rollback_timeout (NMCheckpointManager *self)
+static GVariant *
+rollback_checkpoint (NMCheckpointManager *self, NMCheckpoint *checkpoint)
{
- CheckpointItem *item;
- gint64 ts, delta, next = G_MAXINT64;
+ GVariant *result;
+ const CList *iter;
- c_list_for_each_entry (item, &self->list, list) {
- ts = nm_checkpoint_get_rollback_ts (item->checkpoint);
- if (ts && ts < next)
- next = ts;
- }
+ nm_assert (c_list_contains (&self->checkpoints_lst_head, &checkpoint->checkpoints_lst));
- nm_clear_g_source (&self->rollback_timeout_id);
+ /* 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);
- 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);
+ iter = iter->next;
+ if (nm_checkpoint_includes_devices_of (cp, checkpoint)) {
+ /* the younger checkpoint has overlapping devices and gets obsoleted.
+ * Destroy it. */
+ destroy_checkpoint (self, cp, TRUE);
+ }
}
+
+ result = nm_checkpoint_rollback (checkpoint);
+ destroy_checkpoint (self, checkpoint, FALSE);
+ return result;
}
-static NMCheckpoint *
-find_checkpoint_for_device (NMCheckpointManager *self, NMDevice *device)
+static void
+rollback_timeout_cb (NMCheckpoint *checkpoint,
+ gpointer user_data)
{
- CheckpointItem *item;
-
- c_list_for_each_entry (item, &self->list, list) {
- if (nm_checkpoint_includes_device (item->checkpoint, device))
- return item->checkpoint;
- }
+ NMCheckpointManager *self = user_data;
+ gs_unref_variant GVariant *result = NULL;
- 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);
+ devices = g_ptr_array_new ();
+
if (!device_paths || !device_paths[0]) {
- const char *device_path;
- const CList *all_devices;
- GPtrArray *paths;
+ const CList *tmp_lst;
- paths = g_ptr_array_new ();
- all_devices = nm_manager_get_devices (manager);
- c_list_for_each_entry (device, all_devices, devices_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;
+ } 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);
+ }
}
- 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;
- }
- g_ptr_array_add (devices, device);
+ if (!devices->len) {
+ g_set_error_literal (error,
+ NM_MANAGER_ERROR,
+ NM_MANAGER_ERROR_INVALID_ARGUMENTS,
+ "no device available");
+ return NULL;
}
- if (!NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL)) {
- for (i = 0; i < devices->len; i++) {
- device = devices->pdata[i];
- checkpoint = find_checkpoint_for_device (self, device);
- if (checkpoint) {
+ 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;
-
- if (NM_FLAGS_HAS (flags, NM_CHECKPOINT_CREATE_FLAG_DESTROY_ALL))
- g_hash_table_remove_all (self->checkpoints);
+ checkpoint = nm_checkpoint_new (manager, devices, rollback_timeout, flags);
- 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;
+
+ g_return_val_if_fail (self, NULL);
- num = g_hash_table_size (self->checkpoints);
- if (!num) {
- nm_assert (c_list_is_empty (&self->list));
+ 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);
}
diff --git a/src/nm-checkpoint-manager.h b/src/nm-checkpoint-manager.h
index 4ff75303ed..ca66ef168a 100644
--- a/src/nm-checkpoint-manager.h
+++ b/src/nm-checkpoint-manager.h
@@ -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__ */
diff --git a/src/nm-checkpoint.c b/src/nm-checkpoint.c
index d85d2d5499..c508405185 100644
--- a/src/nm-checkpoint.c
+++ b/src/nm-checkpoint.c
@@ -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)
+{
+ _LOGI ("destroy %s", nm_dbus_object_get_path (NM_DBUS_OBJECT (self)));
+}
+
+void
+nm_checkpoint_set_timeout_callback (NMCheckpoint *self,
+ NMCheckpointTimeoutCallback callback,
+ gpointer user_data)
+{
+ NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
+
+ /* 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)
{
- g_return_val_if_fail (NM_IS_CHECKPOINT (self), 0);
+ NMCheckpointPrivate *priv = NM_CHECKPOINT_GET_PRIVATE (self);
+ guint i;
- return NM_CHECKPOINT_GET_PRIVATE (self)->rollback_ts;
+ for (i = 0; i < n_devices; i++) {
+ if (g_hash_table_contains (priv->devices, devices[i]))
+ return devices[i];
+ }
+ return NULL;
}
-gboolean
-nm_checkpoint_includes_device (NMCheckpoint *self, NMDevice *device)
+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;
- return g_hash_table_contains (priv->devices, 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);
diff --git a/src/nm-checkpoint.h b/src/nm-checkpoint.h
index 5d0f73295a..c8598f380a 100644
--- a/src/nm-checkpoint.h
+++ b/src/nm-checkpoint.h
@@ -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__ */
diff --git a/src/nm-dbus-utils.c b/src/nm-dbus-utils.c
index eab6cb6125..2464ff79f7 100644
--- a/src/nm-dbus-utils.c
+++ b/src/nm-dbus-utils.c
@@ -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;
-
- paths = g_new (char *, g_slist_length (objects) + 1);
- for (i = 0, iter = objects; iter; iter = iter->next) {
- NMDBusObject *object = iter->data;
+ NMDBusObject *obj;
+ char **strv;
+ guint i, n;
+ GHashTableIter iter;
+
+ 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)
- continue;
- if ( filter_func
- && !filter_func ((GObject *) object, user_data))
+ path = nm_dbus_object_get_path (obj);
+ if (!path) {
+ nm_assert (!expect_all_exported);
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);
}
/*****************************************************************************/
-
-
diff --git a/src/nm-dbus-utils.h b/src/nm-dbus-utils.h
index 4b0ec5c477..1d9c92ec36 100644
--- a/src/nm-dbus-utils.h
+++ b/src/nm-dbus-utils.h
@@ -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__ */
diff --git a/src/nm-manager.c b/src/nm-manager.c
index 7629d0df34..b64cb39aa4 100644
--- a/src/nm-manager.c
+++ b/src/nm-manager.c
@@ -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,
diff --git a/src/nm-manager.h b/src/nm-manager.h
index 638ceed6ea..3d651c7f7d 100644
--- a/src/nm-manager.h
+++ b/src/nm-manager.h
@@ -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,
diff --git a/src/nm-policy.c b/src/nm-policy.c
index 72351efe06..3984feb326 100644
--- a/src/nm-policy.c
+++ b/src/nm-policy.c
@@ -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;