1 /* -*- Mode: C; tab-width: 4; indent-tabs-mode: t; c-basic-offset: 4 -*- */
2 /* This program is free software; you can redistribute it and/or modify
3 * it under the terms of the GNU General Public License as published by
4 * the Free Software Foundation; either version 2, or (at your option)
7 * This program is distributed in the hope that it will be useful,
8 * but WITHOUT ANY WARRANTY; without even the implied warranty of
9 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
10 * GNU General Public License for more details.
12 * You should have received a copy of the GNU General Public License along
13 * with this program; if not, write to the Free Software Foundation, Inc.,
14 * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
16 * Copyright (C) 2010 - 2012 Red Hat, Inc.
20 #include "nm-default.h"
25 #include <sys/types.h>
28 #include "nm-core-internal.h"
30 #include "nm-dns-plugin.h"
31 #include "NetworkManagerUtils.h"
40 #define NM_DNS_PLUGIN_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), NM_TYPE_DNS_PLUGIN, NMDnsPluginPrivate))
42 G_DEFINE_TYPE_EXTENDED (NMDnsPlugin, nm_dns_plugin, G_TYPE_OBJECT, G_TYPE_FLAG_ABSTRACT, {})
49 static guint signals[LAST_SIGNAL] = { 0 };
51 /********************************************/
54 nm_dns_plugin_update (NMDnsPlugin *self,
55 const GSList *vpn_configs,
56 const GSList *dev_configs,
57 const GSList *other_configs,
58 const NMGlobalDnsConfig *global_config,
61 g_return_val_if_fail (NM_DNS_PLUGIN_GET_CLASS (self)->update != NULL, FALSE);
63 return NM_DNS_PLUGIN_GET_CLASS (self)->update (self,
72 is_caching (NMDnsPlugin *self)
78 nm_dns_plugin_is_caching (NMDnsPlugin *self)
80 return NM_DNS_PLUGIN_GET_CLASS (self)->is_caching (self);
84 nm_dns_plugin_get_name (NMDnsPlugin *self)
86 g_assert (NM_DNS_PLUGIN_GET_CLASS (self)->get_name);
87 return NM_DNS_PLUGIN_GET_CLASS (self)->get_name (self);
90 /********************************************/
93 _clear_pidfile (NMDnsPlugin *self)
95 NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
98 unlink (priv->pidfile);
99 g_free (priv->pidfile);
100 priv->pidfile = NULL;
105 kill_existing (const char *progname, const char *pidfile, const char *kill_match)
108 gs_free char *contents = NULL;
109 gs_free char *cmdline_contents = NULL;
112 gs_free GError *error = NULL;
118 g_return_if_reached ();
120 if (!g_file_get_contents (pidfile, &contents, NULL, &error)) {
121 if (g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT))
126 pid = _nm_utils_ascii_str_to_int64 (contents, 10, 2, INT_MAX, -1);
130 start_time = nm_utils_get_start_time_for_pid (pid, NULL, NULL);
134 nm_sprintf_buf (proc_path, "/proc/%ld/cmdline", pid);
135 if (!g_file_get_contents (proc_path, &cmdline_contents, NULL, NULL))
138 if (!strstr (cmdline_contents, kill_match))
141 nm_utils_kill_process_sync (pid, start_time, SIGKILL, LOGD_DNS,
142 progname ?: "<dns-process>",
150 watch_cb (GPid pid, gint status, gpointer user_data)
152 NMDnsPlugin *self = NM_DNS_PLUGIN (user_data);
153 NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
157 g_free (priv->progname);
158 priv->progname = NULL;
160 _clear_pidfile (self);
162 g_signal_emit (self, signals[CHILD_QUIT], 0, status);
166 nm_dns_plugin_child_spawn (NMDnsPlugin *self,
169 const char *kill_match)
171 NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
172 GError *error = NULL;
175 g_return_val_if_fail (argv != NULL, 0);
176 g_return_val_if_fail (argv[0] != NULL, 0);
178 g_warn_if_fail (priv->progname == NULL);
179 g_free (priv->progname);
180 priv->progname = g_path_get_basename (argv[0]);
182 kill_existing (priv->progname, pidfile, kill_match);
184 g_warn_if_fail (priv->pidfile == NULL);
185 g_clear_pointer (&priv->pidfile, g_free);
186 priv->pidfile = g_strdup (pidfile);
188 nm_log_info (LOGD_DNS, "DNS: starting %s...", priv->progname);
189 cmdline = g_strjoinv (" ", (char **) argv);
190 nm_log_dbg (LOGD_DNS, "DNS: command line: %s", cmdline);
194 if (g_spawn_async (NULL, (char **) argv, NULL,
195 G_SPAWN_DO_NOT_REAP_CHILD,
196 nm_utils_setpgid, NULL,
199 nm_log_dbg (LOGD_DNS, "%s started with pid %d", priv->progname, priv->pid);
200 priv->watch_id = g_child_watch_add (priv->pid, (GChildWatchFunc) watch_cb, self);
202 nm_log_warn (LOGD_DNS, "Failed to spawn %s: %s",
203 priv->progname, error->message);
204 g_clear_error (&error);
211 nm_dns_plugin_child_kill (NMDnsPlugin *self)
213 NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
215 nm_clear_g_source (&priv->watch_id);
218 nm_utils_kill_child_sync (priv->pid, SIGTERM, LOGD_DNS, priv->progname, NULL, 1000, 0);
220 g_free (priv->progname);
221 priv->progname = NULL;
224 _clear_pidfile (self);
229 /********************************************/
232 nm_dns_plugin_init (NMDnsPlugin *self)
237 dispose (GObject *object)
239 NMDnsPlugin *self = NM_DNS_PLUGIN (object);
241 nm_dns_plugin_child_kill (self);
243 G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object);
247 finalize (GObject *object)
249 NMDnsPlugin *self = NM_DNS_PLUGIN (object);
250 NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self);
252 g_free (priv->progname);
253 g_free (priv->pidfile);
255 G_OBJECT_CLASS (nm_dns_plugin_parent_class)->finalize (object);
259 nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class)
261 GObjectClass *object_class = G_OBJECT_CLASS (plugin_class);
263 g_type_class_add_private (plugin_class, sizeof (NMDnsPluginPrivate));
265 /* virtual methods */
266 object_class->dispose = dispose;
267 object_class->finalize = finalize;
268 plugin_class->is_caching = is_caching;
272 g_signal_new (NM_DNS_PLUGIN_FAILED,
273 G_OBJECT_CLASS_TYPE (object_class),
275 G_STRUCT_OFFSET (NMDnsPluginClass, failed),
277 g_cclosure_marshal_VOID__VOID,
280 signals[CHILD_QUIT] =
281 g_signal_new (NM_DNS_PLUGIN_CHILD_QUIT,
282 G_OBJECT_CLASS_TYPE (object_class),
284 G_STRUCT_OFFSET (NMDnsPluginClass, child_quit),
286 g_cclosure_marshal_VOID__INT,
287 G_TYPE_NONE, 1, G_TYPE_INT);