Patch by Josh Elsasser.
* os_get_runtime_executable_path() extended with an argument to
indicate if the returned path should be externally usable (which
precludes paths such as /proc/curproc/file).
* If os_get_runtime_executable_path() fails, use an argv[0] derived
path instead.
* Check build_id when saving executable cores to make sure we got
the right runtime -- since using the argv[0] method can otherwise
go wrong once in a blue moon.
Fixes Launchpad #375549.
* bug fix: SB-POSIX build was broken when SBCL was compiled without the
:SB-DOC feature. (lp#552564)
* bug fix: SB-INTROSPECT build issues on GENGC/PPC. (lp#490490)
+ * bug fix: more robust runtime executable path detection. (lp#375549)
changes in sbcl-1.0.37 relative to sbcl-1.0.36:
* enhancement: Backtrace from THROW to uncaught tag on x86oids now shows
(sb!alien:define-alien-variable ("posix_argv" *native-posix-argv*) (* (* char)))
(sb!alien:define-alien-variable ("core_string" *native-core-string*) (* char))
-(sb!alien:define-alien-routine os-get-runtime-executable-path sb!alien:c-string)
+(sb!alien:define-alien-routine
+ os-get-runtime-executable-path sb!alien:c-string (external-path boolean))
+(sb!alien:define-alien-variable
+ ("saved_runtime_path" *native-saved-runtime-path*) (* char))
;;; if something ever needs to be done differently for one OS, then
;;; split out the different part into per-os functions.
(setf *core-pathname*
(merge-pathnames (native-pathname *core-string*)))
(/show0 "setting *RUNTIME-PATHNAME*")
- (let ((exe (os-get-runtime-executable-path)))
- (setf *runtime-pathname* (when exe (native-pathname exe))))
+ (let ((exe (os-get-runtime-executable-path t))
+ (saved (sb!alien:cast *native-saved-runtime-path* sb!alien:c-string)))
+ (setf *runtime-pathname*
+ (when (or exe saved) (native-pathname (or exe saved)))))
(/show0 "leaving OS-COLD-INIT-OR-REINIT"))
#endif
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
char path[PATH_MAX + 1];
}
#elif defined(LISP_FEATURE_NETBSD) || defined(LISP_FEATURE_OPENBSD)
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
struct stat sb;
- char *path = strdup("/proc/curproc/file");
- if (path && ((stat(path, &sb)) == 0))
- return path;
- else {
- fprintf(stderr, "Couldn't stat /proc/curproc/file; is /proc mounted?\n");
- return NULL;
- }
+ if (!external && stat("/proc/curproc/file", &sb) == 0)
+ return copied_string("/proc/curproc/file");
+ return NULL;
}
#else /* Not DARWIN or FREEBSD or NETBSD or OPENBSD */
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
return NULL;
}
#include <errno.h>
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
char path[PATH_MAX + 1];
uint32_t size = sizeof(path);
}
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
- return copied_string("NOPE");
+ return NULL;
}
/* when inside call_into_lisp, we will first jump to the stub
}
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
char path[PATH_MAX + 1];
int size;
int os_get_errno(void);
/* Return an absolute path to the runtime executable, or NULL if this
- * information is unavailable. If a non-null pathname is returned, it
- * must be 'free'd. */
-extern char *os_get_runtime_executable_path(void);
+ * information is unavailable. Unless external_path is non-zero the
+ * returned path may only be valid for the current process, ie:
+ * something like /proc/curproc/file. If a non-null pathname is
+ * returned, it must be 'free'd. */
+extern char *os_get_runtime_executable_path(int external_path);
#endif
}
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
return NULL;
}
return copied_string(filename);
}
}
+
+#ifndef LISP_FEATURE_WIN32
+char *
+copied_realpath(const char *pathname)
+{
+ char *messy, *tidy;
+ size_t len;
+
+ /* realpath() supposedly can't be counted on to always return
+ * an absolute path, so we prepend the cwd to relative paths */
+ messy = NULL;
+ if (pathname[0] != '/') {
+ messy = successful_malloc(PATH_MAX + 1);
+ if (getcwd(messy, PATH_MAX + 1) == NULL) {
+ free(messy);
+ return NULL;
+ }
+ len = strlen(messy);
+ snprintf(messy + len, PATH_MAX + 1 - len, "/%s", pathname);
+ }
+
+ tidy = successful_malloc(PATH_MAX + 1);
+ if (realpath((messy ? messy : pathname), tidy) == NULL) {
+ free(messy);
+ free(tidy);
+ return NULL;
+ }
+
+ return tidy;
+}
+#endif /* LISP_FEATURE_WIN32 */
\f
/* miscellaneous chattiness */
return core;
}
+/* Try to find the path to an executable from argv[0], this is only
+ * used when os_get_runtime_executable_path() returns NULL */
+#ifdef LISP_FEATURE_WIN32
+char *
+search_for_executable(const char *argv0)
+{
+ return NULL;
+}
+#else /* LISP_FEATURE_WIN32 */
+char *
+search_for_executable(const char *argv0)
+{
+ char *search, *start, *end, *buf;
+
+ /* If argv[0] contains a slash then it's probably an absolute path
+ * or relative to the current directory, so check if it exists. */
+ if (strchr(argv0, '/') != NULL && access(argv0, F_OK) == 0)
+ return copied_realpath(argv0);
+
+ /* Bail on an absolute path which doesn't exist */
+ if (argv0[0] == '/')
+ return NULL;
+
+ /* Otherwise check if argv[0] exists relative to any directory in PATH */
+ search = getenv("PATH");
+ if (search == NULL)
+ return NULL;
+ search = copied_string(search);
+ buf = successful_malloc(PATH_MAX + 1);
+ for (start = search; (end = strchr(start, ':')) != NULL; start = end + 1) {
+ *end = '\0';
+ snprintf(buf, PATH_MAX + 1, "%s/%s", start, argv0);
+ if (access(buf, F_OK) == 0) {
+ free(search);
+ search = copied_realpath(buf);
+ free(buf);
+ return search;
+ }
+ }
+
+ free(search);
+ free(buf);
+ return NULL;
+}
+#endif /* LISP_FEATURE_WIN32 */
+
char **posix_argv;
char *core_string;
struct runtime_options *runtime_options;
+char *saved_runtime_path = NULL;
\f
int
main(int argc, char *argv[], char *envp[])
runtime_options = NULL;
+ /* Save the argv[0] derived runtime path in case
+ * os_get_runtime_executable_path(1) isn't able to get an
+ * externally-usable path later on. */
+ saved_runtime_path = search_for_executable(argv[0]);
+
/* Check early to see if this executable has an embedded core,
* which also populates runtime_options if the core has runtime
* options */
- runtime_path = os_get_runtime_executable_path();
- if (runtime_path) {
- os_vm_offset_t offset = search_for_embedded_core(runtime_path);
+ runtime_path = os_get_runtime_executable_path(0);
+ if (runtime_path || saved_runtime_path) {
+ os_vm_offset_t offset = search_for_embedded_core(
+ runtime_path ? runtime_path : saved_runtime_path);
if (offset != -1) {
embedded_core_offset = offset;
- core = runtime_path;
+ core = (runtime_path ? runtime_path :
+ copied_string(saved_runtime_path));
} else {
free(runtime_path);
}
size_t thread_control_stack_size;
};
+/* saved runtime path computed from argv[0] */
+extern char *saved_runtime_path;
+
#endif /* _SBCL_RUNTIME_H_ */
exit(0);
}
+/* Check if the build_id for the current runtime is present in a
+ * buffer. */
+int
+check_runtime_build_id(void *buf, size_t size)
+{
+ size_t idlen;
+ char *pos;
+
+ idlen = strlen(build_id) - 1;
+ while ((pos = memchr(buf, build_id[0], size)) != NULL) {
+ size -= (pos + 1) - (char *)buf;
+ buf = (pos + 1);
+ if (idlen <= size && memcmp(buf, build_id + 1, idlen) == 0)
+ return 1;
+ }
+
+ return 0;
+}
+
/* Slurp the executable portion of the runtime into a malloced buffer
* and return it. Places the size in bytes of the runtime into
* 'size_out'. Returns NULL if the runtime cannot be loaded from
goto lose;
}
+ if (!check_runtime_build_id(buf, size)) {
+ fprintf(stderr, "Failed to locate current build_id in runtime: %s\n",
+ runtime_path);
+ goto lose;
+ }
+
fclose(input);
*size_out = size;
return buf;
char *runtime_path;
if (prepend_runtime) {
- runtime_path = os_get_runtime_executable_path();
+ runtime_path = os_get_runtime_executable_path(0);
- if (runtime_path == NULL) {
+ if (runtime_path == NULL && saved_runtime_path == NULL) {
fprintf(stderr, "Unable to get default runtime path.\n");
return NULL;
}
- *runtime_bytes = load_runtime(runtime_path, runtime_size);
- free(runtime_path);
+ if (runtime_path == NULL)
+ *runtime_bytes = load_runtime(saved_runtime_path, runtime_size);
+ else {
+ *runtime_bytes = load_runtime(runtime_path, runtime_size);
+ free(runtime_path);
+ }
if (*runtime_bytes == NULL)
return 0;
}
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
- int ret;
char path[] = "/proc/self/object/a.out";
- ret = access(path, R_OK);
- if (ret == -1)
+ if (external || access(path, R_OK) == -1)
return NULL;
return copied_string(path);
}
char *
-os_get_runtime_executable_path()
+os_get_runtime_executable_path(int external)
{
char path[MAX_PATH + 1];
DWORD bufsize = sizeof(path);
;;; checkins which aren't released. (And occasionally for internal
;;; versions, especially for internal versions off the main CVS
;;; branch, it gets hairier, e.g. "0.pre7.14.flaky4.13".)
-"1.0.37.53"
+"1.0.37.54"