diff --git a/meson.build b/meson.build index 74aa2d3a..8ec7a625 100644 --- a/meson.build +++ b/meson.build @@ -31,6 +31,7 @@ add_project_arguments(cppflags, language : 'cpp') config_h = configuration_data() config_h.set('_GNU_SOURCE', '1') +config_h.set_quoted('MESON_BUILD_ROOT', meson.build_root()) prefix = '''#define _GNU_SOURCE 1 #include @@ -688,6 +689,23 @@ executable('ptraccel-debug', install : false ) +# the libinput tools check whether we execute from the builddir, this is +# the test to verify that lookup. We test twice, once as normal test +# run from the builddir, once after copying to /tmp +test_builddir_lookup = executable('test-builddir-lookup', + 'tools/test-builddir-lookup.c', + dependencies : [ dep_tools_shared], + include_directories : [includes_src, includes_include], + install : false) +test('tools-builddir-lookup', + test_builddir_lookup, + args : ['--builddir-is-set']) +test('tools-builddir-lookup-installed', + find_program('tools/helper-copy-and-exec-from-tmp.sh'), + args : [test_builddir_lookup.full_path(), '--builddir-is-null'], + env : ['LD_LIBRARY_PATH=@0@'.format(meson.build_root())], + workdir : '/tmp') + ############ tests ############ test_symbols_leak = find_program('test/symbols-leak-test.in') diff --git a/tools/helper-copy-and-exec-from-tmp.sh b/tools/helper-copy-and-exec-from-tmp.sh new file mode 100755 index 00000000..2ae8ec64 --- /dev/null +++ b/tools/helper-copy-and-exec-from-tmp.sh @@ -0,0 +1,18 @@ +#!/bin/bash -x +# +# Usage: helper-copy-and-exec-from-tmp.sh /path/to/binary [args] +# +# Copies the given binary into a unique file in /tmp and executes it with +# [args]. Exits with the same return code as the binary did. + +executable="$1" +shift + +target_name=$(mktemp) +cp "$executable" "$target_name" +chmod +x "$target_name" + +"$target_name" "$@" +rc=$? +rm "$target_name" +exit $rc diff --git a/tools/shared.c b/tools/shared.c index f2ed1fd0..74c0cdad 100644 --- a/tools/shared.c +++ b/tools/shared.c @@ -467,18 +467,51 @@ out: return is_touchpad; } +/* Try to read the directory we're executing from and if it matches the + * builddir, return it as path. Otherwise, return NULL. + */ +char * +tools_execdir_is_builddir(void) +{ + char execdir[PATH_MAX] = {0}; + char *pathsep; + ssize_t sz; + + sz = readlink("/proc/self/exe", execdir, sizeof(execdir) - 1); + if (sz <= 0 || sz == sizeof(execdir) - 1) + return NULL; + + /* readlink doesn't terminate the string and readlink says + anything past sz is undefined */ + execdir[sz + 1] = '\0'; + + pathsep = strrchr(execdir, '/'); + if (!pathsep) + return NULL; + + *pathsep = '\0'; + if (!streq(execdir, MESON_BUILD_ROOT)) + return NULL; + + return safe_strdup(execdir); +} + static inline void setup_path(void) { const char *path = getenv("PATH"); char new_path[PATH_MAX]; + char *builddir; + + builddir = tools_execdir_is_builddir(); snprintf(new_path, sizeof(new_path), "%s:%s", - LIBINPUT_TOOL_PATH, + builddir ? builddir : LIBINPUT_TOOL_PATH, path ? path : ""); setenv("PATH", new_path, 1); + free(builddir); } int diff --git a/tools/shared.h b/tools/shared.h index e30bc39f..364babe6 100644 --- a/tools/shared.h +++ b/tools/shared.h @@ -119,4 +119,7 @@ tools_list_device_quirks(struct quirks_context *ctx, void (*callback)(void *userdata, const char *str), void *userdata); +char * +tools_execdir_is_builddir(void); + #endif diff --git a/tools/test-builddir-lookup.c b/tools/test-builddir-lookup.c new file mode 100644 index 00000000..fc50b0f6 --- /dev/null +++ b/tools/test-builddir-lookup.c @@ -0,0 +1,47 @@ +/* + * Copyright © 2018 Red Hat, Inc. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include "config.h" +#include "libinput-util.h" +#include "shared.h" + +int main(int argc, char **argv) { + char *builddir; + char *mode; + + assert(argc == 2); + mode = argv[1]; + + builddir = tools_execdir_is_builddir(); + if (streq(mode, "--builddir-is-null")) { + assert(builddir == NULL); + } else if (streq(mode, "--builddir-is-set")) { + assert(builddir != NULL); + assert(streq(MESON_BUILD_ROOT, builddir)); + free(builddir); + } else { + abort(); + } + + return 0; +}