diff --git a/src/dns/nm-dns-manager.c b/src/dns/nm-dns-manager.c index 1f7eb96412..1f6c2eede4 100644 --- a/src/dns/nm-dns-manager.c +++ b/src/dns/nm-dns-manager.c @@ -1642,32 +1642,68 @@ _check_resconf_immutable (NMDnsManagerResolvConfManager rc_manager) static gboolean _resolvconf_resolved_managed (void) { - static const char *const resolved_paths[] = { + static const char *const RESOLVED_PATHS[] = { "/run/systemd/resolve/resolv.conf", "/lib/systemd/resolv.conf", "/usr/lib/systemd/resolv.conf", }; - GFile *f; - GFileInfo *info; - gboolean ret = FALSE; + struct stat st, st_test; + guint i; - f = g_file_new_for_path (_PATH_RESCONF); - info = g_file_query_info (f, - G_FILE_ATTRIBUTE_STANDARD_IS_SYMLINK","\ - G_FILE_ATTRIBUTE_STANDARD_SYMLINK_TARGET, - G_FILE_QUERY_INFO_NOFOLLOW_SYMLINKS, - NULL, NULL); + if (lstat (_PATH_RESCONF, &st) != 0) + return FALSE; - if (info && g_file_info_get_is_symlink (info)) { - ret = nm_utils_strv_find_first ((gchar **) resolved_paths, - G_N_ELEMENTS (resolved_paths), - g_file_info_get_symlink_target (info)) >= 0; + if (S_ISLNK (st.st_mode)) { + gs_free char *full_path = NULL; + nm_auto_free char *real_path = NULL; + + /* see if resolv.conf is a symlink with a target that is + * exactly like one of the candidates. + * + * This check will work for symlinks, even if the target + * does not exist and realpath() cannot resolve anything. + * + * We want to handle that, because systemd-resolved might not + * have started yet. */ + full_path = g_file_read_link (_PATH_RESCONF, NULL); + if (nm_utils_strv_find_first ((char **) RESOLVED_PATHS, + G_N_ELEMENTS (RESOLVED_PATHS), + full_path) >= 0) + return TRUE; + + /* see if resolv.conf is a symlink that resolves exactly one + * of the candidate paths. + * + * This check will work for symlinks that can be resolved + * to a realpath, but the actual file might not exist. + * + * We want to handle that, because systemd-resolved might not + * have started yet. */ + real_path = realpath (_PATH_RESCONF, NULL); + if (nm_utils_strv_find_first ((char **) RESOLVED_PATHS, + G_N_ELEMENTS (RESOLVED_PATHS), + real_path) >= 0) + return TRUE; + + /* fall-through and resolve the symlink, to check the file + * it points to (below). + * + * This check is the most reliable, but it only works if + * systemd-resolved already started and created the file. */ + if (stat (_PATH_RESCONF, &st) != 0) + return FALSE; } - g_clear_object(&info); - g_clear_object(&f); + /* see if resolv.conf resolves to one of the candidate + * paths (or whether it is hard-linked). */ + for (i = 0; i < G_N_ELEMENTS (RESOLVED_PATHS); i++) { + if ( stat (RESOLVED_PATHS[i], &st_test) == 0 + && st.st_dev == st_test.st_dev + && st.st_ino == st_test.st_ino) + return TRUE; + } - return ret; + return FALSE; } static void