2016-02-18 07:11:59 -08:00
|
|
|
/**************************************************************************/
|
|
|
|
/* */
|
|
|
|
/* OCaml */
|
|
|
|
/* */
|
|
|
|
/* Xavier Leroy, projet Cristal, INRIA Rocquencourt */
|
|
|
|
/* */
|
|
|
|
/* Copyright 2001 Institut National de Recherche en Informatique et */
|
|
|
|
/* en Automatique. */
|
|
|
|
/* */
|
|
|
|
/* All rights reserved. This file is distributed under the terms of */
|
|
|
|
/* the GNU Lesser General Public License version 2.1, with the */
|
|
|
|
/* special exception on linking described in the file LICENSE. */
|
|
|
|
/* */
|
|
|
|
/**************************************************************************/
|
2001-08-28 07:47:48 -07:00
|
|
|
|
2016-07-04 10:00:57 -07:00
|
|
|
#define CAML_INTERNALS
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
/* Unix-specific stuff */
|
|
|
|
|
2007-11-10 08:32:20 -08:00
|
|
|
#define _GNU_SOURCE
|
|
|
|
/* Helps finding RTLD_DEFAULT in glibc */
|
2017-06-23 08:32:50 -07:00
|
|
|
/* also secure_getenv */
|
2007-11-10 08:32:20 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
#include <stddef.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <sys/types.h>
|
|
|
|
#include <sys/stat.h>
|
2015-11-30 02:42:16 -08:00
|
|
|
#include <errno.h>
|
2017-11-26 06:49:31 -08:00
|
|
|
#include <sys/ioctl.h>
|
2001-08-28 07:47:48 -07:00
|
|
|
#include <fcntl.h>
|
2014-12-27 06:41:49 -08:00
|
|
|
#include "caml/config.h"
|
2001-08-28 07:47:48 -07:00
|
|
|
#ifdef SUPPORT_DYNAMIC_LINKING
|
2015-07-17 07:31:05 -07:00
|
|
|
#ifdef __CYGWIN__
|
2007-11-06 07:16:56 -08:00
|
|
|
#include "flexdll.h"
|
2003-01-09 00:42:13 -08:00
|
|
|
#else
|
2001-08-28 07:47:48 -07:00
|
|
|
#include <dlfcn.h>
|
|
|
|
#endif
|
2003-01-09 00:42:13 -08:00
|
|
|
#endif
|
2002-04-26 06:33:25 -07:00
|
|
|
#ifdef HAS_UNISTD
|
|
|
|
#include <unistd.h>
|
|
|
|
#endif
|
2003-03-03 09:16:15 -08:00
|
|
|
#ifdef HAS_DIRENT
|
|
|
|
#include <dirent.h>
|
|
|
|
#else
|
|
|
|
#include <sys/dir.h>
|
|
|
|
#endif
|
2016-09-04 23:49:25 -07:00
|
|
|
#ifdef __APPLE__
|
|
|
|
#include <mach-o/dyld.h>
|
|
|
|
#endif
|
2015-12-04 03:01:10 -08:00
|
|
|
#include "caml/fail.h"
|
2014-12-27 06:41:49 -08:00
|
|
|
#include "caml/memory.h"
|
|
|
|
#include "caml/misc.h"
|
|
|
|
#include "caml/osdeps.h"
|
2015-12-04 03:01:10 -08:00
|
|
|
#include "caml/signals.h"
|
|
|
|
#include "caml/sys.h"
|
2016-10-04 05:22:03 -07:00
|
|
|
#include "caml/io.h"
|
Unicode support for the Windows runtime (#1200)
* Add support code
* Explicitly reference ANSI Windows APIs
* Adapt Sys.is_directory
* Adapt ocamlrun
* Add Changes entry
* Add testsuite
* Adapt Unix.open_process{_in,_out,_full,}, Unix.create_process{_env,}
* Adapt headernt.c
* Adapt Pervasives.open_{in,out}, Filename.temp_file, etc.
* Adapt Sys.file_exists
* Adapt Sys.remove
* Adapt Sys.chdir
* Adapt Sys.getcwd
* Adapt Sys.getenv
* Adapt Sys.command
* Adapt Sys.readdir
* Adapt CPLUGINS
* Remove use of FormatMessageA, CreateFileA
* Adapt Unix.mkdir
* Adapt Unix.openfile
* Adapt Unix.readlink
* Adapt Unix.rename
* Adapt Unix.{LargeFile,}.{l,}stat
* Adapt Unix.system
* Adapt Unix.{open,read}dir
* Adapt Unix.link
* Adapt Unix.symlink
* Adapt Unix.getcwd
* Adapt Unix.rmdir
* Adapt Unix.utimes
* Adapt Unix.unlink
* Adapt Unix.chdir
* Adapt Unix.chmod
* Adapt Unix.{execv,execve,execvp,execvpe}
* Compile with -DUNICODE -D_UNICODE under Windows
* Add configure-time switch, Config.windows_unicode
* Adapt Unix.putenv
* Re-implement Unix.environment using GetEnvironmentStrings()
* Use Unicode-aware flexdll
* Adapt Unix.environment
* AppVeyor: bootstrap flexdll
* Adapt tests/embedded/cmmain.c
* Adapt tests/lib-dynlink-csharp/entry.c
* Remove exec tests
* Fixup
* Pass -municode to MinGW compiler
* Try to fix tests/embedded
* Adapt Sys.rename
* Correct Changes entry
* Makefile.several: use $(O) and $(NATIVECODE_ONLY)
* Display => skipped correctly for tests/win-unicode
* Add missing casts to execv* calls
It's not clear why these aren't necessary for with char, but they are
necessary with wchar_t on GCC (but not MSVC).
* Missing header in systhreads (Win32 only)
* Revert "Pass -municode to MinGW compiler"
This reverts commit a4ce7fb319c429068a5b9d1ab14a2cc3969c355f.
* Revert "Try to fix tests/embedded"
This reverts commit 5197d8922295b7b339b970ec3189374aa15de4b8.
* Revert "Remove exec tests"
This reverts commit 306ccef2e79eca5b38ecfa285b912c7bcf3e9f52.
* Don't pass $(LDFLAGS) when build ocamlc.opt
It's already included via CC anyway, and it causes Unicode problems for
Winodws (because the linker options need to be prefixed "-link" to go via
flexlink).
* Use wmain on Windows for ocamlrun
* Build Unicode applications on Windows
* Use wmain in headernt.c
* Minor correction to win-unicode Makefile
* Switch submodule to FlexDLL 0.36
* Build ocamlyacc as an ANSI application
* Revert "Fixup"
This reverts commit 500bd6b575ffd6c5b71c6953e55d740f0b090185.
* Fix casts for execvp/execve
* Remove tabs from test code
* Fix Changes entry
* shell32.lib is no longer necessary
* Free allocated string
* Changes: signal breaking change
* Disable exec_tests
* Protect with CAML_INTERNALS
2017-09-18 08:41:29 -07:00
|
|
|
#include "caml/alloc.h"
|
2001-08-28 07:47:48 -07:00
|
|
|
|
|
|
|
#ifndef S_ISREG
|
|
|
|
#define S_ISREG(mode) (((mode) & S_IFMT) == S_IFREG)
|
|
|
|
#endif
|
|
|
|
|
2015-12-04 02:40:11 -08:00
|
|
|
#ifndef EINTR
|
|
|
|
#define EINTR (-1)
|
|
|
|
#endif
|
|
|
|
#ifndef EAGAIN
|
|
|
|
#define EAGAIN (-1)
|
|
|
|
#endif
|
|
|
|
#ifndef EWOULDBLOCK
|
|
|
|
#define EWOULDBLOCK (-1)
|
|
|
|
#endif
|
|
|
|
|
|
|
|
int caml_read_fd(int fd, int flags, void * buf, int n)
|
2015-11-30 02:42:16 -08:00
|
|
|
{
|
|
|
|
int retcode;
|
2020-06-24 09:16:21 -07:00
|
|
|
caml_enter_blocking_section_no_pending();
|
|
|
|
retcode = read(fd, buf, n);
|
|
|
|
caml_leave_blocking_section();
|
|
|
|
if (retcode == -1) {
|
|
|
|
if (errno == EINTR) return Io_interrupted;
|
|
|
|
else caml_sys_io_error(NO_ARG);
|
|
|
|
}
|
2015-11-30 02:42:16 -08:00
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2015-12-04 02:40:11 -08:00
|
|
|
int caml_write_fd(int fd, int flags, void * buf, int n)
|
2015-11-30 02:42:16 -08:00
|
|
|
{
|
|
|
|
int retcode;
|
|
|
|
again:
|
2020-06-24 09:16:21 -07:00
|
|
|
caml_enter_blocking_section_no_pending();
|
2015-11-30 02:42:16 -08:00
|
|
|
retcode = write(fd, buf, n);
|
2015-12-04 02:40:11 -08:00
|
|
|
caml_leave_blocking_section();
|
2015-11-30 02:42:16 -08:00
|
|
|
if (retcode == -1) {
|
2020-06-24 09:16:21 -07:00
|
|
|
if (errno == EINTR) return Io_interrupted;
|
2015-11-30 02:42:16 -08:00
|
|
|
if ((errno == EAGAIN || errno == EWOULDBLOCK) && n > 1) {
|
|
|
|
/* We couldn't do a partial write here, probably because
|
|
|
|
n <= PIPE_BUF and POSIX says that writes of less than
|
|
|
|
PIPE_BUF characters must be atomic.
|
|
|
|
We first try again with a partial write of 1 character.
|
|
|
|
If that fails too, we'll return an error code. */
|
|
|
|
n = 1; goto again;
|
|
|
|
}
|
|
|
|
}
|
2015-12-04 02:40:11 -08:00
|
|
|
if (retcode == -1) caml_sys_io_error(NO_ARG);
|
|
|
|
CAMLassert (retcode > 0);
|
2015-11-30 02:42:16 -08:00
|
|
|
return retcode;
|
|
|
|
}
|
|
|
|
|
2016-01-05 10:10:21 -08:00
|
|
|
caml_stat_string caml_decompose_path(struct ext_table * tbl, char * path)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
char * p, * q;
|
2014-04-15 10:09:13 -07:00
|
|
|
size_t n;
|
2001-08-28 07:47:48 -07:00
|
|
|
|
|
|
|
if (path == NULL) return NULL;
|
2016-01-05 09:39:12 -08:00
|
|
|
p = caml_stat_strdup(path);
|
2001-08-28 07:47:48 -07:00
|
|
|
q = p;
|
|
|
|
while (1) {
|
|
|
|
for (n = 0; q[n] != 0 && q[n] != ':'; n++) /*nothing*/;
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_ext_table_add(tbl, q);
|
2001-08-28 07:47:48 -07:00
|
|
|
q = q + n;
|
|
|
|
if (*q == 0) break;
|
|
|
|
*q = 0;
|
|
|
|
q += 1;
|
|
|
|
}
|
|
|
|
return p;
|
|
|
|
}
|
|
|
|
|
2017-08-03 06:19:13 -07:00
|
|
|
caml_stat_string caml_search_in_path(struct ext_table * path, const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2017-08-03 06:19:13 -07:00
|
|
|
const char * p;
|
|
|
|
char * dir, * fullname;
|
2001-08-28 07:47:48 -07:00
|
|
|
int i;
|
|
|
|
struct stat st;
|
|
|
|
|
|
|
|
for (p = name; *p != 0; p++) {
|
|
|
|
if (*p == '/') goto not_found;
|
|
|
|
}
|
|
|
|
for (i = 0; i < path->size; i++) {
|
2014-04-15 10:09:13 -07:00
|
|
|
dir = path->contents[i];
|
|
|
|
if (dir[0] == 0) dir = "."; /* empty path component = current dir */
|
2016-01-05 09:39:12 -08:00
|
|
|
fullname = caml_stat_strconcat(3, dir, "/", name);
|
2014-04-15 10:09:13 -07:00
|
|
|
if (stat(fullname, &st) == 0 && S_ISREG(st.st_mode))
|
|
|
|
return fullname;
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(fullname);
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
not_found:
|
2016-01-05 09:39:12 -08:00
|
|
|
return caml_stat_strdup(name);
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
|
2015-07-17 07:31:05 -07:00
|
|
|
#ifdef __CYGWIN__
|
2001-08-28 07:47:48 -07:00
|
|
|
|
|
|
|
/* Cygwin needs special treatment because of the implicit ".exe" at the
|
|
|
|
end of executable file names */
|
|
|
|
|
2017-08-11 03:13:00 -07:00
|
|
|
static int cygwin_file_exists(const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2017-10-19 04:46:58 -07:00
|
|
|
int fd, ret;
|
|
|
|
struct stat st;
|
2001-08-28 07:47:48 -07:00
|
|
|
/* Cannot use stat() here because it adds ".exe" implicitly */
|
|
|
|
fd = open(name, O_RDONLY);
|
|
|
|
if (fd == -1) return 0;
|
2017-10-19 04:46:58 -07:00
|
|
|
ret = fstat(fd, &st);
|
2001-08-28 07:47:48 -07:00
|
|
|
close(fd);
|
2017-10-19 04:46:58 -07:00
|
|
|
return ret == 0 && S_ISREG(st.st_mode);
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
|
2017-08-12 13:24:41 -07:00
|
|
|
static caml_stat_string cygwin_search_exe_in_path(struct ext_table * path,
|
|
|
|
const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2017-08-11 03:13:00 -07:00
|
|
|
const char * p;
|
|
|
|
char * dir, * fullname;
|
2001-08-28 07:47:48 -07:00
|
|
|
int i;
|
|
|
|
|
|
|
|
for (p = name; *p != 0; p++) {
|
|
|
|
if (*p == '/' || *p == '\\') goto not_found;
|
|
|
|
}
|
|
|
|
for (i = 0; i < path->size; i++) {
|
2014-04-15 10:09:13 -07:00
|
|
|
dir = path->contents[i];
|
|
|
|
if (dir[0] == 0) dir = "."; /* empty path component = current dir */
|
2016-01-05 09:39:12 -08:00
|
|
|
fullname = caml_stat_strconcat(3, dir, "/", name);
|
2001-08-28 07:47:48 -07:00
|
|
|
if (cygwin_file_exists(fullname)) return fullname;
|
2014-04-15 10:09:13 -07:00
|
|
|
caml_stat_free(fullname);
|
2016-01-05 09:39:12 -08:00
|
|
|
fullname = caml_stat_strconcat(4, dir, "/", name, ".exe");
|
2001-08-28 07:47:48 -07:00
|
|
|
if (cygwin_file_exists(fullname)) return fullname;
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(fullname);
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
not_found:
|
2016-01-05 09:39:12 -08:00
|
|
|
if (cygwin_file_exists(name)) return caml_stat_strdup(name);
|
|
|
|
fullname = caml_stat_strconcat(2, name, ".exe");
|
2001-08-28 07:47:48 -07:00
|
|
|
if (cygwin_file_exists(fullname)) return fullname;
|
2014-04-15 10:09:13 -07:00
|
|
|
caml_stat_free(fullname);
|
2016-01-05 09:39:12 -08:00
|
|
|
return caml_stat_strdup(name);
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
2008-12-03 10:09:09 -08:00
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
#endif
|
|
|
|
|
2017-08-03 06:19:13 -07:00
|
|
|
caml_stat_string caml_search_exe_in_path(const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
struct ext_table path;
|
|
|
|
char * tofree;
|
2016-01-05 10:10:21 -08:00
|
|
|
caml_stat_string res;
|
2001-08-28 07:47:48 -07:00
|
|
|
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_ext_table_init(&path, 8);
|
2004-01-01 08:42:43 -08:00
|
|
|
tofree = caml_decompose_path(&path, getenv("PATH"));
|
2015-07-17 07:31:05 -07:00
|
|
|
#ifndef __CYGWIN__
|
2004-01-01 08:42:43 -08:00
|
|
|
res = caml_search_in_path(&path, name);
|
2001-08-28 07:47:48 -07:00
|
|
|
#else
|
|
|
|
res = cygwin_search_exe_in_path(&path, name);
|
|
|
|
#endif
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(tofree);
|
2003-12-29 14:15:02 -08:00
|
|
|
caml_ext_table_free(&path, 0);
|
2001-08-28 07:47:48 -07:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
2017-08-12 13:24:41 -07:00
|
|
|
caml_stat_string caml_search_dll_in_path(struct ext_table * path,
|
|
|
|
const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2016-01-05 10:10:21 -08:00
|
|
|
caml_stat_string dllname;
|
|
|
|
caml_stat_string res;
|
2014-04-15 10:09:13 -07:00
|
|
|
|
2016-01-05 09:39:12 -08:00
|
|
|
dllname = caml_stat_strconcat(2, name, ".so");
|
2004-01-01 08:42:43 -08:00
|
|
|
res = caml_search_in_path(path, dllname);
|
2003-12-31 06:20:40 -08:00
|
|
|
caml_stat_free(dllname);
|
2001-08-28 07:47:48 -07:00
|
|
|
return res;
|
|
|
|
}
|
|
|
|
|
|
|
|
#ifdef SUPPORT_DYNAMIC_LINKING
|
2015-07-17 07:31:05 -07:00
|
|
|
#ifdef __CYGWIN__
|
2007-11-06 07:16:56 -08:00
|
|
|
/* Use flexdll */
|
|
|
|
|
2008-04-22 05:24:10 -07:00
|
|
|
void * caml_dlopen(char * libname, int for_execution, int global)
|
2007-11-06 07:16:56 -08:00
|
|
|
{
|
2008-04-22 05:24:10 -07:00
|
|
|
int flags = (global ? FLEXDLL_RTLD_GLOBAL : 0);
|
2007-11-06 07:16:56 -08:00
|
|
|
if (!for_execution) flags |= FLEXDLL_RTLD_NOEXEC;
|
|
|
|
return flexdll_dlopen(libname, flags);
|
|
|
|
}
|
|
|
|
|
|
|
|
void caml_dlclose(void * handle)
|
|
|
|
{
|
|
|
|
flexdll_dlclose(handle);
|
|
|
|
}
|
|
|
|
|
2017-08-03 06:19:13 -07:00
|
|
|
void * caml_dlsym(void * handle, const char * name)
|
2007-11-06 07:16:56 -08:00
|
|
|
{
|
|
|
|
return flexdll_dlsym(handle, name);
|
|
|
|
}
|
|
|
|
|
2017-08-11 03:13:00 -07:00
|
|
|
void * caml_globalsym(const char * name)
|
2007-11-06 07:16:56 -08:00
|
|
|
{
|
2008-12-03 04:56:59 -08:00
|
|
|
return flexdll_dlsym(flexdll_dlopen(NULL,0), name);
|
2007-11-06 07:16:56 -08:00
|
|
|
}
|
|
|
|
|
|
|
|
char * caml_dlerror(void)
|
|
|
|
{
|
|
|
|
return flexdll_dlerror();
|
|
|
|
}
|
|
|
|
|
2003-01-09 00:42:13 -08:00
|
|
|
#else
|
|
|
|
/* Use normal dlopen */
|
2001-08-28 07:47:48 -07:00
|
|
|
|
2001-09-09 01:35:55 -07:00
|
|
|
#ifndef RTLD_GLOBAL
|
|
|
|
#define RTLD_GLOBAL 0
|
|
|
|
#endif
|
2010-08-02 07:37:22 -07:00
|
|
|
#ifndef RTLD_LOCAL
|
|
|
|
#define RTLD_LOCAL 0
|
|
|
|
#endif
|
2001-09-09 01:35:55 -07:00
|
|
|
|
2008-04-22 05:24:10 -07:00
|
|
|
void * caml_dlopen(char * libname, int for_execution, int global)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
2014-05-30 17:33:48 -07:00
|
|
|
return dlopen(libname, RTLD_NOW | (global ? RTLD_GLOBAL : RTLD_LOCAL));
|
2006-09-29 01:18:22 -07:00
|
|
|
/* Could use RTLD_LAZY if for_execution == 0, but needs testing */
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
|
|
|
|
void caml_dlclose(void * handle)
|
|
|
|
{
|
|
|
|
dlclose(handle);
|
|
|
|
}
|
|
|
|
|
2017-08-03 06:19:13 -07:00
|
|
|
void * caml_dlsym(void * handle, const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
return dlsym(handle, name);
|
|
|
|
}
|
|
|
|
|
2017-08-03 06:19:13 -07:00
|
|
|
void * caml_globalsym(const char * name)
|
2007-11-06 07:16:56 -08:00
|
|
|
{
|
2007-11-10 08:32:20 -08:00
|
|
|
#ifdef RTLD_DEFAULT
|
2007-11-08 02:55:57 -08:00
|
|
|
return caml_dlsym(RTLD_DEFAULT, name);
|
2007-11-10 08:32:20 -08:00
|
|
|
#else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
2007-11-06 07:16:56 -08:00
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
char * caml_dlerror(void)
|
|
|
|
{
|
2007-11-08 02:55:57 -08:00
|
|
|
return (char*) dlerror();
|
2001-08-28 07:47:48 -07:00
|
|
|
}
|
|
|
|
|
2003-01-09 00:42:13 -08:00
|
|
|
#endif
|
2001-08-28 07:47:48 -07:00
|
|
|
#else
|
|
|
|
|
2008-04-22 05:24:10 -07:00
|
|
|
void * caml_dlopen(char * libname, int for_execution, int global)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
void caml_dlclose(void * handle)
|
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2017-09-06 03:13:14 -07:00
|
|
|
void * caml_dlsym(void * handle, const char * name)
|
2001-08-28 07:47:48 -07:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2017-09-06 03:13:14 -07:00
|
|
|
void * caml_globalsym(const char * name)
|
2007-11-06 07:16:56 -08:00
|
|
|
{
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2001-08-28 07:47:48 -07:00
|
|
|
char * caml_dlerror(void)
|
|
|
|
{
|
|
|
|
return "dynamic loading not supported on this platform";
|
|
|
|
}
|
|
|
|
|
|
|
|
#endif
|
|
|
|
|
2003-03-03 09:16:15 -08:00
|
|
|
/* Add to [contents] the (short) names of the files contained in
|
|
|
|
the directory named [dirname]. No entries are added for [.] and [..].
|
|
|
|
Return 0 on success, -1 on error; set errno in the case of error. */
|
|
|
|
|
2016-07-06 07:37:56 -07:00
|
|
|
CAMLexport int caml_read_directory(char * dirname, struct ext_table * contents)
|
2003-03-03 09:16:15 -08:00
|
|
|
{
|
|
|
|
DIR * d;
|
|
|
|
#ifdef HAS_DIRENT
|
|
|
|
struct dirent * e;
|
|
|
|
#else
|
|
|
|
struct direct * e;
|
|
|
|
#endif
|
|
|
|
|
|
|
|
d = opendir(dirname);
|
|
|
|
if (d == NULL) return -1;
|
|
|
|
while (1) {
|
|
|
|
e = readdir(d);
|
|
|
|
if (e == NULL) break;
|
|
|
|
if (strcmp(e->d_name, ".") == 0 || strcmp(e->d_name, "..") == 0) continue;
|
2016-01-05 09:39:12 -08:00
|
|
|
caml_ext_table_add(contents, caml_stat_strdup(e->d_name));
|
2003-03-03 09:16:15 -08:00
|
|
|
}
|
|
|
|
closedir(d);
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
2002-09-03 06:56:36 -07:00
|
|
|
/* Recover executable name from /proc/self/exe if possible */
|
|
|
|
|
2016-09-04 23:49:25 -07:00
|
|
|
char * caml_executable_name(void)
|
2002-09-03 06:56:36 -07:00
|
|
|
{
|
2016-09-04 23:49:25 -07:00
|
|
|
#if defined(__linux__)
|
|
|
|
int namelen, retcode;
|
|
|
|
char * name;
|
2002-09-03 06:56:36 -07:00
|
|
|
struct stat st;
|
|
|
|
|
2016-09-04 23:49:25 -07:00
|
|
|
/* 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) {
|
2017-08-25 09:24:01 -07:00
|
|
|
name = caml_stat_alloc(namelen);
|
2016-09-04 23:49:25 -07:00
|
|
|
retcode = readlink("/proc/self/exe", name, namelen);
|
|
|
|
if (retcode == -1) { caml_stat_free(name); return NULL; }
|
2017-08-25 08:56:45 -07:00
|
|
|
if (retcode < namelen) break;
|
2016-09-04 23:49:25 -07:00
|
|
|
caml_stat_free(name);
|
|
|
|
if (namelen >= 1024*1024) return NULL; /* avoid runaway and overflow */
|
|
|
|
namelen *= 2;
|
|
|
|
}
|
2017-08-25 09:24:01 -07:00
|
|
|
/* readlink() does not zero-terminate its result.
|
|
|
|
There is room for a final zero since retcode < namelen. */
|
2002-09-03 06:56:36 -07:00
|
|
|
name[retcode] = 0;
|
|
|
|
/* Make sure that the contents of /proc/self/exe is a regular file.
|
|
|
|
(Old Linux kernels return an inode number instead.) */
|
2016-09-04 23:49:25 -07:00
|
|
|
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;
|
Unicode support for the Windows runtime (#1200)
* Add support code
* Explicitly reference ANSI Windows APIs
* Adapt Sys.is_directory
* Adapt ocamlrun
* Add Changes entry
* Add testsuite
* Adapt Unix.open_process{_in,_out,_full,}, Unix.create_process{_env,}
* Adapt headernt.c
* Adapt Pervasives.open_{in,out}, Filename.temp_file, etc.
* Adapt Sys.file_exists
* Adapt Sys.remove
* Adapt Sys.chdir
* Adapt Sys.getcwd
* Adapt Sys.getenv
* Adapt Sys.command
* Adapt Sys.readdir
* Adapt CPLUGINS
* Remove use of FormatMessageA, CreateFileA
* Adapt Unix.mkdir
* Adapt Unix.openfile
* Adapt Unix.readlink
* Adapt Unix.rename
* Adapt Unix.{LargeFile,}.{l,}stat
* Adapt Unix.system
* Adapt Unix.{open,read}dir
* Adapt Unix.link
* Adapt Unix.symlink
* Adapt Unix.getcwd
* Adapt Unix.rmdir
* Adapt Unix.utimes
* Adapt Unix.unlink
* Adapt Unix.chdir
* Adapt Unix.chmod
* Adapt Unix.{execv,execve,execvp,execvpe}
* Compile with -DUNICODE -D_UNICODE under Windows
* Add configure-time switch, Config.windows_unicode
* Adapt Unix.putenv
* Re-implement Unix.environment using GetEnvironmentStrings()
* Use Unicode-aware flexdll
* Adapt Unix.environment
* AppVeyor: bootstrap flexdll
* Adapt tests/embedded/cmmain.c
* Adapt tests/lib-dynlink-csharp/entry.c
* Remove exec tests
* Fixup
* Pass -municode to MinGW compiler
* Try to fix tests/embedded
* Adapt Sys.rename
* Correct Changes entry
* Makefile.several: use $(O) and $(NATIVECODE_ONLY)
* Display => skipped correctly for tests/win-unicode
* Add missing casts to execv* calls
It's not clear why these aren't necessary for with char, but they are
necessary with wchar_t on GCC (but not MSVC).
* Missing header in systhreads (Win32 only)
* Revert "Pass -municode to MinGW compiler"
This reverts commit a4ce7fb319c429068a5b9d1ab14a2cc3969c355f.
* Revert "Try to fix tests/embedded"
This reverts commit 5197d8922295b7b339b970ec3189374aa15de4b8.
* Revert "Remove exec tests"
This reverts commit 306ccef2e79eca5b38ecfa285b912c7bcf3e9f52.
* Don't pass $(LDFLAGS) when build ocamlc.opt
It's already included via CC anyway, and it causes Unicode problems for
Winodws (because the linker options need to be prefixed "-link" to go via
flexlink).
* Use wmain on Windows for ocamlrun
* Build Unicode applications on Windows
* Use wmain in headernt.c
* Minor correction to win-unicode Makefile
* Switch submodule to FlexDLL 0.36
* Build ocamlyacc as an ANSI application
* Revert "Fixup"
This reverts commit 500bd6b575ffd6c5b71c6953e55d740f0b090185.
* Fix casts for execvp/execve
* Remove tabs from test code
* Fix Changes entry
* shell32.lib is no longer necessary
* Free allocated string
* Changes: signal breaking change
* Disable exec_tests
* Protect with CAML_INTERNALS
2017-09-18 08:41:29 -07:00
|
|
|
|
2013-06-18 03:25:01 -07:00
|
|
|
#else
|
2016-09-04 23:49:25 -07:00
|
|
|
return NULL;
|
2013-06-18 03:25:01 -07:00
|
|
|
|
2002-09-03 06:56:36 -07:00
|
|
|
#endif
|
2016-09-04 23:49:25 -07:00
|
|
|
}
|
2017-06-23 08:32:50 -07:00
|
|
|
|
|
|
|
char *caml_secure_getenv (char const *var)
|
|
|
|
{
|
|
|
|
#ifdef HAS_SECURE_GETENV
|
|
|
|
return secure_getenv (var);
|
2017-06-28 05:02:15 -07:00
|
|
|
#elif defined (HAS___SECURE_GETENV)
|
|
|
|
return __secure_getenv (var);
|
2017-06-23 08:32:50 -07:00
|
|
|
#elif defined(HAS_ISSETUGID)
|
|
|
|
if (!issetugid ())
|
2018-07-03 10:22:51 -07:00
|
|
|
return getenv(var);
|
2017-06-23 08:32:50 -07:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
#else
|
|
|
|
if (geteuid () == getuid () && getegid () == getgid ())
|
2018-07-03 10:22:51 -07:00
|
|
|
return getenv(var);
|
2017-06-23 08:32:50 -07:00
|
|
|
else
|
|
|
|
return NULL;
|
|
|
|
#endif
|
|
|
|
}
|
2017-11-26 06:49:31 -08:00
|
|
|
|
|
|
|
int caml_num_rows_fd(int fd)
|
|
|
|
{
|
|
|
|
#ifdef TIOCGWINSZ
|
|
|
|
struct winsize w;
|
|
|
|
w.ws_row = -1;
|
|
|
|
if (ioctl(fd, TIOCGWINSZ, &w) == 0)
|
|
|
|
return w.ws_row;
|
|
|
|
else
|
|
|
|
return -1;
|
|
|
|
#else
|
|
|
|
return -1;
|
|
|
|
#endif
|
|
|
|
}
|