summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorBeniamino Galvani <bgalvani@redhat.com>2023-09-29 14:07:53 +0200
committerBeniamino Galvani <bgalvani@redhat.com>2024-02-21 11:16:04 +0100
commitee5845063d81ba5da7ed68b4caf9d0920ebb78db (patch)
tree2164353e2a2f5a934a6935d76a13dbb42c77ee24
parent8fd0d39444ddb3a386808a22badb0aad9b3b0d58 (diff)
dispatcher: support device-handler actions
"device-add" and "device-delete" actions are called for device-handlers of generic devices. They differ from other actions in the following aspects: - only one script is invoked, the one with name specified by the device-handler property; - the script is searched in the "device" subdirectory; - since there is only one script executed, the result and error string from that script are returned by NM in the callback function.
-rw-r--r--src/core/nm-dispatcher.c215
-rw-r--r--src/core/nm-dispatcher.h15
-rw-r--r--src/libnm-core-aux-extern/nm-dispatcher-api.h2
-rw-r--r--src/nm-dispatcher/nm-dispatcher.c108
4 files changed, 263 insertions, 77 deletions
diff --git a/src/core/nm-dispatcher.c b/src/core/nm-dispatcher.c
index f2016f14e5..b6c3cd6dc4 100644
--- a/src/core/nm-dispatcher.c
+++ b/src/core/nm-dispatcher.c
@@ -52,18 +52,22 @@
/*****************************************************************************/
+/* Type for generic callback function; must be cast to either
+ * NMDispatcherFunc or NMDispatcherFuncDH before using. */
+typedef void (*NMDispatcherCallback)(void);
+
struct NMDispatcherCallId {
- NMDispatcherFunc callback;
- gpointer user_data;
- const char *log_ifname;
- const char *log_con_uuid;
- GVariant *action_params;
- gint64 start_at_msec;
- NMDispatcherAction action;
- guint idle_id;
- guint32 request_id;
- bool is_action2 : 1;
- char extra_strings[];
+ NMDispatcherCallback callback;
+ gpointer user_data;
+ const char *log_ifname;
+ const char *log_con_uuid;
+ GVariant *action_params;
+ gint64 start_at_msec;
+ NMDispatcherAction action;
+ guint idle_id;
+ guint32 request_id;
+ bool is_action2 : 1;
+ char extra_strings[];
};
/*****************************************************************************/
@@ -98,14 +102,20 @@ action_need_device(NMDispatcherAction action)
return TRUE;
}
+static gboolean
+action_is_device_handler(NMDispatcherAction action)
+{
+ return NM_IN_SET(action, NM_DISPATCHER_ACTION_DEVICE_ADD, NM_DISPATCHER_ACTION_DEVICE_DELETE);
+}
+
static NMDispatcherCallId *
-dispatcher_call_id_new(guint32 request_id,
- gint64 start_at_msec,
- NMDispatcherAction action,
- NMDispatcherFunc callback,
- gpointer user_data,
- const char *log_ifname,
- const char *log_con_uuid)
+dispatcher_call_id_new(guint32 request_id,
+ gint64 start_at_msec,
+ NMDispatcherAction action,
+ NMDispatcherCallback callback,
+ gpointer user_data,
+ const char *log_ifname,
+ const char *log_con_uuid)
{
NMDispatcherCallId *call_id;
gsize l_log_ifname;
@@ -388,19 +398,42 @@ dispatch_result_to_string(DispatchResult result)
g_assert_not_reached();
}
+/*
+ * dispatcher_results_process:
+ * @action: the dispatcher action
+ * @request_id: request id
+ * @start_at_msec: the timestamp at which the dispatcher call was started
+ * @now_msec: the current timestamp in milliseconds
+ * @log_ifname: the interface name for logging
+ * @log_con_uuid: the connection UUID for logging
+ * @out_success: (out): for device-handler actions, the result of the script
+ * @out_error_msg: (out)(transfer full): for device-handler actions, the
+ * error message in case of failure
+ * @v_results: the GVariant containing the results to parse
+ * @is_action2: whether the D-Bus method is "Action2()" (or "Action()")
+ *
+ * Process the results of the dispatcher call.
+ *
+ */
static void
-dispatcher_results_process(guint32 request_id,
- gint64 start_at_msec,
- gint64 now_msec,
- const char *log_ifname,
- const char *log_con_uuid,
- GVariant *v_results,
- gboolean is_action2)
+dispatcher_results_process(NMDispatcherAction action,
+ guint32 request_id,
+ gint64 start_at_msec,
+ gint64 now_msec,
+ const char *log_ifname,
+ const char *log_con_uuid,
+ gboolean *out_success,
+ char **out_error_msg,
+ GVariant *v_results,
+ gboolean is_action2)
{
nm_auto_free_variant_iter GVariantIter *results = NULL;
const char *script, *err;
guint32 result;
gsize n_children;
+ gboolean action_is_dh = action_is_device_handler(action);
+
+ nm_assert(!action_is_dh || is_action2);
if (is_action2)
g_variant_get(v_results, "(a(susa{sv}))", &results);
@@ -417,8 +450,13 @@ dispatcher_results_process(guint32 request_id,
(int) ((now_msec - start_at_msec) % 1000),
n_children);
- if (n_children == 0)
+ if (n_children == 0) {
+ if (action_is_dh) {
+ NM_SET_OUT(out_success, FALSE);
+ NM_SET_OUT(out_error_msg, g_strdup("no result returned from dispatcher service"));
+ }
return;
+ }
while (TRUE) {
gs_unref_variant GVariant *options = NULL;
@@ -442,6 +480,11 @@ dispatcher_results_process(guint32 request_id,
dispatch_result_to_string(result),
err);
}
+ if (action_is_dh) {
+ NM_SET_OUT(out_success, result == DISPATCH_RESULT_SUCCESS);
+ NM_SET_OUT(out_error_msg, g_strdup(err));
+ break;
+ }
}
}
@@ -452,6 +495,9 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
gs_free_error GError *error = NULL;
NMDispatcherCallId *call_id = user_data;
gint64 now_msec;
+ gboolean action_is_dh;
+ gboolean success = TRUE;
+ gs_free char *error_msg = NULL;
nm_assert((gpointer) source == gl.dbus_connection);
@@ -459,7 +505,7 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
ret = g_dbus_connection_call_finish(G_DBUS_CONNECTION(source), result, &error);
- if (!ret && call_id->is_action2
+ if (!ret && call_id->is_action2 && !action_is_device_handler(call_id->action)
&& g_error_matches(error, G_DBUS_ERROR, G_DBUS_ERROR_UNKNOWN_METHOD)) {
_LOG3D(call_id,
"dispatcher service does not implement Action2() method, falling back to Action()");
@@ -493,38 +539,54 @@ dispatcher_done_cb(GObject *source, GAsyncResult *result, gpointer user_data)
(int) ((now_msec - call_id->start_at_msec) % 1000),
error->message);
} else {
- dispatcher_results_process(call_id->request_id,
+ dispatcher_results_process(call_id->action,
+ call_id->request_id,
call_id->start_at_msec,
now_msec,
call_id->log_ifname,
call_id->log_con_uuid,
+ &success,
+ &error_msg,
ret,
call_id->is_action2);
}
g_hash_table_remove(gl.requests, call_id);
+ action_is_dh = action_is_device_handler(call_id->action);
+
+ if (call_id->callback) {
+ if (action_is_dh) {
+ NMDispatcherFuncDH cb = (NMDispatcherFuncDH) call_id->callback;
+
+ cb(call_id, call_id->user_data, success, error_msg);
+ } else {
+ NMDispatcherFunc cb = (NMDispatcherFunc) call_id->callback;
- if (call_id->callback)
- call_id->callback(call_id, call_id->user_data);
+ cb(call_id, call_id->user_data);
+ }
+ }
dispatcher_call_id_free(call_id);
}
-static const char *action_table[] = {[NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME,
- [NM_DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP,
- [NM_DISPATCHER_ACTION_UP] = NMD_ACTION_UP,
- [NM_DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN,
- [NM_DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN,
- [NM_DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP,
- [NM_DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP,
- [NM_DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN,
- [NM_DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN,
- [NM_DISPATCHER_ACTION_DHCP_CHANGE_4] = NMD_ACTION_DHCP4_CHANGE,
- [NM_DISPATCHER_ACTION_DHCP_CHANGE_6] = NMD_ACTION_DHCP6_CHANGE,
- [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] =
- NMD_ACTION_CONNECTIVITY_CHANGE,
- [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY,
- [NM_DISPATCHER_ACTION_DNS_CHANGE] = NMD_ACTION_DNS_CHANGE};
+static const char *action_table[] = {
+ [NM_DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME,
+ [NM_DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP,
+ [NM_DISPATCHER_ACTION_UP] = NMD_ACTION_UP,
+ [NM_DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN,
+ [NM_DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN,
+ [NM_DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP,
+ [NM_DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP,
+ [NM_DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN,
+ [NM_DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN,
+ [NM_DISPATCHER_ACTION_DHCP_CHANGE_4] = NMD_ACTION_DHCP4_CHANGE,
+ [NM_DISPATCHER_ACTION_DHCP_CHANGE_6] = NMD_ACTION_DHCP6_CHANGE,
+ [NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE] = NMD_ACTION_CONNECTIVITY_CHANGE,
+ [NM_DISPATCHER_ACTION_REAPPLY] = NMD_ACTION_REAPPLY,
+ [NM_DISPATCHER_ACTION_DNS_CHANGE] = NMD_ACTION_DNS_CHANGE,
+ [NM_DISPATCHER_ACTION_DEVICE_ADD] = NMD_ACTION_DEVICE_ADD,
+ [NM_DISPATCHER_ACTION_DEVICE_DELETE] = NMD_ACTION_DEVICE_DELETE,
+};
static const char *
action_to_string(NMDispatcherAction action)
@@ -664,7 +726,7 @@ _dispatcher_call(NMDispatcherAction action,
NMConnectivityState connectivity_state,
const char *vpn_iface,
const NML3ConfigData *l3cd,
- NMDispatcherFunc callback,
+ NMDispatcherCallback callback,
gpointer user_data,
NMDispatcherCallId **out_call_id)
{
@@ -784,11 +846,14 @@ _dispatcher_call(NMDispatcherAction action,
error->message);
return FALSE;
}
- dispatcher_results_process(request_id,
+ dispatcher_results_process(action,
+ request_id,
start_at_msec,
now_msec,
log_ifname,
log_con_uuid,
+ NULL,
+ NULL,
ret,
is_action2);
return TRUE;
@@ -856,7 +921,7 @@ nm_dispatcher_call_hostname(NMDispatcherFunc callback,
NM_CONNECTIVITY_UNKNOWN,
NULL,
NULL,
- callback,
+ (NMDispatcherCallback) callback,
user_data,
out_call_id);
}
@@ -866,7 +931,7 @@ _dispatcher_call_device(NMDispatcherAction action,
NMDevice *device,
gboolean blocking,
NMActRequest *act_request,
- NMDispatcherFunc callback,
+ NMDispatcherCallback callback,
gpointer user_data,
NMDispatcherCallId **out_call_id)
{
@@ -919,11 +984,48 @@ nm_dispatcher_call_device(NMDispatcherAction action,
gpointer user_data,
NMDispatcherCallId **out_call_id)
{
+ g_return_val_if_fail(!action_is_device_handler(action), FALSE);
+
return _dispatcher_call_device(action,
device,
FALSE,
act_request,
- callback,
+ (NMDispatcherCallback) callback,
+ user_data,
+ out_call_id);
+}
+
+/**
+ * nm_dispatcher_call_device_handler:
+ * @action: the %NMDispatcherAction, must be device-add or device-remove
+ * @device: the #NMDevice the action applies to
+ * @act_request: the #NMActRequest for the action. If %NULL, use the
+ * current request of the device.
+ * @callback: a caller-supplied device-handler callback to execute when done
+ * @user_data: caller-supplied pointer passed to @callback
+ * @out_call_id: on success, a call identifier which can be passed to
+ * nm_dispatcher_call_cancel()
+ *
+ * This method always invokes the device dispatcher action asynchronously. To ignore
+ * the result, pass %NULL to @callback.
+ *
+ * Returns: %TRUE if the action was dispatched, %FALSE on failure
+ */
+gboolean
+nm_dispatcher_call_device_handler(NMDispatcherAction action,
+ NMDevice *device,
+ NMActRequest *act_request,
+ NMDispatcherFuncDH callback,
+ gpointer user_data,
+ NMDispatcherCallId **out_call_id)
+{
+ g_return_val_if_fail(action_is_device_handler(action), FALSE);
+
+ return _dispatcher_call_device(action,
+ device,
+ FALSE,
+ act_request,
+ (NMDispatcherCallback) callback,
user_data,
out_call_id);
}
@@ -945,6 +1047,8 @@ nm_dispatcher_call_device_sync(NMDispatcherAction action,
NMDevice *device,
NMActRequest *act_request)
{
+ g_return_val_if_fail(!action_is_device_handler(action), FALSE);
+
return _dispatcher_call_device(action, device, TRUE, act_request, NULL, NULL, NULL);
}
@@ -986,7 +1090,7 @@ nm_dispatcher_call_vpn(NMDispatcherAction action,
NM_CONNECTIVITY_UNKNOWN,
vpn_iface,
l3cd,
- callback,
+ (NMDispatcherCallback) callback,
user_data,
out_call_id);
}
@@ -1013,6 +1117,8 @@ nm_dispatcher_call_vpn_sync(NMDispatcherAction action,
const char *vpn_iface,
const NML3ConfigData *l3cd)
{
+ g_return_val_if_fail(!action_is_device_handler(action), FALSE);
+
return _dispatcher_call(action,
TRUE,
parent_device,
@@ -1054,7 +1160,7 @@ nm_dispatcher_call_connectivity(NMConnectivityState connectivity_state,
connectivity_state,
NULL,
NULL,
- callback,
+ (NMDispatcherCallback) callback,
user_data,
out_call_id);
}
@@ -1086,7 +1192,10 @@ nm_dispatcher_call_dns_change(void)
void
nm_dispatcher_call_cancel(NMDispatcherCallId *call_id)
{
- if (!call_id || g_hash_table_lookup(gl.requests, call_id) != call_id || !call_id->callback)
+ if (!call_id || g_hash_table_lookup(gl.requests, call_id) != call_id)
+ g_return_if_reached();
+
+ if (!call_id->callback)
g_return_if_reached();
/* Canceling just means the callback doesn't get called, so set the
diff --git a/src/core/nm-dispatcher.h b/src/core/nm-dispatcher.h
index a1cb96b798..fc317ca899 100644
--- a/src/core/nm-dispatcher.h
+++ b/src/core/nm-dispatcher.h
@@ -24,6 +24,8 @@ typedef enum {
NM_DISPATCHER_ACTION_CONNECTIVITY_CHANGE,
NM_DISPATCHER_ACTION_REAPPLY,
NM_DISPATCHER_ACTION_DNS_CHANGE,
+ NM_DISPATCHER_ACTION_DEVICE_ADD,
+ NM_DISPATCHER_ACTION_DEVICE_DELETE,
} NMDispatcherAction;
#define NM_DISPATCHER_ACTION_DHCP_CHANGE_X(IS_IPv4) \
@@ -31,7 +33,13 @@ typedef enum {
typedef struct NMDispatcherCallId NMDispatcherCallId;
+/* Callback function for regular dispatcher calls */
typedef void (*NMDispatcherFunc)(NMDispatcherCallId *call_id, gpointer user_data);
+/* Callback function for device-handler dispatcher calls */
+typedef void (*NMDispatcherFuncDH)(NMDispatcherCallId *call_id,
+ gpointer user_data,
+ gboolean success,
+ const char *error_msg);
gboolean nm_dispatcher_call_hostname(NMDispatcherFunc callback,
gpointer user_data,
@@ -44,6 +52,13 @@ gboolean nm_dispatcher_call_device(NMDispatcherAction action,
gpointer user_data,
NMDispatcherCallId **out_call_id);
+gboolean nm_dispatcher_call_device_handler(NMDispatcherAction action,
+ NMDevice *device,
+ NMActRequest *act_request,
+ NMDispatcherFuncDH callback_dh,
+ gpointer user_data,
+ NMDispatcherCallId **out_call_id);
+
gboolean nm_dispatcher_call_device_sync(NMDispatcherAction action,
NMDevice *device,
NMActRequest *act_request);
diff --git a/src/libnm-core-aux-extern/nm-dispatcher-api.h b/src/libnm-core-aux-extern/nm-dispatcher-api.h
index 7cb370a92e..635b4fb3a8 100644
--- a/src/libnm-core-aux-extern/nm-dispatcher-api.h
+++ b/src/libnm-core-aux-extern/nm-dispatcher-api.h
@@ -35,6 +35,8 @@
#define NMD_ACTION_CONNECTIVITY_CHANGE "connectivity-change"
#define NMD_ACTION_REAPPLY "reapply"
#define NMD_ACTION_DNS_CHANGE "dns-change"
+#define NMD_ACTION_DEVICE_ADD "device-add"
+#define NMD_ACTION_DEVICE_DELETE "device-delete"
typedef enum {
DISPATCH_RESULT_UNKNOWN = 0,
diff --git a/src/nm-dispatcher/nm-dispatcher.c b/src/nm-dispatcher/nm-dispatcher.c
index 722d6e290d..a28b895a64 100644
--- a/src/nm-dispatcher/nm-dispatcher.c
+++ b/src/nm-dispatcher/nm-dispatcher.c
@@ -86,6 +86,7 @@ struct Request {
char **envp;
gboolean debug;
gboolean is_action2;
+ gboolean is_device_handler;
GPtrArray *scripts; /* list of ScriptInfo */
guint idx;
@@ -615,6 +616,31 @@ _compare_basenames(gconstpointer a, gconstpointer b)
return 0;
}
+static gboolean
+check_file(Request *request, const char *path)
+{
+ gs_free char *link_target = NULL;
+ const char *err_msg = NULL;
+ struct stat st;
+ int err;
+
+ link_target = g_file_read_link(path, NULL);
+ if (nm_streq0(link_target, "/dev/null"))
+ return FALSE;
+
+ err = stat(path, &st);
+ if (err) {
+ return FALSE;
+ } else if (!S_ISREG(st.st_mode) || st.st_size == 0) {
+ /* silently skip. */
+ return FALSE;
+ } else if (!check_permissions(&st, &err_msg)) {
+ _LOG_R_W(request, "find-scripts: Cannot execute '%s': %s", path, err_msg);
+ return FALSE;
+ }
+ return TRUE;
+}
+
static void
_find_scripts(Request *request, GHashTable *scripts, const char *base, const char *subdir)
{
@@ -647,7 +673,7 @@ _find_scripts(Request *request, GHashTable *scripts, const char *base, const cha
}
static GSList *
-find_scripts(Request *request)
+find_scripts(Request *request, const char *device_handler)
{
gs_unref_hashtable GHashTable *scripts = NULL;
GSList *script_list = NULL;
@@ -656,6 +682,33 @@ find_scripts(Request *request)
char *path;
char *filename;
+ if (request->is_device_handler) {
+ const char *const dirs[] = {NMCONFDIR, NMLIBDIR};
+ guint i;
+
+ nm_assert(device_handler);
+
+ for (i = 0; i < G_N_ELEMENTS(dirs); i++) {
+ gs_free char *full_name = NULL;
+
+ full_name = g_build_filename(dirs[i], "dispatcher.d", "device", device_handler, NULL);
+ if (check_file(request, full_name)) {
+ script_list = g_slist_prepend(script_list, g_steal_pointer(&full_name));
+ return script_list;
+ }
+ }
+
+ _LOG_R_W(request,
+ "find-scripts: no device-handler script found with name \"%s\"",
+ device_handler);
+ return NULL;
+ }
+
+ nm_assert(!device_handler);
+
+ /* Use a hash-table to deduplicate scripts with same name from /etc and /usr */
+ scripts = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
+
if (NM_IN_STRSET(request->action, NMD_ACTION_PRE_UP, NMD_ACTION_VPN_PRE_UP))
subdir = "pre-up.d";
else if (NM_IN_STRSET(request->action, NMD_ACTION_PRE_DOWN, NMD_ACTION_VPN_PRE_DOWN))
@@ -663,33 +716,13 @@ find_scripts(Request *request)
else
subdir = NULL;
- scripts = g_hash_table_new_full(nm_str_hash, g_str_equal, g_free, g_free);
-
_find_scripts(request, scripts, NMLIBDIR, subdir);
_find_scripts(request, scripts, NMCONFDIR, subdir);
g_hash_table_iter_init(&iter, scripts);
while (g_hash_table_iter_next(&iter, (gpointer *) &filename, (gpointer *) &path)) {
- gs_free char *link_target = NULL;
- const char *err_msg = NULL;
- struct stat st;
- int err;
-
- link_target = g_file_read_link(path, NULL);
- if (nm_streq0(link_target, "/dev/null"))
- continue;
-
- err = stat(path, &st);
- if (err)
- _LOG_R_W(request, "find-scripts: Failed to stat '%s': %d", path, err);
- else if (!S_ISREG(st.st_mode) || st.st_size == 0) {
- /* silently skip. */
- } else if (!check_permissions(&st, &err_msg))
- _LOG_R_W(request, "find-scripts: Cannot execute '%s': %s", path, err_msg);
- else {
- /* success */
+ if (check_file(request, path)) {
script_list = g_slist_prepend(script_list, g_strdup(path));
- continue;
}
}
@@ -725,6 +758,27 @@ script_must_wait(const char *path)
return TRUE;
}
+static char *
+get_device_handler(GVariant *connection)
+{
+ gs_unref_variant GVariant *generic_setting = NULL;
+ const char *device_handler = NULL;
+
+ generic_setting = g_variant_lookup_value(connection,
+ NM_SETTING_GENERIC_SETTING_NAME,
+ NM_VARIANT_TYPE_SETTING);
+ if (generic_setting) {
+ if (g_variant_lookup(generic_setting,
+ NM_SETTING_GENERIC_DEVICE_HANDLER,
+ "&s",
+ &device_handler)) {
+ return g_strdup(device_handler);
+ }
+ }
+
+ return NULL;
+}
+
static void
_handle_action(GDBusMethodInvocation *invocation, GVariant *parameters, gboolean is_action2)
{
@@ -739,6 +793,7 @@ _handle_action(GDBusMethodInvocation *invocation, GVariant *parameters, gboolean
gs_unref_variant GVariant *device_dhcp6_config = NULL;
const char *connectivity_state;
const char *vpn_ip_iface;
+ gs_free char *device_handler = NULL;
gs_unref_variant GVariant *vpn_proxy_properties = NULL;
gs_unref_variant GVariant *vpn_ip4_config = NULL;
gs_unref_variant GVariant *vpn_ip6_config = NULL;
@@ -829,6 +884,8 @@ _handle_action(GDBusMethodInvocation *invocation, GVariant *parameters, gboolean
request->context = invocation;
request->action = g_strdup(action);
request->is_action2 = is_action2;
+ request->is_device_handler =
+ NM_IN_STRSET(action, NMD_ACTION_DEVICE_ADD, NMD_ACTION_DEVICE_DELETE);
request->envp = nm_dispatcher_utils_construct_envp(action,
connection,
@@ -846,11 +903,14 @@ _handle_action(GDBusMethodInvocation *invocation, GVariant *parameters, gboolean
vpn_ip6_config,
&request->iface,
&error_message);
-
if (!error_message) {
+ if (request->is_device_handler) {
+ device_handler = get_device_handler(connection);
+ }
+
request->scripts = g_ptr_array_new_full(5, script_info_free);
- sorted_scripts = find_scripts(request);
+ sorted_scripts = find_scripts(request, device_handler);
for (iter = sorted_scripts; iter; iter = g_slist_next(iter)) {
ScriptInfo *s;