summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDan Williams <dcbw@redhat.com>2014-06-02 14:07:46 -0500
committerDan Williams <dcbw@redhat.com>2014-06-06 13:43:46 -0500
commit1383f4bc14a83b56e06210222ecf2e6b18dfc18e (patch)
tree15deab8378ca11f019e39baa0fb6c907aad0a994
parent7eaaa6a475b3d73e0967c9fa928268c1498f6b50 (diff)
downloadNetworkManager-1383f4bc14a83b56e06210222ecf2e6b18dfc18e.tar.gz
dispatcher: use separate directories for pre-up/pre-down events
To ensure that NetworkManager does not block needlessly for events which have no scripts, require scripts that respond to blocking events to opt into the action.
-rw-r--r--callouts/nm-dispatcher-api.h17
-rw-r--r--callouts/nm-dispatcher.c20
-rw-r--r--man/NetworkManager.xml49
-rw-r--r--src/nm-dispatcher.c69
4 files changed, 124 insertions, 31 deletions
diff --git a/callouts/nm-dispatcher-api.h b/callouts/nm-dispatcher-api.h
index 96db789283..eb6b33fe0c 100644
--- a/callouts/nm-dispatcher-api.h
+++ b/callouts/nm-dispatcher-api.h
@@ -20,7 +20,9 @@
#include <dbus/dbus-glib.h>
-#define NMD_SCRIPT_DIR NMCONFDIR "/dispatcher.d"
+#define NMD_SCRIPT_DIR NMCONFDIR "/dispatcher.d"
+#define NMD_PRE_UP_DIR NMD_SCRIPT_DIR "/pre-up.d"
+#define NMD_PRE_DOWN_DIR NMD_SCRIPT_DIR "/pre-down.d"
/* dbus-glib types for dispatcher call return value */
#define DISPATCHER_TYPE_RESULT (dbus_g_type_get_struct ("GValueArray", G_TYPE_STRING, G_TYPE_UINT, G_TYPE_STRING, G_TYPE_INVALID))
@@ -38,6 +40,19 @@
#define NMD_DEVICE_PROPS_STATE "state"
#define NMD_DEVICE_PROPS_PATH "path"
+/* Actions */
+#define NMD_ACTION_HOSTNAME "hostname"
+#define NMD_ACTION_PRE_UP "pre-up"
+#define NMD_ACTION_UP "up"
+#define NMD_ACTION_PRE_DOWN "pre-down"
+#define NMD_ACTION_DOWN "down"
+#define NMD_ACTION_VPN_PRE_UP "vpn-pre-up"
+#define NMD_ACTION_VPN_UP "vpn-up"
+#define NMD_ACTION_VPN_PRE_DOWN "vpn-pre-down"
+#define NMD_ACTION_VPN_DOWN "vpn-down"
+#define NMD_ACTION_DHCP4_CHANGE "dhcp4-change"
+#define NMD_ACTION_DHCP6_CHANGE "dhcp6-change"
+
typedef enum {
DISPATCH_RESULT_UNKNOWN = 0,
DISPATCH_RESULT_SUCCESS = 1,
diff --git a/callouts/nm-dispatcher.c b/callouts/nm-dispatcher.c
index 3747fd563a..6c9c294f27 100644
--- a/callouts/nm-dispatcher.c
+++ b/callouts/nm-dispatcher.c
@@ -414,16 +414,26 @@ dispatch_one_script (Request *request)
}
static GSList *
-find_scripts (void)
+find_scripts (const char *str_action)
{
GDir *dir;
const char *filename;
GSList *sorted = NULL;
GError *error = NULL;
+ const char *dirname;
+
+ if ( strcmp (str_action, NMD_ACTION_PRE_UP) == 0
+ || strcmp (str_action, NMD_ACTION_VPN_PRE_UP) == 0)
+ dirname = NMD_PRE_UP_DIR;
+ else if ( strcmp (str_action, NMD_ACTION_PRE_DOWN) == 0
+ || strcmp (str_action, NMD_ACTION_VPN_PRE_DOWN) == 0)
+ dirname = NMD_PRE_DOWN_DIR;
+ else
+ dirname = NMD_SCRIPT_DIR;
- if (!(dir = g_dir_open (NMD_SCRIPT_DIR, 0, &error))) {
+ if (!(dir = g_dir_open (dirname, 0, &error))) {
g_warning ("Failed to open dispatcher directory '%s': (%d) %s",
- NMD_SCRIPT_DIR, error->code, error->message);
+ dirname, error->code, error->message);
g_error_free (error);
return NULL;
}
@@ -436,7 +446,7 @@ find_scripts (void)
if (!check_filename (filename))
continue;
- path = g_build_filename (NMD_SCRIPT_DIR, filename, NULL);
+ path = g_build_filename (dirname, filename, NULL);
err = stat (path, &st);
if (err)
@@ -476,7 +486,7 @@ impl_dispatch (Handler *h,
char **p;
char *iface = NULL;
- sorted_scripts = find_scripts ();
+ sorted_scripts = find_scripts (str_action);
if (!sorted_scripts) {
dbus_g_method_return (context, g_ptr_array_new ());
diff --git a/man/NetworkManager.xml b/man/NetworkManager.xml
index 70e49aa16a..229c390cdc 100644
--- a/man/NetworkManager.xml
+++ b/man/NetworkManager.xml
@@ -53,9 +53,9 @@
<title>Dispatcher scripts</title>
<para>
NetworkManager will execute scripts in the
- /etc/NetworkManager/dispatcher.d directory in alphabetical order
- in response to network events. Each script should be a regular
- executable file, owned by root. Furthermore, it must not be
+ /etc/NetworkManager/dispatcher.d directory or subdirectories in
+ alphabetical order in response to network events. Each script should
+ be a regular executable file owned by root. Furthermore, it must not be
writable by group or other, and not setuid.
</para>
<para>
@@ -65,22 +65,65 @@
<para>The actions are:</para>
<variablelist class="dispatcher-options">
<varlistentry>
+ <term><varname>pre-up</varname></term>
+ <listitem><para>The interface is connected to the network but is not
+ yet fully activated. Scripts acting on this event must be placed or
+ symlinked into the /etc/NetworkManager/dispatcher.d/pre-up.d directory,
+ and NetworkManager will wait for script execution to complete before
+ indicating to applications that the interface is fully activated.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>up</varname></term>
<listitem><para>The interface has been activated.</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>pre-down</varname></term>
+ <listitem><para>The interface will be deactivated but has not yet been
+ disconnected from the network. Scripts acting on this event must be
+ placed or symlinked into the /etc/NetworkManager/dispatcher.d/pre-down.d
+ directory, and NetworkManager will wait for script execution to complete
+ before disconnecting the interface from its network. Note that this
+ event is not emitted for forced disconnections, like when carrier is
+ lost or a wireless signal fades. It is only emitted when there is
+ an opportunity to cleanly handle a network disconnection event.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>down</varname></term>
<listitem><para>
The interface has been deactivated.
</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>vpn-pre-up</varname></term>
+ <listitem><para>The VPN is connected to the network but is not yet
+ fully activated. Scripts acting on this event must be placed or
+ symlinked into the /etc/NetworkManager/dispatcher.d/pre-up.d directory,
+ and NetworkManager will wait for script execution to complete before
+ indicating to applications that the VPN is fully activated.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>vpn-up</varname></term>
<listitem><para>
A VPN connection has been activated.
</para></listitem>
</varlistentry>
<varlistentry>
+ <term><varname>vpn-pre-down</varname></term>
+ <listitem><para>The VPN will be deactivated but has not yet been
+ disconnected from the network. Scripts acting on this event must be
+ placed or symlinked into the /etc/NetworkManager/dispatcher.d/pre-down.d
+ directory, and NetworkManager will wait for script execution to complete
+ before disconnecting the VPN from its network. Note that this
+ event is not emitted for forced disconnections, like when the VPN
+ terminates unexpectedly or general connectivity is lost. It is only
+ emitted when there is an opportunity to cleanly handle a VPN
+ disconnection event.
+ </para></listitem>
+ </varlistentry>
+ <varlistentry>
<term><varname>vpn-down</varname></term>
<listitem><para>
A VPN connection has been deactivated.
diff --git a/src/nm-dispatcher.c b/src/nm-dispatcher.c
index 51b9a8a196..29b0329d4a 100644
--- a/src/nm-dispatcher.c
+++ b/src/nm-dispatcher.c
@@ -271,17 +271,17 @@ dispatcher_done_cb (DBusGProxy *proxy, DBusGProxyCall *call, gpointer user_data)
}
static const char *action_table[] = {
- [DISPATCHER_ACTION_HOSTNAME] = "hostname",
- [DISPATCHER_ACTION_PRE_UP] = "pre-up",
- [DISPATCHER_ACTION_UP] = "up",
- [DISPATCHER_ACTION_PRE_DOWN] = "pre-down",
- [DISPATCHER_ACTION_DOWN] = "down",
- [DISPATCHER_ACTION_VPN_PRE_UP] = "vpn-pre-up",
- [DISPATCHER_ACTION_VPN_UP] = "vpn-up",
- [DISPATCHER_ACTION_VPN_PRE_DOWN] = "vpn-pre-down",
- [DISPATCHER_ACTION_VPN_DOWN] = "vpn-down",
- [DISPATCHER_ACTION_DHCP4_CHANGE] = "dhcp4-change",
- [DISPATCHER_ACTION_DHCP6_CHANGE] = "dhcp6-change",
+ [DISPATCHER_ACTION_HOSTNAME] = NMD_ACTION_HOSTNAME,
+ [DISPATCHER_ACTION_PRE_UP] = NMD_ACTION_PRE_UP,
+ [DISPATCHER_ACTION_UP] = NMD_ACTION_UP,
+ [DISPATCHER_ACTION_PRE_DOWN] = NMD_ACTION_PRE_DOWN,
+ [DISPATCHER_ACTION_DOWN] = NMD_ACTION_DOWN,
+ [DISPATCHER_ACTION_VPN_PRE_UP] = NMD_ACTION_VPN_PRE_UP,
+ [DISPATCHER_ACTION_VPN_UP] = NMD_ACTION_VPN_UP,
+ [DISPATCHER_ACTION_VPN_PRE_DOWN] = NMD_ACTION_VPN_PRE_DOWN,
+ [DISPATCHER_ACTION_VPN_DOWN] = NMD_ACTION_VPN_DOWN,
+ [DISPATCHER_ACTION_DHCP4_CHANGE] = NMD_ACTION_DHCP4_CHANGE,
+ [DISPATCHER_ACTION_DHCP6_CHANGE] = NMD_ACTION_DHCP6_CHANGE,
};
static const char *
@@ -605,32 +605,57 @@ nm_dispatcher_call_cancel (guint call_id)
g_return_if_reached ();
}
+typedef struct {
+ const char *dir;
+ GFileMonitor *monitor;
+ gboolean has_scripts;
+} Monitor;
+
+static Monitor monitors[3] = {
+ { NMD_SCRIPT_DIR, NULL, TRUE },
+ { NMD_PRE_UP_DIR, NULL, TRUE },
+ { NMD_PRE_DOWN_DIR, NULL, TRUE }
+};
+
static void
-dispatcher_dir_changed (GFileMonitor *monitor)
+dispatcher_dir_changed (GFileMonitor *monitor,
+ GFile *file,
+ GFile *other_file,
+ GFileMonitorEvent event_type,
+ Monitor *item)
{
GDir *dir;
+ guint i;
/* Default to dispatching on any errors */
- do_dispatch = TRUE;
- dir = g_dir_open (NMD_SCRIPT_DIR, 0, NULL);
+ item->has_scripts = TRUE;
+
+ dir = g_dir_open (item->dir, 0, NULL);
if (dir) {
- do_dispatch = !!g_dir_read_name (dir);
+ item->has_scripts = !!g_dir_read_name (dir);
g_dir_close (dir);
}
+
+ /* Recheck all dirs for scripts and update global variable */
+ do_dispatch = FALSE;
+ for (i = 0; i < G_N_ELEMENTS (monitors); i++)
+ do_dispatch |= monitors[i].has_scripts;
}
void
nm_dispatcher_init (void)
{
GFile *file;
- static GFileMonitor *monitor;
+ guint i;
- file = g_file_new_for_path (NMD_SCRIPT_DIR);
- monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
- if (monitor) {
- g_signal_connect (monitor, "changed", G_CALLBACK (dispatcher_dir_changed), NULL);
- dispatcher_dir_changed (monitor);
+ for (i = 0; i < G_N_ELEMENTS (monitors); i++) {
+ file = g_file_new_for_path (monitors[i].dir);
+ monitors[i].monitor = g_file_monitor_directory (file, G_FILE_MONITOR_NONE, NULL, NULL);
+ if (monitors[i].monitor) {
+ g_signal_connect (monitors[i].monitor, "changed", G_CALLBACK (dispatcher_dir_changed), &monitors[i]);
+ dispatcher_dir_changed (monitors[i].monitor, file, NULL, 0, &monitors[i]);
+ }
+ g_object_unref (file);
}
- g_object_unref (file);
}