diff options
| author | Michael Biebl <biebl@debian.org> | 2016-03-30 00:56:30 +0200 |
|---|---|---|
| committer | Michael Biebl <biebl@debian.org> | 2016-03-30 00:56:30 +0200 |
| commit | d9c99a29a0d3384c9c3d2adce430f5cb1134ab6a (patch) | |
| tree | fa41baf72753961e71dd8d5bdbe2b89c9109e4f1 /src/dns-manager | |
| parent | c2de0d98ba39e0a1a970d066fd19be786092f376 (diff) | |
Imported Upstream version 1.1.92 upstream/1.1.92
Diffstat (limited to 'src/dns-manager')
| -rw-r--r-- | src/dns-manager/nm-dns-dnsmasq.c | 47 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-manager.c | 238 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-manager.h | 10 | ||||
| -rw-r--r-- | src/dns-manager/nm-dns-plugin.c | 120 |
4 files changed, 264 insertions, 151 deletions
diff --git a/src/dns-manager/nm-dns-dnsmasq.c b/src/dns-manager/nm-dns-dnsmasq.c index 8663dfd8..460feaac 100644 --- a/src/dns-manager/nm-dns-dnsmasq.c +++ b/src/dns-manager/nm-dns-dnsmasq.c @@ -46,7 +46,20 @@ typedef struct { guint32 foo; } NMDnsDnsmasqPrivate; -/*******************************************/ +/*****************************************************************************/ + +#define _NMLOG_DOMAIN LOGD_DNS +#define _NMLOG_PREFIX_NAME "dnsmasq" +#define _NMLOG(level, ...) \ + G_STMT_START { \ + nm_log ((level), _NMLOG_DOMAIN, \ + "%s[%p]: " _NM_UTILS_MACRO_FIRST(__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + (self) \ + _NM_UTILS_MACRO_REST(__VA_ARGS__)); \ + } G_STMT_END + +/*****************************************************************************/ static gboolean add_ip4_config (GString *str, NMIP4Config *ip4, gboolean split) @@ -246,7 +259,7 @@ update (NMDnsPlugin *plugin, dm_binary = nm_utils_find_helper ("dnsmasq", DNSMASQ_PATH, NULL); if (!dm_binary) { - nm_log_warn (LOGD_DNS, "Could not find dnsmasq binary"); + _LOGW ("could not find dnsmasq binary"); return FALSE; } @@ -283,17 +296,16 @@ update (NMDnsPlugin *plugin, /* Write out the config file */ if (!g_file_set_contents (CONFFILE, conf->str, -1, &error)) { - nm_log_warn (LOGD_DNS, "Failed to write dnsmasq config file %s: (%d) %s", - CONFFILE, - error ? error->code : -1, - error && error->message ? error->message : "(unknown)"); + _LOGW ("failed to write dnsmasq config file %s: %s", + CONFFILE, + error->message); g_clear_error (&error); goto out; } ignored = chmod (CONFFILE, 0644); - nm_log_dbg (LOGD_DNS, "dnsmasq local caching DNS configuration:"); - nm_log_dbg (LOGD_DNS, "%s", conf->str); + _LOGD ("dnsmasq local caching DNS configuration:"); + _LOGD ("%s", conf->str); argv[idx++] = dm_binary; argv[idx++] = "--no-resolv"; /* Use only commandline */ @@ -351,18 +363,17 @@ child_quit (NMDnsPlugin *plugin, gint status) if (WIFEXITED (status)) { err = WEXITSTATUS (status); if (err) { - nm_log_warn (LOGD_DNS, "dnsmasq exited with error: %s (%d)", - dm_exit_code_to_msg (err), - err); + _LOGW ("dnsmasq exited with error: %s (%d)", + dm_exit_code_to_msg (err), + err); } else failed = FALSE; - } else if (WIFSTOPPED (status)) { - nm_log_warn (LOGD_DNS, "dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status)); - } else if (WIFSIGNALED (status)) { - nm_log_warn (LOGD_DNS, "dnsmasq died with signal %d", WTERMSIG (status)); - } else { - nm_log_warn (LOGD_DNS, "dnsmasq died from an unknown cause"); - } + } else if (WIFSTOPPED (status)) + _LOGW ("dnsmasq stopped unexpectedly with signal %d", WSTOPSIG (status)); + else if (WIFSIGNALED (status)) + _LOGW ("dnsmasq died with signal %d", WTERMSIG (status)); + else + _LOGW ("dnsmasq died from an unknown cause"); unlink (CONFFILE); if (failed) diff --git a/src/dns-manager/nm-dns-manager.c b/src/dns-manager/nm-dns-manager.c index 79d345be..ec83e600 100644 --- a/src/dns-manager/nm-dns-manager.c +++ b/src/dns-manager/nm-dns-manager.c @@ -100,14 +100,11 @@ NM_DEFINE_SINGLETON_INSTANCE (NMDnsManager); const NMDnsManager *const __self = (self); \ \ _nm_log (__level, _NMLOG_DOMAIN, 0, \ - "%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ - ((__self == singleton_instance) \ - ? _NMLOG_PREFIX_NAME \ - : ({ \ - g_snprintf (__prefix, sizeof (__prefix), "%s[%p]", _NMLOG_PREFIX_NAME, __self); \ - __prefix; \ - }) \ - ) \ + "%s%s: " _NM_UTILS_MACRO_FIRST (__VA_ARGS__), \ + _NMLOG_PREFIX_NAME, \ + ((!__self || __self == singleton_instance) \ + ? "" \ + : nm_sprintf_buf (__prefix, "[%p]", __self)) \ _NM_UTILS_MACRO_REST (__VA_ARGS__)); \ } \ } G_STMT_END @@ -128,6 +125,9 @@ typedef struct { NMDnsManagerResolvConfMode resolv_conf_mode; NMDnsManagerResolvConfManager rc_manager; + char *last_mode; + bool last_immutable:1; + bool mode_initialized:1; NMDnsPlugin *plugin; NMConfig *config; @@ -164,6 +164,15 @@ typedef struct { GPtrArray *nis_servers; } NMResolvConfData; +NM_UTILS_LOOKUP_STR_DEFINE_STATIC (_rc_manager_to_string, NMDnsManagerResolvConfManager, + NM_UTILS_LOOKUP_DEFAULT_WARN (NULL), + NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE, "none"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE, "file"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, "resolvconf"), + NM_UTILS_LOOKUP_STR_ITEM (NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, "netconfig"), + NM_UTILS_LOOKUP_ITEM_IGNORE (_NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY), +); + static void add_string_item (GPtrArray *array, const char *str) { @@ -406,12 +415,10 @@ dispatch_netconfig (NMDnsManager *self, return SR_SUCCESS; } -static gboolean -write_resolv_conf (FILE *f, - char **searches, - char **nameservers, - char **options, - GError **error) +static char * +create_resolv_conf (char **searches, + char **nameservers, + char **options) { gs_free char *searches_str = NULL; gs_free char *nameservers_str = NULL; @@ -439,9 +446,9 @@ write_resolv_conf (FILE *f, for (i = 0; i < num; i++) { if (i == 3) { g_string_append (str, "# "); - g_string_append (str, _("NOTE: the libc resolver may not support more than 3 nameservers.")); + g_string_append (str, "NOTE: the libc resolver may not support more than 3 nameservers."); g_string_append (str, "\n# "); - g_string_append (str, _("The nameservers listed below may not be recognized.")); + g_string_append (str, "The nameservers listed below may not be recognized."); g_string_append_c (str, '\n'); } @@ -452,10 +459,18 @@ write_resolv_conf (FILE *f, nameservers_str = g_string_free (str, FALSE); } - if (fprintf (f, "# Generated by NetworkManager\n%s%s%s", - searches_str ? searches_str : "", - nameservers_str ? nameservers_str : "", - options_str ? options_str : "") < 0) { + return g_strdup_printf ("# Generated by NetworkManager\n%s%s%s", + searches_str ?: "", + nameservers_str ?: "", + options_str ?: ""); +} + +static gboolean +write_resolv_conf_contents (FILE *f, + const char *content, + GError **error) +{ + if (fprintf (f, "%s", content) < 0) { g_set_error (error, NM_MANAGER_ERROR, NM_MANAGER_ERROR_FAILED, @@ -467,6 +482,19 @@ write_resolv_conf (FILE *f, return TRUE; } +static gboolean +write_resolv_conf (FILE *f, + char **searches, + char **nameservers, + char **options, + GError **error) +{ + gs_free char *content = NULL; + + content = create_resolv_conf (searches, nameservers, options); + return write_resolv_conf_contents (f, content, error); +} + static SpawnResult dispatch_resolvconf (NMDnsManager *self, char **searches, @@ -539,18 +567,22 @@ update_resolv_conf (NMDnsManager *self, char **nameservers, char **options, GError **error, - gboolean install_etc) + NMDnsManagerResolvConfManager rc_manager) { FILE *f; struct stat st; gboolean success; + gs_free char *content = NULL; + SpawnResult write_file_result = SR_SUCCESS; /* If we are not managing /etc/resolv.conf and it points to * MY_RESOLV_CONF, don't write the private DNS configuration to * MY_RESOLV_CONF otherwise we would overwrite the changes done by * some external application. - */ - if (!install_etc) { + * + * This is the only situation, where we don't try to update our + * internal resolv.conf file. */ + if (rc_manager == _NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY) { gs_free char *path = g_file_read_link (_PATH_RESCONF, NULL); if (g_strcmp0 (path, MY_RESOLV_CONF) == 0) { @@ -560,6 +592,18 @@ update_resolv_conf (NMDnsManager *self, } } + content = create_resolv_conf (searches, nameservers, options); + + if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) { + /* we first write to /etc/resolv.conf directly. If that fails, + * we still continue to write to runstatedir but remember the + * error. */ + if (!g_file_set_contents (_PATH_RESCONF, content, -1, error)) { + write_file_result = SR_ERROR; + error = NULL; + } + } + if ((f = fopen (MY_RESOLV_CONF_TMP, "w")) == NULL) { g_set_error (error, NM_MANAGER_ERROR, @@ -570,7 +614,7 @@ update_resolv_conf (NMDnsManager *self, return SR_ERROR; } - success = write_resolv_conf (f, searches, nameservers, options, error); + success = write_resolv_conf_contents (f, content, error); if (fclose (f) < 0) { if (success) { @@ -598,7 +642,10 @@ update_resolv_conf (NMDnsManager *self, return SR_ERROR; } - if (!install_etc) + if (rc_manager == NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE) + return write_file_result; + + if (rc_manager != NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE) return SR_SUCCESS; /* A symlink pointing to NM's own resolv.conf (MY_RESOLV_CONF) is always @@ -920,7 +967,7 @@ update_dns (NMDnsManager *self, nis_domain = rc.nis_domain; /* Let any plugins do their thing first */ - if (update && priv->plugin) { + if (priv->plugin) { NMDnsPlugin *plugin = priv->plugin; const char *plugin_name = nm_dns_plugin_get_name (plugin); GSList *vpn_configs = NULL, *dev_configs = NULL, *other_configs = NULL; @@ -973,7 +1020,8 @@ update_dns (NMDnsManager *self, if (update) { switch (priv->rc_manager) { case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: - result = update_resolv_conf (self, searches, nameservers, options, error, TRUE); + case NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: + result = update_resolv_conf (self, searches, nameservers, options, error, priv->rc_manager); resolv_conf_updated = TRUE; break; case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: @@ -990,7 +1038,7 @@ update_dns (NMDnsManager *self, if (result == SR_NOTFOUND) { _LOGD ("update-dns: program not available, writing to resolv.conf"); g_clear_error (error); - result = update_resolv_conf (self, searches, nameservers, options, error, TRUE); + result = update_resolv_conf (self, searches, nameservers, options, error, NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE); resolv_conf_updated = TRUE; } } @@ -998,7 +1046,7 @@ update_dns (NMDnsManager *self, /* Unless we've already done it, update private resolv.conf in NMRUNDIR ignoring any errors */ if (!resolv_conf_updated) - update_resolv_conf (self, searches, nameservers, options, NULL, FALSE); + update_resolv_conf (self, searches, nameservers, options, NULL, _NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY); /* signal that resolv.conf was changed */ if (update && result == SR_SUCCESS) @@ -1318,70 +1366,105 @@ nm_dns_manager_end_updates (NMDnsManager *self, const char *func) /******************************************************************/ +static bool +_get_resconf_immutable (int *immutable_cached) +{ + int fd, flags; + int immutable; + + immutable = *immutable_cached; + if (!NM_IN_SET (immutable, FALSE, TRUE)) { + immutable = FALSE; + fd = open (_PATH_RESCONF, O_RDONLY); + if (fd != -1) { + if (ioctl (fd, FS_IOC_GETFLAGS, &flags) != -1) + immutable = NM_FLAGS_HAS (flags, FS_IMMUTABLE_FL); + close (fd); + } + *immutable_cached = immutable; + } + return immutable; +} + NM_DEFINE_SINGLETON_GETTER (NMDnsManager, nm_dns_manager_get, NM_TYPE_DNS_MANAGER); static void init_resolv_conf_mode (NMDnsManager *self) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - const char *mode; - int fd, flags; - - g_clear_object (&priv->plugin); + const char *mode, *mode_unknown; + int immutable = -1; 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; - goto out; + + if ( priv->mode_initialized + && nm_streq0 (mode, priv->last_mode) + && ( nm_streq0 (mode, "none") + || priv->last_immutable == _get_resconf_immutable (&immutable))) { + /* we call init_resolv_conf_mode() on every SIGHUP to possibly reload + * when either "mode" or "immutable" changed. However, we don't want to + * re-create the plugin, when the paramters didn't actually change. So + * detect that we would recreate the same plugin and return early. */ + return; } - fd = open (_PATH_RESCONF, O_RDONLY); - if (fd != -1) { - if (ioctl (fd, FS_IOC_GETFLAGS, &flags) == -1) - flags = 0; - close (fd); + priv->mode_initialized = TRUE; + g_free (priv->last_mode); + priv->last_mode = g_strdup (mode); + priv->last_immutable = FALSE; + g_clear_object (&priv->plugin); + priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED; - if (flags & FS_IMMUTABLE_FL) { - _LOGI ("set resolv-conf-mode: none -- " _PATH_RESCONF " is immutable"); - priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_UNMANAGED; - return; - } + if (nm_streq0 (mode, "none")) { + _LOGI ("%s%s", "set resolv-conf-mode: ", "none"); + return; } - if (!g_strcmp0 (mode, "dnsmasq")) { - priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_PROXY; - priv->plugin = nm_dns_dnsmasq_new (); - } else if (!g_strcmp0 (mode, "unbound")) { - priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_PROXY; - priv->plugin = nm_dns_unbound_new (); - } else { - priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT; - if (mode && g_strcmp0 (mode, "default") != 0) { - _LOGW ("set resolve-conf-mode: default -- unknown configuration '%s'", mode); - return; - } - mode = "default"; - } + priv->last_immutable = _get_resconf_immutable (&immutable); + + if (NM_IN_STRSET (mode, "dnsmasq", "unbound")) { + if (!immutable) + priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_PROXY; + if (nm_streq (mode, "dnsmasq")) + priv->plugin = nm_dns_dnsmasq_new (); + else + priv->plugin = nm_dns_unbound_new (); - if (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); + + _NMLOG (immutable ? LOGL_WARN : LOGL_INFO, + "%s%s%s%s%s%s", + "set resolv-conf-mode: ", + immutable ? "none" : mode, + ", plugin=\"", nm_dns_plugin_get_name (priv->plugin), "\"", + immutable ? ", resolv.conf immutable" : ""); + return; } -out: - _LOGI ("set resolv-conf-mode: %s%s%s%s", mode, - NM_PRINT_FMT_QUOTED (priv->plugin, ", plugin=\"", nm_dns_plugin_get_name (priv->plugin), "\"", "")); + if (!immutable) + priv->resolv_conf_mode = NM_DNS_MANAGER_RESOLV_CONF_EXPLICIT; + + mode_unknown = mode && !nm_streq (mode, "default") ? mode : NULL; + _NMLOG (mode_unknown ? LOGL_WARN : LOGL_INFO, + "%s%s%s%s%s%s", + "set resolv-conf-mode: ", + immutable ? "none" : "default", + NM_PRINT_FMT_QUOTED (mode_unknown, " -- unknown configuration '", mode_unknown, "'", ""), + immutable ? ", resolv.conf immutable" : ""); } static void init_resolv_conf_manager (NMDnsManager *self) { NMDnsManagerPrivate *priv = NM_DNS_MANAGER_GET_PRIVATE (self); - const char *man, *desc = ""; + const char *man; man = nm_config_data_get_rc_manager (nm_config_get_data (priv->config)); if (!g_strcmp0 (man, "none")) priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE; + else if (nm_streq0 (man, "file")) + priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE; else if (!g_strcmp0 (man, "resolvconf")) priv->rc_manager = NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF; else if (!g_strcmp0 (man, "netconfig")) @@ -1398,19 +1481,7 @@ init_resolv_conf_manager (NMDnsManager *self) _LOGW ("unknown resolv.conf manager '%s'", man); } - switch (priv->rc_manager) { - case NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: - desc = "resolvconf"; - break; - case NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: - desc = "netconfig"; - break; - case NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: - desc = "none"; - break; - } - - _LOGI ("using resolv.conf manager '%s'", desc); + _LOGI ("using resolv.conf manager '%s'", _rc_manager_to_string (priv->rc_manager)); } static void @@ -1422,8 +1493,15 @@ config_changed_cb (NMConfig *config, { GError *error = NULL; - if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_DNS_MODE)) + if (NM_FLAGS_ANY (changes, NM_CONFIG_CHANGE_DNS_MODE | + NM_CONFIG_CHANGE_SIGHUP)) { + /* reload the resolv-conf mode also on SIGHUP (when DNS_MODE didn't change). + * The reason is, that the configuration also depends on whether resolv.conf + * is immutable, thus, without the configuration changing, we always want to + * re-configure the mode. */ init_resolv_conf_mode (self); + } + if (NM_FLAGS_HAS (changes, NM_CONFIG_CHANGE_RC_MANAGER)) init_resolv_conf_manager (self); @@ -1474,6 +1552,8 @@ dispose (GObject *object) g_clear_object (&priv->plugin); } + g_clear_pointer (&priv->last_mode, g_free); + /* If we're quitting, leave a valid resolv.conf in place, not one * pointing to 127.0.0.1 if any plugins were active. Thus update * DNS after disposing of all plugins. But if we haven't done any diff --git a/src/dns-manager/nm-dns-manager.h b/src/dns-manager/nm-dns-manager.h index 7a55f1a2..dd5c9e98 100644 --- a/src/dns-manager/nm-dns-manager.h +++ b/src/dns-manager/nm-dns-manager.h @@ -101,7 +101,13 @@ typedef enum { /** * NMDnsManagerResolvConfManager - * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: NM directly writes resolv.conf + * @_NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY: dummy-manager + * to not write resolv.conf at all, only the internal file in + * NM's run state directory. + * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE: NM writes resolv.conf + * by symlinking it to the run state directory. + * @NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE: Like NONE, but instead of symlinking + * resolv.conf, write it as a file. * @NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF: NM is managing resolv.conf through resolvconf * @NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG: NM is managing resolv.conf @@ -110,7 +116,9 @@ typedef enum { * NMDnsManager's management of resolv.conf */ typedef enum { + _NM_DNS_MANAGER_RESOLV_CONF_MAN_INTERNAL_ONLY, NM_DNS_MANAGER_RESOLV_CONF_MAN_NONE, + NM_DNS_MANAGER_RESOLV_CONF_MAN_FILE, NM_DNS_MANAGER_RESOLV_CONF_MAN_RESOLVCONF, NM_DNS_MANAGER_RESOLV_CONF_MAN_NETCONFIG, } NMDnsManagerResolvConfManager; diff --git a/src/dns-manager/nm-dns-plugin.c b/src/dns-manager/nm-dns-plugin.c index 8313ed13..47322d2a 100644 --- a/src/dns-manager/nm-dns-plugin.c +++ b/src/dns-manager/nm-dns-plugin.c @@ -25,12 +25,12 @@ #include <sys/types.h> #include <sys/wait.h> +#include "nm-core-internal.h" + #include "nm-dns-plugin.h" #include "NetworkManagerUtils.h" typedef struct { - gboolean disposed; - GPid pid; guint watch_id; char *progname; @@ -90,36 +90,60 @@ nm_dns_plugin_get_name (NMDnsPlugin *self) /********************************************/ static void +_clear_pidfile (NMDnsPlugin *self) +{ + NMDnsPluginPrivate *priv = NM_DNS_PLUGIN_GET_PRIVATE (self); + + if (priv->pidfile) { + unlink (priv->pidfile); + g_free (priv->pidfile); + priv->pidfile = NULL; + } +} + +static void kill_existing (const char *progname, const char *pidfile, const char *kill_match) { - char *contents = NULL; glong pid; - char *proc_path = NULL; - char *cmdline_contents = NULL; + 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 (!g_file_get_contents (pidfile, &contents, NULL, NULL)) + if (!pidfile) return; - pid = strtol (contents, NULL, 10); - if (pid < 1 || pid > INT_MAX) + 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; - proc_path = g_strdup_printf ("/proc/%ld/cmdline", pid); + 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)) { - if (kill (pid, 0) == 0) { - nm_log_dbg (LOGD_DNS, "Killing stale %s child process %ld", progname, pid); - kill (pid, SIGKILL); - } - unlink (pidfile); - } + if (!strstr (cmdline_contents, kill_match)) + goto out; + + nm_utils_kill_process_sync (pid, start_time, SIGKILL, LOGD_DNS, + progname ?: "<dns-process>", + 0, 0, 1000); out: - g_free (cmdline_contents); - g_free (proc_path); - g_free (contents); + unlink (pidfile); } static void @@ -133,6 +157,8 @@ watch_cb (GPid pid, gint status, gpointer user_data) g_free (priv->progname); priv->progname = NULL; + _clear_pidfile (self); + g_signal_emit (self, signals[CHILD_QUIT], 0, status); } @@ -153,13 +179,11 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self, 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); + kill_existing (priv->progname, pidfile, kill_match); - g_free (priv->pidfile); - priv->pidfile = g_strdup (pidfile); - } + g_warn_if_fail (priv->pidfile == NULL); + g_clear_pointer (&priv->pidfile, g_free); + priv->pidfile = g_strdup (pidfile); nm_log_info (LOGD_DNS, "DNS: starting %s...", priv->progname); cmdline = g_strjoinv (" ", (char **) argv); @@ -175,9 +199,8 @@ nm_dns_plugin_child_spawn (NMDnsPlugin *self, 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)"); + nm_log_warn (LOGD_DNS, "Failed to spawn %s: %s", + priv->progname, error->message); g_clear_error (&error); } @@ -198,11 +221,7 @@ nm_dns_plugin_child_kill (NMDnsPlugin *self) priv->progname = NULL; } - if (priv->pidfile) { - unlink (priv->pidfile); - g_free (priv->pidfile); - priv->pidfile = NULL; - } + _clear_pidfile (self); return TRUE; } @@ -218,13 +237,8 @@ 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); - } + nm_dns_plugin_child_kill (self); G_OBJECT_CLASS (nm_dns_plugin_parent_class)->dispose (object); } @@ -255,21 +269,21 @@ nm_dns_plugin_class_init (NMDnsPluginClass *plugin_class) /* signals */ signals[FAILED] = - g_signal_new (NM_DNS_PLUGIN_FAILED, - G_OBJECT_CLASS_TYPE (object_class), - G_SIGNAL_RUN_FIRST, - G_STRUCT_OFFSET (NMDnsPluginClass, failed), - NULL, NULL, - g_cclosure_marshal_VOID__VOID, - G_TYPE_NONE, 0); + g_signal_new (NM_DNS_PLUGIN_FAILED, + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_FIRST, + G_STRUCT_OFFSET (NMDnsPluginClass, failed), + 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); + 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); } |