summary refs log tree commit diff
path: root/src/dns-manager/nm-dns-manager.c
diff options
context:
space:
mode:
Diffstat (limited to 'src/dns-manager/nm-dns-manager.c')
-rw-r--r--src/dns-manager/nm-dns-manager.c159
1 files changed, 94 insertions, 65 deletions
diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c
index 2f8ceab5..f041c29e 100644
--- a/src/dns-manager/nm-dns-manager.c
+++ b/src/dns-manager/nm-dns-manager.c
@@ -43,7 +43,6 @@
 #include "nm-ip6-config.h"
 #include "nm-logging.h"
 #include "NetworkManagerUtils.h"
-#include "nm-posix-signals.h"
 #include "nm-config.h"
 
 #include "nm-dns-plugin.h"
@@ -87,6 +86,8 @@ typedef struct {
 	NMDnsManagerResolvConfMode resolv_conf_mode;
 	NMDnsPlugin *plugin;
 
+	NMConfig *config;
+
 	gboolean dns_touched;
 } NMDnsManagerPrivate;
 
@@ -129,7 +130,7 @@ add_string_item (GPtrArray *array, const char *str)
 static void
 merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
 {
-	guint32 num, i;
+	guint32 num, num_domains, num_searches, i;
 
 	num = nm_ip4_config_get_num_nameservers (src);
 	for (i = 0; i < num; i++) {
@@ -137,18 +138,10 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
 		                 nm_utils_inet4_ntop (nm_ip4_config_get_nameserver (src, i), NULL));
 	}
 
-	num = nm_ip4_config_get_num_domains (src);
-	for (i = 0; i < num; i++) {
-		const char *domain;
-
-		domain = nm_ip4_config_get_domain (src, i);
-		if (!DOMAIN_IS_VALID (domain))
-			continue;
-		add_string_item (rc->searches, domain);
-	}
+	num_domains = nm_ip4_config_get_num_domains (src);
+	num_searches = nm_ip4_config_get_num_searches (src);
 
