diff --git a/config.h.meson b/config.h.meson index ff355d306..928a758ae 100644 --- a/config.h.meson +++ b/config.h.meson @@ -36,3 +36,6 @@ /* Define if polkit defines autocleanup functions */ #mesondefine HAVE_POLKIT_AUTOCLEANUP + +/* Define to 1 if the and header file exist. */ +#mesondefine HAVE_EXE_INTROSPECTION diff --git a/meson.build b/meson.build index 252fb1ec4..0be7bf769 100644 --- a/meson.build +++ b/meson.build @@ -148,6 +148,8 @@ cdata.set('HAVE_FDWALK', cc.has_function('fdwalk')) cdata.set('HAVE_MALLINFO', cc.has_function('mallinfo')) cdata.set('HAVE_MALLINFO2', cc.has_function('mallinfo2')) cdata.set('HAVE_SYS_RESOURCE_H', cc.has_header('sys/resource.h')) +cdata.set('HAVE_EXE_INTROSPECTION', + cc.has_header('elf.h') and cc.has_header('link.h')) cdata.set('HAVE__NL_TIME_FIRST_WEEKDAY', cc.has_header_symbol('langinfo.h', '_NL_TIME_FIRST_WEEKDAY') ) diff --git a/src/main.c b/src/main.c index 269fe56c9..9913bbccb 100644 --- a/src/main.c +++ b/src/main.c @@ -18,6 +18,11 @@ #include #include #include +#include + +#ifdef HAVE_EXE_INTROSPECTION +#include +#endif #include "shell-global.h" #include "shell-global-private.h" @@ -123,6 +128,74 @@ shell_dbus_init (gboolean replace) g_object_unref (session); } +#ifdef HAVE_EXE_INTROSPECTION +static void +maybe_add_rpath_introspection_paths (void) +{ + ElfW (Dyn) *dyn; + ElfW (Dyn) *rpath = NULL; + ElfW (Dyn) *runpath = NULL; + const char *strtab = NULL; + g_auto (GStrv) paths = NULL; + g_autofree char *exe_dir = NULL; + GStrv str; + + for (dyn = _DYNAMIC; dyn->d_tag != DT_NULL; dyn++) + { + if (dyn->d_tag == DT_RPATH) + rpath = dyn; + else if (dyn->d_tag == DT_RUNPATH) + runpath = dyn; + else if (dyn->d_tag == DT_STRTAB) + strtab = (const char *) dyn->d_un.d_val; + } + + if ((!rpath && !runpath) || !strtab) + return; + + if (rpath) + paths = g_strsplit (strtab + rpath->d_un.d_val, ":", -1); + else + paths = g_strsplit (strtab + runpath->d_un.d_val, ":", -1); + + if (!paths) + return; + + for (str = paths; *str; str++) + { + g_autoptr (GError) error = NULL; + g_autoptr (GString) rpath_dir = NULL; + + if (!strstr (*str, "$ORIGIN")) + continue; + + if (!exe_dir) + { + g_autofree char *exe_path = NULL; + + exe_path = g_file_read_link ("/proc/self/exe", &error); + if (!exe_path) + { + g_warning ("Failed to find directory of executable: %s", + error->message); + return; + } + + exe_dir = g_path_get_dirname (exe_path); + } + + rpath_dir = g_string_new (*str); + g_string_replace (rpath_dir, "$ORIGIN", exe_dir, 0); + + g_debug ("Prepending RPATH directory '%s' " + "to introsepciton library search path", + rpath_dir->str); + g_irepository_prepend_search_path (rpath_dir->str); + g_irepository_prepend_library_path (rpath_dir->str); + } +} +#endif /* HAVE_EXE_INTROSPECTION */ + static void shell_introspection_init (void) { @@ -137,6 +210,10 @@ shell_introspection_init (void) */ g_irepository_prepend_library_path (MUTTER_TYPELIB_DIR); g_irepository_prepend_library_path (GNOME_SHELL_PKGLIBDIR); + +#ifdef HAVE_EXE_INTROSPECTION + maybe_add_rpath_introspection_paths (); +#endif } static void