plugin: API: GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE

When a plugin declares a dependency using this flag, all the
relative paths are considered to be relative to the path of
the main executable.

We try to determine the path of the executable portably,
with implementations provided for Linux, Windows and Mac.

If retrieval of the path fails, we will not detect changes.

In order for the main executable path to be the same when
scanning a plugin in a child process, a new variable is
exposed in gst_private.h, _gst_executable_path

https://bugzilla.gnome.org/show_bug.cgi?id=788152
This commit is contained in:
Mathieu Duponchelle 2017-09-25 20:35:59 +02:00
parent 0c614a0bd3
commit 6cddce7663
7 changed files with 100 additions and 8 deletions

View file

@ -106,6 +106,10 @@
#define WIN32_LEAN_AND_MEAN /* prevents from including too many things */
#include <windows.h> /* GetStdHandle, windows console */
#endif
#if defined (__APPLE__)
#include <errno.h>
#include <libproc.h> /* proc_pidpath, PROC_PIDPATHINFO_MAXSIZE */
#endif
#include "gst-i18n-lib.h"
#include <locale.h> /* for LC_ALL */
@ -133,6 +137,8 @@ extern gboolean _priv_gst_disable_registry;
extern gboolean _priv_gst_disable_registry_update;
#endif
gchar *_gst_executable_path = NULL;
#ifndef GST_DISABLE_GST_DEBUG
const gchar *priv_gst_dump_dot_dir;
#endif
@ -311,6 +317,56 @@ gst_init_get_option_group (void)
#endif
}
#if defined(__linux__)
static void
find_executable_path (void)
{
GError *error = NULL;
gchar *path;
if (_gst_executable_path)
return;
path = g_file_read_link ("/proc/self/exe", &error);
if (path) {
_gst_executable_path = g_path_get_dirname (path);
g_free (path);
}
}
#elif defined(G_OS_WIN32)
static void
find_executable_path (void)
{
char buffer[MAX_PATH];
if (!GetModuleFilename (NULL, buffer, MAX_PATH))
return;
_gst_executable_path = g_strdup (buffer);
}
#elif defined(__APPLE__)
static void
find_executable_path (void)
{
int ret;
pid_t pid;
char pathbuf[PROC_PIDPATHINFO_MAXSIZE];
pid = getpid ();
ret = proc_pidpath (pid, pathbuf, sizeof (pathbuf));
if (ret > 0)
_gst_executable_path = g_strdup (pathbuf)
}
#else
static void
find_executable_path (void)
{
GST_FIXME ("Couldn't look up executable path, add support for this platform");
}
#endif
/**
* gst_init_check:
* @argc: (inout) (allow-none): pointer to application's argc
@ -343,6 +399,9 @@ gst_init_check (int *argc, char **argv[], GError ** err)
g_mutex_unlock (&init_lock);
return TRUE;
}
find_executable_path ();
#ifndef GST_DISABLE_OPTION_PARSING
ctx = g_option_context_new ("- GStreamer initialization");
g_option_context_set_ignore_unknown_options (ctx, TRUE);
@ -1019,6 +1078,11 @@ gst_deinit (void)
_priv_gst_plugin_paths = NULL;
#endif
if (_gst_executable_path) {
g_free (_gst_executable_path);
_gst_executable_path = NULL;
}
clock = gst_system_clock_obtain ();
gst_object_unref (clock);
gst_object_unref (clock);

View file

@ -229,6 +229,10 @@ GstCapsFeatures * __gst_caps_get_features_unchecked (const GstCaps * caps, guint
GST_EXPORT gboolean _gst_disable_registry_cache;
#endif
/* Secret variable to let the plugin scanner use the same base path
* as the main application in order to determine dependencies */
GST_EXPORT gchar *_gst_executable_path;
/* provide inline gst_g_value_get_foo_unchecked(), used in gststructure.c */
#define DEFINE_INLINE_G_VALUE_GET_UNCHECKED(ret_type,name_type,v_field) \
static inline ret_type \

View file

