diff options
| author | Michael Biebl <biebl@debian.org> | 2017-01-17 20:25:09 +0100 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2017-01-17 20:25:09 +0100 |
| commit | 58f8be580039b0575b197b9573a1c92745d96d30 (patch) | |
| tree | 2c226233f623a0dcb529be0eb8cdf97e4a2ae0c0 /src/dns/nm-dns-plugin.c | |
| parent | 45cb5bb3c0e6edb887cf69b417fcaf7053814a9b (diff) | |
New upstream version 1.5.90 upstream/1.5.90
Diffstat (limited to 'src/dns/nm-dns-plugin.c')
| -rw-r--r-- | src/dns/nm-dns-plugin.c | 316 |
1 files changed, 316 insertions, 0 deletions
diff --git a/src/dns/nm-dns-plugin.c b/src/dns/nm-dns-plugin.c new file mode 100644 index 00000000..3a3bc646 --- /dev/null +++ b/src/dns/nm-dns-plugin.c @@ -0,0 +1,316 @@ +/* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */ +/* This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2, or (at your option) + * any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along + * with this program; if not, write to the Free Software Foundation, Inc., + * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. + * + * Copyright (C) 2010 - 2012 Red Hat, Inc. + * + */ + +#include "nm-default.h" + +#include "nm-dns-plugin.h" + +#include <string.h> +#include <stdlib.h> +#include <unistd.h> +#include <sys/types.h> +#include <sys/wait.h> + +#include "nm-core-internal.h" +#include "NetworkManagerUtils.h" + +/*****************************************************************************/ + +enum { + FAILED, + CHILD_QUIT, + LAST_SIGNAL, +}; + +static guint signals[LAST_SIGNAL] = { 0 }; + +typedef struct _NMDnsPluginPrivate { + GPid pid; + guint watch_id; + char *progname; + char *pidfile; +} NMDnsPluginPrivate; + +G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {}) + +#define NM_DNS_PLUGIN_GET_PRIVATE(self) _NM_GET_PRIVATE_PTR (self, NMDnsPlugin, NM_IS_DNS_PLUGIN) + +/*****************************************************************************/ + +#define _NMLOG_PREFIX_NAME "dns-plugin" +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG(level, ...) \ + G_STMT_START { \ + const NMLogLevel __level = (level); \ + \ + if (nm_logging_enabled (__level, _NMLOG_DOMAIN)) { \ + char __prefix[20]; \ + const NMDnsPlugin *const __self = (self); \ + \ + _nm_log (__level, _NMLOG_DOMAIN, 0, \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (!__self \ + ? "" \ + : nm_sprintf_buf (__prefix, "[%p]", __self)) \ + _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ + } \ + } G_STMT_END + +/*****************************************************************************/ + +gboolean +nm_dns_plugin_update (NMDnsPlugin *self, + const NMDnsIPConfigData **configs, + const NMGlobalDnsConfig *global_config, + const char *hostname) +{ + g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE); + + return NM_DNS_PLUGIN_GET_CLASS (self)->update (self, + configs, + global_config, + hostname); +} + +static gboolean +is_caching (NMDnsPlugin *self) +{ + return FALSE; +} + +gboolean +nm_dns_plugin_is_caching (NMDnsPlugin *self) +{ + return NM_DNS_PLUGIN_GET_CLASS (self)->is_caching (self); +} + +const char * +nm_dns_plugin_get_name (NMDnsPlugin *self) +{ + g_assert (NM_DNS_PLUGIN_GET_CLASS (self)->get_name); + return NM_DNS_PLUGIN_GET_CLASS (self)->get_name (self); +} + +/*****************************************************************************/ + +static void +_clear_pidfile (NMDnsPlugin *self) +{ + NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); + + if (priv->pidfile) { + unlink (priv->pidfile); + g_clear_pointer (&priv->pidfile, g_free); + } +} + +static void +kill_existing (const char *progname, const char *pidfile, const char *kill_match) +{ + glong pid; + gs_free char *contents = NULL; + gs_free char *cmdline_contents = NULL; + guint64 start_time; + char proc_path[256]; + gs_free_error GError *error = NULL; + + if (!pidfile) + return; + + if (!kill_match) + g_return_if_reached (); + + if (!g_file_get_contents (pidfile, &contents, NULL, &error)) { + if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT)) + return; + goto out; + } + + pid = _nm_utils_ascii_str_to_int64 (contents, 10, 2, INT_MAX, -1); + if (pid == -1) + goto out; + + start_time = nm_utils_get_start_time_for_pid (pid, NULL, NULL); + if (start_time == 0) + goto out; + + nm_sprintf_buf (proc_path, "/proc/%ld/cmdline", pid); + if (!g_file_get_contents (proc_path, &cmdline_contents, NULL, NULL)) + goto out; + + if (!strstr (cmdline_contents, kill_match)) + goto out; + + nm_utils_kill_process_sync (pid, start_time, SIGKILL, _NMLOG_DOMAIN, + progname ?: "<dns-process>", + 0, 0, 1000); + +out: + unlink (pidfile); +} + +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; + priv->watch_id = 0; + g_clear_pointer (&priv->progname, g_free); + _clear_pidfile (self); + + g_signal_emit (self, signals[CHILD_QUIT], 0, status); +} + +GPid +nm_dns_plugin_child_pid (NMDnsPlugin *self) +{ + NMDnsPluginPrivate *priv; + + g_return_val_if_fail (NM_IS_DNS_PLUGIN (self), 0); + + priv = NM_DNS_PLUGIN_GET_PRIVATE (self); + return priv->pid; +} + +GPid +nm_dns_plugin_child_spawn (NMDnsPlugin *self, + const char **argv, + const char *pidfile, + const char *kill_match) +{ + NMDnsPluginPrivate *priv; + GError *error = NULL; + GPid pid; + gs_free char *cmdline = NULL; + gs_free char *progname = NULL; + + g_return_val_if_fail (argv && argv[0], 0); + g_return_val_if_fail (NM_IS_DNS_PLUGIN (self), 0); + + priv = NM_DNS_PLUGIN_GET_PRIVATE (self); + + g_return_val_if_fail (!priv->pid, 0); + nm_assert (!priv->progname); + nm_assert (!priv->watch_id); + nm_assert (!priv->pidfile); + + progname = g_path_get_basename (argv[0]); + kill_existing (progname, pidfile, kill_match); + + _LOGI ("starting %s...", progname); + _LOGD ("command line: %s", + (cmdline = g_strjoinv (" ", (char **) argv))); + + if (!g_spawn_async (NULL, (char **) argv, NULL, + G_SPAWN_DO_NOT_REAP_CHILD, + nm_utils_setpgid, NULL, + &pid, + &error)) { + _LOGW ("failed to spawn %s: %s", + progname, error->message); + g_clear_error (&error); + return 0; + } + + _LOGD ("%s started with pid %d", progname, pid); + priv->watch_id = g_child_watch_add (pid, (GChildWatchFunc) watch_cb, self); + priv->pid = pid; + priv->progname = g_steal_pointer (&progname); + priv->pidfile = g_strdup (pidfile); + + return pid; +} + +gboolean +nm_dns_plugin_child_kill (NMDnsPlugin *self) +{ + NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); + + nm_clear_g_source (&priv->watch_id); + if (priv->pid) { + nm_utils_kill_child_sync (priv->pid, SIGTERM, _NMLOG_DOMAIN, + priv->progname ?: "<dns-process>", NULL, 1000, 0); + priv->pid = 0; + g_clear_pointer (&priv->progname, g_free); + } + _clear_pidfile (self); + + return TRUE; +} + +void +nm_dns_plugin_stop (NMDnsPlugin *self) +{ + nm_dns_plugin_child_kill (self); +} + +/*****************************************************************************/ + +static void +nm_dns_plugin_init (NMDnsPlugin *self) +{ + self->_priv = G_TYPE_INSTANCE_GET_PRIVATE (self, NM_TYPE_DNS_PLUGIN, NMDnsPluginPrivate); +} + +static void +dispose (GObject *object) +{ + NMDnsPlugin *self = NM_DNS_PLUGIN (object); + + nm_dns_plugin_stop (self); + + G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object); +} + +static void +nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class) +{ + GObjectClass *object_class = G_OBJECT_CLASS (plugin_class); + + g_type_class_add_private (plugin_class, sizeof (NMDnsPluginPrivate)); + + object_class->dispose = dispose; + + plugin_class->is_caching = is_caching; + + /* Emitted by the plugin and consumed by NMDnsManager when + * some error happens with the nameserver subprocess. Causes NM to fall + * back to writing out a non-local-caching resolv.conf until the next + * DNS update. + */ + signals[FAILED] = + g_signal_new (NM_DNS_PLUGIN_FAILED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + 0, NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, 0); + + signals[CHILD_QUIT] = + g_signal_new (NM_DNS_PLUGIN_CHILD_QUIT, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDnsPluginClass, child_quit), + NULL, NULL, + g_cclosure_marshal_VOID__INT, + G_TYPE_NONE, 1, G_TYPE_INT); +} |