From c85418746c3e0d80d666586b7347a0626dee4bf2 Mon Sep 17 00:00:00 2001 From: Thomas Haller Date: Thu, 8 Dec 2016 15:12:52 +0100 Subject: [PATCH] platform: implement sysctl access via relative path to sysctl_open_netdir() --- src/platform/nm-linux-platform.c | 97 +++++++++++++++++++------------- src/platform/nm-platform.c | 28 +++++++++ src/platform/nm-platform.h | 11 ++++ 3 files changed, 98 insertions(+), 38 deletions(-) diff --git a/src/platform/nm-linux-platform.c b/src/platform/nm-linux-platform.c index 6e7f4ccf67..82c644870e 100644 --- a/src/platform/nm-linux-platform.c +++ b/src/platform/nm-linux-platform.c @@ -2510,32 +2510,32 @@ ASSERT_NETNS_CURRENT (NMPlatform *platform) } G_STMT_END static void -_log_dbg_sysctl_set_impl (NMPlatform *platform, const char *path, const char *value) +_log_dbg_sysctl_set_impl (NMPlatform *platform, const char *pathid, int dirfd, const char *path, const char *value) { GError *error = NULL; char *contents, *contents_escaped; char *value_escaped = g_strescape (value, NULL); - if (!g_file_get_contents (path, &contents, NULL, &error)) { - _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", path, value_escaped, error->message); + if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) { + _LOGD ("sysctl: setting '%s' to '%s' (current value cannot be read: %s)", pathid, value_escaped, error->message); g_clear_error (&error); } else { g_strstrip (contents); contents_escaped = g_strescape (contents, NULL); if (strcmp (contents, value) == 0) - _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", path, value_escaped); + _LOGD ("sysctl: setting '%s' to '%s' (current value is identical)", pathid, value_escaped); else - _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", path, value_escaped, contents_escaped); + _LOGD ("sysctl: setting '%s' to '%s' (current value is '%s')", pathid, value_escaped, contents_escaped); g_free (contents); g_free (contents_escaped); } g_free (value_escaped); } -#define _log_dbg_sysctl_set(platform, path, value) \ +#define _log_dbg_sysctl_set(platform, pathid, dirfd, path, value) \ G_STMT_START { \ if (_LOGD_ENABLED ()) { \ - _log_dbg_sysctl_set_impl (platform, path, value); \ + _log_dbg_sysctl_set_impl (platform, pathid, dirfd, path, value); \ } \ } G_STMT_END @@ -2555,26 +2555,44 @@ sysctl_set (NMPlatform *platform, const char *pathid, int dirfd, const char *pat ASSERT_SYSCTL_ARGS (pathid, dirfd, path); - if (!nm_platform_netns_push (platform, &netns)) { - errno = ENETDOWN; - return FALSE; - } - - fd = open (path, O_WRONLY | O_TRUNC); - if (fd == -1) { - errsv = errno; - if (errsv == ENOENT) { - _LOGD ("sysctl: failed to open '%s': (%d) %s", - path, errsv, strerror (errsv)); - } else { - _LOGE ("sysctl: failed to open '%s': (%d) %s", - path, errsv, strerror (errsv)); + if (dirfd < 0) { + if (!nm_platform_netns_push (platform, &netns)) { + errno = ENETDOWN; + return FALSE; + } + + pathid = path; + + fd = open (path, O_WRONLY | O_TRUNC | O_CLOEXEC); + if (fd == -1) { + errsv = errno; + if (errsv == ENOENT) { + _LOGD ("sysctl: failed to open '%s': (%d) %s", + pathid, errsv, strerror (errsv)); + } else { + _LOGE ("sysctl: failed to open '%s': (%d) %s", + pathid, errsv, strerror (errsv)); + } + errno = errsv; + return FALSE; + } + } else { + fd = openat (dirfd, path, O_WRONLY | O_TRUNC | O_CLOEXEC); + if (fd == -1) { + errsv = errno; + if (errsv == ENOENT) { + _LOGD ("sysctl: failed to openat '%s': (%d) %s", + pathid, errsv, strerror (errsv)); + } else { + _LOGE ("sysctl: failed to openat '%s': (%d) %s", + pathid, errsv, strerror (errsv)); + } + errno = errsv; + return FALSE; } - errno = errsv; - return FALSE; } - _log_dbg_sysctl_set (platform, path, value); + _log_dbg_sysctl_set (platform, pathid, dirfd, path, value); /* Most sysfs and sysctl options don't care about a trailing LF, while some * (like infiniband) do. So always add the LF. Also, neither sysfs nor @@ -2647,7 +2665,7 @@ _nm_logging_clear_platform_logging_cache_impl (void) } static void -_log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *contents) +_log_dbg_sysctl_get_impl (NMPlatform *platform, const char *pathid, const char *contents) { NMLinuxPlatformPrivate *priv = NM_LINUX_PLATFORM_GET_PRIVATE (platform); const char *prev_value = NULL; @@ -2657,24 +2675,24 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *co sysctl_clear_cache_list = g_slist_prepend (sysctl_clear_cache_list, platform); priv->sysctl_get_prev_values = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); } else - prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, path); + prev_value = g_hash_table_lookup (priv->sysctl_get_prev_values, pathid); if (prev_value) { if (strcmp (prev_value, contents) != 0) { char *contents_escaped = g_strescape (contents, NULL); char *prev_value_escaped = g_strescape (prev_value, NULL); - _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", path, contents_escaped, prev_value_escaped); + _LOGD ("sysctl: reading '%s': '%s' (changed from '%s' on last read)", pathid, contents_escaped, prev_value_escaped); g_free (contents_escaped); g_free (prev_value_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents)); + g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); } } else { char *contents_escaped = g_strescape (contents, NULL); - _LOGD ("sysctl: reading '%s': '%s'", path, contents_escaped); + _LOGD ("sysctl: reading '%s': '%s'", pathid, contents_escaped); g_free (contents_escaped); - g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (path), g_strdup (contents)); + g_hash_table_insert (priv->sysctl_get_prev_values, g_strdup (pathid), g_strdup (contents)); } if ( !priv->sysctl_get_warned @@ -2684,10 +2702,10 @@ _log_dbg_sysctl_get_impl (NMPlatform *platform, const char *path, const char *co } } -#define _log_dbg_sysctl_get(platform, path, contents) \ +#define _log_dbg_sysctl_get(platform, pathid, contents) \ G_STMT_START { \ if (_LOGD_ENABLED ()) \ - _log_dbg_sysctl_get_impl (platform, path, contents); \ + _log_dbg_sysctl_get_impl (platform, pathid, contents); \ } G_STMT_END static char * @@ -2699,24 +2717,27 @@ sysctl_get (NMPlatform *platform, const char *pathid, int dirfd, const char *pat ASSERT_SYSCTL_ARGS (pathid, dirfd, path); - if (!nm_platform_netns_push (platform, &netns)) - return NULL; + if (dirfd < 0) { + if (!nm_platform_netns_push (platform, &netns)) + return NULL; + pathid = path; + } - if (!g_file_get_contents (path, &contents, NULL, &error)) { + if (nm_utils_file_get_contents (dirfd, path, 1*1024*1024, &contents, NULL, &error) < 0) { /* We assume FAILED means EOPNOTSUP */ if ( g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NOENT) || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_NODEV) || g_error_matches (error, G_FILE_ERROR, G_FILE_ERROR_FAILED)) - _LOGD ("error reading %s: %s", path, error->message); + _LOGD ("error reading %s: %s", pathid, error->message); else - _LOGE ("error reading %s: %s", path, error->message); + _LOGE ("error reading %s: %s", pathid, error->message); g_clear_error (&error); return NULL; } g_strstrip (contents); - _log_dbg_sysctl_get (platform, path, contents); + _log_dbg_sysctl_get (platform, pathid, contents); return contents; } diff --git a/src/platform/nm-platform.c b/src/platform/nm-platform.c index 57f69c9884..99a7f14657 100644 --- a/src/platform/nm-platform.c +++ b/src/platform/nm-platform.c @@ -265,6 +265,34 @@ nm_platform_process_events (NMPlatform *self) /*****************************************************************************/ +/** + * nm_platform_sysctl_open_netdir: + * @self: platform instance + * @ifindex: the ifindex for which to open /sys/class/net/%s + * @out_ifname: optional output argument of the found ifname. + * + * Wraps nmp_utils_sysctl_open_netdir() by first changing into the right + * network-namespace. + * + * Returns: on success, the open file descriptor to the /sys/class/net/%s + * directory. + */ +int +nm_platform_sysctl_open_netdir (NMPlatform *self, int ifindex, char *out_ifname) +{ + const char*ifname_guess; + _CHECK_SELF_NETNS (self, klass, netns, -1); + + g_return_val_if_fail (ifindex > 0, -1); + + /* we don't have an @ifname_guess argument to make the API nicer. + * But still do a cache-lookup first. Chances are good that we have + * the right ifname cached and save if_indextoname() */ + ifname_guess = nm_platform_link_get_name (self, ifindex); + + return nmp_utils_sysctl_open_netdir (ifindex, ifname_guess, out_ifname); +} + /** * nm_platform_sysctl_set: * @self: platform instance diff --git a/src/platform/nm-platform.h b/src/platform/nm-platform.h index 5ed978e469..b2afce3345 100644 --- a/src/platform/nm-platform.h +++ b/src/platform/nm-platform.h @@ -720,6 +720,17 @@ const char *_nm_platform_error_to_string (NMPlatformError error); #define NMP_SYSCTL_PATHID_ABSOLUTE(path) \ ((const char *) NULL), -1, (path) +#define NMP_SYSCTL_PATHID_NETDIR_unsafe(dirfd, ifname, path) \ + nm_sprintf_bufa (NM_STRLEN ("net:/sys/class/net//\0") + IFNAMSIZ + strlen (path), \ + "net:/sys/class/net/%s/%s", (ifname), (path)), \ + (dirfd), (path) + +#define NMP_SYSCTL_PATHID_NETDIR(dirfd, ifname, path) \ + nm_sprintf_bufa (NM_STRLEN ("net:/sys/class/net//"path"/\0") + IFNAMSIZ, \ + "net:/sys/class/net/%s/%s", (ifname), path), \ + (dirfd), (""path"") + +int nm_platform_sysctl_open_netdir (NMPlatform *self, int ifindex, char *out_ifname); gboolean nm_platform_sysctl_set (NMPlatform *self, const char *pathid, int dirfd, const char *path, const char *value); char *nm_platform_sysctl_get (NMPlatform *self, const char *pathid, int dirfd, const char *path); gint32 nm_platform_sysctl_get_int32 (NMPlatform *self, const char *pathid, int dirfd, const char *path, gint32 fallback);