From ee20ebb0fbfbd8e2cea7fe8a8ef0e8370d2e91a8 Mon Sep 17 00:00:00 2001 From: Dan Winship Date: Fri, 19 Dec 2014 10:34:19 -0500 Subject: [PATCH] ifcfg-rh: handle DEVTIMEOUT property (rh #1171917) If an ifcfg file has a DEVTIMEOUT property (and a DEVICE, and is ONBOOT=yes), and the device is not present at startup, then wait up to DEVTIMEOUT seconds for it to appear before declaring the connection ready. This allows for a hacky workaround to devices that take a bizarrely long time to be probed. (cherry picked from commit 62d870e1a6dd852e50f39b2a32cd291734766402) --- .../plugins/ifcfg-rh/nm-ifcfg-connection.c | 112 +++++++++++++++++- src/settings/plugins/ifcfg-rh/reader.c | 22 ++++ src/settings/plugins/ifcfg-rh/reader.h | 2 + 3 files changed, 135 insertions(+), 1 deletion(-) diff --git a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c index ec143edd03..b044fe01c4 100644 --- a/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c +++ b/src/settings/plugins/ifcfg-rh/nm-ifcfg-connection.c @@ -33,6 +33,8 @@ #include #include #include +#include +#include #include "common.h" #include "nm-config.h" @@ -63,6 +65,9 @@ typedef struct { char *unmanaged_spec; char *unrecognized_spec; + + gulong devtimeout_link_changed_handler; + guint devtimeout_timeout_id; } NMIfcfgConnectionPrivate; enum { @@ -80,6 +85,97 @@ enum { static guint signals[LAST_SIGNAL] = { 0 }; +static gboolean +devtimeout_ready (gpointer user_data) +{ + NMIfcfgConnection *self = user_data; + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); + + priv->devtimeout_timeout_id = 0; + nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), TRUE); + return FALSE; +} + +static void +link_changed (NMPlatform *platform, int ifindex, NMPlatformLink *link, + NMPlatformSignalChangeType change_type, NMPlatformReason reason, + NMConnection *self) +{ + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); + const char *ifname; + + ifname = nm_connection_get_interface_name (self); + if (g_strcmp0 (link->name, ifname) != 0) + return; + + /* Shouldn't happen, but... */ + if (change_type == NM_PLATFORM_SIGNAL_REMOVED) + return; + + nm_log_info (LOGD_SETTINGS, "Device %s appeared; connection '%s' now ready", + ifname, nm_connection_get_id (self)); + + g_signal_handler_disconnect (platform, priv->devtimeout_link_changed_handler); + priv->devtimeout_link_changed_handler = 0; + g_source_remove (priv->devtimeout_timeout_id); + + /* Don't declare the connection ready right away, since NMManager may not have + * started processing the device yet. + */ + priv->devtimeout_timeout_id = g_idle_add (devtimeout_ready, self); +} + +static gboolean +devtimeout_expired (gpointer user_data) +{ + NMIfcfgConnection *self = user_data; + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); + + nm_log_info (LOGD_SETTINGS, "Device for connection '%s' did not appear before timeout", + nm_connection_get_id (NM_CONNECTION (self))); + + g_signal_handler_disconnect (nm_platform_get (), priv->devtimeout_link_changed_handler); + priv->devtimeout_link_changed_handler = 0; + priv->devtimeout_timeout_id = 0; + + nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), TRUE); + return FALSE; +} + +static void +nm_ifcfg_connection_check_devtimeout (NMIfcfgConnection *self) +{ + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (self); + NMSettingConnection *s_con; + const char *ifname; + guint devtimeout; + + s_con = nm_connection_get_setting_connection (NM_CONNECTION (self)); + + if (!nm_setting_connection_get_autoconnect (s_con)) + return; + ifname = nm_setting_connection_get_interface_name (s_con); + if (!ifname) + return; + devtimeout = devtimeout_from_file (nm_ifcfg_connection_get_path (self)); + if (!devtimeout) + return; + + if (nm_platform_link_get_ifindex (ifname) != 0) + return; + + /* ONBOOT=yes, DEVICE and DEVTIMEOUT are set, but device is not present */ + nm_settings_connection_set_ready (NM_SETTINGS_CONNECTION (self), FALSE); + + nm_log_info (LOGD_SETTINGS, "Waiting %u seconds for %s to appear for connection '%s'", + devtimeout, ifname, nm_connection_get_id (NM_CONNECTION (self))); + + priv->devtimeout_link_changed_handler = + g_signal_connect (nm_platform_get (), NM_PLATFORM_SIGNAL_LINK_CHANGED, + G_CALLBACK (link_changed), self); + priv->devtimeout_timeout_id = g_timeout_add_seconds (devtimeout, devtimeout_expired, self); +} + static void files_changed_cb (NMInotifyHelper *ih, struct inotify_event *evt, @@ -141,8 +237,10 @@ nm_ifcfg_connection_new (NMConnection *source, update_unsaved, error)) { /* Set the path and start monitoring */ - if (full_path) + if (full_path) { nm_ifcfg_connection_set_path (NM_IFCFG_CONNECTION (object), full_path); + nm_ifcfg_connection_check_devtimeout (NM_IFCFG_CONNECTION (object)); + } } else g_clear_object (&object); @@ -368,8 +466,20 @@ get_property (GObject *object, guint prop_id, static void dispose (GObject *object) { + NMIfcfgConnectionPrivate *priv = NM_IFCFG_CONNECTION_GET_PRIVATE (object); + path_watch_stop (NM_IFCFG_CONNECTION (object)); + if (priv->devtimeout_link_changed_handler) { + g_signal_handler_disconnect (nm_platform_get (), + priv->devtimeout_link_changed_handler); + priv->devtimeout_link_changed_handler = 0; + } + if (priv->devtimeout_timeout_id) { + g_source_remove (priv->devtimeout_timeout_id); + priv->devtimeout_timeout_id = 0; + } + G_OBJECT_CLASS (nm_ifcfg_connection_parent_class)->dispose (object); } diff --git a/src/settings/plugins/ifcfg-rh/reader.c b/src/settings/plugins/ifcfg-rh/reader.c index c44c6e78ab..dbe77c87aa 100644 --- a/src/settings/plugins/ifcfg-rh/reader.c +++ b/src/settings/plugins/ifcfg-rh/reader.c @@ -4862,3 +4862,25 @@ connection_from_file_test (const char *filename, NULL); } +guint +devtimeout_from_file (const char *filename) +{ + shvarFile *ifcfg; + char *devtimeout_str; + guint devtimeout; + + g_return_val_if_fail (filename != NULL, 0); + + ifcfg = svOpenFile (filename, NULL); + if (!ifcfg) + return 0; + + devtimeout_str = svGetValue (ifcfg, "DEVTIMEOUT", FALSE); + if (devtimeout_str) { + devtimeout = nm_utils_ascii_str_to_int64 (devtimeout_str, 10, 0, G_MAXUINT, 0); + g_free (devtimeout_str); + } else + devtimeout = 0; + + return devtimeout; +} diff --git a/src/settings/plugins/ifcfg-rh/reader.h b/src/settings/plugins/ifcfg-rh/reader.h index 6a6af167ff..70e9ce4e24 100644 --- a/src/settings/plugins/ifcfg-rh/reader.h +++ b/src/settings/plugins/ifcfg-rh/reader.h @@ -32,6 +32,8 @@ NMConnection *connection_from_file (const char *filename, char *uuid_from_file (const char *filename); +guint devtimeout_from_file (const char *filename); + /* for test-ifcfg-rh */ NMConnection *connection_from_file_test (const char *filename, const char *network_file,