diff options
author | Dan Williams <dcbw@redhat.com> | 2014-06-02 14:07:46 -0500 |
---|---|---|
committer | Dan Williams <dcbw@redhat.com> | 2014-06-06 13:43:46 -0500 |
commit | 1383f4bc14a83b56e06210222ecf2e6b18dfc18e (patch) | |
tree | 15deab8378ca11f019e39baa0fb6c907aad0a994 | |
parent | 7eaaa6a475b3d73e0967c9fa928268c1498f6b50 (diff) | |
download | NetworkManager-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.h | 17 | ||||
-rw-r--r-- | callouts/nm-dispatcher.c | 20 | ||||
-rw-r--r-- | man/NetworkManager.xml | 49 | ||||
-rw-r--r-- | src/nm-dispatcher.c | 69 |
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); } |