Search for scripts relative to the executable on all(?) platforms 89/3889/7
authorAndreas Fritiofson <andreas.fritiofson@gmail.com>
Sat, 19 Nov 2016 20:43:22 +0000 (21:43 +0100)
committerPaul Fertser <fercerpav@gmail.com>
Sun, 25 Dec 2016 09:22:29 +0000 (09:22 +0000)
Add a helper to hide the platform-dependent method to get a
canonical, absolute, /-separated path to the executable.

Use this and the relative path from BINDIR to PKGDATADIR to
construct a search path that finds the scripts even if the
installation dir is moved, as long as the structure below $prefix
is maintained.

This method should fully support all the tricks you can to with
autotools to customize the installed layout such as overriding the
default directories at configure-time and overriding the configured
directories at build-time.

The exe path detection methods are combined from
http://openocd.zylin.com/3388 by Rick Foos and
http://openocd.zylin.com/3537 by Steven Stallion, as well as tips
found all over internet.

Change-Id: Ifc9cc9dd0bf52fbd67b1b0f2383318cda0c422c4
Signed-off-by: Andreas Fritiofson <andreas.fritiofson@gmail.com>
Signed-off-by: Steven Stallion <sstallion@gmail.com>
Reviewed-on: http://openocd.zylin.com/3889
Tested-by: jenkins
Reviewed-by: Rick Foos <rfoos@solengtech.com>
Reviewed-by: Paul Fertser <fercerpav@gmail.com>
configure.ac
src/helper/options.c

index 5630b11169737030126e06bc8c29794e3a04c320..687e95ce9a11c767142c92ff192ca045021bb8b1 100644 (file)
@@ -57,6 +57,7 @@ AC_CHECK_HEADERS([sys/ioctl.h])
 AC_CHECK_HEADERS([sys/param.h])
 AC_CHECK_HEADERS([sys/select.h])
 AC_CHECK_HEADERS([sys/stat.h])
+AC_CHECK_HEADERS([sys/sysctl.h])
 AC_CHECK_HEADERS([sys/time.h])
 AC_CHECK_HEADERS([sys/types.h])
 AC_CHECK_HEADERS([unistd.h])
@@ -86,6 +87,7 @@ AC_CHECK_FUNCS([strnlen])
 AC_CHECK_FUNCS([gettimeofday])
 AC_CHECK_FUNCS([usleep])
 AC_CHECK_FUNCS([vasprintf])
+AC_CHECK_FUNCS([realpath])
 
 # guess-rev.sh only exists in the repository, not in the released archives
 AC_MSG_CHECKING([whether to build a release])
index b7db10f92e47131a802c20314a5335e5ceedddc8..409abeebb4ab4e37ad031aa69c811b9ab82da29b 100644 (file)
 
 #include <getopt.h>
 
