Merge pull request #795 from xavierleroy/fix-exe-name
More robust determination of full path to current executablemaster
commit
70d880a41a
|
@ -102,8 +102,7 @@ extern void caml_install_invalid_parameter_handler();
|
|||
|
||||
void caml_main(char **argv)
|
||||
{
|
||||
char * exe_name;
|
||||
static char proc_self_exe[256];
|
||||
char * exe_name, * proc_self_exe;
|
||||
value res;
|
||||
char tos;
|
||||
|
||||
|
@ -133,7 +132,8 @@ void caml_main(char **argv)
|
|||
caml_debugger_init (); /* force debugger.o stub to be linked */
|
||||
exe_name = argv[0];
|
||||
if (exe_name == NULL) exe_name = "";
|
||||
if (caml_executable_name(proc_self_exe, sizeof(proc_self_exe)) == 0)
|
||||
proc_self_exe = caml_executable_name();
|
||||
if (proc_self_exe != NULL)
|
||||
exe_name = proc_self_exe;
|
||||
else
|
||||
exe_name = caml_search_exe_in_path(exe_name);
|
||||
|
|
|
@ -82,8 +82,9 @@ extern char * caml_dlerror(void);
|
|||
extern int caml_read_directory(char * dirname, struct ext_table * contents);
|
||||
|
||||
/* Recover executable name if possible (/proc/sef/exe under Linux,
|
||||
GetModuleFileName under Windows). */
|
||||
extern int caml_executable_name(char * name, int name_len);
|
||||
GetModuleFileName under Windows). Return NULL on error,
|
||||
string allocated with [caml_stat_alloc] on success. */
|
||||
extern char * caml_executable_name(void);
|
||||
|
||||
#endif /* CAML_INTERNALS */
|
||||
|
||||
|
|
|
@ -97,11 +97,11 @@ int caml_attempt_open(char **name, struct exec_trailer *trail,
|
|||
char buf [2];
|
||||
|
||||
truename = caml_search_exe_in_path(*name);
|
||||
*name = truename;
|
||||
caml_gc_message(0x100, "Opening bytecode executable %s\n",
|
||||
(uintnat) truename);
|
||||
fd = open(truename, O_RDONLY | O_BINARY);
|
||||
if (fd == -1) {
|
||||
caml_stat_free(truename);
|
||||
caml_gc_message(0x100, "Cannot open file\n", 0);
|
||||
return FILE_NOT_FOUND;
|
||||
}
|
||||
|
@ -109,6 +109,7 @@ int caml_attempt_open(char **name, struct exec_trailer *trail,
|
|||
err = read (fd, buf, 2);
|
||||
if (err < 2 || (buf [0] == '#' && buf [1] == '!')) {
|
||||
close(fd);
|
||||
caml_stat_free(truename);
|
||||
caml_gc_message(0x100, "Rejected #! script\n", 0);
|
||||
return BAD_BYTECODE;
|
||||
}
|
||||
|
@ -116,9 +117,11 @@ int caml_attempt_open(char **name, struct exec_trailer *trail,
|
|||
err = read_trailer(fd, trail);
|
||||
if (err != 0) {
|
||||
close(fd);
|
||||
caml_stat_free(truename);
|
||||
caml_gc_message(0x100, "Not a bytecode executable\n", 0);
|
||||
return err;
|
||||
}
|
||||
*name = truename;
|
||||
return fd;
|
||||
}
|
||||
|
||||
|
@ -279,8 +282,7 @@ CAMLexport void caml_main(char **argv)
|
|||
struct channel * chan;
|
||||
value res;
|
||||
char * shared_lib_path, * shared_libs, * req_prims;
|
||||
char * exe_name;
|
||||
static char proc_self_exe[256];
|
||||
char * exe_name, * proc_self_exe;
|
||||
|
||||
ensure_spacetime_dot_o_is_included++;
|
||||
|
||||
|
@ -308,12 +310,16 @@ CAMLexport void caml_main(char **argv)
|
|||
exe_name = argv[0];
|
||||
fd = caml_attempt_open(&exe_name, &trail, 0);
|
||||
|
||||
/* Should we really do that at all? The current executable is ocamlrun
|
||||
itself, it's never a bytecode program. */
|
||||
if (fd < 0
|
||||
&& caml_executable_name(proc_self_exe, sizeof(proc_self_exe)) == 0) {
|
||||
/* Little grasshopper wonders why we do that at all, since
|
||||
"The current executable is ocamlrun itself, it's never a bytecode
|
||||
program". Little grasshopper "ocamlc -custom" in mind should keep.
|
||||
With -custom, we have an executable that is ocamlrun itself
|
||||
concatenated with the bytecode. So, if the attempt with argv[0]
|
||||
failed, it is worth trying again with executable_name. */
|
||||
if (fd < 0 && (proc_self_exe = caml_executable_name()) != NULL) {
|
||||
exe_name = proc_self_exe;
|
||||
fd = caml_attempt_open(&exe_name, &trail, 0);
|
||||
caml_stat_free(proc_self_exe);
|
||||
}
|
||||
|
||||
if (fd < 0) {
|
||||
|
@ -400,7 +406,6 @@ CAMLexport void caml_startup_code(
|
|||
value res;
|
||||
char * cds_file;
|
||||
char * exe_name;
|
||||
static char proc_self_exe[256];
|
||||
|
||||
caml_init_ieee_floats();
|
||||
#if defined(_MSC_VER) && __STDC_SECURE_LIB__ >= 200411L
|
||||
|
@ -415,9 +420,8 @@ CAMLexport void caml_startup_code(
|
|||
caml_cds_file = caml_strdup(cds_file);
|
||||
}
|
||||
caml_parse_ocamlrunparam();
|
||||
exe_name = argv[0];
|
||||
if (caml_executable_name(proc_self_exe, sizeof(proc_self_exe)) == 0)
|
||||
exe_name = proc_self_exe;
|
||||
exe_name = caml_executable_name();
|
||||
if (exe_name == NULL) exe_name = caml_search_exe_in_path(argv[0]);
|
||||
caml_external_raise = NULL;
|
||||
/* Initialize the abstract machine */
|
||||
caml_init_gc (caml_init_minor_heap_wsz, caml_init_heap_wsz,
|
||||
|
@ -456,6 +460,7 @@ CAMLexport void caml_startup_code(
|
|||
caml_section_table_size = section_table_size;
|
||||
/* Initialize system libraries */
|
||||
caml_sys_init(exe_name, argv);
|
||||
caml_stat_free(exe_name);
|
||||
/* Execute the program */
|
||||
caml_debugger(PROGRAM_START);
|
||||
res = caml_interprete(caml_start_code, caml_code_size);
|
||||
|
|
|
@ -43,6 +43,9 @@
|
|||
#else
|
||||
#include <sys/dir.h>
|
||||
#endif
|
||||
#ifdef __APPLE__
|
||||
#include <mach-o/dyld.h>
|
||||
#endif
|
||||
#include "caml/fail.h"
|
||||
#include "caml/memory.h"
|
||||
#include "caml/misc.h"
|
||||
|
@ -347,28 +350,50 @@ CAMLexport int caml_read_directory(char * dirname, struct ext_table * contents)
|
|||
|
||||
/* Recover executable name from /proc/self/exe if possible */
|
||||
|
||||
#ifdef __linux__
|
||||
|
||||
int caml_executable_name(char * name, int name_len)
|
||||
char * caml_executable_name(void)
|
||||
{
|
||||
int retcode;
|
||||
#if defined(__linux__)
|
||||
int namelen, retcode;
|
||||
char * name;
|
||||
struct stat st;
|
||||
|
||||
retcode = readlink("/proc/self/exe", name, name_len);
|
||||
if (retcode == -1 || retcode >= name_len) return -1;
|
||||
/* lstat("/proc/self/exe") returns st_size == 0 so we cannot use it
|
||||
to determine the size of the buffer. Instead, we guess and adjust. */
|
||||
namelen = 256;
|
||||
while (1) {
|
||||
name = caml_stat_alloc(namelen + 1);
|
||||
retcode = readlink("/proc/self/exe", name, namelen);
|
||||
if (retcode == -1) { caml_stat_free(name); return NULL; }
|
||||
if (retcode <= namelen) break;
|
||||
caml_stat_free(name);
|
||||
if (namelen >= 1024*1024) return NULL; /* avoid runaway and overflow */
|
||||
namelen *= 2;
|
||||
}
|
||||
/* readlink() does not zero-terminate its result */
|
||||
name[retcode] = 0;
|
||||
/* Make sure that the contents of /proc/self/exe is a regular file.
|
||||
(Old Linux kernels return an inode number instead.) */
|
||||
if (stat(name, &st) != 0) return -1;
|
||||
if (! S_ISREG(st.st_mode)) return -1;
|
||||
return 0;
|
||||
}
|
||||
if (stat(name, &st) == -1 || ! S_ISREG(st.st_mode)) {
|
||||
caml_stat_free(name); return NULL;
|
||||
}
|
||||
return name;
|
||||
|
||||
#elif defined(__APPLE__)
|
||||
unsigned int namelen;
|
||||
char * name;
|
||||
|
||||
namelen = 256;
|
||||
name = caml_stat_alloc(namelen);
|
||||
if (_NSGetExecutablePath(name, &namelen) == 0) return name;
|
||||
caml_stat_free(name);
|
||||
/* Buffer is too small, but namelen now contains the size needed */
|
||||
name = caml_stat_alloc(namelen);
|
||||
if (_NSGetExecutablePath(name, &namelen) == 0) return name;
|
||||
caml_stat_free(name);
|
||||
return NULL;
|
||||
|
||||
#else
|
||||
|
||||
int caml_executable_name(char * name, int name_len)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
return NULL;
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
@ -609,13 +609,22 @@ void caml_install_invalid_parameter_handler()
|
|||
|
||||
/* Recover executable name */
|
||||
|
||||
int caml_executable_name(char * name, int name_len)
|
||||
char * caml_executable_name(void)
|
||||
{
|
||||
int retcode;
|
||||
|
||||
int ret = GetModuleFileName(NULL, name, name_len);
|
||||
if (0 == ret || ret >= name_len) return -1;
|
||||
return 0;
|
||||
char * name;
|
||||
DWORD namelen, ret;
|
||||
|
||||
namelen = 256;
|
||||
while (1) {
|
||||
name = caml_stat_alloc(namelen);
|
||||
ret = GetModuleFileName(NULL, name, namelen);
|
||||
if (ret == 0) { caml_stat_free(name); return NULL; }
|
||||
if (ret < namelen) break;
|
||||
caml_stat_free(name);
|
||||
if (namelen >= 1024*1024) return NULL; /* avoid runaway and overflow */
|
||||
namelen *= 2;
|
||||
}
|
||||
return name;
|
||||
}
|
||||
|
||||
/* snprintf emulation */
|
||||
|
|
Loading…
Reference in New Issue