gboolean
nm_dns_plugin_child_kill (NMDnsPlugin *self)
{
	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);

	if (priv->watch_id) {
		g_source_remove (priv->watch_id);
		priv->watch_id = 0;
	}

	if (priv->pid) {
		nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, priv->progname, NULL, 1000, 0);
		priv->pid = 0;
		g_free (priv->progname);
		priv->progname = NULL;
	}

	if (priv->pidfile) {
		unlink (priv->pidfile);
		g_free (priv->pidfile);
		priv->pidfile = NULL;
	}

	return TRUE;
}
static void
finalize (GObject *object)
{
	NMDnsPlugin *self = NM_DNS_PLUGIN (object);
	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);

	g_free (priv->progname);
	g_free (priv->pidfile);

	G_OBJECT_CLASS (nm_dns_plugin_parent_class)->finalize (object);
}
static void
watch_cb (GPid pid, gint status, gpointer user_data)
{
	NMDnsPlugin *self = NM_DNS_PLUGIN (user_data);
	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);

	priv->pid = 0;
	g_free (priv->progname);
	priv->progname = NULL;

	g_signal_emit (self, signals[CHILD_QUIT], 0, status);
}
static void
dispose (GObject *object)
{
	NMDnsPlugin *self = NM_DNS_PLUGIN (object);
	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);

	if (!priv->disposed) {
		priv->disposed = TRUE;

		nm_dns_plugin_child_kill (self);
	}

	G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object);
}
GPid
nm_dns_plugin_child_spawn (NMDnsPlugin *self,
                           const char **argv,
                           const char *pidfile,
                           const char *kill_match)
{
	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
	GError *error = NULL;
	char *cmdline;

	g_return_val_if_fail (argv != NULL, 0);
	g_return_val_if_fail (argv[0] != NULL, 0);

	g_warn_if_fail (priv->progname == NULL);
	g_free (priv->progname);
	priv->progname = g_path_get_basename (argv[0]);

	if (pidfile) {
		g_return_val_if_fail (kill_match != NULL, 0);
		kill_existing (priv->progname, pidfile, kill_match);

		g_free (priv->pidfile);
		priv->pidfile = g_strdup (pidfile);
	}

	nm_log_info (LOGD_DNS, "DNS: starting %s...", priv->progname);
	cmdline = g_strjoinv (" ", (char **) argv);
	nm_log_dbg (LOGD_DNS, "DNS: command line: %s", cmdline);
	g_free (cmdline);

	priv->pid = 0;
	if (g_spawn_async (NULL, (char **) argv, NULL,
	                   G_SPAWN_DO_NOT_REAP_CHILD,
	                   child_setup,
	                   NULL, &priv->pid,
	                   &error)) {
		nm_log_dbg (LOGD_DNS, "%s started with pid %d", priv->progname, priv->pid);
		priv->watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) watch_cb, self);
	} else {
		nm_log_warn (LOGD_DNS, "Failed to spawn %s: (%d) %s",
		             priv->progname, error ? error->code : -1,
		             error && error->message ? error->message : "(unknown)");
		g_clear_error (&error);
	}

	return priv->pid;
}
gboolean nm_dns_plugin_child_kill (NMDnsPlugin *self)
{
	NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);

	if (priv->watch_id) {
		g_source_remove (priv->watch_id);
		priv->watch_id = 0;
	}

	if (priv->pid) {
		KillInfo *info;

		if (kill (priv->pid, SIGTERM) == 0) {
			info = g_malloc0 (sizeof (KillInfo));
			info->pid = priv->pid;
			info->progname = g_strdup (priv->progname);
			g_timeout_add_seconds (2, ensure_killed, info);
		} else {
			kill (priv->pid, SIGKILL);

			/* ensure the child is reaped */
			nm_log_dbg (LOGD_DNS, "waiting for %s pid %d to exit", priv->progname, priv->pid);
			waitpid (priv->pid, NULL, 0);
			nm_log_dbg (LOGD_DNS, "%s pid %d cleaned up", priv->progname, priv->pid);
		}
		priv->pid = 0;
		g_free (priv->progname);
		priv->progname = NULL;
	}

	if (priv->pidfile) {
		unlink (priv->pidfile);
		g_free (priv->pidfile);
		priv->pidfile = NULL;
	}

	return TRUE;
}