[sysprof] libsysprof: use mountinfo helper for path translations
- From: Christian Hergert <chergert src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [sysprof] libsysprof: use mountinfo helper for path translations
- Date: Fri, 2 Aug 2019 20:10:34 +0000 (UTC)
commit ba725d15992f1f20df9ea04caf3343ef727412a6
Author: Christian Hergert <chergert redhat com>
Date: Fri Aug 2 13:10:28 2019 -0700
libsysprof: use mountinfo helper for path translations
src/libsysprof/sysprof-proc-source.c | 214 ++++-------------------------------
1 file changed, 21 insertions(+), 193 deletions(-)
---
diff --git a/src/libsysprof/sysprof-proc-source.c b/src/libsysprof/sysprof-proc-source.c
index 7846a02..181c9cf 100644
--- a/src/libsysprof/sysprof-proc-source.c
+++ b/src/libsysprof/sysprof-proc-source.c
@@ -44,6 +44,7 @@
#include <string.h>
#include "sysprof-helpers.h"
+#include "sysprof-mountinfo.h"
#include "sysprof-proc-source.h"
struct _SysprofProcSource
@@ -51,38 +52,14 @@ struct _SysprofProcSource
GObject parent_instance;
SysprofCaptureWriter *writer;
GArray *pids;
+ SysprofMountinfo *mountinfo;
};
-static void source_iface_init (SysprofSourceInterface *iface);
-static gchar **proc_readlines (const gchar *format,
- ...)
- G_GNUC_PRINTF (1, 2);
+static void source_iface_init (SysprofSourceInterface *iface);
G_DEFINE_TYPE_EXTENDED (SysprofProcSource, sysprof_proc_source, G_TYPE_OBJECT, 0,
G_IMPLEMENT_INTERFACE (SYSPROF_TYPE_SOURCE, source_iface_init))
-static gchar **
-proc_readlines (const gchar *format,
- ...)
-{
- SysprofHelpers *helpers = sysprof_helpers_get_default ();
- g_autofree gchar *filename = NULL;
- g_autofree gchar *contents = NULL;
- gchar **ret = NULL;
- va_list args;
-
- g_assert (format != NULL);
-
- va_start (args, format);
- filename = g_strdup_vprintf (format, args);
- va_end (args);
-
- if (sysprof_helpers_get_proc_file (helpers, filename, NULL, &contents, NULL))
- ret = g_strsplit (contents, "\n", 0);
-
- return g_steal_pointer (&ret);
-}
-
static void
sysprof_proc_source_populate_process (SysprofProcSource *self,
GPid pid,
@@ -98,151 +75,9 @@ sysprof_proc_source_populate_process (SysprofProcSource *self,
cmdline);
}
-static gboolean
-strv_at_least_len (GStrv strv,
- guint len)
-{
- for (guint i = 0; i < len; i++)
- {
- if (strv[i] == NULL)
- return FALSE;
- }
-
- return TRUE;
-}
-
-static gchar *
-find_mount (GStrv mounts,
- const gchar *mount)
-{
- gsize len = strlen (mount);
-
- for (guint i = 0; mounts[i]; i++)
- {
- const gchar *endptr;
- const gchar *begin;
-
- if (!g_str_has_prefix (mounts[i], mount))
- continue;
-
- if (mounts[i][len] != ' ')
- continue;
-
- begin = &mounts[i][len + 1];
- endptr = strchr (begin, ' ');
- if (endptr == NULL)
- continue;
-
- return g_strndup (begin, endptr - begin);
- }
-
- return NULL;
-}
-
-/**
- * sysprof_proc_source_translate_path:
- * @file: the path to the file inside target mount namespace
- * @mountinfo: mount info to locate translated path
- * @out_file: (out): location for the translated path
- * @out_file_len: length of @out_file
- *
- * This function will use @mountinfo to locate the longest common prefix
- * to determine which mount contains @file. That will be used to translate
- * the path pointed to by @file into the host namespace.
- *
- * The result is stored in @out_file and will always be NULL terminated.
- */
-static void
-sysprof_proc_source_translate_path (const gchar *file,
- GStrv mountinfo,
- GStrv mounts,
- gchar *out_file,
- gsize out_file_len)
-{
- g_autofree gchar *closest_host = NULL;
- g_autofree gchar *closest_guest = NULL;
- g_autofree gchar *closest_mount = NULL;
- gsize closest_len = 0;
-
- g_assert (file != NULL);
- g_assert (g_str_has_prefix (file, "/newroot/"));
- g_assert (mountinfo != NULL);
- g_assert (out_file != NULL);
-
- if (!g_str_has_prefix (file, "/newroot/"))
- goto failure;
-
- file += strlen ("/newroot");
-
- for (guint i = 0; mountinfo[i] != NULL; i++)
- {
- g_auto(GStrv) parts = g_strsplit (mountinfo[i], " ", 11);
- const gchar *host;
- const gchar *guest;
- const gchar *mount;
-
- /*
- * Not ideal to do the string split here, but it is much easier
- * to just do that until we get this right, and then improve
- * things later when a strok()/etc parser.
- */
-
- if (!strv_at_least_len (parts, 10))
- continue;
-
- host = parts[3];
- guest = parts[4];
- mount = parts[9];
-
- if (g_str_has_prefix (file, guest))
- {
- gsize len = strlen (guest);
-
- if (len > closest_len && (file[len] == '\0' || file[len] == '/'))
- {
- g_free (closest_host);
- g_free (closest_guest);
- g_free (closest_mount);
-
- closest_guest = g_strdup (guest);
- closest_host = g_strdup (host);
- closest_mount = g_strdup (mount);
-
- closest_len = len;
- }
- }
- }
-
- if (closest_len > 0)
- {
- /*
- * The translated path is relative to the mount. So we need to add that
- * prefix to this as well, based on matching it from the closest_mount.
- */
- g_autofree gchar *mount = NULL;
-
- mount = find_mount (mounts, closest_mount);
-
- if (mount != NULL)
- {
- g_autofree gchar *path = NULL;
-
- path = g_build_filename (mount, closest_host, file + strlen (closest_guest), NULL);
- g_strlcpy (out_file, path, out_file_len);
-
- return;
- }
- }
-
-failure:
- /* Fallback to just copying the source */
- g_strlcpy (out_file, file, out_file_len);
-}
-
static void
sysprof_proc_source_populate_maps (SysprofProcSource *self,
GPid pid,
- GStrv mounts,
const gchar *mapsstr,
const gchar *mountinfostr)
{
@@ -255,13 +90,15 @@ sysprof_proc_source_populate_maps (SysprofProcSource *self,
g_assert (mountinfostr != NULL);
g_assert (pid > 0);
+ sysprof_mountinfo_reset (self->mountinfo);
+ sysprof_mountinfo_parse_mountinfo (self->mountinfo, mountinfostr);
+
maps = g_strsplit (mapsstr, "\n", 0);
- mountinfo = g_strsplit (mountinfostr, "\n", 0);
for (i = 0; maps [i] != NULL; i++)
{
- gchar file[256];
- gchar translated[256];
+ g_autofree gchar *translated = NULL;
+ gchar file[512];
const gchar *fileptr = file;
gulong start;
gulong end;
@@ -270,9 +107,8 @@ sysprof_proc_source_populate_maps (SysprofProcSource *self,
gint r;
r = sscanf (maps [i],
- "%lx-%lx %*15s %lx %*x:%*x %lu %255s",
+ "%lx-%lx %*15s %lx %*x:%*x %lu %512s",
&start, &end, &offset, &inode, file);
-
file [sizeof file - 1] = '\0';
if (r != 5)
@@ -293,23 +129,9 @@ sysprof_proc_source_populate_maps (SysprofProcSource *self,
inode = 0;
}
- if (g_str_has_prefix (file, "/newroot/"))
- {
- /*
- * If this file starts with /newroot/, then it is in a different
- * mount-namespace from our profiler process. This means that we need
- * to translate the filename to the real path on disk inside our
- * (hopefully the default) mount-namespace. To do this, we have to
- * look at /proc/$pid/mountinfo to locate the longest-common-prefix
- * for the path.
- */
- sysprof_proc_source_translate_path (file,
- mountinfo,
- mounts,
- translated,
- sizeof translated);
- fileptr = translated;
- }
+ /* Possibly translate the path based on mounts/mountinfo data */
+ if ((translated = sysprof_mountinfo_translate (self->mountinfo, file)))
+ fileptr = translated;
sysprof_capture_writer_add_map (self->writer,
SYSPROF_CAPTURE_CURRENT_TIME,
@@ -343,7 +165,8 @@ static void
sysprof_proc_source_populate (SysprofProcSource *self,
GVariant *info)
{
- g_auto(GStrv) mounts = NULL;
+ g_autofree gchar *mounts = NULL;
+ SysprofHelpers *helpers;
gsize n_pids = 0;
g_assert (SYSPROF_IS_PROC_SOURCE (self));
@@ -353,9 +176,12 @@ sysprof_proc_source_populate (SysprofProcSource *self,
if (self->writer == NULL)
return;
- if (!(mounts = proc_readlines ("/proc/mounts")))
+ helpers = sysprof_helpers_get_default ();
+ if (!sysprof_helpers_get_proc_file (helpers, "/proc/mounts", NULL, &mounts, NULL))
return;
+ sysprof_mountinfo_parse_mounts (self->mountinfo, mounts);
+
n_pids = g_variant_n_children (info);
for (gsize i = 0; i < n_pids; i++)
{
@@ -386,7 +212,7 @@ sysprof_proc_source_populate (SysprofProcSource *self,
maps = "";
sysprof_proc_source_populate_process (self, pid, *cmdline ? cmdline : comm);
- sysprof_proc_source_populate_maps (self, pid, mounts, maps, mountinfo);
+ sysprof_proc_source_populate_maps (self, pid, maps, mountinfo);
skip:
g_variant_dict_clear (&dict);
@@ -492,6 +318,7 @@ sysprof_proc_source_finalize (GObject *object)
g_clear_pointer (&self->writer, sysprof_capture_writer_unref);
g_clear_pointer (&self->pids, g_array_unref);
+ g_clear_pointer (&self->mountinfo, sysprof_mountinfo_free);
G_OBJECT_CLASS (sysprof_proc_source_parent_class)->finalize (object);
}
@@ -508,6 +335,7 @@ static void
sysprof_proc_source_init (SysprofProcSource *self)
{
self->pids = g_array_new (FALSE, FALSE, sizeof (GPid));
+ self->mountinfo = sysprof_mountinfo_new ();
}
SysprofSource *
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]