@ -1702,6 +1702,7 @@ static guint
gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
{
gboolean paths_are_default_only;
gboolean paths_are_relative_to_exe;
GQueue scan_paths = G_QUEUE_INIT;
guint scan_hash = 0;
gchar *path;
@ -1710,6 +1711,8 @@ gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
paths_are_default_only =
dep->flags & GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY;
paths_are_relative_to_exe =
dep->flags & GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE;
gst_plugin_ext_dep_extract_env_vars_paths (plugin, dep, &scan_paths);
@ -1718,12 +1721,26 @@ gst_plugin_ext_dep_get_stat_hash (GstPlugin * plugin, GstPluginDep * dep)
for (paths = dep->paths; paths != NULL && *paths != NULL; ++paths) {
const gchar *path = *paths;
gchar *full_path;
if (!g_queue_find_custom (&scan_paths, path, (GCompareFunc) strcmp)) {
GST_LOG_OBJECT (plugin, "path: '%s'", path);
g_queue_push_tail (&scan_paths, g_strdup (path));
if (paths_are_relative_to_exe && !g_path_is_absolute (path)) {
if (!_gst_executable_path) {
GST_FIXME_OBJECT (plugin,
"Path dependency %s relative to executable path but could not retrieve executable path",
path);
continue;
}
full_path = g_build_filename (_gst_executable_path, path, NULL);
} else {
GST_LOG_OBJECT (plugin, "path: '%s' (duplicate, ignoring)", path);
full_path = g_strdup (path);
}
if (!g_queue_find_custom (&scan_paths, full_path, (GCompareFunc) strcmp)) {
GST_LOG_OBJECT (plugin, "path: '%s'", full_path);
g_queue_push_tail (&scan_paths, full_path);
} else {
GST_LOG_OBJECT (plugin, "path: '%s' (duplicate, ignoring)", full_path);
g_free (full_path);
}
}
}

View file

@ -98,6 +98,9 @@ typedef enum
* @GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX : interpret
* filename argument as filter prefix and check all matching files in
* the directory. Since 1.8.
* @GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE : interpret
* non-absolute paths as relative to the main executable directory. Since
* 1.14.
*
* Flags used in connection with gst_plugin_add_dependency().
*/
@ -106,7 +109,8 @@ typedef enum {
GST_PLUGIN_DEPENDENCY_FLAG_RECURSE = (1 << 0),
GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_DEFAULT_ONLY = (1 << 1),
GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_SUFFIX = (1 << 2),
GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX = (1 << 3)
GST_PLUGIN_DEPENDENCY_FLAG_FILE_NAME_IS_PREFIX = (1 << 3),
GST_PLUGIN_DEPENDENCY_FLAG_PATHS_ARE_RELATIVE_TO_EXE = (1 << 4)
} GstPluginDependencyFlags;
/**

View file

@ -408,7 +408,7 @@ gst_plugin_loader_use_usr_bin_arch (void)
static gboolean
gst_plugin_loader_try_helper (GstPluginLoader * loader, gchar * location)
{
char *argv[5] = { NULL, };
char *argv[6] = { NULL, };
int c = 0;
#if defined (__APPLE__) && defined (USR_BIN_ARCH_SWITCH)
@ -419,9 +419,10 @@ gst_plugin_loader_try_helper (GstPluginLoader * loader, gchar * location)
#endif
argv[c++] = location;
argv[c++] = (char *) "-l";
argv[c++] = _gst_executable_path;
argv[c++] = NULL;
if (c > 3) {
if (c > 4) {
GST_LOG ("Trying to spawn gst-plugin-scanner helper at %s with arch %s",
location, argv[1]);
} else {

View file

@ -38,7 +38,7 @@ main (int argc, char *argv[])
char **my_argv;
int my_argc;
if (argc != 2 || strcmp (argv[1], "-l"))
if (argc != 3 || strcmp (argv[1], "-l"))
return 1;
my_argc = 2;
@ -50,6 +50,7 @@ main (int argc, char *argv[])
_gst_disable_registry_cache = TRUE;
#endif
_gst_executable_path = g_strdup (argv[2]);
res = gst_init_check (&my_argc, &my_argv, NULL);
g_free (my_argv);

View file

@ -50,6 +50,7 @@ EXPORTS
_gst_debug_nameof_funcptr
_gst_debug_register_funcptr
_gst_disable_registry_cache DATA
_gst_executable_path DATA
_gst_double_range_type DATA
_gst_element_error_printf
_gst_event_type DATA