diff --git a/src/libsysprof/meson.build b/src/libsysprof/meson.build index 2f21dd3b..12e3ac66 100644 --- a/src/libsysprof/meson.build +++ b/src/libsysprof/meson.build @@ -65,6 +65,7 @@ libsysprof_private_sources = [ 'binfile.c', 'demangle.cpp', 'elfparser.c', + 'sysprof-flatpak.c', 'sysprof-helpers.c', 'sysprof-kallsyms.c', 'sysprof-line-reader.c', diff --git a/src/libsysprof/sysprof-flatpak.c b/src/libsysprof/sysprof-flatpak.c new file mode 100644 index 00000000..5f470e0b --- /dev/null +++ b/src/libsysprof/sysprof-flatpak.c @@ -0,0 +1,136 @@ +/* sysprof-flatpak.c + * + * Copyright 2019 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#include "config.h" + +#include + +#include "sysprof-flatpak.h" + +#define ETC_INSTALLATIONS_D "/etc/flatpak/installations.d" + +gchar ** +get_installations (void) +{ + GPtrArray *ret = g_ptr_array_new (); + g_autoptr(GDir) dir = NULL; + + /* We might be running from a container, so ignore XDG_DATA_HOME as + * that will likely be different that what we care about the host. + * TODO: Can we find a way to support non-standard XDG_DATA_HOME? + */ + g_ptr_array_add (ret, g_build_filename (g_get_home_dir (), ".local", "share", "flatpak", NULL)); + g_ptr_array_add (ret, g_strdup ("/var/lib/flatpak")); + + /* Now look at /etc/flatpak/installations.d for keyfiles with Path= */ + if ((dir = g_dir_open (ETC_INSTALLATIONS_D, 0, NULL))) + { + const gchar *name; + + while ((name = g_dir_read_name (dir))) + { + g_autofree gchar *path = g_build_filename (ETC_INSTALLATIONS_D, name, NULL); + g_autoptr(GKeyFile) kf = g_key_file_new (); + + if (g_key_file_load_from_file (kf, path, G_KEY_FILE_NONE, NULL)) + { + g_auto(GStrv) groups = g_key_file_get_groups (kf, NULL); + + for (guint i = 0; groups[i]; i++) + { + if (g_key_file_has_key (kf, groups[i], "Path", NULL)) + { + gchar *val = g_key_file_get_string (kf, groups[i], "Path", NULL); + + if (val) + g_ptr_array_add (ret, g_steal_pointer (&val)); + } + } + } + } + } + + g_ptr_array_add (ret, NULL); + return (gchar **)g_ptr_array_free (ret, FALSE); +} + +static void +get_arch (gchar *out, + gsize len) +{ + struct utsname u; + uname (&u); + g_strlcpy (out, u.machine, len); +} + +void +_sysprof_flatpak_debug_dirs (GPtrArray *dirs) +{ + g_auto(GStrv) installs = get_installations (); + gchar arch[32]; + + g_assert (dirs != NULL); + + get_arch (arch, sizeof arch); + + /* For each of the installations, we want to look at all of the runtimes that + * exist within it. Of those runtimes, we want to limit ourselves to the active + * version of each runtime, and see if we have a deployment for the current + * system arch that contains a "lib/debug" directory. We could add more, but + * it's just too many directories. + */ + + for (guint i = 0; installs[i]; i++) + { + g_autofree gchar *repo_dir = g_build_filename (installs[i], "runtime", NULL); + g_autoptr(GDir) dir = g_dir_open (repo_dir, 0, NULL); + const gchar *name; + + if (dir == NULL) + continue; + + while ((name = g_dir_read_name (dir))) + { + g_autofree gchar *version_dir = g_build_filename (installs[i], "runtime", name, arch, NULL); + g_autoptr(GDir) vdir = g_dir_open (version_dir, 0, NULL); + const gchar *version; + + if (vdir == NULL) + continue; + + while ((version = g_dir_read_name (vdir))) + { + g_autofree gchar *lib_debug = g_build_filename (version_dir, version, "active", "files", "lib", "debug", NULL); + + if (g_file_test (lib_debug, G_FILE_TEST_EXISTS)) + g_ptr_array_add (dirs, g_steal_pointer (&lib_debug)); + } + } + } +} + +gchar ** +sysprof_flatpak_debug_dirs (void) +{ + GPtrArray *dirs = g_ptr_array_new (); + _sysprof_flatpak_debug_dirs (dirs); + g_ptr_array_add (dirs, NULL); + return (gchar **)g_ptr_array_free (dirs, FALSE); +} diff --git a/src/libsysprof/sysprof-flatpak.h b/src/libsysprof/sysprof-flatpak.h new file mode 100644 index 00000000..04cc0043 --- /dev/null +++ b/src/libsysprof/sysprof-flatpak.h @@ -0,0 +1,29 @@ +/* sysprof-flatpak.h + * + * Copyright 2019 Christian Hergert + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + * + * SPDX-License-Identifier: GPL-3.0-or-later + */ + +#pragma once + +#include + +G_BEGIN_DECLS + +gchar **sysprof_flatpak_debug_dirs (void); + +G_END_DECLS diff --git a/src/tests/meson.build b/src/tests/meson.build index 690ec5c1..ac809975 100644 --- a/src/tests/meson.build +++ b/src/tests/meson.build @@ -50,6 +50,13 @@ test_mountinfo = executable('test-mountinfo', dependencies: test_deps, ) +test_flatpak = executable('test-flatpak', + [ 'test-flatpak.c', + '../libsysprof/sysprof-flatpak.c'], + c_args: test_cflags, + dependencies: test_deps, +) + if get_option('enable_gtk') diff --git a/src/tests/test-flatpak.c b/src/tests/test-flatpak.c new file mode 100644 index 00000000..52abfba4 --- /dev/null +++ b/src/tests/test-flatpak.c @@ -0,0 +1,13 @@ +#include "sysprof-flatpak.h" + +gint +main (gint argc, + gchar *argv[]) +{ + g_auto(GStrv) debug_dirs = sysprof_flatpak_debug_dirs (); + + for (guint i = 0; debug_dirs[i]; i++) + g_print ("%s\n", debug_dirs[i]); + + return 0; +}