diff --git src/code/common-os.lisp src/code/common-os.lisp index 7b32419..bf71744 100644 --- src/code/common-os.lisp +++ src/code/common-os.lisp @@ -15,7 +15,10 @@ (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. @@ -43,6 +46,8 @@ (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")) diff --git src/runtime/bsd-os.c src/runtime/bsd-os.c index 3b88379..1b1db92 100644 --- src/runtime/bsd-os.c +++ src/runtime/bsd-os.c @@ -428,7 +428,7 @@ futex_wake(int *lock_word, int n) #endif char * -os_get_runtime_executable_path() +os_get_runtime_executable_path(int external) { char path[PATH_MAX + 1]; @@ -456,20 +456,16 @@ os_get_runtime_executable_path() } #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; } diff --git src/runtime/darwin-os.c src/runtime/darwin-os.c index a60dc30..95de326 100644 --- src/runtime/darwin-os.c +++ src/runtime/darwin-os.c @@ -24,7 +24,7 @@ #include char * -os_get_runtime_executable_path() +os_get_runtime_executable_path(int external) { char path[PATH_MAX + 1]; uint32_t size = sizeof(path); diff --git src/runtime/hpux-os.c src/runtime/hpux-os.c index 605cd8b..bff662f 100644 --- src/runtime/hpux-os.c +++ src/runtime/hpux-os.c @@ -135,9 +135,9 @@ os_install_interrupt_handlers(void) } 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 diff --git src/runtime/linux-os.c src/runtime/linux-os.c index 9b2e3cf..e25527a 100644 --- src/runtime/linux-os.c +++ src/runtime/linux-os.c @@ -450,7 +450,7 @@ os_install_interrupt_handlers(void) } char * -os_get_runtime_executable_path() +os_get_runtime_executable_path(int external) { char path[PATH_MAX + 1]; int size; diff --git src/runtime/os.h src/runtime/os.h index a471ab6..814b18d 100644 --- src/runtime/os.h +++ src/runtime/os.h @@ -173,8 +173,10 @@ extern void os_deallocate(os_vm_address_t addr, os_vm_size_t len); 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 diff --git src/runtime/osf1-os.c src/runtime/osf1-os.c index 4c3b011..183a4a4 100644 --- src/runtime/osf1-os.c +++ src/runtime/osf1-os.c @@ -146,7 +146,7 @@ os_install_interrupt_handlers(void) } char * -os_get_runtime_executable_path() +os_get_runtime_executable_path(int external) { return NULL; } diff --git src/runtime/runtime.c src/runtime/runtime.c index 573b389..e4ec0e9 100644 --- src/runtime/runtime.c +++ src/runtime/runtime.c @@ -127,6 +127,37 @@ copied_existing_filename_or_null(char *filename) 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 */ /* miscellaneous chattiness */ @@ -205,11 +236,58 @@ search_for_core () 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; int main(int argc, char *argv[], char *envp[]) @@ -241,15 +319,22 @@ 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); } diff --git src/runtime/runtime.h src/runtime/runtime.h index 8602432..de83bc8 100644 --- src/runtime/runtime.h +++ src/runtime/runtime.h @@ -272,4 +272,7 @@ struct runtime_options { size_t thread_control_stack_size; }; +/* saved runtime path computed from argv[0] */ +extern char *saved_runtime_path; + #endif /* _SBCL_RUNTIME_H_ */ diff --git src/runtime/save.c src/runtime/save.c index 726f012..b3addc9 100644 --- src/runtime/save.c +++ src/runtime/save.c @@ -383,6 +383,25 @@ save_to_filehandle(FILE *file, char *filename, lispobj init_function, 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 @@ -414,6 +433,12 @@ load_runtime(char *runtime_path, size_t *size_out) 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; @@ -460,15 +485,19 @@ prepare_to_save(char *filename, boolean prepend_runtime, void **runtime_bytes, 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; diff --git src/runtime/sunos-os.c src/runtime/sunos-os.c index 89c0d71..027e2d6 100644 --- src/runtime/sunos-os.c +++ src/runtime/sunos-os.c @@ -234,13 +234,11 @@ os_install_interrupt_handlers() } 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); diff --git src/runtime/win32-os.c src/runtime/win32-os.c index 32ff6d0..1ecd69d 100644 --- src/runtime/win32-os.c +++ src/runtime/win32-os.c @@ -571,7 +571,7 @@ void scratch(void) } char * -os_get_runtime_executable_path() +os_get_runtime_executable_path(int external) { char path[MAX_PATH + 1]; DWORD bufsize = sizeof(path);