+#include <limits.h>
+#include <stdlib.h>
+#if IS_DARWIN
+#include <libproc.h>
+#endif
+#ifdef HAVE_SYS_SYSCTL_H
+#include <sys/sysctl.h>
+#endif
+
 static int help_flag, version_flag;
 
 static const struct option long_options[] = {
@@ -50,52 +59,129 @@ int configuration_output_handler(struct command_context *context, const char *li
        return ERROR_OK;
 }
 
-#ifdef _WIN32
-static char *find_suffix(const char *text, const char *suffix)
+/* Return the canonical path to the directory the openocd executable is in.
+ * The path should be absolute, use / as path separator and have all symlinks
+ * resolved. The returned string is malloc'd. */
+static char *find_exe_path(void)
 {
-       size_t text_len = strlen(text);
-       size_t suffix_len = strlen(suffix);
+       char *exepath = NULL;
+
+       do {
+#if IS_WIN32 && !IS_CYGWIN
+               exepath = malloc(MAX_PATH);
+               if (exepath == NULL)
+                       break;
+               GetModuleFileName(NULL, exepath, MAX_PATH);
 
-       if (suffix_len == 0)
-               return (char *)text + text_len;
+               /* Convert path separators to UNIX style, should work on Windows also. */
+               for (char *p = exepath; *p; p++) {
+                       if (*p == '\\')
+                               *p = '/';
+               }
 
-       if (suffix_len > text_len || strncmp(text + text_len - suffix_len, suffix, suffix_len) != 0)
-               return NULL; /* Not a suffix of text */
+#elif IS_DARWIN
+               exepath = malloc(PROC_PIDPATHINFO_MAXSIZE);
+               if (exepath == NULL)
+                       break;
+               if (proc_pidpath(getpid(), exepath, PROC_PIDPATHINFO_MAXSIZE) <= 0) {
+                       free(exepath);
+                       exepath = NULL;
+               }
 
-       return (char *)text + text_len - suffix_len;
-}
+#elif defined(CTL_KERN) && defined(KERN_PROC) && defined(KERN_PROC_PATHNAME) /* *BSD */
+#ifndef PATH_MAX
+#define PATH_MAX 1024
 #endif
+               char *path = malloc(PATH_MAX);
+               if (path == NULL)
+                       break;
+               int mib[] = { CTL_KERN, KERN_PROC, KERN_PROC_PATHNAME, -1 };
+               size_t size = PATH_MAX;
 
-static void add_default_dirs(void)
-{
-       const char *run_prefix;
-       char *path;
+               if (sysctl(mib, (u_int)ARRAY_SIZE(mib), path, &size, NULL, 0) != 0)
+                       break;
 
-#ifdef _WIN32
-       char strExePath[MAX_PATH];
-       GetModuleFileName(NULL, strExePath, MAX_PATH);
+#ifdef HAVE_REALPATH
+               exepath = realpath(path, NULL);
+               free(path);
+#else
+               exepath = path;
+#endif
 
-       /* Strip executable file name, leaving path */
-       *strrchr(strExePath, '\\') = '\0';
+#elif defined(HAVE_REALPATH) /* Assume POSIX.1-2008 */
+               /* Try Unices in order of likelihood. */
+               exepath = realpath("/proc/self/exe", NULL); /* Linux/Cygwin */
+               if (exepath == NULL)
+                       exepath = realpath("/proc/self/path/a.out", NULL); /* Solaris */
+               if (exepath == NULL)
+                       exepath = realpath("/proc/curproc/file", NULL); /* FreeBSD (Should be covered above) */
+#endif
+       } while (0);
+
+       if (exepath != NULL) {
+               /* Strip executable file name, leaving path */
+               *strrchr(exepath, '/') = '\0';
+       } else {
+               LOG_WARNING("Could not determine executable path, using configured BINDIR.");
+               LOG_DEBUG("BINDIR = %s", BINDIR);
+#ifdef HAVE_REALPATH
+               exepath = realpath(BINDIR, NULL);
+#else
+               exepath = strdup(BINDIR);
+#endif
+       }
+
+       return exepath;
+}
 
-       /* Convert path separators to UNIX style, should work on Windows also. */
-       for (char *p = strExePath; *p; p++) {
-               if (*p == '\\')
-                       *p = '/';
+static char *find_relative_path(const char *from, const char *to)
+{
+       size_t i;
+
+       /* Skip common /-separated parts of from and to */
+       i = 0;
+       for (size_t n = 0; from[n] == to[n]; n++) {
+               if (from[n] == '\0') {
+                       i = n;
+                       break;
+               }
+               if (from[n] == '/')
+                       i = n + 1;
+       }
+       from += i;
+       to += i;
+
+       /* Count number of /-separated non-empty parts of from */
+       i = 0;
+       while (from[0] != '\0') {
+               if (from[0] != '/')
+                       i++;
+               char *next = strchr(from, '/');
+               if (next == NULL)
+                       break;
+               from = next + 1;
        }
 
-       char *end_of_prefix = find_suffix(strExePath, BINDIR);
-       if (end_of_prefix != NULL)
-               *end_of_prefix = '\0';
+       /* Prepend that number of ../ in front of to */
+       char *relpath = malloc(i * 3 + strlen(to) + 1);
+       relpath[0] = '\0';
+       for (size_t n = 0; n < i; n++)
+               strcat(relpath, "../");
+       strcat(relpath, to);
 
-       run_prefix = strExePath;
-#else
-       run_prefix = "";
-#endif
+       return relpath;
+}
+
+static void add_default_dirs(void)
+{
+       char *path;
+       char *exepath = find_exe_path();
+       char *bin2data = find_relative_path(BINDIR, PKGDATADIR);
 
        LOG_DEBUG("bindir=%s", BINDIR);
        LOG_DEBUG("pkgdatadir=%s", PKGDATADIR);
-       LOG_DEBUG("run_prefix=%s", run_prefix);
+       LOG_DEBUG("exepath=%s", exepath);
+       LOG_DEBUG("bin2data=%s", bin2data);
 
        /*
         * The directory containing OpenOCD-supplied scripts should be
@@ -129,17 +215,20 @@ static void add_default_dirs(void)
        }
 #endif
 
-       path = alloc_printf("%s%s%s", run_prefix, PKGDATADIR, "/site");
+       path = alloc_printf("%s/%s/%s", exepath, bin2data, "site");
        if (path) {
                add_script_search_dir(path);
                free(path);
        }
 
-       path = alloc_printf("%s%s%s", run_prefix, PKGDATADIR, "/scripts");
+       path = alloc_printf("%s/%s/%s", exepath, bin2data, "scripts");
        if (path) {
                add_script_search_dir(path);
                free(path);
        }
+
+       free(exepath);
+       free(bin2data);
 }
 
 int parse_cmdline_args(struct command_context *cmd_ctx, int argc, char *argv[])

Linking to existing account procedure

If you already have an account and want to add another login method you MUST first sign in with your existing account and then change URL to read https://review.openocd.org/login/?link to get to this page again but this time it'll work for linking. Thank you.

SSH host keys fingerprints

1024 SHA256:YKx8b7u5ZWdcbp7/4AeXNaqElP49m6QrwfXaqQGJAOk gerrit-code-review@openocd.zylin.com (DSA)
384 SHA256:jHIbSQa4REvwCFG4cq5LBlBLxmxSqelQPem/EXIrxjk gerrit-code-review@openocd.org (ECDSA)
521 SHA256:UAOPYkU9Fjtcao0Ul/Rrlnj/OsQvt+pgdYSZ4jOYdgs gerrit-code-review@openocd.org (ECDSA)
256 SHA256:A13M5QlnozFOvTllybRZH6vm7iSt0XLxbA48yfc2yfY gerrit-code-review@openocd.org (ECDSA)
256 SHA256:spYMBqEYoAOtK7yZBrcwE8ZpYt6b68Cfh9yEVetvbXg gerrit-code-review@openocd.org (ED25519)
+--[ED25519 256]--+
|=..              |
|+o..   .         |
|*.o   . .        |
|+B . . .         |
|Bo. = o S        |
|Oo.+ + =         |
|oB=.* = . o      |
| =+=.+   + E     |
|. .=o   . o      |
+----[SHA256]-----+
2048 SHA256:0Onrb7/PHjpo6iVZ7xQX2riKN83FJ3KGU0TvI0TaFG4 gerrit-code-review@openocd.zylin.com (RSA)