aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/common
diff options
context:
space:
mode:
Diffstat (limited to 'erts/etc/common')
-rw-r--r--erts/etc/common/Makefile.in141
-rw-r--r--erts/etc/common/ct_run.c82
-rw-r--r--erts/etc/common/dialyzer.c104
-rw-r--r--erts/etc/common/erlc.c384
-rw-r--r--erts/etc/common/erlexec.c95
-rw-r--r--erts/etc/common/escript.c247
-rw-r--r--erts/etc/common/heart.c117
-rw-r--r--erts/etc/common/inet_gethost.c2
-rw-r--r--erts/etc/common/run_erl_common.c686
-rw-r--r--erts/etc/common/run_erl_common.h96
-rw-r--r--erts/etc/common/run_erl_vsn.h29
-rw-r--r--erts/etc/common/safe_string.c122
-rw-r--r--erts/etc/common/safe_string.h64
-rw-r--r--erts/etc/common/to_erl_common.c716
-rw-r--r--erts/etc/common/to_erl_common.h28
-rw-r--r--erts/etc/common/typer.c97
16 files changed, 2413 insertions, 597 deletions
diff --git a/erts/etc/common/Makefile.in b/erts/etc/common/Makefile.in
index 5c1ce51644..0cf965f915 100644
--- a/erts/etc/common/Makefile.in
+++ b/erts/etc/common/Makefile.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -20,6 +20,10 @@
include $(ERL_TOP)/make/output.mk
include $(ERL_TOP)/make/target.mk
+ifeq ($(findstring ose,$(TARGET)),ose)
+include $(ERL_TOP)/make/$(TARGET)/ose_lm.mk
+endif
+
ERTS_LIB_TYPEMARKER=.$(TYPE)
USING_MINGW=@MIXED_CYGWIN_MINGW@
@@ -62,7 +66,9 @@ LIBS = @LIBS@
LDFLAGS = @LDFLAGS@
# For clock_gettime in heart
+ifneq ($(TARGET),arm-unknown-linux-androideabi)
RTLIBS = @LIBRT@
+endif
ifeq ($(TARGET),win32)
ifeq ($(TYPE),debug)
@@ -82,6 +88,16 @@ OSEETC = ../ose
WINETC = ../win32
ifeq ($(TARGET), win32)
+ETC = $(WINETC)
+else
+ifeq ($(findstring ose,$(TARGET)),ose)
+ETC = $(OSEETC)
+else
+ETC = $(UXETC)
+endif
+endif
+
+ifeq ($(TARGET), win32)
ERLEXEC = erlexec.dll
else
ERLEXEC = erlexec
@@ -147,7 +163,8 @@ INSTALL_TOP_BIN = $(BINDIR)/Install.exe
INSTALL_PROGS = \
$(INET_GETHOST) \
$(BINDIR)/heart.exe $(BINDIR)/erlsrv.exe \
- $(BINDIR)/erl.exe $(BINDIR)/werl.exe \
+ $(BINDIR)/erl.exe $(BINDIR)/erl_log.exe \
+ $(BINDIR)/werl.exe \
$(BINDIR)/$(ERLEXEC) \
$(INSTALL_EMBEDDED_PROGS)
@@ -161,7 +178,26 @@ endif
PORT_ENTRY_POINT=erl_port_entry
ENTRY_LDFLAGS=-entry:$(PORT_ENTRY_POINT)
-else # UNIX (!win32)
+else
+ifeq ($(findstring ose,$(TARGET)),ose)
+ENTRY_LDFLAGS=
+ENTRY_OBJ=
+ERLSRV_OBJECTS=
+MC_OUTPUTS=
+INET_GETHOST =
+INSTALL_EMBEDDED_PROGS = $(BINDIR)/run_erl_lm
+INSTALL_EMBEDDED_DATA =
+INSTALL_TOP = Install
+INSTALL_TOP_BIN =
+INSTALL_MISC =
+INSTALL_SRC =
+ERLEXECDIR = .
+INSTALL_LIBS =
+INSTALL_OBJS =
+INSTALL_INCLUDES =
+TEXTFILES = Install erl.src
+INSTALL_PROGS = $(INSTALL_EMBEDDED_PROGS)
+else # UNIX (!win32 && !ose)
ENTRY_LDFLAGS=
ENTRY_OBJ=
ERLSRV_OBJECTS=
@@ -170,11 +206,11 @@ INET_GETHOST = $(BINDIR)/inet_gethost@EXEEXT@
INSTALL_EMBEDDED_PROGS += $(BINDIR)/typer@EXEEXT@ $(BINDIR)/dialyzer@EXEEXT@ \
$(BINDIR)/erlc@EXEEXT@ $(BINDIR)/escript@EXEEXT@ $(BINDIR)/ct_run@EXEEXT@ \
$(BINDIR)/run_erl $(BINDIR)/to_erl $(BINDIR)/dyn_erl
-INSTALL_EMBEDDED_DATA = ../unix/start.src ../unix/start_erl.src
+INSTALL_EMBEDDED_DATA = $(UXETC)/start.src $(UXETC)/start_erl.src
INSTALL_TOP = Install
INSTALL_TOP_BIN =
-INSTALL_MISC = ../unix/format_man_pages ../unix/makewhatis
-INSTALL_SRC = ../unix/setuid_socket_wrap.c #delivered as an example
+INSTALL_MISC = $(UXETC)/format_man_pages $(UXETC)/makewhatis
+INSTALL_SRC = $(UXETC)/setuid_socket_wrap.c #delivered as an example
ERLEXECDIR = .
INSTALL_LIBS =
INSTALL_OBJS =
@@ -186,6 +222,7 @@ INSTALL_PROGS = \
$(BINDIR)/$(ERLEXEC) \
$(INSTALL_EMBEDDED_PROGS)
endif
+endif
.PHONY: etc
etc: $(ENTRY_OBJ) $(INSTALL_PROGS) $(INSTALL_LIBS) $(TEXTFILES) $(INSTALL_TOP_BIN)
@@ -230,11 +267,14 @@ endif
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/run_erl.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/to_erl.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/dyn_erl.o
- rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/safe_string.o
+ rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/safe_string.o
+ rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/run_erl_common.o
+ rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/to_erl_common.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/typer.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/ct_run.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/vxcall.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl.o
+ rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/erl_log.o
rm -f $(ERL_TOP)/erts/obj*/$(TARGET)/werl.o
rm -f $(TEXTFILES)
rm -f *~ core
@@ -258,6 +298,9 @@ $(BINDIR)/erl@EXEEXT@: $(OBJDIR)/erl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_
$(BINDIR)/werl@EXEEXT@: $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
$(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/werl.o $(OBJDIR)/init_file.o $(OBJDIR)/$(ERLRES_OBJ)
+$(BINDIR)/erl_log@EXEEXT@: $(OBJDIR)/erl_log.o
+ $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/erl_log.o
+
$(BINDIR)/start_erl@EXEEXT@: $(OBJDIR)/start_erl.o
$(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/start_erl.o
@@ -311,6 +354,10 @@ $(OBJDIR)/werl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED)
$(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-DWIN32_WERL -o $@ -c $(WINETC)/erl.c
+$(OBJDIR)/erl_log.o: $(WINETC)/erl_log.c $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
+ -o $@ -c $(WINETC)/erl_log.c
+
$(OBJDIR)/erl.o: $(WINETC)/erl.c $(WINETC)/init_file.h $(RC_GENERATED)
$(V_CC) $(CFLAGS) -DBUILD_TYPE=\"-$(TYPE)\" -DERL_RUN_SHARED_LIB=1 \
-o $@ -c $(WINETC)/erl.c
@@ -370,29 +417,33 @@ $(OBJDIR)/heart.o: heart.c $(RC_GENERATED)
$(OBJDIR)/inet_gethost.o: inet_gethost.c $(RC_GENERATED)
$(V_CC) $(CFLAGS) -o $@ -c inet_gethost.c
+# inet_gethost
$(BINDIR)/inet_gethost@EXEEXT@: $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(ERTS_LIB)
$(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) $(ENTRY_LDFLAGS) -o $@ $(OBJDIR)/inet_gethost.o $(ENTRY_OBJ) $(LIBS) $(ERTS_INTERNAL_LIBS)
-$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o
- $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(LIBS)
-
-$(OBJDIR)/run_erl.o: ../unix/run_erl.c $(RC_GENERATED)
- $(V_CC) $(CFLAGS) -o $@ -c ../unix/run_erl.c
-
-$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
- $(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o
-
-$(OBJDIR)/to_erl.o: ../unix/to_erl.c $(RC_GENERATED)
- $(V_CC) $(CFLAGS) -o $@ -c ../unix/to_erl.c
-
+# run_erl
+$(BINDIR)/run_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(OBJDIR)/run_erl_common.o
+ $(V_LD) $(LDFLAGS) -o $@ $^ $(LIBS)
+$(OBJDIR)/run_erl.o: $(ETC)/run_erl.c ../common/run_erl_common.h $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -I ../common/ -o $@ -c $(ETC)/run_erl.c
+$(OBJDIR)/run_erl_common.o: ../common/run_erl_common.c ../common/run_erl_common.h $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -o $@ -c $<
+
+# to_erl
+$(BINDIR)/to_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/to_erl.o $(OBJDIR)/to_erl_common.o
+ $(V_LD) $(LDFLAGS) -o $@ $^
+$(OBJDIR)/to_erl.o: $(ETC)/to_erl.c ../common/safe_string.h $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -I ../common/ -o $@ -c $(ETC)/to_erl.c
+$(OBJDIR)/to_erl_common.o: ../common/to_erl_common.c ../common/to_erl_common.h $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -o $@ -c $<
+
+# dyn_erl
$(BINDIR)/dyn_erl: $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
$(V_LD) $(LDFLAGS) -o $@ $(OBJDIR)/safe_string.o $(OBJDIR)/dyn_erl.o
-
-$(OBJDIR)/dyn_erl.o: ../unix/dyn_erl.c $(RC_GENERATED)
- $(V_CC) $(CFLAGS) -o $@ -c ../unix/dyn_erl.c
-
-$(OBJDIR)/safe_string.o: ../unix/safe_string.c $(RC_GENERATED)
- $(V_CC) $(CFLAGS) -o $@ -c ../unix/safe_string.c
+$(OBJDIR)/dyn_erl.o: $(UXETC)/dyn_erl.c $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -o $@ -c $(UXETC)/dyn_erl.c
+$(OBJDIR)/safe_string.o: ../common/safe_string.c $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -o $@ -c ../common/safe_string.c
ifneq ($(TARGET),win32)
$(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB)
@@ -401,6 +452,7 @@ $(BINDIR)/$(ERLEXEC): $(OBJDIR)/$(ERLEXEC).o $(ERTS_LIB)
$(OBJDIR)/$(ERLEXEC).o: $(ERLEXECDIR)/$(ERLEXEC).c $(RC_GENERATED)
$(V_CC) -I$(EMUDIR) $(CFLAGS) -o $@ -c $(ERLEXECDIR)/$(ERLEXEC).c
endif
+
$(BINDIR)/erlc@EXEEXT@: $(OBJDIR)/erlc.o $(ERTS_LIB)
$(ld_verbose)$(PURIFY) $(LD) $(LDFLAGS) -o $@ $(OBJDIR)/erlc.o -L$(OBJDIR) $(LIBS) $(ERTS_INTERNAL_LIBS)
@@ -433,18 +485,42 @@ $(OBJDIR)/ct_run.o: ct_run.c $(RC_GENERATED)
-Install: ../unix/Install.src ../../vsn.mk $(TARGET)/Makefile
+Install: $(UXETC)/Install.src ../../vsn.mk $(TARGET)/Makefile
$(vsn_verbose)sed -e 's;%I_VSN%;$(VSN);' \
-e 's;%EMULATOR%;$(EMULATOR);' \
-e 's;%EMULATOR_NUMBER%;$(EMULATOR_NUMBER);' \
-e 's;%I_SYSTEM_VSN%;$(SYSTEM_VSN);' \
- ../unix/Install.src > Install
+ $(UXETC)/Install.src > Install
-erl.src: ../unix/erl.src.src ../../vsn.mk $(TARGET)/Makefile
+erl.src: $(UXETC)/erl.src.src ../../vsn.mk $(TARGET)/Makefile
$(vsn_verbose)sed -e 's;%EMULATOR%;$(EMULATOR);' \
-e 's;%EMULATOR_NUMBER%;$(EMULATOR_NUMBER);' \
-e 's;%VSN%;$(VSN);' \
- ../unix/erl.src.src > erl.src
+ $(UXETC)/erl.src.src > erl.src
+
+#---------------------------------------------------------
+# OSE specific targets
+#---------------------------------------------------------
+ifeq ($(findstring ose,$(TARGET)),ose)
+$(OBJDIR)/ose_confd.o: $(OSE_CONFD)
+ $(V_CC) $(CFLAGS) -o $@ -c $<
+$(OBJDIR)/crt0_lm.o: $(CRT0_LM)
+ $(V_CC) $(CFLAGS) -o $@ -c $<
+OSE_LM_OBJS += $(OBJDIR)/ose_confd.o $(OBJDIR)/crt0_lm.o
+
+$(BINDIR)/run_erl_lm: $(OBJDIR)/run_erl_main.o $(OBJDIR)/safe_string.o $(OBJDIR)/run_erl.o $(OBJDIR)/run_erl_common.o $(OBJDIR)/to_erl_common.o $(OSE_LM_OBJS)
+ $(call build-ose-load-module, $@, $^, $(LIBS), $(RUN_ERL_LMCONF))
+
+
+$(OBJDIR)/run_erl_main.o: $(OSEETC)/run_erl_main.c $(OSEETC)/run_erl.h ../common/to_erl_common.h $(RC_GENERATED)
+ $(V_CC) $(CFLAGS) -I ../common/ -o $@ -c $(OSEETC)/run_erl_main.c
+
+endif
+
+#---------------------------------------------------------
+# End of ose specific targets.
+#---------------------------------------------------------
+
# ----------------------------------------------------
# Release Target
@@ -478,17 +554,12 @@ ifneq ($(INSTALL_MISC),)
$(INSTALL_DIR) "$(RELEASE_PATH)/misc"
$(INSTALL_SCRIPT) $(INSTALL_MISC) "$(RELEASE_PATH)/misc"
endif
-ifneq ($(INSTALL_ERL_OSE),)
- $(INSTALL_DIR) "$(RELEASE_PATH)/build_erl_ose"
- cd $(OSEETC) && $(TAR) erl_ose_$(SYSTEM_VSN).tar $(INSTALL_ERL_OSE)
- cd $(OSEETC) && $(INSTALL_SCRIPT) erl_ose_$(SYSTEM_VSN).tar "$(RELEASE_PATH)/build_erl_ose"
-endif
ifneq ($(INSTALL_SRC),)
$(INSTALL_DIR) "$(RELEASE_PATH)/erts-$(VSN)/src"
$(INSTALL_DATA) $(INSTALL_SRC) "$(RELEASE_PATH)/erts-$(VSN)/src"
endif
ifneq ($(INSTALL_EMBEDDED_DATA),)
- $(INSTALL_DATA) $(INSTALL_EMBEDDED_DATA) "$(RELEASE_PATH)/erts-$(VSN)/bin"
+ $(INSTALL_SCRIPT) $(INSTALL_EMBEDDED_DATA) "$(RELEASE_PATH)/erts-$(VSN)/bin"
endif
ifneq ($(INSTALL_LIBS),)
$(INSTALL_DATA) $(INSTALL_LIBS) "$(RELEASE_PATH)/erts-$(VSN)/bin"
diff --git a/erts/etc/common/ct_run.c b/erts/etc/common/ct_run.c
index 853785dcd1..bb59b93998 100644
--- a/erts/etc/common/ct_run.c
+++ b/erts/etc/common/ct_run.c
@@ -117,9 +117,14 @@ char *strerror(int errnum)
}
#endif /* !HAVE_STRERROR */
-int
-main(int argc, char** argv)
+#ifdef __WIN32__
+int wmain(int argc, wchar_t **wcargv)
+{
+ char** argv;
+#else
+int main(int argc, char** argv)
{
+#endif
int eargv_size;
int eargc_base; /* How many arguments in the base of eargv. */
char* emulator;
@@ -129,7 +134,21 @@ main(int argc, char** argv)
int dist_mode;
int cnt;
int erl_args;
- char** argv0 = argv;
+ char** argv0;
+
+#ifdef __WIN32__
+ int i;
+ int len;
+ /* Convert argv to utf8 */
+ argv = malloc((argc+1) * sizeof(char*));
+ for (i=0; i<argc; i++) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
+ argv[i] = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
+ }
+ argv[argc] = NULL;
+#endif
+ argv0 = argv;
emulator = get_default_emulator(argv[0]);
@@ -295,48 +314,50 @@ push_words(char* src)
PUSH(strsave(sbuf));
}
#ifdef __WIN32__
-char *make_commandline(char **argv)
+wchar_t *make_commandline(char **argv)
{
- static char *buff = NULL;
+ static wchar_t *buff = NULL;
static int siz = 0;
- int num = 0;
- char **arg, *p;
+ int num = 0, len;
+ char **arg;
+ wchar_t *p;
- if (*argv == NULL) {
- return "";
+ if (*argv == NULL) {
+ return L"";
}
for (arg = argv; *arg != NULL; ++arg) {
num += strlen(*arg)+1;
}
if (!siz) {
siz = num;
- buff = malloc(siz*sizeof(char));
+ buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = realloc(buff,siz*sizeof(char));
+ buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
}
p = buff;
+ num=0;
for (arg = argv; *arg != NULL; ++arg) {
- strcpy(p,*arg);
- p+=strlen(*arg);
- *p++=' ';
+ len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, p, siz);
+ p+=(len-1);
+ *p++=L' ';
}
- *(--p) = '\0';
+ *(--p) = L'\0';
if (debug) {
- printf("Processed commandline:%s\n",buff);
+ printf("Processed command line:%S\n",buff);
}
return buff;
}
int my_spawnvp(char **argv)
{
- STARTUPINFO siStartInfo;
+ STARTUPINFOW siStartInfo;
PROCESS_INFORMATION piProcInfo;
DWORD ec;
- memset(&siStartInfo,0,sizeof(STARTUPINFO));
- siStartInfo.cb = sizeof(STARTUPINFO);
+ memset(&siStartInfo,0,sizeof(STARTUPINFOW));
+ siStartInfo.cb = sizeof(STARTUPINFOW);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -345,7 +366,7 @@ int my_spawnvp(char **argv)
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
- if (!CreateProcess(NULL,
+ if (!CreateProcessW(NULL,
make_commandline(argv),
NULL,
NULL,
@@ -432,6 +453,18 @@ strsave(char* string)
return p;
}
+static int
+file_exists(char *progname)
+{
+#ifdef __WIN32__
+ wchar_t wcsbuf[MAXPATHLEN];
+ MultiByteToWideChar(CP_UTF8, 0, progname, -1, wcsbuf, MAXPATHLEN);
+ return (_waccess(wcsbuf, 0) != -1);
+#else
+ return (access(progname, 1) != -1);
+#endif
+}
+
static char*
get_default_emulator(char* progname)
{
@@ -445,15 +478,8 @@ get_default_emulator(char* progname)
for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
if (IS_DIRSEP(*s)) {
strcpy(s+1, ERL_NAME);
-#ifdef __WIN32__
- if (_access(sbuf, 0) != -1) {
+ if(file_exists(sbuf))
return strsave(sbuf);
- }
-#else
- if (access(sbuf, 1) != -1) {
- return strsave(sbuf);
- }
-#endif
break;
}
}
diff --git a/erts/etc/common/dialyzer.c b/erts/etc/common/dialyzer.c
index b8a7a2bf03..09afb25182 100644
--- a/erts/etc/common/dialyzer.c
+++ b/erts/etc/common/dialyzer.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2006-2012. All Rights Reserved.
+ * Copyright Ericsson AB 2006-2013. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -104,20 +104,31 @@ get_env(char *key)
{
#ifdef __WIN32__
DWORD size = 32;
- char *value = NULL;
+ char *value=NULL;
+ wchar_t *wcvalue = NULL;
+ wchar_t wckey[256];
+ int len;
+
+ MultiByteToWideChar(CP_UTF8, 0, key, -1, wckey, 256);
+
while (1) {
DWORD nsz;
- if (value)
- free(value);
- value = emalloc(size);
+ if (wcvalue)
+ free(wcvalue);
+ wcvalue = (wchar_t*) emalloc(size*sizeof(wchar_t));
SetLastError(0);
- nsz = GetEnvironmentVariable((LPCTSTR) key, (LPTSTR) value, size);
+ nsz = GetEnvironmentVariableW(wckey, wcvalue, size);
if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
- free(value);
+ free(wcvalue);
return NULL;
}
- if (nsz <= size)
+ if (nsz <= size) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, NULL, 0, NULL, NULL);
+ value = emalloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, value, len, NULL, NULL);
+ free(wcvalue);
return value;
+ }
size = nsz;
}
#else
@@ -134,9 +145,14 @@ free_env_val(char *value)
#endif
}
-int
-main(int argc, char** argv)
+#ifdef __WIN32__
+int wmain(int argc, wchar_t **wcargv)
+{
+ char** argv;
+#else
+int main(int argc, char** argv)
{
+#endif
int eargv_size;
int eargc_base; /* How many arguments in the base of eargv. */
char* emulator;
@@ -144,6 +160,18 @@ main(int argc, char** argv)
int i;
int need_shell = 0;
+#ifdef __WIN32__
+ int len;
+ /* Convert argv to utf8 */
+ argv = malloc((argc+1) * sizeof(char*));
+ for (i=0; i<argc; i++) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
+ argv[i] = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
+ }
+ argv[argc] = NULL;
+#endif
+
env = get_env("DIALYZER_EMULATOR");
emulator = env ? env : get_default_emulator(argv[0]);
@@ -260,49 +288,52 @@ push_words(char* src)
if (sbuf[0])
PUSH(strsave(sbuf));
}
+
#ifdef __WIN32__
-char *make_commandline(char **argv)
+wchar_t *make_commandline(char **argv)
{
- static char *buff = NULL;
+ static wchar_t *buff = NULL;
static int siz = 0;
- int num = 0;
- char **arg, *p;
+ int num = 0, len;
+ char **arg;
+ wchar_t *p;
if (*argv == NULL) {
- return "";
+ return L"";
}
for (arg = argv; *arg != NULL; ++arg) {
num += strlen(*arg)+1;
}
if (!siz) {
siz = num;
- buff = malloc(siz*sizeof(char));
+ buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = realloc(buff,siz*sizeof(char));
+ buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
}
p = buff;
+ num=0;
for (arg = argv; *arg != NULL; ++arg) {
- strcpy(p,*arg);
- p+=strlen(*arg);
- *p++=' ';
+ len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, p, siz);
+ p+=(len-1);
+ *p++=L' ';
}
- *(--p) = '\0';
+ *(--p) = L'\0';
if (debug) {
- printf("Processed commandline:%s\n",buff);
+ printf("Processed command line:%S\n",buff);
}
return buff;
}
int my_spawnvp(char **argv)
{
- STARTUPINFO siStartInfo;
+ STARTUPINFOW siStartInfo;
PROCESS_INFORMATION piProcInfo;
DWORD ec;
- memset(&siStartInfo,0,sizeof(STARTUPINFO));
- siStartInfo.cb = sizeof(STARTUPINFO);
+ memset(&siStartInfo,0,sizeof(STARTUPINFOW));
+ siStartInfo.cb = sizeof(STARTUPINFOW);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -311,7 +342,7 @@ int my_spawnvp(char **argv)
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
- if (!CreateProcess(NULL,
+ if (!CreateProcessW(NULL,
make_commandline(argv),
NULL,
NULL,
@@ -398,6 +429,18 @@ strsave(char* string)
return p;
}
+static int
+file_exists(char *progname)
+{
+#ifdef __WIN32__
+ wchar_t wcsbuf[MAXPATHLEN];
+ MultiByteToWideChar(CP_UTF8, 0, progname, -1, wcsbuf, MAXPATHLEN);
+ return (_waccess(wcsbuf, 0) != -1);
+#else
+ return (access(progname, 1) != -1);
+#endif
+}
+
static char*
get_default_emulator(char* progname)
{
@@ -411,15 +454,8 @@ get_default_emulator(char* progname)
for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
if (IS_DIRSEP(*s)) {
strcpy(s+1, ERL_NAME);
-#ifdef __WIN32__
- if (_access(sbuf, 0) != -1) {
+ if(file_exists(sbuf))
return strsave(sbuf);
- }
-#else
- if (access(sbuf, 1) != -1) {
- return strsave(sbuf);
- }
-#endif
break;
}
}
diff --git a/erts/etc/common/erlc.c b/erts/etc/common/erlc.c
index c2d7c7c76d..055064abc4 100644
--- a/erts/etc/common/erlc.c
+++ b/erts/etc/common/erlc.c
@@ -60,7 +60,6 @@ static int eargc; /* Number of arguments in eargv. */
#define PUSH2(s, t) PUSH(s); PUSH(t)
#define PUSH3(s, t, u) PUSH2(s, t); PUSH(u)
-static char* output_type = NULL; /* Type of output file. */
#ifdef __WIN32__
static int pause_after_execution = 0;
#endif
@@ -71,7 +70,6 @@ static int pause_after_execution = 0;
static char* process_opt(int* pArgc, char*** pArgv, int offset);
static void error(char* format, ...);
-static void usage(void);
static char* emalloc(size_t size);
static char* strsave(char* string);
static void push_words(char* src);
@@ -114,20 +112,31 @@ get_env(char *key)
{
#ifdef __WIN32__
DWORD size = 32;
- char *value = NULL;
+ char *value=NULL;
+ wchar_t *wcvalue = NULL;
+ wchar_t wckey[256];
+ int len;
+
+ MultiByteToWideChar(CP_UTF8, 0, key, -1, wckey, 256);
+
while (1) {
DWORD nsz;
- if (value)
- free(value);
- value = emalloc(size);
+ if (wcvalue)
+ free(wcvalue);
+ wcvalue = (wchar_t *) emalloc(size*sizeof(wchar_t));
SetLastError(0);
- nsz = GetEnvironmentVariable((LPCTSTR) key, (LPTSTR) value, size);
+ nsz = GetEnvironmentVariableW(wckey, wcvalue, size);
if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
- free(value);
+ free(wcvalue);
return NULL;
}
- if (nsz <= size)
+ if (nsz <= size) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, NULL, 0, NULL, NULL);
+ value = emalloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, value, len, NULL, NULL);
+ free(wcvalue);
return value;
+ }
size = nsz;
}
#else
@@ -144,16 +153,32 @@ free_env_val(char *value)
#endif
}
-
-int
-main(int argc, char** argv)
+#ifdef __WIN32__
+int wmain(int argc, wchar_t **wcargv)
{
- char cwd[MAXPATHLEN]; /* Current working directory. */
+ char** argv;
+#else
+int main(int argc, char** argv)
+{
+#endif
int eargv_size;
int eargc_base; /* How many arguments in the base of eargv. */
char* emulator;
char *env;
+#ifdef __WIN32__
+ int i;
+ int len;
+ /* Convert argv to utf8 */
+ argv = malloc((argc+1) * sizeof(char*));
+ for (i=0; i<argc; i++) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
+ argv[i] = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
+ }
+ argv[argc] = NULL;
+#endif
+
env = get_env("ERLC_EMULATOR");
emulator = env ? env : get_default_emulator(argv[0]);
@@ -191,176 +216,41 @@ main(int argc, char** argv)
PUSH2("-mode", "minimal");
PUSH2("-boot", "start_clean");
PUSH3("-s", "erl_compile", "compile_cmdline");
+ PUSH("-extra");
/*
* Push standard arguments to Erlang.
- *
- * The @cwd argument was once needed, but from on R13B02 is optional.
- * For maximum compatibility between erlc and erl of different versions,
- * still provide the @cwd argument, unless it is too long to be
- * represented as an atom.
*/
- if (getcwd(cwd, sizeof(cwd)) == NULL)
- error("Failed to get current working directory: %s", strerror(errno));
-#ifdef __WIN32__
- (void) GetShortPathName(cwd, cwd, sizeof(cwd));
-#endif
- if (strlen(cwd) < 256) {
- PUSH2("@cwd", cwd);
- }
/*
* Parse all command line switches.
*/
- while (argc > 1 && (argv[1][0] == '-' || argv[1][0] == '+')) {
+ while (argc > 1) {
/*
* Options starting with '+' are passed on to Erlang.
*/
- if (argv[1][0] == '+') {
- PUSH2("@option", argv[1]+1);
- } else {
- /*
- * Interpret options starting with '-'.
- */
-
+ switch (argv[1][0]) {
+ case '+':
+ PUSH(argv[1]);
+ break;
+ case '-':
switch (argv[1][1]) {
- case 'b':
- output_type = process_opt(&argc, &argv, 0);
- PUSH2("@output_type", output_type);
- break;
- case 'c': /* Allowed for compatibility with 'erl'. */
- if (strcmp(argv[1], "-compile") != 0)
- goto error;
- break;
case 'd':
- debug = 1;
- break;
- case 'D':
- {
- char* def = process_opt(&argc, &argv, 0);
- char* equals;
-
- def = strsave(def); /* Do not clobber original. */
- if ((equals = strchr(def, '=')) == NULL) {
- PUSH2("@d", def);
- } else {
- *equals = '\0';
- equals++;
- PUSH3("@dv", def, equals);
- }
- }
- break;
- case 'I':
- PUSH2("@i", process_opt(&argc, &argv, 0));
- break;
- case 'M':
- {
- char *buf, *key, *val;
- size_t buf_len;
-
- if (argv[1][2] == '\0') { /* -M */
- /* Push the following options:
- * o 'makedep'
- * o {makedep_output, standard_io}
- */
- buf = strsave("makedep");
- PUSH2("@option", buf);
-
- key = "makedep_output";
- val = "standard_io";
- buf_len = 1 + strlen(key) + 1 + strlen(val) + 1 + 1;
- buf = emalloc(buf_len);
- snprintf(buf, buf_len, "{%s,%s}", key, val);
- PUSH2("@option", buf);
- } else if (argv[1][3] == '\0') {
- switch(argv[1][2]) {
- case 'D': /* -MD */
- /* Push the following options:
- * o 'makedep'
- */
- buf = strsave("makedep");
- PUSH2("@option", buf);
- break;
- case 'F': /* -MF <file> */
- /* Push the following options:
- * o 'makedep'
- * o {makedep_output, <file>}
- */
- buf = strsave("makedep");
- PUSH2("@option", buf);
-
- key = "makedep_output";
- val = process_opt(&argc, &argv, 1);
- buf_len = 1 + strlen(key) + 2 + strlen(val) + 2 + 1;
- buf = emalloc(buf_len);
- snprintf(buf, buf_len, "{%s,\"%s\"}", key, val);
- PUSH2("@option", buf);
- break;
- case 'T': /* -MT <target> */
- /* Push the following options:
- * o {makedep_target, <target>}
- */
- key = "makedep_target";
- val = process_opt(&argc, &argv, 1);
- buf_len = 1 + strlen(key) + 2 + strlen(val) + 2 + 1;
- buf = emalloc(buf_len);
- snprintf(buf, buf_len, "{%s,\"%s\"}", key, val);
- PUSH2("@option", buf);
- break;
- case 'Q': /* -MQ <target> */
- /* Push the following options:
- * o {makedep_target, <target>}
- * o makedep_quote_target
- */
- key = "makedep_target";
- val = process_opt(&argc, &argv, 1);
- buf_len = 1 + strlen(key) + 2 + strlen(val) + 2 + 1;
- buf = emalloc(buf_len);
- snprintf(buf, buf_len, "{%s,\"%s\"}", key, val);
- PUSH2("@option", buf);
-
- buf = strsave("makedep_quote_target");
- PUSH2("@option", buf);
- break;
- case 'G': /* -MG */
- /* Push the following options:
- * o makedep_add_missing
- */
- buf = strsave("makedep_add_missing");
- PUSH2("@option", buf);
- break;
- case 'P': /* -MP */
- /* Push the following options:
- * o makedep_phony
- */
- buf = strsave("makedep_phony");
- PUSH2("@option", buf);
- break;
- default:
- goto error;
- }
- }
+ if (argv[1][2] == '\0') {
+ debug = 1;
+ } else {
+ PUSH(argv[1]);
}
break;
- case 'o':
- PUSH2("@outdir", process_opt(&argc, &argv, 0));
- break;
- case 'O':
- PUSH("@optimize");
- if (argv[1][2] == '\0')
- PUSH("1");
- else
- PUSH(argv[1]+2);
- break;
case 'p':
{
int c = argv[1][2];
if (c != 'a' && c != 'z') {
- goto error;
+ PUSH(argv[1]);
#ifdef __WIN32__
} else if (strcmp(argv[1], "-pause") == 0) {
pause_after_execution = 1;
@@ -381,81 +271,21 @@ main(int argc, char** argv)
if (strcmp(argv[1], "-smp") == 0) {
UNSHIFT(argv[1]);
} else {
- goto error;
- }
- break;
- case 'v': /* Verbose. */
- PUSH2("@verbose", "true");
- break;
- case 'V':
- /** XXX Version perhaps, but of what? **/
- break;
- case 'W': /* Enable warnings. */
- if (strcmp(argv[1]+2, "all") == 0) {
- PUSH2("@warn", "999");
- } else if (strcmp(argv[1]+2, "error") == 0) {
- PUSH2("@option", "warnings_as_errors");
- } else if (isdigit((int)argv[1][2])) {
- PUSH2("@warn", argv[1]+2);
- } else {
- PUSH2("@warn", "1");
- }
- break;
- case 'E':
- case 'S':
- case 'P':
- {
- char* buf;
-
- /*
- * From the given upper-case letter, construct
- * a quoted atom. This is a convenience for the
- * Erlang compiler, to avoid fighting with the shell's
- * quoting.
- */
-
- buf = emalloc(4);
- buf[0] = '\'';
- buf[1] = argv[1][1];
- buf[2] = '\'';
- buf[3] = '\0';
-
- PUSH2("@option", buf);
+ PUSH(argv[1]);
}
break;
-
- case '-':
- goto no_more_options;
-
default:
- error:
- usage();
+ PUSH(argv[1]);
break;
}
+ break;
+ default:
+ PUSH(argv[1]);
+ break;
}
argc--, argv++;
}
- no_more_options:
-
- if (argc <= 1) {
- /*
- * To avoid starting an Erlang system unless absolutely needed
- * exit if no files were specified on the command line.
- */
- exit(0);
- }
-
- /*
- * The rest of the command line must be filenames. Simply push them.
- */
-
- PUSH("@files");
- while (argc > 1) {
- PUSH(argv[1]);
- argc--, argv++;
- }
-
/*
* Move up the commands for invoking the emulator and adjust eargv
* accordingly.
@@ -520,48 +350,50 @@ push_words(char* src)
PUSH(strsave(sbuf));
}
#ifdef __WIN32__
-char *make_commandline(char **argv)
+wchar_t *make_commandline(char **argv)
{
- static char *buff = NULL;
+ static wchar_t *buff = NULL;
static int siz = 0;
- int num = 0;
- char **arg, *p;
+ int num = 0, len;
+ char **arg;
+ wchar_t *p;
if (*argv == NULL) {
- return "";
+ return L"";
}
for (arg = argv; *arg != NULL; ++arg) {
num += strlen(*arg)+1;
}
if (!siz) {
siz = num;
- buff = malloc(siz*sizeof(char));
+ buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = realloc(buff,siz*sizeof(char));
+ buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
}
p = buff;
+ num=0;
for (arg = argv; *arg != NULL; ++arg) {
- strcpy(p,*arg);
- p+=strlen(*arg);
- *p++=' ';
+ len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, p, siz);
+ p+=(len-1);
+ *p++=L' ';
}
- *(--p) = '\0';
+ *(--p) = L'\0';
if (debug) {
- printf("Processed commandline:%s\n",buff);
+ printf("Processed command line:%S\n",buff);
}
return buff;
}
int my_spawnvp(char **argv)
{
- STARTUPINFO siStartInfo;
+ STARTUPINFOW siStartInfo;
PROCESS_INFORMATION piProcInfo;
DWORD ec;
- memset(&siStartInfo,0,sizeof(STARTUPINFO));
- siStartInfo.cb = sizeof(STARTUPINFO);
+ memset(&siStartInfo,0,sizeof(STARTUPINFOW));
+ siStartInfo.cb = sizeof(STARTUPINFOW);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
@@ -570,7 +402,7 @@ int my_spawnvp(char **argv)
siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
- if (!CreateProcess(NULL,
+ if (!CreateProcessW(NULL,
make_commandline(argv),
NULL,
NULL,
@@ -633,53 +465,6 @@ run_erlang(char* progname, char** argv)
}
static void
-usage(void)
-{
- static struct {
- char* name;
- char* desc;
- } options[] = {
- {"-b type", "type of output file (e.g. jam or beam)"},
- {"-d", "turn on debugging of erlc itself"},
- {"-Dname", "define name"},
- {"-Dname=value", "define name to have value"},
- {"-help", "shows this help text"},
- {"-I path", "where to search for include files"},
- {"-M", "generate a rule for make(1) describing the dependencies"},
- {"-MF file", "write the dependencies to 'file'"},
- {"-MT target", "change the target of the rule emitted by dependency "
- "generation"},
- {"-MQ target", "same as -MT but quote characters special to make(1)"},
- {"-MG", "consider missing headers as generated files and add them to "
- "the dependencies"},
- {"-MP", "add a phony target for each dependency"},
- {"-MD", "same as -M -MT file (with default 'file')"},
- {"-o name", "name output directory or file"},
- {"-pa path", "add path to the front of Erlang's code path"},
- {"-pz path", "add path to the end of Erlang's code path"},
- {"-smp", "compile using SMP emulator"},
- {"-v", "verbose compiler output"},
- {"-Werror", "make all warnings into errors"},
- {"-W0", "disable warnings"},
- {"-Wnumber", "set warning level to number"},
- {"-Wall", "enable all warnings"},
- {"-W", "enable warnings (default; same as -W1)"},
- {"-E", "generate listing of expanded code (Erlang compiler)"},
- {"-S", "generate assembly listing (Erlang compiler)"},
- {"-P", "generate listing of preprocessed code (Erlang compiler)"},
- {"+term", "pass the Erlang term unchanged to the compiler"},
- };
- int i;
-
- fprintf(stderr, "Usage:\terlc [options] file.ext ...\n");
- fprintf(stderr, "Options:\n");
- for (i = 0; i < sizeof(options)/sizeof(options[0]); i++) {
- fprintf(stderr, "%-14s %s\n", options[i].name, options[i].desc);
- }
- exit(1);
-}
-
-static void
error(char* format, ...)
{
char sbuf[1024];
@@ -709,6 +494,18 @@ strsave(char* string)
return p;
}
+static int
+file_exists(char *progname)
+{
+#ifdef __WIN32__
+ wchar_t wcsbuf[MAXPATHLEN];
+ MultiByteToWideChar(CP_UTF8, 0, progname, -1, wcsbuf, MAXPATHLEN);
+ return (_waccess(wcsbuf, 0) != -1);
+#else
+ return (access(progname, 1) != -1);
+#endif
+}
+
static char*
get_default_emulator(char* progname)
{
@@ -722,15 +519,8 @@ get_default_emulator(char* progname)
for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
if (IS_DIRSEP(*s)) {
strcpy(s+1, ERL_NAME);
-#ifdef __WIN32__
- if (_access(sbuf, 0) != -1) {
+ if(file_exists(sbuf))
return strsave(sbuf);
- }
-#else
- if (access(sbuf, 1) != -1) {
- return strsave(sbuf);
- }
-#endif
break;
}
}
diff --git a/erts/etc/common/erlexec.c b/erts/etc/common/erlexec.c
index f098e56a2e..709c6f02d1 100644
--- a/erts/etc/common/erlexec.c
+++ b/erts/etc/common/erlexec.c
@@ -42,7 +42,7 @@
#define DEFAULT_PROGNAME "erl"
#ifdef __WIN32__
-#define INI_FILENAME "erl.ini"
+#define INI_FILENAME L"erl.ini"
#define INI_SECTION "erlang"
#define DIRSEP "\\"
#define PATHSEP ";"
@@ -135,6 +135,7 @@ static char *pluss_val_switches[] = {
"ws",
"ss",
"pp",
+ "ub",
NULL
};
/* +h arguments with values */
@@ -828,7 +829,21 @@ int main(int argc, char **argv)
if (argv[i][2] == 'P') {
if (argv[i][3] != '\0')
goto the_default;
- } else if (argv[i][2] != '\0')
+ }
+#ifdef ERTS_DIRTY_SCHEDULERS
+ else if (argv[i][2] == 'D') {
+ char* type = argv[i]+3;
+ if (strncmp(type, "cpu", 3) != 0 &&
+ strncmp(type, "Pcpu", 4) != 0 &&
+ strncmp(type, "io", 2) != 0)
+ usage(argv[i]);
+ if ((argv[i][3] == 'c' && argv[i][6] != '\0') ||
+ (argv[i][3] == 'P' && argv[i][7] != '\0') ||
+ (argv[i][3] == 'i' && argv[i][5] != '\0'))
+ goto the_default;
+ }
+#endif
+ else if (argv[i][2] != '\0')
goto the_default;
if (i+1 >= argc)
usage(argv[i]);
@@ -1195,11 +1210,14 @@ start_epmd(char *epmd)
strcat(epmd, arg1);
}
{
- STARTUPINFO start;
+ wchar_t wcepmd[MAXPATHLEN+100];
+ STARTUPINFOW start;
PROCESS_INFORMATION pi;
memset(&start, 0, sizeof (start));
start.cb = sizeof (start);
- if (!CreateProcess(NULL, epmd, NULL, NULL, FALSE,
+ MultiByteToWideChar(CP_UTF8, 0, epmd, -1, wcepmd, MAXPATHLEN+100);
+
+ if (!CreateProcessW(NULL, wcepmd, NULL, NULL, FALSE,
CREATE_DEFAULT_ERROR_MODE | DETACHED_PROCESS,
NULL, NULL, &start, &pi))
result = -1;
@@ -1393,53 +1411,49 @@ static void get_start_erl_data(char *file)
}
-static char *replace_filename(char *path, char *new_base)
+static wchar_t *replace_filename(wchar_t *path, wchar_t *new_base)
{
- int plen = strlen(path);
- char *res = emalloc((plen+strlen(new_base)+1)*sizeof(char));
- char *p;
+ int plen = wcslen(path);
+ wchar_t *res = (wchar_t *) emalloc((plen+wcslen(new_base)+1)*sizeof(wchar_t));
+ wchar_t *p;
- strcpy(res,path);
- for (p = res+plen-1 ;p >= res && *p != '\\'; --p)
+ wcscpy(res,path);
+ for (p = res+plen-1 ;p >= res && *p != L'\\'; --p)
;
- *(p+1) ='\0';
- strcat(res,new_base);
+ *(p+1) =L'\0';
+ wcscat(res,new_base);
return res;
}
-static char *path_massage(char *long_path)
+static char *path_massage(wchar_t *long_path)
{
char *p;
-
- p = emalloc(MAX_PATH+1);
- strcpy(p, long_path);
- GetShortPathName(p, p, MAX_PATH);
+ int len;
+ len = WideCharToMultiByte(CP_UTF8, 0, long_path, -1, NULL, 0, NULL, NULL);
+ p = emalloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, long_path, -1, p, len, NULL, NULL);
return p;
}
static char *do_lookup_in_section(InitSection *inis, char *name,
- char *section, char *filename, int is_path)
+ char *section, wchar_t *filename, int is_path)
{
char *p = lookup_init_entry(inis, name);
if (p == NULL) {
- error("Could not find key %s in section %s of file %s",
+ error("Could not find key %s in section %s of file %S",
name,section,filename);
}
- if (is_path) {
- return path_massage(p);
- } else {
- return strsave(p);
- }
+ return strsave(p);
}
-
+// Setup bindir, rootdir and progname as utf8 buffers
static void get_parameters(int argc, char** argv)
{
- char *p;
- char buffer[MAX_PATH];
- char *ini_filename;
+ wchar_t *p;
+ wchar_t buffer[MAX_PATH];
+ wchar_t *ini_filename;
HANDLE module = GetModuleHandle(NULL); /* This might look strange, but we want the erl.ini
that resides in the same dir as erl.exe, not
an erl.ini in our directory */
@@ -1450,34 +1464,35 @@ static void get_parameters(int argc, char** argv)
error("Cannot GetModuleHandle()");
}
- if (GetModuleFileName(module,buffer,MAX_PATH) == 0) {
+ if (GetModuleFileNameW(module,buffer,MAX_PATH) == 0) {
error("Could not GetModuleFileName");
}
ini_filename = replace_filename(buffer,INI_FILENAME);
if ((inif = load_init_file(ini_filename)) == NULL) {
+ wchar_t wbindir[MAX_PATH];
+ wchar_t wrootdir[MAX_PATH];
+
/* Assume that the path is absolute and that
it does not contain any symbolic link */
-
- char buffer[MAX_PATH];
-
+
/* Determine bindir */
- if (GetEnvironmentVariable("ERLEXEC_DIR", buffer, MAX_PATH) == 0) {
- strcpy(buffer, ini_filename);
- for (p = buffer+strlen(buffer)-1; p >= buffer && *p != '\\'; --p)
+ if (GetEnvironmentVariableW(L"ERLEXEC_DIR", buffer, MAX_PATH) == 0) {
+ wcscpy(buffer, ini_filename);
+ for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
;
- *p ='\0';
+ *p = L'\0';
}
bindir = path_massage(buffer);
/* Determine rootdir */
- for (p = buffer+strlen(buffer)-1; p >= buffer && *p != '\\'; --p)
+ for (p = buffer+wcslen(buffer)-1; p >= buffer && *p != L'\\'; --p)
;
p--;
- for (;p >= buffer && *p != '\\'; --p)
+ for (;p >= buffer && *p != L'\\'; --p)
;
- *p ='\0';
+ *p =L'\0';
rootdir = path_massage(buffer);
/* Hardcoded progname */
@@ -1989,7 +2004,7 @@ initial_argv_massage(int *argc, char ***argv)
vix = 0;
- av = build_args_from_env("ERL_" OTP_SYSTEM_VERSION "_FLAGS");
+ av = build_args_from_env("ERL_OTP" OTP_SYSTEM_VERSION "_FLAGS");
if (av)
avv[vix++].argv = av;
diff --git a/erts/etc/common/escript.c b/erts/etc/common/escript.c
index 118bc6ef90..c92fedee4b 100644
--- a/erts/etc/common/escript.c
+++ b/erts/etc/common/escript.c
@@ -45,7 +45,8 @@ static int eargc; /* Number of arguments in eargv. */
# define QUOTE(s) possibly_quote(s)
# define IS_DIRSEP(c) ((c) == '/' || (c) == '\\')
# define DIRSEPSTR "\\"
-# define PATHSEPSTR ";"
+# define LDIRSEPSTR L"\\"
+# define LPATHSEPSTR L";"
# define PMAX MAX_PATH
# define ERL_NAME "erl.exe"
#else
@@ -112,20 +113,31 @@ get_env(char *key)
{
#ifdef __WIN32__
DWORD size = 32;
- char *value = NULL;
+ char *value=NULL;
+ wchar_t *wcvalue = NULL;
+ wchar_t wckey[256];
+ int len;
+
+ MultiByteToWideChar(CP_UTF8, 0, key, -1, wckey, 256);
+
while (1) {
DWORD nsz;
- if (value)
- efree(value);
- value = emalloc(size);
+ if (wcvalue)
+ efree(wcvalue);
+ wcvalue = (wchar_t *) emalloc(size*sizeof(wchar_t));
SetLastError(0);
- nsz = GetEnvironmentVariable((LPCTSTR) key, (LPTSTR) value, size);
+ nsz = GetEnvironmentVariableW(wckey, wcvalue, size);
if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
- efree(value);
+ efree(wcvalue);
return NULL;
}
- if (nsz <= size)
+ if (nsz <= size) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, NULL, 0, NULL, NULL);
+ value = emalloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, value, len, NULL, NULL);
+ efree(wcvalue);
return value;
+ }
size = nsz;
}
#else
@@ -145,6 +157,88 @@ free_env_val(char *value)
* Find absolute path to this program
*/
+#ifdef __WIN32__
+static char *
+find_prog(char *origpath)
+{
+ wchar_t relpath[PMAX];
+ wchar_t abspath[PMAX];
+
+ if (strlen(origpath) >= PMAX)
+ error("Path too long");
+
+ MultiByteToWideChar(CP_UTF8, 0, origpath, -1, relpath, PMAX);
+
+ if (wcsstr(relpath, LDIRSEPSTR) == NULL) {
+ /* Just a base name */
+ int sz;
+ wchar_t *envpath;
+ sz = GetEnvironmentVariableW(L"PATH", NULL, 0);
+ if (sz) {
+ /* Try to find the executable in the path */
+ wchar_t dir[PMAX];
+ wchar_t *beg;
+ wchar_t *end;
+
+ HANDLE dir_handle; /* Handle to directory. */
+ wchar_t wildcard[PMAX]; /* Wildcard to search for. */
+ WIN32_FIND_DATAW find_data; /* Data found by FindFirstFile() or FindNext(). */
+
+ BOOL look_for_sep = TRUE;
+
+ envpath = (wchar_t *) emalloc(sz * sizeof(wchar_t*));
+ GetEnvironmentVariableW(L"PATH", envpath, sz);
+ beg = envpath;
+
+ while (look_for_sep) {
+ end = wcsstr(beg, LPATHSEPSTR);
+ if (end != NULL) {
+ sz = end - beg;
+ } else {
+ sz = wcslen(beg);
+ look_for_sep = FALSE;
+ }
+ if (sz >= PMAX) {
+ beg = end + 1;
+ continue;
+ }
+ wcsncpy(dir, beg, sz);
+ dir[sz] = L'\0';
+ beg = end + 1;
+
+ swprintf(wildcard, PMAX, L"%s" LDIRSEPSTR L"%s",
+ dir, relpath /* basename */);
+ dir_handle = FindFirstFileW(wildcard, &find_data);
+ if (dir_handle == INVALID_HANDLE_VALUE) {
+ /* Try next directory in path */
+ continue;
+ } else {
+ /* Wow we found the executable. */
+ wcscpy(relpath, wildcard);
+ FindClose(dir_handle);
+ look_for_sep = FALSE;
+ break;
+ }
+ }
+ efree(envpath);
+ }
+ }
+
+ {
+ DWORD size;
+ wchar_t *absrest;
+ size = GetFullPathNameW(relpath, PMAX, abspath, &absrest);
+ if ((size == 0) || (size > PMAX)) {
+ /* Cannot determine absolute path to escript. Try the origin. */
+ return strsave(origpath);
+ } else {
+ char utf8abs[PMAX];
+ WideCharToMultiByte(CP_UTF8, 0, abspath, -1, utf8abs, PMAX, NULL, NULL);
+ return strsave(utf8abs);
+ }
+ }
+}
+#else
static char *
find_prog(char *origpath)
{
@@ -168,14 +262,8 @@ find_prog(char *origpath)
char *end;
int sz;
-#ifdef __WIN32__
- HANDLE dir_handle; /* Handle to directory. */
- char wildcard[PMAX]; /* Wildcard to search for. */
- WIN32_FIND_DATA find_data; /* Data found by FindFirstFile() or FindNext(). */
-#else
DIR *dp; /* Pointer to directory structure. */
struct dirent* dirp; /* Pointer to directory entry. */
-#endif /* __WIN32__ */
BOOL look_for_sep = TRUE;
@@ -195,21 +283,6 @@ find_prog(char *origpath)
dir[sz] = '\0';
beg = end + 1;
-#ifdef __WIN32__
- erts_snprintf(wildcard, sizeof(wildcard), "%s" DIRSEPSTR "%s",
- dir, relpath /* basename */);
- dir_handle = FindFirstFile(wildcard, &find_data);
- if (dir_handle == INVALID_HANDLE_VALUE) {
- /* Try next directory in path */
- continue;
- } else {
- /* Wow we found the executable. */
- strcpy(relpath, wildcard);
- FindClose(dir_handle);
- look_for_sep = FALSE;
- break;
- }
-#else
dp = opendir(dir);
if (dp != NULL) {
while (TRUE) {
@@ -230,21 +303,12 @@ find_prog(char *origpath)
}
}
}
-#endif /* __WIN32__ */
}
}
}
{
-#ifdef __WIN32__
- DWORD size;
- char *absrest;
- size = GetFullPathName(relpath, PMAX, abspath, &absrest);
- if ((size == 0) || (size > PMAX)) {
-
-#else
if (!realpath(relpath, abspath)) {
-#endif /* __WIN32__ */
/* Cannot determine absolute path to escript. Try the origin. */
return strsave(origpath);
} else {
@@ -252,12 +316,21 @@ find_prog(char *origpath)
}
}
}
+#endif
static void
append_shebang_args(char* scriptname)
{
/* Open script file */
- FILE* fd = fopen (scriptname,"r");
+ FILE* fd;
+#ifdef __WIN32__
+ wchar_t wcscriptname[PMAX];
+
+ MultiByteToWideChar(CP_UTF8, 0, scriptname, -1, wcscriptname, PMAX);
+ fd = _wfopen(wcscriptname, L"r");
+#else
+ fd = fopen (scriptname,"r");
+#endif
if (fd != NULL) {
/* Read first line in script file */
@@ -321,9 +394,15 @@ append_shebang_args(char* scriptname)
}
}
+#ifdef __WIN32__
+int wmain(int argc, wchar_t **wcargv)
+{
+ char** argv;
+#else
int
main(int argc, char** argv)
{
+#endif
int eargv_size;
int eargc_base; /* How many arguments in the base of eargv. */
char* emulator;
@@ -333,6 +412,19 @@ main(int argc, char** argv)
char scriptname[PMAX];
char** last_opt;
char** first_opt;
+
+#ifdef __WIN32__
+ int i;
+ int len;
+ /* Convert argv to utf8 */
+ argv = malloc((argc+1) * sizeof(char*));
+ for (i=0; i<argc; i++) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
+ argv[i] = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
+ }
+ argv[argc] = NULL;
+#endif
emulator = env = get_env("ESCRIPT_EMULATOR");
if (emulator == NULL) {
@@ -412,9 +504,8 @@ main(int argc, char** argv)
#endif
erts_snprintf(scriptname, sizeof(scriptname), "%s.escript",
- absname);
+ absname);
efree(absname);
-
}
/*
@@ -483,63 +574,65 @@ push_words(char* src)
PUSH(strsave(sbuf));
}
#ifdef __WIN32__
-char *make_commandline(char **argv)
+wchar_t *make_commandline(char **argv)
{
- static char *buff = NULL;
+ static wchar_t *buff = NULL;
static int siz = 0;
- int num = 0;
- char **arg, *p;
+ int num = 0, len;
+ char **arg;
+ wchar_t *p;
if (*argv == NULL) {
- return "";
+ return L"";
}
for (arg = argv; *arg != NULL; ++arg) {
num += strlen(*arg)+1;
}
if (!siz) {
siz = num;
- buff = emalloc(siz*sizeof(char));
+ buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = realloc(buff,siz*sizeof(char));
+ buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
}
p = buff;
+ num=0;
for (arg = argv; *arg != NULL; ++arg) {
- strcpy(p,*arg);
- p+=strlen(*arg);
- *p++=' ';
+ len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, p, siz);
+ p+=(len-1);
+ *p++=L' ';
}
- *(--p) = '\0';
+ *(--p) = L'\0';
if (debug) {
- printf("Processed command line:%s\n",buff);
+ printf("Processed command line:%S\n",buff);
}
return buff;
}
int my_spawnvp(char **argv)
{
- STARTUPINFO siStartInfo;
+ STARTUPINFOW siStartInfo;
PROCESS_INFORMATION piProcInfo;
DWORD ec;
- memset(&siStartInfo,0,sizeof(STARTUPINFO));
- siStartInfo.cb = sizeof(STARTUPINFO);
+ memset(&siStartInfo,0,sizeof(STARTUPINFOW));
+ siStartInfo.cb = sizeof(STARTUPINFOW);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
- if (!CreateProcess(NULL,
- make_commandline(argv),
- NULL,
- NULL,
- TRUE,
- 0,
- NULL,
- NULL,
- &siStartInfo,
- &piProcInfo)) {
+ if (!CreateProcessW(NULL,
+ make_commandline(argv),
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &siStartInfo,
+ &piProcInfo)) {
return -1;
}
CloseHandle(piProcInfo.hThread);
@@ -623,6 +716,18 @@ strsave(char* string)
return p;
}
+static int
+file_exists(char *progname)
+{
+#ifdef __WIN32__
+ wchar_t wcsbuf[MAXPATHLEN];
+ MultiByteToWideChar(CP_UTF8, 0, progname, -1, wcsbuf, MAXPATHLEN);
+ return (_waccess(wcsbuf, 0) != -1);
+#else
+ return (access(progname, 1) != -1);
+#endif
+}
+
static char*
get_default_emulator(char* progname)
{
@@ -636,15 +741,11 @@ get_default_emulator(char* progname)
for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
if (IS_DIRSEP(*s)) {
strcpy(s+1, ERL_NAME);
-#ifdef __WIN32__
- if (_access(sbuf, 0) != -1) {
+ if(file_exists(sbuf))
return strsave(sbuf);
- }
-#else
- if (access(sbuf, 1) != -1) {
+ strcpy(s+1, "bin" DIRSEPSTR ERL_NAME);
+ if(file_exists(sbuf))
return strsave(sbuf);
- }
-#endif
break;
}
}
diff --git a/erts/etc/common/heart.c b/erts/etc/common/heart.c
index 81d797dc7e..2830641802 100644
--- a/erts/etc/common/heart.c
+++ b/erts/etc/common/heart.c
@@ -1,7 +1,7 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2012. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2013. All Rights Reserved.
*
* The contents of this file are subject to the Erlang Public License,
* Version 1.1, (the "License"); you may not use this file except in
@@ -201,7 +201,6 @@ static BOOL do_shutdown(int);
static void print_last_error(void);
static HANDLE start_reader_thread(void);
static DWORD WINAPI reader(LPVOID);
-static int test_win95(void);
#define read _read
#define write _write
#endif
@@ -239,24 +238,39 @@ get_env(char *key)
{
#ifdef __WIN32__
DWORD size = 32;
- char *value = NULL;
+ char *value=NULL;
+ wchar_t *wcvalue = NULL;
+ wchar_t wckey[256];
+ int len;
+
+ MultiByteToWideChar(CP_UTF8, 0, key, -1, wckey, 256);
+
while (1) {
DWORD nsz;
- if (value)
- free(value);
- value = malloc(size);
- if (!value) {
+ if (wcvalue)
+ free(wcvalue);
+ wcvalue = malloc(size*sizeof(wchar_t));
+ if (!wcvalue) {
print_error("Failed to allocate memory. Terminating...");
exit(1);
}
SetLastError(0);
- nsz = GetEnvironmentVariable((LPCTSTR) key, (LPTSTR) value, size);
+ nsz = GetEnvironmentVariableW(wckey, wcvalue, size);
if (nsz == 0 && GetLastError() == ERROR_ENVVAR_NOT_FOUND) {
- free(value);
+ free(wcvalue);
return NULL;
}
- if (nsz <= size)
+ if (nsz <= size) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, NULL, 0, NULL, NULL);
+ value = malloc(len*sizeof(char));
+ if (!value) {
+ print_error("Failed to allocate memory. Terminating...");
+ exit(1);
+ }
+ WideCharToMultiByte(CP_UTF8, 0, wcvalue, -1, value, len, NULL, NULL);
+ free(wcvalue);
return value;
+ }
size = nsz;
}
#else
@@ -564,13 +578,22 @@ void win_system(char *command)
char *comspec;
char * cmdbuff;
char * extra = " /C ";
+ wchar_t *wccmdbuff;
char *env;
- STARTUPINFO start;
+ STARTUPINFOW start;
SECURITY_ATTRIBUTES attr;
PROCESS_INFORMATION info;
+ int len;
- if (!debug_on || test_win95()) {
- system(command);
+ if (!debug_on) {
+ len = MultiByteToWideChar(CP_UTF8, 0, command, -1, NULL, 0);
+ wccmdbuff = malloc(len*sizeof(wchar_t));
+ if (!wccmdbuff) {
+ print_error("Failed to allocate memory. Terminating...");
+ exit(1);
+ }
+ MultiByteToWideChar(CP_UTF8, 0, command, -1, wccmdbuff, len);
+ _wsystem(wccmdbuff);
return;
}
comspec = env = get_env("COMSPEC");
@@ -602,20 +625,29 @@ void win_system(char *command)
fflush(stderr);
- if (!CreateProcess(NULL,
- cmdbuff,
- &attr,
- NULL,
- TRUE,
- 0,
- NULL,
- NULL,
- &start,
- &info)) {
+ len = MultiByteToWideChar(CP_UTF8, 0, cmdbuff, -1, NULL, 0);
+ wccmdbuff = malloc(len*sizeof(wchar_t));
+ if (!wccmdbuff) {
+ print_error("Failed to allocate memory. Terminating...");
+ exit(1);
+ }
+ MultiByteToWideChar(CP_UTF8, 0, cmdbuff, -1, wccmdbuff, len);
+
+ if (!CreateProcessW(NULL,
+ wccmdbuff,
+ &attr,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &start,
+ &info)) {
debugf("Could not create process for the command %s.\r\n", cmdbuff);
}
WaitForSingleObject(info.hProcess,INFINITE);
free(cmdbuff);
+ free(wccmdbuff);
}
#endif /* defined(__WIN32__) */
@@ -966,16 +998,6 @@ void print_last_error() {
LocalFree( lpMsgBuf );
}
-static int test_win95(void)
-{
- OSVERSIONINFO osinfo;
- osinfo.dwOSVersionInfoSize=sizeof(OSVERSIONINFO);
- GetVersionEx(&osinfo);
- if (osinfo.dwPlatformId == VER_PLATFORM_WIN32_WINDOWS)
- return 1;
- else
- return 0;
-}
static BOOL enable_privilege() {
HANDLE ProcessHandle;
@@ -993,27 +1015,18 @@ static BOOL enable_privilege() {
}
static BOOL do_shutdown(int really_shutdown) {
- if (test_win95()) {
- if (ExitWindowsEx(EWX_REBOOT,0)) {
- return TRUE;
- } else {
- print_last_error();
- return FALSE;
- }
- } else {
- enable_privilege();
- if (really_shutdown) {
- if (InitiateSystemShutdown(NULL,"shutdown by HEART",10,TRUE,TRUE))
- return TRUE;
- } else if (InitiateSystemShutdown(NULL,
- "shutdown by HEART\n"
- "will be interrupted",
- 30,TRUE,TRUE)) {
- AbortSystemShutdown(NULL);
+ enable_privilege();
+ if (really_shutdown) {
+ if (InitiateSystemShutdown(NULL,"shutdown by HEART",10,TRUE,TRUE))
return TRUE;
- }
- return FALSE;
+ } else if (InitiateSystemShutdown(NULL,
+ "shutdown by HEART\n"
+ "will be interrupted",
+ 30,TRUE,TRUE)) {
+ AbortSystemShutdown(NULL);
+ return TRUE;
}
+ return FALSE;
}
DWORD WINAPI reader(LPVOID lpvParam) {
diff --git a/erts/etc/common/inet_gethost.c b/erts/etc/common/inet_gethost.c
index bef97862a3..9ec4192667 100644
--- a/erts/etc/common/inet_gethost.c
+++ b/erts/etc/common/inet_gethost.c
@@ -1209,7 +1209,7 @@ static void start_que_request(Worker *w)
#endif
}
-#ifndef WIN32
+#ifndef WIN32
/* Signal utilities */
static RETSIGTYPE (*sys_sigset(int sig, RETSIGTYPE (*func)(int)))(int)
{
diff --git a/erts/etc/common/run_erl_common.c b/erts/etc/common/run_erl_common.c
new file mode 100644
index 0000000000..dc55c2bea4
--- /dev/null
+++ b/erts/etc/common/run_erl_common.c
@@ -0,0 +1,686 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2014. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <dirent.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+#include <time.h>
+#include <unistd.h>
+
+#ifdef HAVE_SYSLOG_H
+# include <syslog.h>
+#endif
+
+#ifdef __OSE__
+# include "ramlog.h"
+#endif
+
+#include "run_erl_common.h"
+#include "safe_string.h"
+
+#define DEFAULT_LOG_GENERATIONS 5
+#define LOG_MAX_GENERATIONS 1000 /* No more than 1000 log files */
+#define LOG_MIN_GENERATIONS 2 /* At least two to switch between */
+#define DEFAULT_LOG_MAXSIZE 100000
+#define LOG_MIN_MAXSIZE 1000 /* Smallast value for changing log file */
+#define LOG_STUBNAME "erlang.log."
+#define LOG_PERM 0664
+#define DEFAULT_LOG_ACTIVITY_MINUTES 5
+#define DEFAULT_LOG_ALIVE_MINUTES 15
+#define DEFAULT_LOG_ALIVE_FORMAT "%a %b %e %T %Z %Y"
+#define ALIVE_BUFFSIZ 1024
+
+#define STATUSFILENAME "/run_erl.log"
+
+#define PIPE_STUBNAME "erlang.pipe"
+#define PIPE_STUBLEN strlen(PIPE_STUBNAME)
+#define PERM (S_IWUSR | S_IRUSR | S_IWOTH | S_IROTH | S_IWGRP | S_IRGRP)
+
+/* OSE has defined O_SYNC but it is not recognized by open */
+#if !defined(O_SYNC) || defined(__OSE__)
+#undef O_SYNC
+#define O_SYNC 0
+#define USE_FSYNC 1
+#endif
+
+/* Global variable definitions
+ * We need this complex way of handling global variables because of how
+ * OSE works here. We want to make it possible to run the shell command
+ * run_erl multiple times with different global variables without them
+ * effecting eachother.
+ */
+typedef struct run_erl_ run_erl;
+
+#ifdef __OSE__
+static OSPPDKEY run_erl_pp_key;
+#define RE_DATA (*(run_erl**)ose_get_ppdata(run_erl_pp_key))
+#else
+static run_erl re;
+#define RE_DATA (&re)
+#endif
+
+#define STATUSFILE (RE_DATA->statusfile)
+#define LOG_DIR (RE_DATA->log_dir)
+#define STDSTATUS (RE_DATA->stdstatus)
+#define LOG_GENERATIONS (RE_DATA->log_generations)
+#define LOG_MAXSIZE (RE_DATA->log_maxsize)
+#define LOG_ACTIVITY_MINUTES (RE_DATA->log_activity_minutes)
+#define LOG_ALIVE_IN_GMT (RE_DATA->log_alive_in_gmt)
+#define LOG_ALIVE_FORMAT (RE_DATA->log_alive_format)
+#define RUN_DAEMON (RE_DATA->run_daemon)
+#define LOG_ALIVE_MINUTES (RE_DATA->log_alive_minutes)
+#define LOG_NUM (RE_DATA->log_num)
+#define LFD (RE_DATA->lfd)
+#define PROTOCOL_VER (RE_DATA->protocol_ver)
+
+struct run_erl_ {
+ /* constant config data */
+ char statusfile[FILENAME_BUFSIZ];
+ char log_dir[FILENAME_BUFSIZ];
+ FILE *stdstatus;
+ int log_generations;
+ int log_maxsize;
+ int log_activity_minutes;
+ int log_alive_in_gmt;
+ char log_alive_format[ALIVE_BUFFSIZ+1];
+ int run_daemon;
+ int log_alive_minutes;
+ /* Current log number and log fd */
+ int log_num;
+ int lfd;
+ unsigned protocol_ver;
+};
+
+/* prototypes */
+
+static int next_log(int log_num);
+static int prev_log(int log_num);
+static int find_next_log_num(void);
+static int open_log(int log_num, int flags);
+
+/*
+ * getenv_int:
+ */
+static char *getenv_int(const char *name) {
+#ifdef __OSE__
+ return get_env(get_bid(current_process()),name);
+#else
+ return getenv(name);
+#endif
+}
+
+/*
+ * next_log:
+ * Returns the index number that follows the given index number.
+ * (Wrapping after log_generations)
+ */
+static int next_log(int log_num) {
+ return log_num>=LOG_GENERATIONS?1:log_num+1;
+}
+
+/*
+ * prev_log:
+ * Returns the index number that precedes the given index number.
+ * (Wrapping after log_generations)
+ */
+static int prev_log(int log_num) {
+ return log_num<=1?LOG_GENERATIONS:log_num-1;
+}
+
+/*
+ * find_next_log_num()
+ * Searches through the log directory to check which logs that already
+ * exist. It finds the "hole" in the sequence, and returns the index
+ * number for the last log in the log sequence. If there is no hole, index
+ * 1 is returned.
+ */
+static int find_next_log_num(void) {
+ int i, next_gen, log_gen;
+ DIR *dirp;
+ struct dirent *direntp;
+ int log_exists[LOG_MAX_GENERATIONS+1];
+ int stub_len = strlen(LOG_STUBNAME);
+
+ /* Initialize exiting log table */
+
+ for(i=LOG_GENERATIONS; i>=0; i--)
+ log_exists[i] = 0;
+ dirp = opendir(LOG_DIR);
+ if(!dirp) {
+ ERRNO_ERR1(LOG_ERR,"Can't access log directory '%s'", LOG_DIR);
+ exit(1);
+ }
+
+ /* Check the directory for existing logs */
+
+ while((direntp=readdir(dirp)) != NULL) {
+ if(strncmp(direntp->d_name,LOG_STUBNAME,stub_len)==0) {
+ int num = atoi(direntp->d_name+stub_len);
+ if(num < 1 || num > LOG_GENERATIONS)
+ continue;
+ log_exists[num] = 1;
+ }
+ }
+ closedir(dirp);
+
+ /* Find out the next available log file number */
+
+ next_gen = 0;
+ for(i=LOG_GENERATIONS; i>=0; i--) {
+ if(log_exists[i])
+ if(next_gen)
+ break;
+ else
+ ;
+ else
+ next_gen = i;
+ }
+
+ /* Find out the current log file number */
+
+ if(next_gen)
+ log_gen = prev_log(next_gen);
+ else
+ log_gen = 1;
+
+ return log_gen;
+} /* find_next_log_num() */
+
+static int open_log(int log_num, int flags)
+{
+ char buf[FILENAME_MAX];
+ time_t now;
+ struct tm *tmptr;
+ char log_buffer[ALIVE_BUFFSIZ+1];
+
+ /* Remove the next log (to keep a "hole" in the log sequence) */
+ sn_printf(buf, sizeof(buf), "%s/%s%d",
+ LOG_DIR, LOG_STUBNAME, next_log(log_num));
+ unlink(buf);
+
+ /* Create or continue on the current log file */
+ sn_printf(buf, sizeof(buf), "%s/%s%d", LOG_DIR, LOG_STUBNAME, log_num);
+
+ LFD = sf_open(buf, flags, LOG_PERM);
+
+ if(LFD <0){
+ ERRNO_ERR1(LOG_ERR,"Can't open log file '%s'.", buf);
+ exit(1);
+ }
+
+ /* Write a LOGGING STARTED and time stamp into the log file */
+ time(&now);
+ if (LOG_ALIVE_IN_GMT) {
+ tmptr = gmtime(&now);
+ } else {
+ tmptr = localtime(&now);
+ }
+ if (!strftime(log_buffer, ALIVE_BUFFSIZ, LOG_ALIVE_FORMAT,
+ tmptr)) {
+ strn_cpy(log_buffer, sizeof(log_buffer),
+ "(could not format time in 256 positions "
+ "with current format string.)");
+ }
+ log_buffer[ALIVE_BUFFSIZ] = '\0';
+
+ sn_printf(buf, sizeof(buf), "\n=====\n===== LOGGING STARTED %s\n=====\n",
+ log_buffer);
+ if (erts_run_erl_write_all(LFD, buf, strlen(buf)) < 0)
+ erts_run_erl_log_status("Error in writing to log.\n");
+
+#if USE_FSYNC
+ fsync(LFD);
+#endif
+
+ return LFD;
+}
+
+/* Instead of making sure basename exists, we do our own */
+char *simple_basename(char *path)
+{
+ char *ptr;
+ for (ptr = path; *ptr != '\0'; ++ptr) {
+ if (*ptr == '/') {
+ path = ptr + 1;
+ }
+ }
+ return path;
+}
+
+ssize_t sf_read(int fd, void *buffer, size_t len) {
+ ssize_t n = 0;
+
+ do { n = read(fd, buffer, len); } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+ssize_t sf_write(int fd, const void *buffer, size_t len) {
+ ssize_t n = 0;
+
+ do { n = write(fd, buffer, len); } while (n < 0 && errno == EINTR);
+
+ return n;
+}
+
+int sf_open(const char *path, int type, mode_t mode) {
+ int fd = 0;
+
+ do { fd = open(path, type, mode); } while(fd < 0 && errno == EINTR);
+
+ return fd;
+}
+
+int sf_close(int fd) {
+ int res = 0;
+
+ do { res = close(fd); } while(res < 0 && errno == EINTR);
+
+ return res;
+}
+
+/* Call write() until entire buffer has been written or error.
+ * Return len or -1.
+ */
+int erts_run_erl_write_all(int fd, const char* buf, int len)
+{
+ int left = len;
+ int written;
+ for (;;) {
+ do {
+ written = write(fd,buf,left);
+ } while (written < 0 && errno == EINTR);
+ if (written == left) {
+ return len;
+ }
+ if (written < 0) {
+ return -1;
+ }
+ left -= written;
+ buf += written;
+ }
+ return written;
+}
+
+/* erts_run_erl_log_status()
+ * Prints the arguments to a status file
+ * Works like printf (see vfrpintf)
+ */
+void erts_run_erl_log_status(const char *format,...)
+{
+ va_list args;
+ time_t now;
+
+ if (STDSTATUS == NULL)
+ STDSTATUS = fopen(STATUSFILE, "w");
+ if (STDSTATUS == NULL)
+ return;
+ now = time(NULL);
+ fprintf(STDSTATUS, "run_erl [%d] %s",
+#ifdef __OSE__
+ (int)current_process(),
+#else
+ (int)getpid(),
+#endif
+ ctime(&now));
+ va_start(args, format);
+ vfprintf(STDSTATUS, format, args);
+ va_end(args);
+ fflush(STDSTATUS);
+ return;
+}
+
+/* Fetch the current log alive minutes */
+int erts_run_erl_log_alive_minutes() {
+ return LOG_ALIVE_MINUTES;
+}
+
+/* error_logf()
+ * Prints the arguments to stderr or syslog
+ * Works like printf (see vfprintf)
+ */
+void erts_run_erl_log_error(int priority, int line, const char *format, ...)
+{
+ va_list args;
+ va_start(args, format);
+
+#ifdef HAVE_SYSLOG_H
+ if (RUN_DAEMON) {
+ vsyslog(priority,format,args);
+ }
+ else
+#endif
+#ifdef __OSE__
+ if (RUN_DAEMON) {
+ char *buff = malloc(sizeof(char)*1024);
+ vsnprintf(buff,1024,format, args);
+ ramlog_printf(buff);
+ }
+ else
+#endif
+ {
+ time_t now = time(NULL);
+ fprintf(stderr, "run_erl:%d [%d] %s", line,
+#ifdef __OSE__
+ (int)current_process(),
+#else
+ (int)getpid(),
+#endif
+ ctime(&now));
+ vfprintf(stderr, format, args);
+ }
+ va_end(args);
+}
+
+/* erts_run_erl_log_write()
+ * Writes a message to lfd. If the current log file is full,
+ * a new log file is opened.
+ */
+int erts_run_erl_log_write(char* buf, size_t len)
+{
+ int size;
+ ssize_t res;
+ /* Decide if new logfile needed, and open if so */
+
+ size = lseek(LFD,0,SEEK_END);
+ if(size+len > LOG_MAXSIZE) {
+ int res;
+ do {
+ res = close(LFD);
+ } while (res < 0 && errno == EINTR);
+ LOG_NUM = next_log(LOG_NUM);
+ LFD = open_log(LOG_NUM, O_RDWR|O_CREAT|O_TRUNC|O_SYNC);
+ }
+
+ /* Write to log file */
+
+ if ((res = erts_run_erl_write_all(LFD, buf, len)) < 0) {
+ erts_run_erl_log_status("Error in writing to log.\n");
+ }
+
+#if USE_FSYNC
+ fsync(LFD);
+#endif
+ return res;
+}
+
+int erts_run_erl_log_activity(int timeout,time_t now,time_t last_activity) {
+ char log_alive_buffer[ALIVE_BUFFSIZ+1];
+ char buf[BUFSIZ];
+
+ if (timeout || now - last_activity > LOG_ACTIVITY_MINUTES*60) {
+ /* Either a time out: 15 minutes without action, */
+ /* or something is coming in right now, but it's a long time */
+ /* since last time, so let's write a time stamp this message */
+ struct tm *tmptr;
+ if (LOG_ALIVE_IN_GMT) {
+ tmptr = gmtime(&now);
+ } else {
+ tmptr = localtime(&now);
+ }
+ if (!strftime(log_alive_buffer, ALIVE_BUFFSIZ, LOG_ALIVE_FORMAT,
+ tmptr)) {
+ strn_cpy(log_alive_buffer, sizeof(log_alive_buffer),
+ "(could not format time in 256 positions "
+ "with current format string.)");
+ }
+ log_alive_buffer[ALIVE_BUFFSIZ] = '\0';
+
+ sn_printf(buf, sizeof(buf), "\n===== %s%s\n",
+ timeout?"ALIVE ":"", log_alive_buffer);
+ return erts_run_erl_log_write(buf, strlen(buf));
+ }
+ return 0;
+}
+
+int erts_run_erl_log_open() {
+
+ LOG_NUM = find_next_log_num();
+ LFD = open_log(LOG_NUM, O_RDWR|O_APPEND|O_CREAT|O_SYNC);
+ return 0;
+}
+
+int erts_run_erl_log_init(int daemon, char* logdir) {
+ char *p;
+
+#ifdef __OSE__
+ run_erl **re_pp;
+ if (!run_erl_pp_key)
+ ose_create_ppdata("run_erl_ppdata",&run_erl_pp_key);
+ re_pp = (run_erl **)ose_get_ppdata(run_erl_pp_key);
+ *re_pp = malloc(sizeof(run_erl));
+#endif
+
+ STDSTATUS = NULL;
+ LOG_GENERATIONS = DEFAULT_LOG_GENERATIONS;
+ LOG_MAXSIZE = DEFAULT_LOG_MAXSIZE;
+ LOG_ACTIVITY_MINUTES = DEFAULT_LOG_ACTIVITY_MINUTES;
+ LOG_ALIVE_IN_GMT = 0;
+ RUN_DAEMON = 0;
+ LOG_ALIVE_MINUTES = DEFAULT_LOG_ALIVE_MINUTES;
+ LFD = 0;
+ PROTOCOL_VER = RUN_ERL_LO_VER; /* assume lowest to begin with */
+
+ /* Get values for LOG file handling from the environment */
+ if ((p = getenv_int("RUN_ERL_LOG_ALIVE_MINUTES"))) {
+ LOG_ALIVE_MINUTES = atoi(p);
+ if (!LOG_ALIVE_MINUTES) {
+ ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ALIVE_MINUTES is 1 "
+ "(current value is %s)",p);
+ }
+ LOG_ACTIVITY_MINUTES = LOG_ALIVE_MINUTES / 3;
+ if (!LOG_ACTIVITY_MINUTES) {
+ ++LOG_ACTIVITY_MINUTES;
+ }
+ }
+ if ((p = getenv_int(
+ "RUN_ERL_LOG_ACTIVITY_MINUTES"))) {
+ LOG_ACTIVITY_MINUTES = atoi(p);
+ if (!LOG_ACTIVITY_MINUTES) {
+ ERROR1(LOG_ERR,"Minimum value for RUN_ERL_LOG_ACTIVITY_MINUTES is 1 "
+ "(current value is %s)",p);
+ }
+ }
+ if ((p = getenv_int("RUN_ERL_LOG_ALIVE_FORMAT"))) {
+ if (strlen(p) > ALIVE_BUFFSIZ) {
+ ERROR1(LOG_ERR, "RUN_ERL_LOG_ALIVE_FORMAT can contain a maximum of "
+ "%d characters", ALIVE_BUFFSIZ);
+ }
+ strn_cpy(LOG_ALIVE_FORMAT, sizeof(LOG_ALIVE_FORMAT), p);
+ } else {
+ strn_cpy(LOG_ALIVE_FORMAT, sizeof(LOG_ALIVE_FORMAT),
+ DEFAULT_LOG_ALIVE_FORMAT);
+ }
+ if ((p = getenv_int("RUN_ERL_LOG_ALIVE_IN_UTC"))
+ && strcmp(p,"0")) {
+ ++LOG_ALIVE_IN_GMT;
+ }
+ if ((p = getenv_int("RUN_ERL_LOG_GENERATIONS"))) {
+ LOG_GENERATIONS = atoi(p);
+ if (LOG_GENERATIONS < LOG_MIN_GENERATIONS)
+ ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_GENERATIONS is %d",
+ LOG_MIN_GENERATIONS);
+ if (LOG_GENERATIONS > LOG_MAX_GENERATIONS)
+ ERROR1(LOG_ERR,"Maximum RUN_ERL_LOG_GENERATIONS is %d",
+ LOG_MAX_GENERATIONS);
+ }
+
+ if ((p = getenv_int("RUN_ERL_LOG_MAXSIZE"))) {
+ LOG_MAXSIZE = atoi(p);
+ if (LOG_MAXSIZE < LOG_MIN_MAXSIZE)
+ ERROR1(LOG_ERR,"Minimum RUN_ERL_LOG_MAXSIZE is %d", LOG_MIN_MAXSIZE);
+ }
+
+ RUN_DAEMON = daemon;
+
+ strn_cpy(LOG_DIR, sizeof(LOG_DIR), logdir);
+ strn_cpy(STATUSFILE, sizeof(STATUSFILE), LOG_DIR);
+ strn_cat(STATUSFILE, sizeof(STATUSFILE), STATUSFILENAME);
+
+ return 0;
+}
+
+/* create_fifo()
+ * Creates a new fifo with the given name and permission.
+ */
+static int create_fifo(char *name, int perm)
+{
+ if ((mkfifo(name, perm) < 0) && (errno != EEXIST))
+ return -1;
+ return 0;
+}
+
+/*
+ * w- and r_pipename have to be pre-allocated of atleast FILENAME_MAX size
+ */
+int erts_run_erl_open_fifo(char *pipename,char *w_pipename,char *r_pipename) {
+ int calculated_pipename = 0;
+ int highest_pipe_num = 0;
+ int fd;
+
+ /*
+ * Create FIFOs and open them
+ */
+
+ if(*pipename && pipename[strlen(pipename)-1] == '/') {
+ /* The user wishes us to find a unique pipe name in the specified */
+ /* directory */
+ DIR *dirp;
+ struct dirent *direntp;
+
+ calculated_pipename = 1;
+ dirp = opendir(pipename);
+ if(!dirp) {
+ ERRNO_ERR1(LOG_ERR,"Can't access pipe directory '%s'.", pipename);
+ return 1;
+ }
+
+ /* Check the directory for existing pipes */
+
+ while((direntp=readdir(dirp)) != NULL) {
+ if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) {
+ int num = atoi(direntp->d_name+PIPE_STUBLEN+1);
+ if(num > highest_pipe_num)
+ highest_pipe_num = num;
+ }
+ }
+ closedir(dirp);
+ strn_catf(pipename, BUFSIZ, "%s.%d",
+ PIPE_STUBNAME, highest_pipe_num+1);
+ } /* if */
+
+ for(;;) {
+ /* write FIFO - is read FIFO for `to_erl' program */
+ strn_cpy(w_pipename, BUFSIZ, pipename);
+ strn_cat(w_pipename, BUFSIZ, ".r");
+ if (create_fifo(w_pipename, PERM) < 0) {
+ ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.",
+ w_pipename);
+ return 1;
+ }
+
+ /* read FIFO - is write FIFO for `to_erl' program */
+ strn_cpy(r_pipename, BUFSIZ, pipename);
+ strn_cat(r_pipename, BUFSIZ, ".w");
+
+ /* Check that nobody is running run_erl already */
+ if ((fd = sf_open(r_pipename, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {
+ /* Open as client succeeded -- run_erl is already running! */
+ sf_close(fd);
+ if (calculated_pipename) {
+ ++highest_pipe_num;
+ strn_catf(pipename, BUFSIZ, "%s.%d",
+ PIPE_STUBNAME, highest_pipe_num+1);
+ continue;
+ }
+ ERROR1(LOG_ERR, "Erlang already running on pipe %s.\n", pipename);
+ unlink(w_pipename);
+ return 1;
+ }
+ if (create_fifo(r_pipename, PERM) < 0) {
+ unlink(w_pipename);
+ ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.",
+ r_pipename);
+ return 1;
+ }
+ break;
+ }
+ return 0;
+}
+
+/* Extract any control sequences that are ment only for run_erl
+ * and should not be forwarded to the pty.
+ */
+int erts_run_erl_extract_ctrl_seq(char* buf, int len)
+{
+ static const char prefix[] = "\033_";
+ static const char suffix[] = "\033\\";
+ char* bufend = buf + len;
+ char* start = buf;
+ char* command;
+ char* end;
+
+ for (;;) {
+ start = find_str(start, bufend-start, prefix);
+ if (!start) break;
+
+ command = start + strlen(prefix);
+ end = find_str(command, bufend-command, suffix);
+ if (end) {
+ unsigned col, row;
+ if (sscanf(command,"version=%u", &PROTOCOL_VER)==1) {
+ /*fprintf(stderr,"to_erl v%u\n", protocol_ver);*/
+ }
+ else if (sscanf(command,"winsize=%u,%u", &col, &row)==2) {
+#ifdef TIOCSWINSZ
+ struct winsize ws;
+ ws.ws_col = col;
+ ws.ws_row = row;
+ if (ioctl(MFD, TIOCSWINSZ, &ws) < 0) {
+ ERRNO_ERR0(LOG_ERR,"Failed to set window size");
+ }
+#endif
+ }
+ else {
+ ERROR2(LOG_ERR, "Ignoring unknown ctrl command '%.*s'\n",
+ (int)(end-command), command);
+ }
+
+ /* Remove ctrl sequence from buf */
+ end += strlen(suffix);
+ memmove(start, end, bufend-end);
+ bufend -= end - start;
+ }
+ else {
+ ERROR2(LOG_ERR, "Missing suffix in ctrl sequence '%.*s'\n",
+ (int)(bufend-start), start);
+ break;
+ }
+ }
+ return bufend - buf;
+}
diff --git a/erts/etc/common/run_erl_common.h b/erts/etc/common/run_erl_common.h
new file mode 100644
index 0000000000..c47a0db054
--- /dev/null
+++ b/erts/etc/common/run_erl_common.h
@@ -0,0 +1,96 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Functions that are common to both OSE and unix implementations of run_erl
+ */
+#ifndef ERL_RUN_ERL_LOG_H
+#define ERL_RUN_ERL_LOG_H
+
+#include <stdio.h>
+#include <time.h>
+#include <unistd.h>
+
+#include "run_erl_vsn.h"
+
+/* Log handling */
+int erts_run_erl_log_init(int run_daemon, char* logdir);
+int erts_run_erl_log_open(void);
+int erts_run_erl_log_close(void);
+int erts_run_erl_log_write(char *buff, size_t len);
+int erts_run_erl_log_activity(int timeout, time_t now, time_t last_activity);
+
+void erts_run_erl_log_status(const char *format,...);
+void erts_run_erl_log_error(int priority, int line, const char *format,...);
+
+int erts_run_erl_open_fifo(char *pipename,char *w_pipename,char *r_pipename);
+int erts_run_erl_log_alive_minutes(void);
+int erts_run_erl_extract_ctrl_seq(char* buf, int len);
+
+/* File operations */
+ssize_t sf_read(int fd, void *buffer, size_t len);
+ssize_t sf_write(int fd, const void *buffer, size_t len);
+int sf_open(const char *path, int type, mode_t mode);
+int sf_close(int fd);
+int erts_run_erl_write_all(int fd, const char* buf, int len);
+char *simple_basename(char *path);
+
+#ifndef LOG_ERR
+#ifdef __OSE__
+#define LOG_ERR 0
+#else
+#define LOG_ERR NULL
+#endif
+#endif
+
+#define ERROR0(Prio,Format) erts_run_erl_log_error(Prio,__LINE__,Format"\n")
+#define ERROR1(Prio,Format,A1) erts_run_erl_log_error(Prio,__LINE__,Format"\n",A1)
+#define ERROR2(Prio,Format,A1,A2) erts_run_erl_log_error(Prio,__LINE__,Format"\n",A1,A2)
+
+#ifdef HAVE_STRERROR
+# define ADD_ERRNO(Format) "errno=%d '%s'\n"Format"\n",errno,strerror(errno)
+#else
+# define ADD_ERRNO(Format) "errno=%d\n"Format"\n",errno
+#endif
+#define ERRNO_ERR0(Prio,Format) erts_run_erl_log_error(Prio,__LINE__,ADD_ERRNO(Format))
+#define ERRNO_ERR1(Prio,Format,A1) erts_run_erl_log_error(Prio,__LINE__,ADD_ERRNO(Format),A1)
+#define ERRNO_ERR2(Prio,Format,A1,A2) erts_run_erl_log_error(Prio,__LINE__,ADD_ERRNO(Format),A1,A2)
+
+#define RUN_ERL_USAGE \
+ "%s (pipe_name|pipe_dir/) log_dir \"command [parameters ...]\"" \
+ "\n\nDESCRIPTION:\n" \
+ "You may also set the environment variables RUN_ERL_LOG_GENERATIONS\n" \
+ "and RUN_ERL_LOG_MAXSIZE to the number of log files to use and the\n" \
+ "size of the log file when to switch to the next log file\n"
+
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 250
+#endif
+
+#define FILENAME_BUFSIZ FILENAME_MAX
+
+#ifdef O_NONBLOCK
+# define DONT_BLOCK_PLEASE O_NONBLOCK
+#else
+# define DONT_BLOCK_PLEASE O_NDELAY
+# ifndef EAGAIN
+# define EAGAIN -3898734
+# endif
+#endif
+
+#endif
diff --git a/erts/etc/common/run_erl_vsn.h b/erts/etc/common/run_erl_vsn.h
new file mode 100644
index 0000000000..f6ac753bde
--- /dev/null
+++ b/erts/etc/common/run_erl_vsn.h
@@ -0,0 +1,29 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+
+/*
+ * The protocol version number used between to_erl and run_erl.
+ */
+#define RUN_ERL_HI_VER 1 /* My preferred protocol version */
+#define RUN_ERL_LO_VER 0 /* The lowest version I accept to talk with */
+
+/* Version history:
+ * 0: Older, without version handshake
+ * 1: R12B-3, version handshake + window size ctrl
+ */
diff --git a/erts/etc/common/safe_string.c b/erts/etc/common/safe_string.c
new file mode 100644
index 0000000000..b2f8814408
--- /dev/null
+++ b/erts/etc/common/safe_string.c
@@ -0,0 +1,122 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Module: safe_string.c
+ *
+ * This is a bunch of generic string operation
+ * that are safe regarding buffer overflow.
+ *
+ * All string functions terminate the process with an error message
+ * on buffer overflow.
+ */
+
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+#include "safe_string.h"
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+
+static void string_overflow_handler(const char* format, ...)
+{
+ va_list args;
+ va_start(args, format);
+ vfprintf(stderr,format,args);
+ va_end(args);
+ exit(1);
+}
+
+int vsn_printf(char* dst, size_t size, const char* format, va_list args)
+{
+ int ret = vsnprintf(dst, size, format, args);
+ if (ret >= size || ret < 0) {
+ string_overflow_handler("Buffer truncated '%s'\n",dst);
+ }
+ return ret;
+}
+
+int sn_printf(char* dst, size_t size, const char* format, ...)
+{
+ va_list args;
+ int ret;
+ va_start(args, format);
+ ret = vsn_printf(dst,size,format,args);
+ va_end(args);
+ return ret;
+}
+
+int strn_cpy(char* dst, size_t size, const char* src)
+{
+ return sn_printf(dst,size,"%s",src);
+}
+
+int strn_cat(char* dst, size_t size, const char* src)
+{
+ return strn_catf(dst,size,"%s",src);
+}
+
+int strn_catf(char* dst, size_t size, const char* format, ...)
+{
+ int ret;
+ va_list args;
+#ifdef _GNU_SOURCE
+ int len = strnlen(dst,size);
+#else
+ int len = strlen(dst);
+#endif
+
+ if (len >= size) {
+ string_overflow_handler("Buffer already overflowed '%.*s'\n",
+ size, dst);
+ }
+ va_start(args, format);
+ ret = vsn_printf(dst+len, size-len, format, args);
+ va_end(args);
+ return len+ret;
+}
+
+char* find_str(const char* haystack, int hsize, const char* needle)
+{
+ int i = 0;
+ int nsize = strlen(needle);
+ hsize -= nsize - 1;
+ for (i=0; i<hsize; i++) {
+ if (haystack[i]==needle[0] && strncmp(haystack+i,needle,nsize)==0) {
+ return (char*)(haystack+i);
+ }
+ }
+ return NULL;
+}
+
+#ifndef HAVE_MEMMOVE
+void* memmove(void *dest, const void *src, size_t n)
+{
+ int i;
+ if (src > dest) {
+ for (i=0; i<n; i++) ((char*)dest)[i] = ((char*)src)[i];
+ }
+ else {
+ for (i=(int)(n-1); i>=0; i--) ((char*)dest)[i] = ((char*)src)[i];
+ }
+ return dest;
+}
+#endif /* HAVE_MEMMOVE */
diff --git a/erts/etc/common/safe_string.h b/erts/etc/common/safe_string.h
new file mode 100644
index 0000000000..ff063fe641
--- /dev/null
+++ b/erts/etc/common/safe_string.h
@@ -0,0 +1,64 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2009. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Module: safe_string.h
+ *
+ * This is an interface to a bunch of generic string operation
+ * that are safe regarding buffer overflow.
+ *
+ * All string functions terminate the process with an error message
+ * on buffer overflow.
+ */
+
+#include <stdio.h>
+#include <stdarg.h>
+
+/* Like vsnprintf()
+ */
+int vsn_printf(char* dst, size_t size, const char* format, va_list args);
+
+/* Like snprintf()
+ */
+int sn_printf(char* dst, size_t size, const char* format, ...);
+
+/* Like strncpy()
+ * Returns length of copied string.
+ */
+int strn_cpy(char* dst, size_t size, const char* src);
+
+/* Almost like strncat()
+ * size is sizeof entire dst buffer.
+ * Returns length of resulting string.
+ */
+int strn_cat(char* dst, size_t size, const char* src);
+
+/* Combination of strncat() and snprintf()
+ * size is sizeof entire dst buffer.
+ * Returns length of resulting string.
+ */
+int strn_catf(char* dst, size_t size, const char* format, ...);
+
+/* Simular to strstr() but search size bytes of haystack
+ * without regard to '\0' characters.
+ */
+char* find_str(const char* haystack, int size, const char* needle);
+
+#ifndef HAVE_MEMMOVE
+void* memmove(void *dest, const void *src, size_t n);
+#endif
diff --git a/erts/etc/common/to_erl_common.c b/erts/etc/common/to_erl_common.c
new file mode 100644
index 0000000000..ab706fffe0
--- /dev/null
+++ b/erts/etc/common/to_erl_common.c
@@ -0,0 +1,716 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+/*
+ * Module: to_erl.c
+ *
+ * This module implements a process that opens two specified FIFOs, one
+ * for reading and one for writing; reads from its stdin, and writes what
+ * it has read to the write FIF0; reads from the read FIFO, and writes to
+ * its stdout.
+ *
+ ________ _________
+ | |--<-- pipe.r (fifo1) --<--| |
+ | to_erl | | run_erl | (parent)
+ |________|-->-- pipe.w (fifo2) -->--|_________|
+ ^ master pty
+ |
+ | slave pty
+ ____V____
+ | |
+ | "erl" | (child)
+ |_________|
+ */
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif
+
+#include <sys/types.h>
+#include <sys/stat.h>
+#include <sys/time.h>
+#include <sys/types.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <dirent.h>
+#include <errno.h>
+
+#ifdef __OSE__
+#include <aio.h>
+#include "ose.h"
+#include "efs.h"
+#include "ose_spi/fm.sig"
+#else /* __UNIX__ */
+#include <termios.h>
+#include <signal.h>
+#endif
+
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#include "to_erl_common.h"
+#include "run_erl_vsn.h"
+#include "safe_string.h" /* strn_cpy, strn_catf, sn_printf, etc. */
+
+#if defined(O_NONBLOCK)
+# define DONT_BLOCK_PLEASE O_NONBLOCK
+#else
+# define DONT_BLOCK_PLEASE O_NDELAY
+# if !defined(EAGAIN)
+# define EAGAIN -3898734
+# endif
+#endif
+
+#ifdef HAVE_STRERROR
+# define STRERROR(x) strerror(x)
+#else
+# define STRERROR(x) ""
+#endif
+
+#define noDEBUG
+
+#ifdef __OSE__
+#define PIPE_DIR "/pipe/"
+#else
+#define PIPE_DIR "/tmp/"
+#endif
+#define PIPE_STUBNAME "erlang.pipe"
+#define PIPE_STUBLEN strlen(PIPE_STUBNAME)
+
+#ifdef DEBUG
+#define STATUS(s) { fprintf(stderr, (s)); fflush(stderr); }
+#else
+#define STATUS(s)
+#endif
+
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 250
+#endif
+
+static int tty_eof = 0;
+static int protocol_ver = RUN_ERL_LO_VER; /* assume lowest to begin with */
+
+static int write_all(int fd, const char* buf, int len);
+static int version_handshake(char* buf, int len, int wfd);
+
+
+#ifdef __OSE__
+
+#define SET_AIO(REQ,FD,SIZE,BUFF) \
+ /* Make sure to clean data structure of previous request */ \
+ memset(&(REQ),0,sizeof(REQ)); \
+ (REQ).aio_fildes = FD; \
+ (REQ).aio_offset = FM_POSITION_CURRENT; \
+ (REQ).aio_nbytes = SIZE; \
+ (REQ).aio_buf = BUFF; \
+ (REQ).aio_sigevent.sigev_notify = SIGEV_NONE
+
+#define READ_AIO(REQ,FD,SIZE,BUFF) \
+ SET_AIO(REQ,FD,SIZE,BUFF); \
+ if (aio_read(&(REQ)) != 0) \
+ fprintf(stderr,"aio_read of child_read_req(%d) failed" \
+ "with error %d\n",FD,errno)
+
+union SIGNAL {
+ SIGSELECT signo;
+ struct FmReadPtr fm_read_ptr;
+};
+
+#else /* __UNIX__ */
+static int recv_sig = 0;
+static struct termios tty_smode, tty_rmode;
+static int window_size_seq(char* buf, size_t bufsz);
+#ifdef DEBUG
+static void show_terminal_settings(struct termios *);
+#endif
+
+static void handle_ctrlc(int sig)
+{
+ /* Reinstall the handler, and signal break flag */
+ signal(SIGINT,handle_ctrlc);
+ recv_sig = SIGINT;
+}
+
+static void handle_sigwinch(int sig)
+{
+ recv_sig = SIGWINCH;
+}
+#endif
+
+static void usage(char *pname)
+{
+ fprintf(stderr, "Usage: ");
+ fprintf(stderr,TO_ERL_USAGE,pname);
+}
+
+int to_erl(int argc, char **argv)
+{
+ char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX];
+ int i, len, wfd, rfd;
+ char pipename[FILENAME_MAX];
+ int pipeIx = 1;
+ int force_lock = 0;
+ int got_some = 0;
+
+#ifdef __OSE__
+ struct aiocb stdin_read_req, pipe_read_req;
+ FmHandle stdin_fh, pipe_fh;
+ char *stdin_buf, *pipe_buf;
+ char *buf;
+ union SIGNAL *sig;
+#else /* __UNIX__ */
+ char buf[BUFSIZ];
+ fd_set readfds;
+#endif
+
+ if (argc >= 2 && argv[1][0]=='-') {
+ switch (argv[1][1]) {
+ case 'h':
+ usage(argv[0]);
+ exit(1);
+ case 'F':
+ force_lock = 1;
+ break;
+ default:
+ fprintf(stderr,"Invalid option '%s'\n",argv[1]);
+ exit(1);
+ }
+ pipeIx = 2;
+ }
+
+#ifdef DEBUG
+ fprintf(stderr, "%s: pid is : %d\n", argv[0],(int)
+#ifdef __OSE__
+ current_process()
+#else /* __UNIX__ */
+ getpid()
+#endif
+ );
+#endif
+
+ strn_cpy(pipename, sizeof(pipename),
+ (argv[pipeIx] ? argv[pipeIx] : PIPE_DIR));
+
+ if(*pipename && pipename[strlen(pipename)-1] == '/') {
+ /* The user wishes us to find a pipe name in the specified */
+ /* directory */
+ int highest_pipe_num = 0;
+ DIR *dirp;
+ struct dirent *direntp;
+
+ dirp = opendir(pipename);
+ if(!dirp) {
+ fprintf(stderr, "Can't access pipe directory %s: %s\n", pipename, strerror(errno));
+ exit(1);
+ }
+
+ /* Check the directory for existing pipes */
+
+ while((direntp=readdir(dirp)) != NULL) {
+ if(strncmp(direntp->d_name,PIPE_STUBNAME,PIPE_STUBLEN)==0) {
+ int num = atoi(direntp->d_name+PIPE_STUBLEN+1);
+ if(num > highest_pipe_num)
+ highest_pipe_num = num;
+ }
+ }
+ closedir(dirp);
+ strn_catf(pipename, sizeof(pipename), (highest_pipe_num?"%s.%d":"%s"),
+ PIPE_STUBNAME, highest_pipe_num);
+ } /* if */
+
+ /* read FIFO */
+ sn_printf(FIFO1,sizeof(FIFO1),"%s.r",pipename);
+ /* write FIFO */
+ sn_printf(FIFO2,sizeof(FIFO2),"%s.w",pipename);
+
+#ifndef __OSE__
+ /* Check that nobody is running to_erl on this pipe already */
+ if ((wfd = open (FIFO1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) >= 0) {
+ /* Open as server succeeded -- to_erl is already running! */
+ close(wfd);
+ fprintf(stderr, "Another to_erl process already attached to pipe "
+ "%s.\n", pipename);
+ if (force_lock) {
+ fprintf(stderr, "But we proceed anyway by force (-F).\n");
+ }
+ else {
+ exit(1);
+ }
+ }
+#endif
+
+ if ((rfd = open (FIFO1, O_RDONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Could not open FIFO %s for reading.\n", FIFO1);
+#endif
+ fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
+ exit(1);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "to_erl: %s opened for reading\n", FIFO1);
+#endif
+
+ if ((wfd = open (FIFO2, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
+#ifdef DEBUG
+ fprintf(stderr, "Could not open FIFO %s for writing.\n", FIFO2);
+#endif
+ fprintf(stderr, "No running Erlang on pipe %s: %s\n", pipename, strerror(errno));
+ close(rfd);
+ exit(1);
+ }
+#ifdef DEBUG
+ fprintf(stderr, "to_erl: %s opened for writing\n", FIFO2);
+#endif
+
+#ifndef __OSE__
+ fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename);
+#else
+ fprintf(stderr, "Attaching to %s (^C to exit)\n\n", pipename);
+#endif
+
+#ifndef __OSE__
+ /* Set break handler to our handler */
+ signal(SIGINT,handle_ctrlc);
+
+ /*
+ * Save the current state of the terminal, and set raw mode.
+ */
+ if (tcgetattr(0, &tty_rmode) , 0) {
+ fprintf(stderr, "Cannot get terminals current mode\n");
+ exit(-1);
+ }
+ tty_smode = tty_rmode;
+ tty_eof = '\004'; /* Ctrl+D to exit */
+#ifdef DEBUG
+ show_terminal_settings(&tty_rmode);
+#endif
+ tty_smode.c_iflag =
+ 1*BRKINT |/*Signal interrupt on break.*/
+ 1*IGNPAR |/*Ignore characters with parity errors.*/
+ 1*ISTRIP |/*Strip character.*/
+ 0;
+
+#if 0
+0*IGNBRK |/*Ignore break condition.*/
+0*PARMRK |/*Mark parity errors.*/
+0*INPCK |/*Enable input parity check.*/
+0*INLCR |/*Map NL to CR on input.*/
+0*IGNCR |/*Ignore CR.*/
+0*ICRNL |/*Map CR to NL on input.*/
+0*IUCLC |/*Map upper-case to lower-case on input.*/
+0*IXON |/*Enable start/stop output control.*/
+0*IXANY |/*Enable any character to restart output.*/
+0*IXOFF |/*Enable start/stop input control.*/
+0*IMAXBEL|/*Echo BEL on input line too long.*/
+#endif
+
+ tty_smode.c_oflag =
+ 1*OPOST |/*Post-process output.*/
+ 1*ONLCR |/*Map NL to CR-NL on output.*/
+#ifdef XTABS
+ 1*XTABS |/*Expand tabs to spaces. (Linux)*/
+#endif
+#ifdef OXTABS
+ 1*OXTABS |/*Expand tabs to spaces. (FreeBSD)*/
+#endif
+#ifdef NL0
+ 1*NL0 |/*Select newline delays*/
+#endif
+#ifdef CR0
+ 1*CR0 |/*Select carriage-return delays*/
+#endif
+#ifdef TAB0
+ 1*TAB0 |/*Select horizontal tab delays*/
+#endif
+#ifdef BS0
+ 1*BS0 |/*Select backspace delays*/
+#endif
+#ifdef VT0
+ 1*VT0 |/*Select vertical tab delays*/
+#endif
+#ifdef FF0
+ 1*FF0 |/*Select form feed delays*/
+#endif
+ 0;
+
+#if 0
+0*OLCUC |/*Map lower case to upper on output.*/
+0*OCRNL |/*Map CR to NL on output.*/
+0*ONOCR |/*No CR output at column 0.*/
+0*ONLRET |/*NL performs CR function.*/
+0*OFILL |/*Use fill characters for delay.*/
+0*OFDEL |/*Fill is DEL, else NULL.*/
+0*NL1 |
+0*CR1 |
+0*CR2 |
+0*CR3 |
+0*TAB1 |
+0*TAB2 |
+0*TAB3 |/*Expand tabs to spaces.*/
+0*BS1 |
+0*VT1 |
+0*FF1 |
+#endif
+
+ /* JALI: removed setting the tty_smode.c_cflag flags, since this is not */
+ /* advisable if this is a *real* terminal, such as the console. In fact */
+ /* this may hang the entire machine, deep, deep down (signalling break */
+ /* or toggling the abort switch doesn't help) */
+
+ tty_smode.c_lflag =
+ 0;
+
+#if 0
+0*ISIG |/*Enable signals.*/
+0*ICANON |/*Canonical input (erase and kill processing).*/
+0*XCASE |/*Canonical upper/lower presentation.*/
+0*ECHO |/*Enable echo.*/
+0*ECHOE |/*Echo erase character as BS-SP-BS.*/
+0*ECHOK |/*Echo NL after kill character.*/
+0*ECHONL |/*Echo NL.*/
+0*NOFLSH |/*Disable flush after interrupt or quit.*/
+0*TOSTOP |/*Send SIGTTOU for background output.*/
+0*ECHOCTL|/*Echo control characters as ^char, delete as ^?.*/
+0*ECHOPRT|/*Echo erase character as character erased.*/
+0*ECHOKE |/*BS-SP-BS erase entire line on line kill.*/
+0*FLUSHO |/*Output is being flushed.*/
+0*PENDIN |/*Retype pending input at next read or input character.*/
+0*IEXTEN |/*Enable extended (implementation-defined) functions.*/
+#endif
+
+ tty_smode.c_cc[VMIN] =0;/* Note that VMIN is the same as VEOF! */
+ tty_smode.c_cc[VTIME] =0;/* Note that VTIME is the same as VEOL! */
+ tty_smode.c_cc[VINTR] =3;
+
+ tcsetattr(0, TCSADRAIN, &tty_smode);
+
+#ifdef DEBUG
+ show_terminal_settings(&tty_smode);
+#endif
+
+#endif /* !__OSE__ */
+ /*
+ * "Write a ^L to the FIFO which causes the other end to redisplay
+ * the input line."
+ * This does not seem to work as was intended in old comment above.
+ * However, this control character is now (R12B-3) used by run_erl
+ * to trigger the version handshaking between to_erl and run_erl
+ * at the start of every new to_erl-session.
+ */
+
+ if (write(wfd, "\014", 1) < 0) {
+ fprintf(stderr, "Error in writing ^L to FIFO.\n");
+ }
+
+#ifdef __OSE__
+ /* we have a tiny stack so we malloc the buffers */
+ stdin_buf = malloc(sizeof(char) * BUFSIZ);
+ pipe_buf = malloc(sizeof(char) * BUFSIZ);
+
+ efs_examine_fd(rfd,FLIB_FD_HANDLE,&pipe_fh);
+ efs_examine_fd(0,FLIB_FD_HANDLE,&stdin_fh);
+ READ_AIO(stdin_read_req,0,BUFSIZ,stdin_buf);
+ READ_AIO(pipe_read_req,rfd,BUFSIZ,pipe_buf);
+#endif
+
+ /*
+ * read and write
+ */
+ while (1) {
+#ifndef __OSE__
+ FD_ZERO(&readfds);
+ FD_SET(0, &readfds);
+ FD_SET(rfd, &readfds);
+ if (select(rfd + 1, &readfds, NULL, NULL, NULL) < 0) {
+ if (recv_sig) {
+ FD_ZERO(&readfds);
+ }
+ else {
+ fprintf(stderr, "Error in select.\n");
+ break;
+ }
+ }
+ len = 0;
+
+ /*
+ * Read from terminal and write to FIFO
+ */
+ if (recv_sig) {
+ switch (recv_sig) {
+ case SIGINT:
+ fprintf(stderr, "[Break]\n\r");
+ buf[0] = '\003';
+ len = 1;
+ break;
+ case SIGWINCH:
+ len = window_size_seq(buf,sizeof(buf));
+ break;
+ default:
+ fprintf(stderr,"Unexpected signal: %u\n",recv_sig);
+ }
+ recv_sig = 0;
+ }
+ else
+#else /* __OSE__ */
+ SIGSELECT sigsel[] = {0};
+ sig = receive(sigsel);
+ len = 0;
+#endif
+#ifndef __OSE__
+ if (FD_ISSET(0,&readfds)) {
+ len = read(0, buf, sizeof(buf));
+#else /* __OSE__ */
+ if (sig->signo == FM_READ_PTR_REPLY &&
+ sig->fm_read_ptr.handle == stdin_fh) {
+ len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1;
+ buf = sig->fm_read_ptr.buffer;
+#endif
+ if (len <= 0) {
+ close(rfd);
+ close(wfd);
+ if (len < 0) {
+ fprintf(stderr, "Error in reading from stdin.\n");
+ } else {
+ fprintf(stderr, "[EOF]\n\r");
+ }
+ break;
+ }
+ /* check if there is an eof character in input */
+ for (i = 0; i < len-1 && buf[i] != tty_eof; i++);
+ if (buf[i] == tty_eof) {
+ fprintf(stderr, "[Quit]\n\r");
+ break;
+ }
+ }
+
+ if (len) {
+#ifdef DEBUG
+ if(write(1, buf, len));
+#endif
+ if (write_all(wfd, buf, len) != len) {
+ fprintf(stderr, "Error in writing to FIFO.\n");
+ close(rfd);
+ close(wfd);
+ break;
+ }
+ STATUS("\" OK\r\n");
+#ifdef __OSE__
+ aio_dispatch(sig);
+ READ_AIO(stdin_read_req, 0, BUFSIZ, stdin_buf);
+#endif
+ }
+
+ /*
+ * Read from FIFO, write to terminal.
+ */
+#ifndef __OSE__
+ if (FD_ISSET(rfd, &readfds)) {
+ STATUS("FIFO read: ");
+ len = read(rfd, buf, BUFSIZ);
+#else /* __OSE__ */
+ if (sig->signo == FM_READ_PTR_REPLY &&
+ sig->fm_read_ptr.handle == pipe_fh) {
+ len = sig->fm_read_ptr.status == EFS_SUCCESS ? sig->fm_read_ptr.actual : -1;
+ buf = sig->fm_read_ptr.buffer;
+#endif
+ if (len < 0 && errno == EAGAIN) {
+ /*
+ * No data this time, but the writing end of the FIFO is still open.
+ * Do nothing.
+ */
+ ;
+ } else if (len <= 0) {
+ /*
+ * Either an error or end of file. In either case, break out
+ * of the loop.
+ */
+ close(rfd);
+ close(wfd);
+ if (len < 0) {
+ fprintf(stderr, "Error in reading from FIFO.\n");
+ } else
+ fprintf(stderr, "[End]\n\r");
+ break;
+ } else {
+ if (!got_some) {
+ if ((len=version_handshake(buf,len,wfd)) < 0) {
+ close(rfd);
+ close(wfd);
+ break;
+ }
+#ifndef __OSE__
+ if (protocol_ver >= 1) {
+ /* Tell run_erl size of terminal window */
+ signal(SIGWINCH, handle_sigwinch);
+ raise(SIGWINCH);
+ }
+#endif
+ got_some = 1;
+ }
+
+ /*
+ * We successfully read at least one character. Write what we got.
+ */
+ STATUS("Terminal write: \"");
+ if (write_all(1, buf, len) != len) {
+ fprintf(stderr, "Error in writing to terminal.\n");
+ close(rfd);
+ close(wfd);
+ break;
+ }
+ STATUS("\" OK\r\n");
+#ifdef __OSE__
+ aio_dispatch(sig);
+ READ_AIO(pipe_read_req, rfd, BUFSIZ, pipe_buf);
+#endif
+ }
+ }
+ }
+
+#ifndef __OSE__
+ /*
+ * Reset terminal characterstics
+ * XXX
+ */
+ tcsetattr(0, TCSADRAIN, &tty_rmode);
+#endif
+ return 0;
+}
+
+/* Call write() until entire buffer has been written or error.
+ * Return len or -1.
+ */
+static int write_all(int fd, const char* buf, int len)
+{
+ int left = len;
+ int written;
+ while (left) {
+ written = write(fd,buf,left);
+ if (written < 0) {
+ return -1;
+ }
+ left -= written;
+ buf += written;
+ }
+ return len;
+}
+
+#ifndef __OSE__
+static int window_size_seq(char* buf, size_t bufsz)
+{
+#ifdef TIOCGWINSZ
+ struct winsize ws;
+ static const char prefix[] = "\033_";
+ static const char suffix[] = "\033\\";
+ /* This Esc sequence is called "Application Program Command"
+ and seems suitable to use for our own customized stuff. */
+
+ if (ioctl(STDIN_FILENO, TIOCGWINSZ, &ws) == 0) {
+ int len = sn_printf(buf, bufsz, "%swinsize=%u,%u%s",
+ prefix, ws.ws_col, ws.ws_row, suffix);
+ return len;
+ }
+#endif /* TIOCGWINSZ */
+ return 0;
+}
+#endif /* !__OSE__ */
+
+/* to_erl run_erl
+ * | |
+ * |---------- '\014' -------->| (session start)
+ * | |
+ * |<---- "[run_erl v1-0]" ----| (version interval)
+ * | |
+ * |--- Esc_"version=1"Esc\ -->| (common version)
+ * | |
+ */
+static int version_handshake(char* buf, int len, int wfd)
+{
+ unsigned re_high=0, re_low;
+ char *end = find_str(buf,len,"]\n");
+
+ if (end && sscanf(buf,"[run_erl v%u-%u",&re_high,&re_low)==2) {
+ char wbuf[30];
+ int wlen;
+
+ if (re_low > RUN_ERL_HI_VER || re_high < RUN_ERL_LO_VER) {
+ fprintf(stderr,"Incompatible versions: to_erl=v%u-%u run_erl=v%u-%u\n",
+ RUN_ERL_HI_VER, RUN_ERL_LO_VER, re_high, re_low);
+ return -1;
+ }
+ /* Choose highest common version */
+ protocol_ver = re_high < RUN_ERL_HI_VER ? re_high : RUN_ERL_HI_VER;
+
+ wlen = sn_printf(wbuf, sizeof(wbuf), "\033_version=%u\033\\",
+ protocol_ver);
+ if (write_all(wfd, wbuf, wlen) < 0) {
+ fprintf(stderr,"Failed to send version handshake\n");
+ return -1;
+ }
+ end += 2;
+ len -= (end-buf);
+ memmove(buf,end,len);
+
+ }
+ else { /* we assume old run_erl without version handshake */
+ protocol_ver = 0;
+ }
+
+ if (re_high != RUN_ERL_HI_VER) {
+ fprintf(stderr,"run_erl has different version, "
+ "using common protocol level %u\n", protocol_ver);
+ }
+
+ return len;
+}
+
+
+#if defined(DEBUG) && !defined(__OSE__)
+#define S(x) ((x) > 0 ? 1 : 0)
+
+static void show_terminal_settings(struct termios *t)
+{
+ fprintf(stderr,"c_iflag:\n");
+ fprintf(stderr,"Signal interrupt on break: BRKINT %d\n", S(t->c_iflag & BRKINT));
+ fprintf(stderr,"Map CR to NL on input: ICRNL %d\n", S(t->c_iflag & ICRNL));
+ fprintf(stderr,"Ignore break condition: IGNBRK %d\n", S(t->c_iflag & IGNBRK));
+ fprintf(stderr,"Ignore CR: IGNCR %d\n", S(t->c_iflag & IGNCR));
+ fprintf(stderr,"Ignore char with par. err's: IGNPAR %d\n", S(t->c_iflag & IGNPAR));
+ fprintf(stderr,"Map NL to CR on input: INLCR %d\n", S(t->c_iflag & INLCR));
+ fprintf(stderr,"Enable input parity check: INPCK %d\n", S(t->c_iflag & INPCK));
+ fprintf(stderr,"Strip character ISTRIP %d\n", S(t->c_iflag & ISTRIP));
+ fprintf(stderr,"Enable start/stop input ctrl IXOFF %d\n", S(t->c_iflag & IXOFF));
+ fprintf(stderr,"ditto output ctrl IXON %d\n", S(t->c_iflag & IXON));
+ fprintf(stderr,"Mark parity errors PARMRK %d\n", S(t->c_iflag & PARMRK));
+ fprintf(stderr,"\n");
+ fprintf(stderr,"c_oflag:\n");
+ fprintf(stderr,"Perform output processing OPOST %d\n", S(t->c_oflag & OPOST));
+ fprintf(stderr,"\n");
+ fprintf(stderr,"c_cflag:\n");
+ fprintf(stderr,"Ignore modem status lines CLOCAL %d\n", S(t->c_cflag & CLOCAL));
+ fprintf(stderr,"\n");
+ fprintf(stderr,"c_local:\n");
+ fprintf(stderr,"Enable echo ECHO %d\n", S(t->c_lflag & ECHO));
+ fprintf(stderr,"\n");
+ fprintf(stderr,"c_cc:\n");
+ fprintf(stderr,"c_cc[VEOF] %d\n", t->c_cc[VEOF]);
+}
+#endif /* DEBUG && !__OSE__ */
diff --git a/erts/etc/common/to_erl_common.h b/erts/etc/common/to_erl_common.h
new file mode 100644
index 0000000000..9967db94b8
--- /dev/null
+++ b/erts/etc/common/to_erl_common.h
@@ -0,0 +1,28 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2013. All Rights Reserved.
+ *
+ * The contents of this file are subject to the Erlang Public License,
+ * Version 1.1, (the "License"); you may not use this file except in
+ * compliance with the License. You should have received a copy of the
+ * Erlang Public License along with this software. If not, it can be
+ * retrieved online at http://www.erlang.org/.
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
+ * the License for the specific language governing rights and limitations
+ * under the License.
+ *
+ * %CopyrightEnd%
+ */
+#ifndef ERL_TO_ERL_H
+#define ERL_TO_ERL_H
+
+#define TO_ERL_USAGE "to_erl [-h|-F] %s\n" \
+ "\t-h\tThis help text.\n" \
+ "\t-f\tForce connection even though pipe is locked by other to_erl process."
+
+int to_erl(int argc, char **argv);
+
+#endif
diff --git a/erts/etc/common/typer.c b/erts/etc/common/typer.c
index c95959d52d..b45867f845 100644
--- a/erts/etc/common/typer.c
+++ b/erts/etc/common/typer.c
@@ -99,14 +99,33 @@ char *strerror(int errnum)
}
#endif /* !HAVE_STRERROR */
+#ifdef __WIN32__
+int wmain(int argc, wchar_t **wcargv)
+{
+ char** argv;
+#else
int
main(int argc, char** argv)
{
+#endif
int eargv_size;
int eargc_base; /* How many arguments in the base of eargv. */
char* emulator;
int need_shell = 0;
+#ifdef __WIN32__
+ int i;
+ int len;
+ /* Convert argv to utf8 */
+ argv = malloc((argc+1) * sizeof(char*));
+ for (i=0; i<argc; i++) {
+ len = WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, NULL, 0, NULL, NULL);
+ argv[i] = malloc(len*sizeof(char));
+ WideCharToMultiByte(CP_UTF8, 0, wcargv[i], -1, argv[i], len, NULL, NULL);
+ }
+ argv[argc] = NULL;
+#endif
+
emulator = get_default_emulator(argv[0]);
/*
@@ -193,66 +212,65 @@ push_words(char* src)
PUSH(strsave(sbuf));
}
#ifdef __WIN32__
-char *make_commandline(char **argv)
+wchar_t *make_commandline(char **argv)
{
- static char *buff = NULL;
+ static wchar_t *buff = NULL;
static int siz = 0;
- int num = 0;
- char **arg, *p;
+ int num = 0, len;
+ char **arg;
+ wchar_t *p;
if (*argv == NULL) {
- return "";
+ return L"";
}
for (arg = argv; *arg != NULL; ++arg) {
num += strlen(*arg)+1;
}
if (!siz) {
siz = num;
- buff = malloc(siz*sizeof(char));
+ buff = (wchar_t *) emalloc(siz*sizeof(wchar_t));
} else if (siz < num) {
siz = num;
- buff = realloc(buff,siz*sizeof(char));
+ buff = (wchar_t *) realloc(buff,siz*sizeof(wchar_t));
}
p = buff;
+ num=0;
for (arg = argv; *arg != NULL; ++arg) {
- strcpy(p,*arg);
- p+=strlen(*arg);
- *p++=' ';
+ len = MultiByteToWideChar(CP_UTF8, 0, *arg, -1, p, siz);
+ p+=(len-1);
+ *p++=L' ';
}
- *(--p) = '\0';
+ *(--p) = L'\0';
if (debug) {
- printf("Processed commandline:%s\n",buff);
+ printf("Processed command line:%S\n",buff);
}
return buff;
}
int my_spawnvp(char **argv)
{
- STARTUPINFO siStartInfo;
+ STARTUPINFOW siStartInfo;
PROCESS_INFORMATION piProcInfo;
DWORD ec;
- memset(&siStartInfo,0,sizeof(STARTUPINFO));
- siStartInfo.cb = sizeof(STARTUPINFO);
+ memset(&siStartInfo,0,sizeof(STARTUPINFOW));
+ siStartInfo.cb = sizeof(STARTUPINFOW);
siStartInfo.dwFlags = STARTF_USESTDHANDLES;
siStartInfo.hStdInput = GetStdHandle(STD_INPUT_HANDLE);
siStartInfo.hStdOutput = GetStdHandle(STD_OUTPUT_HANDLE);
siStartInfo.hStdError = GetStdHandle(STD_ERROR_HANDLE);
- siStartInfo.wShowWindow = SW_HIDE;
- siStartInfo.dwFlags |= STARTF_USESHOWWINDOW;
-
-
- if (!CreateProcess(NULL,
- make_commandline(argv),
- NULL,
- NULL,
- TRUE,
- 0,
- NULL,
- NULL,
- &siStartInfo,
- &piProcInfo)) {
+
+ if (!CreateProcessW(NULL,
+ make_commandline(argv),
+ NULL,
+ NULL,
+ TRUE,
+ 0,
+ NULL,
+ NULL,
+ &siStartInfo,
+ &piProcInfo)) {
return -1;
}
CloseHandle(piProcInfo.hThread);
@@ -330,6 +348,18 @@ strsave(char* string)
return p;
}
+static int
+file_exists(char *progname)
+{
+#ifdef __WIN32__
+ wchar_t wcsbuf[MAXPATHLEN];
+ MultiByteToWideChar(CP_UTF8, 0, progname, -1, wcsbuf, MAXPATHLEN);
+ return (_waccess(wcsbuf, 0) != -1);
+#else
+ return (access(progname, 1) != -1);
+#endif
+}
+
static char*
get_default_emulator(char* progname)
{
@@ -343,15 +373,8 @@ get_default_emulator(char* progname)
for (s = sbuf+strlen(sbuf); s >= sbuf; s--) {
if (IS_DIRSEP(*s)) {
strcpy(s+1, ERL_NAME);
-#ifdef __WIN32__
- if (_access(sbuf, 0) != -1) {
- return strsave(sbuf);
- }
-#else
- if (access(sbuf, 1) != -1) {
+ if(file_exists(sbuf))
return strsave(sbuf);
- }
-#endif
break;
}
}