Improve OS-dependent determination of file name for the current executable
In several places, the old code was limiting this file name to 256 characters at most. At least one user is bothered by this restriction. - Change API of caml_executable_name() to return a string dynamically allocated with caml_stat_alloc. - Update implementation of caml_executable_name() byterun/unix.c and byterun/win32.c to handle file names of (almost) arbitrary length. - Add special code for MacOS X, not tested yet. Fun fact of the day: under (some versions of) Linux, lstat() on "/proc/self/exe" returns 0 as length, so we can't use it to determine the size of the name in advance.master
parent
1b1f5e2470
commit
a91d6a5470
|
@ -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,11 +132,13 @@ 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);
|
||||
caml_sys_init(exe_name, argv);
|
||||
caml_stat_free(exe_name);
|
||||
if (sigsetjmp(caml_termination_jmpbuf.buf, 0)) {
|
||||
if (caml_termination_hook != NULL) caml_termination_hook(NULL);
|
||||
return;
|
||||
|
|
|
@ -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++;
|
||||
|
||||
|
@ -310,10 +312,10 @@ CAMLexport void caml_main(char **argv)
|
|||
|
||||
/* 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) {
|
||||
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 +402,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 +416,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 +456,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