-	num = nm_ip4_config_get_num_searches (src);
-	for (i = 0; i < num; i++) {
+	for (i = 0; i < num_searches; i++) {
 		const char *search;
 
 		search = nm_ip4_config_get_search (src, i);
@@ -157,6 +150,17 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
 		add_string_item (rc->searches, search);
 	}
 
+	if (num_domains > 1 || !num_searches) {
+		for (i = 0; i < num_domains; i++) {
+			const char *domain;
+
+			domain = nm_ip4_config_get_domain (src, i);
+			if (!DOMAIN_IS_VALID (domain))
+				continue;
+			add_string_item (rc->searches, domain);
+		}
+	}
+
 	/* NIS stuff */
 	num = nm_ip4_config_get_num_nis_servers (src);
 	for (i = 0; i < num; i++) {
@@ -174,7 +178,7 @@ merge_one_ip4_config (NMResolvConfData *rc, NMIP4Config *src)
 static void
 merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 {
-	guint32 num, i;
+	guint32 num, num_domains, num_searches, i;
 	const char *iface;
 
 	iface = g_object_get_data (G_OBJECT (src), IP_CONFIG_IFACE_TAG);
@@ -199,18 +203,10 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 		add_string_item (rc->nameservers, buf);
 	}
 
-	num = nm_ip6_config_get_num_domains (src);
-	for (i = 0; i < num; i++) {
-		const char *domain;
+	num_domains = nm_ip6_config_get_num_domains (src);
+	num_searches = nm_ip6_config_get_num_searches (src);
 
-		domain = nm_ip6_config_get_domain (src, i);
-		if (!DOMAIN_IS_VALID (domain))
-			continue;
-		add_string_item (rc->searches, domain);
-	}
-
-	num = nm_ip6_config_get_num_searches (src);
-	for (i = 0; i < num; i++) {
+	for (i = 0; i < num_searches; i++) {
 		const char *search;
 
 		search = nm_ip6_config_get_search (src, i);
@@ -218,6 +214,17 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 			continue;
 		add_string_item (rc->searches, search);
 	}
+
+	if (num_domains > 1 || !num_searches) {
+		for (i = 0; i < num_domains; i++) {
+			const char *domain;
+
+			domain = nm_ip6_config_get_domain (src, i);
+			if (!DOMAIN_IS_VALID (domain))
+				continue;
+			add_string_item (rc->searches, domain);
+		}
+	}
 }
 
 
@@ -225,19 +232,6 @@ merge_one_ip6_config (NMResolvConfData *rc, NMIP6Config *src)
 /**********************************/
 /* SUSE */
 
-static void
-netconfig_child_setup (gpointer user_data G_GNUC_UNUSED)
-{
-	pid_t pid = getpid ();
-	setpgid (pid, pid);
-
-	/*
-	 * We blocked signals in main(). We need to restore original signal
-	 * mask for netconfig here so that it can receive signals.
-	 */
-	nm_unblock_posix_signals (NULL);
-}
-
 static GPid
 run_netconfig (GError **error, gint *stdin_fd)
 {
@@ -255,7 +249,7 @@ run_netconfig (GError **error, gint *stdin_fd)
 	nm_log_dbg (LOGD_DNS, "spawning '%s'", tmp);
 	g_free (tmp);
 
-	if (!g_spawn_async_with_pipes (NULL, argv, NULL, 0, netconfig_child_setup,
+	if (!g_spawn_async_with_pipes (NULL, argv, NULL, G_SPAWN_DO_NOT_REAP_CHILD, NULL,
 	                               NULL, &pid, stdin_fd, NULL, NULL, error))
 		return -1;
 
@@ -284,10 +278,10 @@ dispatch_netconfig (char **searches,
 	char *str;
 	GPid pid;
 	gint fd;
-	int ret = 1;
+	int status;
 
 	pid = run_netconfig (error, &fd);
-	if (pid < 0)
+	if (pid <= 0)
 		return FALSE;
 
 	/* NM is writing already-merged DNS information to netconfig, so it
@@ -320,24 +314,22 @@ dispatch_netconfig (char **searches,
 	close (fd);
 
 	/* Wait until the process exits */
+	if (!nm_utils_kill_child_sync (pid, 0, LOGD_DNS, "netconfig", &status, 1000, 0)) {
+		int errsv = errno;
 
- again:
-
-	if (waitpid (pid, NULL, 0) < 0) {
-		if (errno == EINTR)
-			goto again;
-		else if (errno == ECHILD) {
-			/* child already exited */
-			ret = pid;
-		} else {
-			g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
-			             "Error waiting for netconfig to exit: %s",
-			             strerror (errno));
-			ret = 0;
-		}
+		g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
+		             "Error waiting for netconfig to exit: %s",
+		             strerror (errsv));
+		return FALSE;
 	}
-
-	return ret > 0;
+	if (!WIFEXITED (status) || WEXITSTATUS (status) != EXIT_SUCCESS) {
+		g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED,
+		             "Error calling netconfig: %s %d",
+		             WIFEXITED (status) ? "exited with status" : (WIFSIGNALED (status) ? "exited with signal" : "exited with unknown reason"),
+		             WIFEXITED (status) ? WEXITSTATUS (status) : (WIFSIGNALED (status) ? WTERMSIG (status) : status));
+		return FALSE;
+	}
+	return TRUE;
 }
 #endif
 
@@ -782,13 +774,16 @@ update_dns (NMDnsManager *self,
 
 #ifdef NETCONFIG_PATH
 	if (success == FALSE) {
+		g_clear_error (error);
 		success = dispatch_netconfig (searches, nameservers,
 		                              nis_domain, nis_servers, error);
 	}
 #endif
 
-	if (success == FALSE)
+	if (success == FALSE) {
+		g_clear_error (error);
 		success = update_resolv_conf (searches, nameservers, error);
+	}
 
 	/* signal that resolv.conf was changed */
 	if (success)
@@ -1099,6 +1094,8 @@ init_resolv_conf_mode (NMDnsManager *self)
 	const char *mode;
 	int fd, flags;
 
+	g_clear_object (&priv->plugin);
+
 	fd = open (_PATH_RESCONF, O_RDONLY);
 	if (fd != -1) {
 		if (ioctl (fd, FS_IOC_GETFLAGS, &flags) == -1)
@@ -1112,7 +1109,7 @@ init_resolv_conf_mode (NMDnsManager *self)
 		}
 	}
 
-	mode = nm_config_get_dns_mode (nm_config_get ());
+	mode = nm_config_data_get_dns_mode (nm_config_get_data (priv->config));
 	if (!g_strcmp0 (mode, "none")) {
 		priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED;
 		nm_log_info (LOGD_DNS, "DNS: not managing " _PATH_RESCONF);
@@ -1127,6 +1124,34 @@ init_resolv_conf_mode (NMDnsManager *self)
 		if (mode && g_strcmp0 (mode, "default") != 0)
 			nm_log_warn (LOGD_DNS, "Unknown DNS mode '%s'", mode);
 	}
+
+	if (priv->plugin) {
+		nm_log_info (LOGD_DNS, "DNS: loaded plugin %s", nm_dns_plugin_get_name (priv->plugin));
+		g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self);
+		g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self);
+	}
+}
+
+static void
+config_changed_cb (NMConfig *config,
+                   NMConfigData *config_data,
+                   NMConfigChangeFlags changes,
+                   NMConfigData *old_data,
+                   NMDnsManager *self)
+{
+	GError *error = NULL;
+
+	if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_DNS_MODE))
+		init_resolv_conf_mode (self);
+
+	if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_SIGHUP |
+	                           NM_CONFIG_CHANGE_SIGUSR1 |
+	                           NM_CONFIG_CHANGE_DNS_MODE)) {
+		if (!update_dns (self, TRUE, &error)) {
+			nm_log_warn (LOGD_DNS, "could not commit DNS changes: %s", error->message);
+			g_clear_error (&error);
+		}
+	}
 }
 
 static void
@@ -1137,13 +1162,12 @@ nm_dns_manager_init (NMDnsManager *self)
 	/* Set the initial hash */
 	compute_hash (self, NM_DNS_MANAGER_GET_PRIVATE (self)->hash);
 
+	priv->config = g_object_ref (nm_config_get ());
+	g_signal_connect (G_OBJECT (priv->config),
+	                  NM_CONFIG_SIGNAL_CONFIG_CHANGED,
+	                  G_CALLBACK (config_changed_cb),
+	                  self);
 	init_resolv_conf_mode (self);
-
-	if (priv->plugin) {
-		nm_log_info (LOGD_DNS, "DNS: loaded plugin %s", nm_dns_plugin_get_name (priv->plugin));
-		g_signal_connect (priv->plugin, NM_DNS_PLUGIN_FAILED, G_CALLBACK (plugin_failed), self);
-		g_signal_connect (priv->plugin, NM_DNS_PLUGIN_CHILD_QUIT, G_CALLBACK (plugin_child_quit), self);
-	}
 }
 
 static void
@@ -1170,6 +1194,11 @@ dispose (GObject *object)
 		priv->dns_touched = FALSE;
 	}
 
+	if (priv->config) {
+		g_signal_handlers_disconnect_by_func (priv->config, config_changed_cb, self);
+		g_clear_object (&priv->config);
+	}
+
 	g_slist_free_full (priv->configs, g_object_unref);
 	priv->configs = NULL;