aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/unix
diff options
context:
space:
mode:
Diffstat (limited to 'erts/etc/unix')
-rw-r--r--erts/etc/unix/Install.src21
-rw-r--r--erts/etc/unix/Makefile25
-rw-r--r--erts/etc/unix/README23
-rw-r--r--erts/etc/unix/RELNOTES21
-rw-r--r--erts/etc/unix/cerl.src131
-rw-r--r--erts/etc/unix/dyn_erl.c31
-rw-r--r--erts/etc/unix/erl.src.src23
-rw-r--r--erts/etc/unix/etp-commands.in1090
-rw-r--r--erts/etc/unix/etp-thr.py21
-rw-r--r--erts/etc/unix/etp_commands.erl23
-rw-r--r--erts/etc/unix/etp_commands.mk23
-rw-r--r--erts/etc/unix/format_man_pages25
-rw-r--r--erts/etc/unix/run_erl.c673
-rw-r--r--erts/etc/unix/run_erl.h31
-rw-r--r--erts/etc/unix/safe_string.c124
-rw-r--r--erts/etc/unix/safe_string.h66
-rw-r--r--erts/etc/unix/setuid_socket_wrap.c23
-rw-r--r--erts/etc/unix/start.src23
-rw-r--r--erts/etc/unix/start_erl.src23
-rw-r--r--erts/etc/unix/to_erl.c612
20 files changed, 2535 insertions, 497 deletions
diff --git a/erts/etc/unix/Install.src b/erts/etc/unix/Install.src
index 8eb1db75bd..e4b842877c 100644
--- a/erts/etc/unix/Install.src
+++ b/erts/etc/unix/Install.src
@@ -2,18 +2,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2013. All Rights Reserved.
+# Copyright Ericsson AB 1996-2017. 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/.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# 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.
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
diff --git a/erts/etc/unix/Makefile b/erts/etc/unix/Makefile
index c137a31ec2..83c64d35fd 100644
--- a/erts/etc/unix/Makefile
+++ b/erts/etc/unix/Makefile
@@ -1,18 +1,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2013. All Rights Reserved.
+# Copyright Ericsson AB 2013-2017. 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/.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# 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.
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
@@ -23,7 +24,7 @@ include $(ERL_TOP)/make/target.mk
include $(ERL_TOP)/make/$(TARGET)/otp.mk
include ../../vsn.mk
-opt debug: etc
+opt debug lcnt: etc
.PHONY: etc
etc: etp-commands
@@ -43,4 +44,4 @@ clean:
include $(ERL_TOP)/make/otp_release_targets.mk
.PHONY: release_spec
-release_spec: etc \ No newline at end of file
+release_spec: etc
diff --git a/erts/etc/unix/README b/erts/etc/unix/README
index 45b4aec2da..b94f28824e 100644
--- a/erts/etc/unix/README
+++ b/erts/etc/unix/README
@@ -1,18 +1,19 @@
%CopyrightBegin%
- Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ Copyright Ericsson AB 1996-2017. 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/.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
- 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.
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
%CopyrightEnd%
@@ -41,7 +42,7 @@ Note that the Install script will terminate if it detects problems -
you will have to correct them and re-run the script. If everything
goes well, the last printout should be:
-Erlang installation sucessfully completed
+Erlang installation successfully completed
If it isn't, something went wrong - check the printouts to find out
what it was.
diff --git a/erts/etc/unix/RELNOTES b/erts/etc/unix/RELNOTES
index d1a110fce3..7b4a1746fe 100644
--- a/erts/etc/unix/RELNOTES
+++ b/erts/etc/unix/RELNOTES
@@ -1,18 +1,19 @@
%CopyrightBegin%
- Copyright Ericsson AB 1996-2009. All Rights Reserved.
+ Copyright Ericsson AB 1996-2016. 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/.
+ Licensed under the Apache License, Version 2.0 (the "License");
+ you may not use this file except in compliance with the License.
+ You may obtain a copy of the License at
- 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.
+ http://www.apache.org/licenses/LICENSE-2.0
+
+ Unless required by applicable law or agreed to in writing, software
+ distributed under the License is distributed on an "AS IS" BASIS,
+ WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ See the License for the specific language governing permissions and
+ limitations under the License.
%CopyrightEnd%
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index 78fefbea55..2e034513b0 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -2,18 +2,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2003-2013. All Rights Reserved.
+# Copyright Ericsson AB 2003-2018. 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/.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# 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.
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
@@ -43,6 +44,9 @@
# -gcov Run emulator compiled for gcov
# -valgrind Run emulator compiled for valgrind
# -lcnt Run emulator compiled for lock counting
+# -icount Run emulator compiled for instruction counting
+# -rr Run emulator under "rr record"
+# Can be combined with compile targets (like -debug) except valgrind.
# -nox Unset the DISPLAY variable to disable us of X Windows
#
# FIXME For GDB you can also set the break point using "-break FUNCTION".
@@ -65,15 +69,6 @@ cxargs_add() {
done
}
-eeargs=
-eeargs_add() {
- while [ $# -gt 0 ]; do
- cargs="$cargs $1"
- eeargs="$eeargs $1"
- shift
- done
-}
-
core=
GDB=
@@ -82,6 +77,8 @@ GDBARGS=
TYPE=
debug=
run_valgrind=no
+run_rr=no
+skip_erlexec=no
# Default rootdir
ROOTDIR=%SRC_ROOTDIR%
@@ -91,8 +88,6 @@ TARGET=%TARGET%
PROGNAME=$ROOTDIR/bin/cerl
EMU=beam
-PRELOADED=$ROOTDIR/erts/preloaded/ebin
-
while [ $# -gt 0 ]; do
case "$1" in
@@ -137,29 +132,6 @@ while [ $# -gt 0 ]; do
shift
unset DISPLAY
;;
- "-smp")
- shift
- if [ $# -le 0 ]; then
- eeargs_add -smp
- else
- case $1 in
- disable)
- shift
- eeargs_add -smpdisable
- ;;
- enable)
- shift
- eeargs_add -smp
- ;;
- *)
- eeargs_add -smp
- esac
- fi
- ;;
- "-smpdisable")
- shift
- eeargs_add -smpdisable
- ;;
"-lcnt")
shift
cargs="$cargs -lcnt"
@@ -180,6 +152,11 @@ while [ $# -gt 0 ]; do
cargs="$cargs -frmptr"
TYPE=.frmptr
;;
+ "-icount")
+ shift
+ cargs="$cargs -icount"
+ TYPE=.icount
+ ;;
"-dump")
shift
GDB=dump
@@ -241,6 +218,13 @@ while [ $# -gt 0 ]; do
cargs="$cargs -valgrind"
TYPE=.valgrind
run_valgrind=yes
+ skip_erlexec=yes
+ ;;
+ "-rr")
+ shift
+ cargs="$cargs -rr"
+ run_rr=yes
+ skip_erlexec=yes
;;
*)
break
@@ -260,24 +244,34 @@ EXEC=$BINDIR/erlexec
PROGNAME="$PROGNAME$cargs"
EMU="$EMU$TYPE"
-EMU_NAME=`$EXEC -emu_name_exit $eeargs`
+EMU_NAME=`$EXEC -emu_name_exit`
+
+if [ $skip_erlexec = yes ]; then
+ emu_xargs=`echo $xargs | sed "s|+|-|g"`
+ beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
-if [ $run_valgrind != yes ]; then
- xargs="$xargs -pz $PRELOADED --"
+ # Prepare for some argument passing voodoo:
+ # $beam_args is a list of command line arguments separated by newlines.
+ # Make "$@" represent those arguments verbatim (including spaces and quotes).
+ SAVE_IFS="$IFS"
+ IFS='
+'
+ set -- $beam_args
+ IFS="$SAVE_IFS"
fi
if [ "x$GDB" = "x" ]; then
if [ $run_valgrind = yes ]; then
valversion=`valgrind --version`
valmajor=`echo $valversion | sed 's,[a-z]*\-\([0-9]*\).*,\1,'`
valminor=`echo $valversion | sed 's,[a-z]*\-[0-9]*.\([0-9]*\).*,\1,'`
- emu_xargs=`echo $xargs | sed "s|+|-|g"`
+ valint=`echo "$valmajor * 1000 + $valminor" | bc`
if [ "x$VALGRIND_LOG_XML" = "x" ]; then
valgrind_xml=
log_file_prefix="--log-file="
else
export VALGRIND_LOG_XML
valgrind_xml="--xml=yes"
- if [ $valmajor -gt 2 -a $valminor -gt 4 ]; then
+ if [ $valint -gt 3004 ]; then
log_file_prefix="--xml-file="
else
log_file_prefix="--log-file="
@@ -286,7 +280,7 @@ if [ "x$GDB" = "x" ]; then
if [ "x$VALGRIND_LOG_DIR" = "x" ]; then
valgrind_log=
else
- if [ $valmajor -gt 2 -a $valminor -gt 4 ]; then
+ if [ $valint -gt 3004 ]; then
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log.$$"
else
valgrind_log="$log_file_prefix$VALGRIND_LOG_DIR/$VALGRIND_LOGFILE_PREFIX$VALGRIND_LOGFILE_INFIX$EMU_NAME.log"
@@ -310,19 +304,12 @@ if [ "x$GDB" = "x" ]; then
sched_arg=
fi
- beam_args=`$EXEC -emu_args_exit ${1+"$@"}`
+ exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@"
- # Time for some argument passing voodoo:
- # $beam_args is a list of command line arguments separated by newlines.
- # Make "$@" represent those arguments verbatim (including spaces and quotes).
- SAVE_IFS="$IFS"
- IFS='
-'
- set -- $beam_args
- IFS="$SAVE_IFS"
- exec $taskset1 valgrind $valgrind_xml $valgrind_log $valgrind_misc_flags $BINDIR/$EMU_NAME $sched_arg $emu_xargs "$@" -pz $PRELOADED
+ elif [ $run_rr = yes ]; then
+ exec rr record --ignore-nested $BINDIR/$EMU_NAME $emu_xargs "$@"
else
- exec $EXEC $eeargs $xargs ${1+"$@"}
+ exec $EXEC $xargs ${1+"$@"}
fi
elif [ "x$GDB" = "xgdb" ]; then
case "x$core" in
@@ -375,7 +362,9 @@ elif [ "x$GDB" = "xegdb" ]; then
# Set annotation level for gdb in emacs 22 and higher. Seems to
# be working with level 1 for emacs 22 and level 3 for emacs 23...
emacs_major=`$EMACS --version | head -1 | sed 's,^[^0-9]*\([0-9]*\).*,\1,g'`
- if [ '!' -z "$emacs_major" -a $emacs_major -gt 22 ]; then
+ if [ '!' -z "$emacs_major" -a $emacs_major -gt 23 ]; then
+ GDBARGS="-i=mi "
+ elif [ '!' -z "$emacs_major" -a $emacs_major -gt 22 ]; then
GDBARGS="--annotate=3 "
elif [ '!' -z "$emacs_major" -a $emacs_major -gt 21 ]; then
GDBARGS="--annotate=1 "
@@ -390,19 +379,29 @@ elif [ "x$GDB" = "xdump" ]; then
cmdfile="/tmp/.cerlgdb.$$"
case "x$core" in
x/*)
- gdbcmd="$EMU_NAME ${core}"
;;
*)
dir=`pwd`
- gdbcmd="$EMU_NAME ${dir}/${core}"
+ core="${dir}/${core}"
;;
esac
- echo "set width 0
+ case `uname` in
+ Darwin)
+ echo "
+thread backtrace all
+quit
+" > $cmdfile
+ exec lldb -s $cmdfile -c ${core} $EMU_NAME
+ ;;
+ *)
+ echo "set width 0
set height 0
set verbose off
source $ROOTDIR/erts/etc/unix/etp-commands
thread apply all bt
" > $cmdfile
- exec gdb --batch --command=$cmdfile $gdbcmd
+ exec gdb --batch --command=$cmdfile $EMU_NAME $core
+ ;;
+ esac
fi
diff --git a/erts/etc/unix/dyn_erl.c b/erts/etc/unix/dyn_erl.c
index 984935417e..c4a2f7217c 100644
--- a/erts/etc/unix/dyn_erl.c
+++ b/erts/etc/unix/dyn_erl.c
@@ -1,18 +1,19 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 2009. All Rights Reserved.
+ * Copyright Ericsson AB 2009-2018. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
@@ -21,13 +22,7 @@
* This is a C version of the erl Bourne shell script
*/
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-
-#include "sys.h"
-#include <stdlib.h>
-#include <stdarg.h>
+#include "etc_common.h"
#define BOOL int
#define TRUE 1
diff --git a/erts/etc/unix/erl.src.src b/erts/etc/unix/erl.src.src
index ce5d2b5def..959c099e8f 100644
--- a/erts/etc/unix/erl.src.src
+++ b/erts/etc/unix/erl.src.src
@@ -2,18 +2,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2012. All Rights Reserved.
+# Copyright Ericsson AB 1996-2016. 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.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 141d51824f..b12a205ba7 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1,18 +1,20 @@
+# -*- gdb-script -*-
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2014. All Rights Reserved.
+# Copyright Ericsson AB 2005-2018. 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.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
@@ -51,7 +53,7 @@ document etp-help
% etpf-cons, etpf-boxed,
%
% Special commands for not really terms:
-% etp-mfa, etp-cp,
+% etp-mfa, etp-cp, etp-disasm,
% etp-msgq, etpf-msgq,
% etp-stacktrace, etp-stackdump, etpf-stackdump, etp-dictdump
% etp-process-info, etp-process-memory-info
@@ -146,14 +148,10 @@ define etp-1
etp-immediate-1 ($arg0)
else
# (($arg0) & 0x3) == 0
- if (($arg0) == 0x0)
+ if (($arg0) == etp_the_non_value)
printf "<the non-value>"
else
- if (($arg0) == 0x4)
- printf "<the non-value debug>"
- else
- etp-cp-1 ($arg0)
- end
+ etp-cp-1 ($arg0)
end
end
end
@@ -355,7 +353,32 @@ define etp-boxed-1
etp-array-1 ((Eterm*)(($arg0)&~0x3)) ($arg1) ($arg1) \
1 ((((Eterm*)(($arg0)&~0x3))[0]>>6)+1) '}'
else
- etp-boxed-immediate-1 ($arg0)
+ if (((Eterm*)(($arg0) & ~0x3))[0] & 0x3c) == 0x3c
+ # A map
+ if (((Eterm*)(($arg0) & ~0x3))[0] & 0xc0) == 0x0
+ # Flat map
+ printf "#{Keys:"
+ etp-1 ((flatmap_t*)(($arg0)&~0x3))->keys (($arg1)+1)
+ printf " Values:{"
+ etp-array-1 ((Eterm*)(($arg0)&~0x3)+3) ($arg1) ($arg1) \
+ 0 ((flatmap_t*)(($arg0)&~0x3))->size '}'
+ printf "}"
+ else
+ # Hashmap
+ printf "#<%x>{", (((((Eterm*)(($arg0)&~0x3))[0])>>(6+2+8))&0xffff)
+ if (((Eterm*)(($arg0) & ~0x3))[0] & 0xc0) >= 0x80
+ # head bitmap/array
+ etp-bitmap-array-1 ((Eterm*)(($arg0)&~0x3)+2) ($arg1) ($arg1) \
+ 0 (((((Eterm*)(($arg0)&~0x3))[0])>>(6+2+8))&0xffff) '}'
+ else
+ # node bitmap
+ etp-bitmap-array-1 ((Eterm*)(($arg0)&~0x3)+1) ($arg1) ($arg1) \
+ 0 (((((Eterm*)(($arg0)&~0x3))[0])>>(6+2+8))&0xffff) '}'
+ end
+ end
+ else
+ etp-boxed-immediate-1 ($arg0)
+ end
end
end
end
@@ -478,6 +501,36 @@ define etp-array-1
end
end
+define etp-bitmap-array-1
+# Args: Eterm* p, int depth, int width, int pos, int bitmap, int end_char
+#
+# Reentrant
+#
+# Same as etp-array-1 with size = bitcount(bitmap)
+#
+ if ($arg4) & 1 != 0
+ if (($arg1) < $etp_max_depth) && (($arg2) < $etp_max_depth)
+ etp-1 (($arg0)[($arg3)]) (($arg1)+1)
+ if (($arg4) & (($arg4)-1)) != 0
+ printf ","
+ end
+ etp-bitmap-array-1 ($arg0) ($arg1) (($arg2)+1) (($arg3)+1) (($arg4)>>1) ($arg5)
+ else
+ printf "...%c", ($arg5)
+ end
+ else
+ if ($arg4) == 0
+ printf "%c", ($arg5)
+ else
+ etp-bitmap-array-1 $arg0 $arg1 $arg2 $arg3 (($arg4)>>1) $arg5
+
+ # WARNING: One might be tempted to optimize the bitcounting here
+ # by passing the bitmap argument as ($arg4 & ($arg4 - 1)). This is a very
+ # bad idea as arguments are passed as string substitution.
+ # The size of $arg4 would thus grow exponentially for each recursion.
+ end
+ end
+end
#define etpa-1
@@ -722,9 +775,9 @@ define etp-pid-1
#
set $etp_pid_1 = (Eterm)($arg0)
if ($etp_pid_1 & 0xF) == 0x3
- if (etp_arch_bits == 64 && etp_halfword == 0)
- if (etp_big_endian)
- set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 36) & 0x0fffffff)
+ if (etp_arch_bits == 64)
+ if (etp_endianness > 0)
+ set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 35) & 0x0fffffff)
else
set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 4) & 0x0fffffff)
end
@@ -782,8 +835,8 @@ define etp-port-1
#
set $etp_port_1 = (Eterm)($arg0)
if ($etp_port_1 & 0xF) == 0x7
- if (etp_arch_bits == 64 && etp_halfword == 0)
- if (etp_big_endian)
+ if (etp_arch_bits == 64)
+ if (etp_endianness > 0)
set $etp_port_data = (unsigned) ((((Uint64) $etp_port_1) >> 36) & 0x0fffffff)
else
set $etp_port_data = (unsigned) ((((Uint64) $etp_port_1) >> 4) & 0x0fffffff)
@@ -900,30 +953,31 @@ define etp-ref-1
if ((Eterm)($arg0) & 0x3) != 0x2
printf "#NotBoxed<%#x>", (Eterm)($arg0)
else
- set $etp_ref_1_p = (RefThing *)((Eterm)($arg0) & ~0x3)
+ set $etp_ref_1_p = (ErtsORefThing *)((Eterm)($arg0) & ~0x3)
if ($etp_ref_1_p->header & 0x3b) != 0x10
printf "#NotRef<%#x>", $etp_ref_1_p->header
else
- set $etp_ref_1_nump = (Uint32 *) 0
- set $etp_ref_1_error = 0
- if ($etp_ref_1_p->header >> 6) == 0
- set $etp_ref_1_error = 1
+ if $etp_ref_1_p->header != etp_ref_header && $etp_ref_1_p->header != etp_magic_ref_header
+ printf "#InternalRefError<%#x>", ($arg0)
else
- if $etp_arch64
- set $etp_ref_1_i = (int) $etp_ref_1_p->data.ui32[0]
- if (($etp_ref_1_i + 1) > (2 * ($etp_ref_1_p->header >> 6)))
- set $etp_ref_1_error = 1
- else
- set $etp_ref_1_nump = &$etp_ref_1_p->data.ui32[1]
+ set $etp_magic_ref = 0
+ set $etp_ref_1_i = 3
+ set $etp_ref_1_error = 0
+ set $etp_ref_1_nump = (Uint32 *) 0
+ if etp_ref_header == etp_magic_ref_header
+ if $etp_ref_1_p->marker != 0xffffffff
+ set $etp_magic_ref = 1
end
+ else
+ if $etp_ref_1_p->header == etp_magic_ref_header
+ set $etp_magic_ref = 1
+ end
+ end
+ if $etp_magic_ref == 0
+ set $etp_ref_1_nump = $etp_ref_1_p->num
else
- set $etp_ref_1_i = (int) ($etp_ref_1_p->header >> 6)
- set $etp_ref_1_nump = &$etp_ref_1_p->data.ui32[0]
+ set $etp_ref_1_nump = ((ErtsMRefThing *) $etp_ref_1_p)->mb->refn
end
- end
- if $etp_ref_1_error
- printf "#InternalRefError<%#x>", ($arg0)
- else
printf "#Ref<0"
set $etp_ref_1_i--
while $etp_ref_1_i >= 0
@@ -1038,12 +1092,10 @@ document etp-mfa
%---------------------------------------------------------------------------
end
-
-
-define etp-cp-1
+define etp-cp-func-info-1
# Args: Eterm cp
#
-# Non-reentrant
+# Non-reentrant, takes cp, sets $etp_cp_p to MFA in func_info
#
set $etp_cp = (Eterm)($arg0)
set $etp_ranges = &r[(int)the_active_code_index]
@@ -1065,8 +1117,8 @@ define etp-cp-1
set $etp_cp_mid = $etp_cp_low + ($etp_cp_high-$etp_cp_low)/2
end
if $etp_cp_p
- # 12 = MI_FUNCTIONS
- set $etp_cp_low = (Eterm**)($etp_cp_p->start + 12)
+ # 13 = MI_FUNCTIONS
+ set $etp_cp_low = (Eterm**)($etp_cp_p->start + 13)
# 0 = MI_NUM_FUNCTIONS
set $etp_cp_high = $etp_cp_low +$etp_cp_p->start[0]
set $etp_cp_p = 0
@@ -1085,8 +1137,21 @@ define etp-cp-1
end
end
if $etp_cp_p
+ set $cp_cp_p_offset = ($etp_cp-((Eterm)($etp_cp_p-2)))
+ else
+ set $cp_cp_p_offset = 0
+ end
+end
+
+define etp-cp-1
+# Args: Eterm cp
+#
+# Non-reentrant
+#
+ etp-cp-func-info-1 $arg0
+ if $etp_cp_p
printf "#Cp"
- etp-mfa-1 ($etp_cp_p) ($etp_cp-((Eterm)($etp_cp_p-2)))
+ etp-mfa-1 $etp_cp_p $cp_cp_p_offset
else
if $etp_cp == beam_apply+1
printf "#Cp<terminate process normally>"
@@ -1167,6 +1232,141 @@ end
# Commands for special term bunches.
#
+define etp-sig-int
+ set $etp_sig_is_message = 0
+ set $etp_sig_tag = ($arg0)->m[0]
+ if ($etp_sig_tag & 0x3) != 0 || $etp_sig_tag == etp_the_non_value
+ set $etp_sig_is_message = !0
+ # A message
+ if $etp_sig_tag != etp_the_non_value
+ etp-1 $etp_sig_tag 0
+ else
+ print "!ENCODED-DIST-MSG"
+ end
+ if ($arg0)->m[1] != $etp_nil
+ printf " @token= "
+ etp-1 ($arg0)->m[1] 0
+ end
+ printf " @from= "
+ etp-1 ($arg0)->m[2] 0
+ else
+ if ($etp_sig_tag & 0x3f) != 0x30
+ print "!INVALID-SIGNAL"
+ else
+ set $etp_sig_op = (($etp_sig_tag >> 6) & 0xff)
+ set $etp_sig_type = (($etp_sig_tag >> 14) & 0xff)
+ if $etp_sig_op == 0
+ printf "!EXIT[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 1
+ printf "!EXIT-LINKED[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 2
+ printf "!MONITOR-DOWN[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 3
+ printf "!MONITOR[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 4
+ printf "!DEMONITOR[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 5
+ printf "!LINK[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 6
+ printf "!UNLINK[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 7
+ printf "!GROUP-LEADER[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 8
+ printf "!TRACE-CHANGE-STATE[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 9
+ printf "!PERSISTENT-MONITOR-MESSAGE[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 10
+ printf "!IS-ALIVE[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 11
+ printf "!PROCESS-INFO[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 12
+ printf "!SYNC-SUSPEND[%d]", $etp_sig_type
+ else
+ if $etp_sig_op == 13
+ printf "!RPC[%d]", $etp_sig_type
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+
+define etp-sigq-int
+# Args: ErlMessageQueue*
+#
+# Non-reentrant
+#
+ set $etp_sig = ($arg0)
+ set $etp_sig_save = ($arg1)
+ set $etp_sig_save_last = ($arg2)
+ set $etp_sigq_msig_len = 0
+ set $etp_sigq_nmsig_len = 0
+
+ printf " ["
+ while $etp_sig != (void *) 0
+ set $etp_sig_next = $etp_sig->next
+ if $etp_sig != ($arg0)
+ printf " "
+ end
+ etp-sig-int $etp_sig
+ if $etp_sig_is_message
+ set $etp_sigq_msig_len++
+ else
+ set $etp_sigq_nmsig_len++
+ end
+ if $etp_sig_next
+ printf ","
+ end
+ if $etp_sig_save && *$etp_sig_save == $etp_sig
+ printf " %% <== SAVE"
+ else
+ if $etp_sig_save_last && *$etp_sig_save_last == $etp_sig
+ printf " %% <== SAVED_LAST"
+ end
+ end
+ if $etp_sig_next
+ printf "\n"
+ end
+ set $etp_sig = $etp_sig_next
+ end
+ printf "]\n\n"
+ printf " Message signals: %d\n", $etp_sigq_msig_len
+ printf " Non-message signals: %d\n\n", $etp_sigq_nmsig_len
+end
+
+define etp-sigqs
+ printf " --- Inner signal queue (message queue) ---\n"
+ etp-sigq-int ($arg0)->sig_qs.first ($arg0)->sig_qs.save ($arg0)->sig_qs.saved_last
+ printf " --- Middle signal queue ---\n"
+ etp-sigq-int ($arg0)->sig_qs.cont ($arg0)->sig_qs.save ($arg0)->sig_qs.saved_last
+ printf " --- Outer queue ---\n"
+ etp-sigq-int ($arg0)->sig_inq.first ($arg0)->sig_qs.save ($arg0)->sig_qs.saved_last
+end
+
define etp-msgq
# Args: ErlMessageQueue*
#
@@ -1225,7 +1425,7 @@ document etp-msgq
% Sequential trace tokens are included in comments and
% the current match position in the queue is marked '<='.
%
-% A process's message queue is process_tab[i]->msg.
+% A process's message queue is process_tab[i]->sig_qs.
%---------------------------------------------------------------------------
end
@@ -1249,23 +1449,30 @@ document etpf-msgq
%---------------------------------------------------------------------------
end
-
+define etp-stack-preamble
+ set $etp_stack_p = ($arg0)->stop
+ set $etp_stack_end = ($arg0)->hend
+ printf "%% Stacktrace (%u)\n", $etp_stack_end-$etp_stack_p
+ etp-1 ((Eterm)($arg0)->i) 0
+ printf " (I)\n"
+ if ($arg0)->cp != 0
+ etp-1 ((Eterm)($arg0)->cp) 0
+ printf " (cp)\n"
+ end
+end
define etp-stacktrace
# Args: Process*
#
# Non-reentrant
#
- set $etp_stacktrace_p = ($arg0)->stop
- set $etp_stacktrace_end = ($arg0)->hend
- printf "%% Stacktrace (%u): ", $etp_stacktrace_end-$etp_stacktrace_p
- etp ($arg0)->cp
- while $etp_stacktrace_p < $etp_stacktrace_end
- if ($etp_stacktrace_p[0] & 0x3) == 0x0
+ etp-stack-preamble ($arg0)
+ while $etp_stack_p < $etp_stack_end
+ if ($etp_stack_p[0] & 0x3) == 0x0
# Continuation pointer
- etp $etp_stacktrace_p[0]
+ etp $etp_stack_p[0]
end
- set $etp_stacktrace_p++
+ set $etp_stack_p++
end
end
@@ -1284,13 +1491,10 @@ define etp-stackdump
#
# Non-reentrant
#
- set $etp_stackdump_p = ($arg0)->stop
- set $etp_stackdump_end = ($arg0)->hend
- printf "%% Stackdump (%u): ", $etp_stackdump_end-$etp_stackdump_p
- etp ($arg0)->cp
- while $etp_stackdump_p < $etp_stackdump_end
- etp $etp_stackdump_p[0]
- set $etp_stackdump_p++
+ etp-stack-preamble ($arg0)
+ while $etp_stack_p < $etp_stack_end
+ etp $etp_stack_p[0]
+ set $etp_stack_p++
end
end
@@ -1525,8 +1729,8 @@ define etp-term-dump-pid
#
set $etp_pid_1 = (Eterm)($arg0)
if ($etp_pid_1 & 0xF) == 0x3
- if (etp_arch_bits == 64 && etp_halfword == 0)
- if (etp_big_endian)
+ if (etp_arch_bits == 64)
+ if (etp_endianness > 0)
set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 36) & 0x0fffffff)
else
set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 4) & 0x0fffffff)
@@ -1570,8 +1774,8 @@ end
define etp-pid2pix-1
# Args: Eterm
#
- if (etp_arch_bits == 64 && etp_halfword == 0)
- if (etp_big_endian)
+ if (etp_arch_bits == 64)
+ if (etp_endianness > 0)
set $etp_pix = (int) (((Uint64) $arg0) & 0x0fffffff)
else
set $etp_pix = (int) ((((Uint64) $arg0) >> 32) & 0x0fffffff)
@@ -1605,8 +1809,29 @@ end
define etp-proc-state-int
# Args: int
#
- if ($arg0 & 0xff000000)
- printf "GARBAGE | "
+ if ($arg0 & 0x80000000)
+ printf "GARBAGE<0x80000000> | "
+ end
+ if ($arg0 & 0x40000000)
+ printf "dirty-running-sys | "
+ end
+ if ($arg0 & 0x20000000)
+ printf "dirty-running | "
+ end
+ if ($arg0 & 0x10000000)
+ printf "dirty-active-sys | "
+ end
+ if ($arg0 & 0x8000000)
+ printf "dirty-io-proc | "
+ end
+ if ($arg0 & 0x4000000)
+ printf "dirty-cpu-proc | "
+ end
+ if ($arg0 & 0x2000000)
+ printf "sig-q | "
+ end
+ if ($arg0 & 0x1000000)
+ printf "off-heap-msgq | "
end
if ($arg0 & 0x800000)
printf "delayed-sys | "
@@ -1624,10 +1849,10 @@ define etp-proc-state-int
printf "active-sys | "
end
if ($arg0 & 0x80000)
- printf "trapping-exit | "
+ printf "sig-in-q | "
end
if ($arg0 & 0x40000)
- printf "bound | "
+ printf "sys-tasks | "
end
if ($arg0 & 0x20000)
printf "garbage-collecting | "
@@ -1645,7 +1870,7 @@ define etp-proc-state-int
printf "active | "
end
if ($arg0 & 0x1000)
- printf "pending-exit | "
+ printf "unused | "
end
if ($arg0 & 0x800)
printf "exiting | "
@@ -1730,59 +1955,199 @@ document etp-proc-state
%---------------------------------------------------------------------------
end
-define etp-process-info
+define etp-proc-flags-int
+# Args: int
+#
+ if ($arg0 & ~0xfffffff)
+ printf "GARBAGE<%x> ", ($arg0 & ~0x1ffffff)
+ end
+ if ($arg0 & 0x8000000)
+ printf "trap-exit "
+ end
+ if ($arg0 & 0x4000000)
+ printf "local-sigs-only "
+ end
+ if ($arg0 & 0x2000000)
+ printf "hibernated "
+ end
+ if ($arg0 & 0x1000000)
+ printf "dirty-minor-gc "
+ end
+ if ($arg0 & 0x800000)
+ printf "dirty-major-gc "
+ end
+ if ($arg0 & 0x400000)
+ printf "dirty-gc-hibernate "
+ end
+ if ($arg0 & 0x200000)
+ printf "dirty-cla "
+ end
+ if ($arg0 & 0x100000)
+ printf "delayed-del-proc "
+ end
+ if ($arg0 & 0x80000)
+ printf "hipe-mode "
+ end
+ if ($arg0 & 0x40000)
+ printf "have-blocked-nmsb "
+ end
+ if ($arg0 & 0x20000)
+ printf "shdlr-onln-wait-q "
+ end
+ if ($arg0 & 0x10000)
+ printf "delay-gc "
+ end
+ if ($arg0 & 0x8000)
+ printf "abandoned-heap-use "
+ end
+ if ($arg0 & 0x4000)
+ printf "off-heap-msgq-chng "
+ end
+ if ($arg0 & 0x2000)
+ printf "on-heap-msgq "
+ end
+ if ($arg0 & 0x1000)
+ printf "off-heap-msgq "
+ end
+ if ($arg0 & 0x800)
+ printf "disable-gc "
+ end
+ if ($arg0 & 0x400)
+ printf "force-gc "
+ end
+ if ($arg0 & 0x200)
+ printf "p2pnr-resched "
+ end
+ if ($arg0 & 0x100)
+ printf "have-blocked-msb "
+ end
+ if ($arg0 & 0x80)
+ printf "using-ddll "
+ end
+ if ($arg0 & 0x40)
+ printf "distribution "
+ end
+ if ($arg0 & 0x20)
+ printf "using-db "
+ end
+ if ($arg0 & 0x10)
+ printf "need-fullsweep "
+ end
+ if ($arg0 & 0x8)
+ printf "heap-grow "
+ end
+ if ($arg0 & 0x4)
+ printf "timo "
+ end
+ if ($arg0 & 0x2)
+ printf "inslpqueue "
+ end
+ if ($arg0 & 0x1)
+ printf "hibernate-sched "
+ end
+ printf "\n"
+end
+
+document etp-proc-flags-int
+%---------------------------------------------------------------------------
+% etp-proc-flags-int int
+%
+% Print flags of process flags value
+%---------------------------------------------------------------------------
+end
+
+
+define etp-proc-flags
+# Args: Process*
+#
+ set $flags_int = ((Process *) $arg0)->flags
+ etp-proc-flags-int $flags_int
+end
+
+document etp-proc-flags
+%---------------------------------------------------------------------------
+% etp-proc-flags Process*
+%
+% Print flags of process
+%---------------------------------------------------------------------------
+end
+
+define etp-process-info-int
# Args: Process*
#
printf " Pid: "
- etp-1 ($arg0)->common.id
+ set $etp_proc = ((Process*)$arg0)
+ etp-1 $etp_proc->common.id
printf "\n State: "
- etp-proc-state $arg0
+ etp-proc-state $etp_proc
+ printf "\n Flags: "
+ etp-proc-flags $etp_proc
if $proxy_process != 0
- printf " Pointer: (Process *) %p\n", $arg0
+ printf " Pointer: (Process *) %p\n", $etp_proc
printf " *** PROXY process struct *** refer to: \n"
- etp-pid2proc-1 $arg0->common.id
+ etp-pid2proc-1 $etp_proc->common.id
etp-process-info $proc
else
- if (*(((Uint32 *) &(((Process *) $arg0)->state))) & 0x4) == 0
- if ($arg0->common.u.alive.reg)
+ if (*(((Uint32 *) &($etp_proc->state))) & 0x4) == 0
+ if ($etp_proc->common.u.alive.reg)
printf " Registered name: "
- etp-1 $arg0->common.u.alive.reg->name
+ etp-1 $etp_proc->common.u.alive.reg->name
printf "\n"
end
end
- if ($arg0->current)
- printf " Current function: "
- etp-1 $arg0->current[0]
+ printf " Current function: "
+ if ($etp_proc->current)
+ etp-1 $etp_proc->current->module
printf ":"
- etp-1 $arg0->current[1]
- printf "/%d\n", $arg0->current[2]
+ etp-1 $etp_proc->current->function
+ printf "/%d\n", $etp_proc->current->arity
+ else
+ printf "unknown\n"
end
- if ($arg0->cp)
- printf " CP: "
- etp-cp-1 $arg0->cp
+ printf " CP: "
+ if ($etp_proc->cp)
+ etp-cp-1 $etp_proc->cp
printf "\n"
+ else
+ printf "unknown\n"
end
- if ($arg0->i)
- printf " I: "
- etp-cp-1 $arg0->i
+ printf " I: "
+ if ($etp_proc->i)
+ etp-cp-1 $etp_proc->i
printf "\n"
+ else
+ printf "unknown\n"
end
- printf " Heap size: %ld\n", $arg0->heap_sz
- if ($arg0->old_heap)
- printf " Old-heap size: %ld\n", $arg0->old_hend - $arg0->old_heap
+ printf " Heap size: %ld\n", $etp_proc->heap_sz
+ printf " Old-heap size: "
+ if ($etp_proc->old_heap)
+ printf "%ld\n", $etp_proc->old_hend - $etp_proc->old_heap
+ else
+ printf "0\n"
end
- printf " Mbuf size: %ld\n", $arg0->mbuf_sz
+ printf " Mbuf size: %ld\n", $etp_proc->mbuf_sz
if (etp_smp_compiled)
- printf " Msgq len: %ld (inner=%ld, outer=%ld)\n", ($arg0->msg.len + $arg0->msg_inq.len), $arg0->msg.len, $arg0->msg_inq.len
+ printf " Msgq len: %ld (inner=%ld, outer=%ld)\n", ($etp_proc->sig_qs.len + $etp_proc->sig_inq.len), $etp_proc->sig_qs.len, $etp_proc->sig_inq.len
else
- printf " Msgq len: %d\n", $arg0->msg.len
+ printf " Msgq len: %d\n", $etp_proc->sig_qs.len
end
printf " Parent: "
- etp-1 $arg0->parent
- printf "\n Pointer: (Process *) %p\n", $arg0
+ etp-1 ((Eterm)($etp_proc->parent))
+ printf "\n Pointer: (Process *) %p\n", $etp_proc
+ end
+ if ($arg1)
+ etp-sigqs $etp_proc
end
end
+define etp-process-info
+ etp-process-info-int ($arg0) 0
+end
+
+define etp-process-info-x
+ etp-process-info-int ($arg0) !0
+end
+
document etp-process-info
%---------------------------------------------------------------------------
% etp-process-info Process*
@@ -1791,17 +2156,28 @@ document etp-process-info
%---------------------------------------------------------------------------
end
-define etp-processes
+define etp-processes-int
if (!erts_initialized)
printf "No processes, since system isn't initialized!\n"
else
set $proc_ix = 0
- while $proc_ix < erts_proc.r.o.max
- set $proc = (Process *) *((UWord *) &erts_proc.r.o.tab[$proc_ix])
- if ($proc != ((Process *) 0) && $proc != &erts_invalid_process)
+ set $proc_max_ix = erts_proc.r.o.max
+ set $proc_tab = erts_proc.r.o.tab
+ set $proc_cnt = erts_proc.vola.tile.count.counter
+ set $invalid_proc = &erts_invalid_process
+ set $proc_decentile = $proc_max_ix / 10
+ set $proc_printile = $proc_decentile
+ while $proc_ix < $proc_max_ix && $proc_cnt > 0
+ set $proc = (Process *) *((UWord *) ($proc_tab + $proc_ix))
+ if ($proc != ((Process *) 0) && $proc != $invalid_proc)
printf "---\n"
printf " Pix: %d\n", $proc_ix
- etp-process-info $proc
+ etp-process-info-int $proc ($arg0)
+ set $proc_cnt--
+ end
+ if $proc_ix == $proc_printile
+ printf "--- %d%% (%d / %d) searched\n", $proc_printile / $proc_decentile * 10, $proc_ix, $proc_max_ix
+ set $proc_printile += $proc_decentile
end
set $proc_ix++
end
@@ -1809,6 +2185,14 @@ define etp-processes
end
end
+define etp-processes
+ etp-processes-int 0
+end
+
+define etp-processes-x
+ etp-processes-int !0
+end
+
document etp-processes
%---------------------------------------------------------------------------
% etp-processes
@@ -1845,57 +2229,58 @@ end
define etp-process-memory-info
# Args: Process*
#
- if ((*(((Uint32 *) &(((Process *) $arg0)->state)))) & 0x400000)
+ set $etp_pmem_proc = ((Process *) $arg0)
+ if ((*(((Uint32 *) &($etp_pmem_proc->state)))) & 0x400000)
set $proxy_process = 1
else
set $proxy_process = 0
end
printf " "
- etp-1 $arg0->common.id
- printf ": (Process *) %p ", $arg0
+ etp-1 $etp_pmem_proc->common.id
+ printf ": (Process *) %p ", $etp_pmem_proc
if $proxy_process != 0
- printf "(Process *) %p ", $arg0
+ printf "(Process *) %p ", $etp_pmem_proc
printf " *** PROXY process struct *** refer to next: \n"
- etp-pid2proc-1 $arg0->common.id
+ etp-pid2proc-1 $etp_pmem_proc->common.id
printf " -"
etp-process-memory-info $proc
else
- printf " [Heap: %5ld", $arg0->heap_sz
- if ($arg0->old_heap)
- printf " | %5ld", $arg0->old_hend - $arg0->old_heap
+ printf " [Heap: %5ld", $etp_pmem_proc->heap_sz
+ if ($etp_pmem_proc->old_heap)
+ printf " | %5ld", $etp_pmem_proc->old_hend - $etp_pmem_proc->old_heap
else
printf " | none "
end
- printf "] [Mbuf: %5ld", $arg0->mbuf_sz
+ printf "] [Mbuf: %5ld", $etp_pmem_proc->mbuf_sz
if (etp_smp_compiled)
- printf " | %3ld (%3ld | %3ld)", ($arg0->msg.len + $arg0->msg_inq.len), $arg0->msg.len, $arg0->msg_inq.len
+ printf " | %3ld (%3ld | %3ld)", ($etp_pmem_proc->sig_qs.len + $etp_pmem_proc->sig_inq.len), $etp_pmem_proc->sig_qs.len, $etp_pmem_proc->sig_inq.len
else
- printf " | %3ld", $arg0->msg.len
+ printf " | %3ld", $etp_pmem_proc->sig_qs.len
end
printf "] "
- if ($arg0->i)
+ if ($etp_pmem_proc->i)
printf " I: "
- etp-cp-1 $arg0->i
+ etp-cp-1 $etp_pmem_proc->i
printf " "
end
- if ($arg0->current)
- etp-1 $arg0->current[0]
+ if ($etp_pmem_proc->current)
+ etp-1 $etp_pmem_proc->current[0]
printf ":"
- etp-1 $arg0->current[1]
- printf "/%d ", $arg0->current[2]
+ etp-1 $etp_pmem_proc->current[1]
+ printf "/%d ", $etp_pmem_proc->current[2]
end
- if (*(((Uint32 *) &(((Process *) $arg0)->state))) & 0x4) == 0
- if ($arg0->common.u.alive.reg)
- etp-1 $arg0->common.u.alive.reg->name
+ if (*(((Uint32 *) &(((Process *) $etp_pmem_proc)->state))) & 0x4) == 0
+ if ($etp_pmem_proc->common.u.alive.reg)
+ etp-1 $etp_pmem_proc->common.u.alive.reg->name
printf " "
end
end
- if ($arg0->cp)
+ if ($etp_pmem_proc->cp)
printf " CP: "
- etp-cp-1 $arg0->cp
+ etp-cp-1 $etp_pmem_proc->cp
printf " "
end
printf "\n"
@@ -1913,8 +2298,8 @@ end
define etp-port-id2pix-1
# Args: Eterm
#
- if (etp_arch_bits == 64 && etp_halfword == 0)
- if (etp_big_endian)
+ if (etp_arch_bits == 64)
+ if (etp_endianness > 0)
set $etp_pix = (int) (((Uint64) $arg0) & 0x0fffffff)
elser
set $etp_pix = (int) ((((Uint64) $arg0) >> 32) & 0x0fffffff)
@@ -1948,40 +2333,46 @@ end
define etp-port-sched-flags-int
# Args: int
#
- if ($arg0 & 0x1)
+ if ($arg0 & (1 << 0))
printf " in-run-queue"
end
- if ($arg0 & 0x2)
+ if ($arg0 & (1 << 1))
printf " executing"
end
- if ($arg0 & 0x4)
+ if ($arg0 & (1 << 2))
printf " have-tasks"
end
- if ($arg0 & 0x8)
+ if ($arg0 & (1 << 3))
printf " exited"
end
- if ($arg0 & 0x10)
+ if ($arg0 & (1 << 4))
printf " busy-port"
end
- if ($arg0 & 0x20)
+ if ($arg0 & (1 << 5))
printf " busy-port-q"
end
- if ($arg0 & 0x40)
+ if ($arg0 & (1 << 6))
printf " chk-unset-busy-port-q"
end
- if ($arg0 & 0x80)
+ if ($arg0 & (1 << 7))
printf " have-busy-tasks"
end
- if ($arg0 & 0x100)
+ if ($arg0 & (1 << 8))
printf " have-nosuspend-tasks"
end
- if ($arg0 & 0x200)
+ if ($arg0 & (1 << 9))
printf " parallelism"
end
- if ($arg0 & 0x400)
+ if ($arg0 & (1 << 10))
printf " force-sched"
end
- if ($arg0 & 0xfffff800)
+ if ($arg0 & (1 << 11))
+ printf " exiting"
+ end
+ if ($arg0 & (1 << 12))
+ printf " exec-imm"
+ end
+ if ($arg0 & 0xffffc000)
printf " GARBAGE"
end
printf "\n"
@@ -2093,23 +2484,24 @@ define etp-port-info
# Args: Port*
#
printf " Port: "
- etp-1 $arg0->common.id
- printf "\n Name: %s\n", $arg0->name
+ set $etp_pinfo_port = ((Port*)$arg0)
+ etp-1 $etp_pinfo_port->common.id
+ printf "\n Name: %s\n", $etp_pinfo_port->name
printf " State:"
- etp-port-state $arg0
+ etp-port-state $etp_pinfo_port
printf " Scheduler flags:"
- etp-port-sched-flags $arg0
- if (*(((Uint32 *) &(((Port *) $arg0)->state))) & 0x5C00) == 0
- if ($arg0->common.u.alive.reg)
+ etp-port-sched-flags $etp_pinfo_port
+ if (*(((Uint32 *) &($etp_pinfo_port->state))) & 0x5C00) == 0
+ if ($etp_pinfo_port->common.u.alive.reg)
printf " Registered name: "
- etp-1 $arg0->common.u.alive.reg->name
+ etp-1 $etp_pinfo_port->common.u.alive.reg->name
printf "\n"
end
end
printf " Connected: "
- set $connected = *(((Eterm *) &(((Port *) $arg0)->connected)))
+ set $connected = *(((Eterm *) &(((Port *) $etp_pinfo_port)->connected)))
etp-1 $connected
- printf "\n Pointer: (Port *) %p\n", $arg0
+ printf "\n Pointer: (Port *) %p\n", $etp_pinfo_port
end
document etp-port-info
@@ -2120,22 +2512,32 @@ document etp-port-info
%---------------------------------------------------------------------------
end
-
define etp-ports
if (!erts_initialized)
printf "No ports, since system isn't initialized!\n"
else
set $port_ix = 0
- while $port_ix < erts_port.r.o.max
- set $port = (Port *) *((UWord *) &erts_port.r.o.tab[$port_ix])
- if ($port != ((Port *) 0) && $port != &erts_invalid_port)
+ set $port_max_ix = erts_port.r.o.max
+ set $port_tab = erts_port.r.o.tab
+ set $port_cnt = erts_proc.vola.tile.count.counter
+ set $invalid_port = &erts_invalid_port
+ set $port_decentile = $port_max_ix / 10
+ set $port_printile = $port_decentile
+ while $port_ix < $port_max_ix && $port_cnt > 0
+ set $port = (Port *) *((UWord *) ($port_tab + $port_ix))
+ if ($port != ((Port *) 0) && $port != $invalid_port)
if (*(((Uint32 *) &(((Port *) $port)->state))) & 0x100) == 0
# I.e, not free
printf "---\n"
printf " Pix: %d\n", $port_ix
etp-port-info $port
+ set $port_cnt--
end
end
+ if $port_ix == $port_printile
+ printf "--- %d%% (%d / %d) searched\n", $port_printile / $port_decentile * 10, $port_ix, $port_max_ix
+ set $port_printile += $port_decentile
+ end
set $port_ix++
end
printf "---\n",
@@ -2256,8 +2658,20 @@ define etp-rq-flags-int
if ($arg0 & 0x4000000)
printf " protected"
end
- if ($arg0 & ~0x7ffffff)
- printf " GARBAGE(0x%x)", ($arg0 & ~0x3ffffff)
+ if ($arg0 & 0x8000000)
+ printf " exec"
+ end
+ if ($arg0 & 0x10000000)
+ printf " msb_exec"
+ end
+ if ($arg0 & 0x20000000)
+ printf " misc_op"
+ end
+ if ($arg0 & 0x40000000)
+ printf " halting"
+ end
+ if ($arg0 & ~0x7fffffff)
+ printf " GARBAGE(0x%x)", ($arg0 & ~0x7fffffff)
end
printf "\n"
end
@@ -2289,6 +2703,9 @@ define etp-ssi-flags
if ($arg0 & 0x10)
printf " suspended"
end
+ if ($arg0 & 0x20)
+ printf " msb_exec"
+ end
printf "\n"
end
@@ -2317,25 +2734,37 @@ define etp-aux-work-flags
printf " fix-alloc-lower-lim"
end
if ($arg0 & 0x10)
- printf " async-ready"
+ printf " later-op"
end
if ($arg0 & 0x20)
- printf " async-ready-clean"
+ printf " canceled-timers"
end
if ($arg0 & 0x40)
- printf " misc-work-thr-prgr"
+ printf " canceled-timers-thr-prgr"
end
if ($arg0 & 0x80)
- printf " misc-work"
+ printf " async-ready"
end
if ($arg0 & 0x100)
- printf " check-children"
+ printf " async-ready-clean"
end
if ($arg0 & 0x200)
- printf " set-tmo"
+ printf " misc-thr-prgr"
end
if ($arg0 & 0x400)
- printf " mseg-cached-check"
+ printf " misc"
+ end
+ if ($arg0 & 0x800)
+ printf " set-tmo"
+ end
+ if ($arg0 & 0x1000)
+ printf " mseg-cache-check"
+ end
+ if ($arg0 & 0x2000)
+ printf " yield"
+ end
+ if ($arg0 & 0x1000)
+ printf " reap-ports"
end
if ($arg0 & ~0x7ff)
printf " GARBAGE"
@@ -2356,57 +2785,238 @@ define etp-schedulers
if (!erts_initialized)
printf "No schedulers, since system isn't initialized!\n"
else
+ set $sched_type = 0
set $sched_ix = 0
while $sched_ix < erts_no_schedulers
- printf "--- Scheduler %d ---\n", $sched_ix+1
- printf " IX: %d\n", $sched_ix
- if (erts_aligned_scheduler_data[$sched_ix].esd.cpu_id < 0)
- printf " CPU Binding: unbound\n"
- else
- printf " CPU Binding: %d\n", erts_aligned_scheduler_data[$sched_ix].esd.cpu_id
- end
- printf " Aux work Flags:"
- set $aux_work_flags = *((Uint32 *) &erts_aligned_scheduler_data[$sched_ix].esd.ssi->aux_work)
- etp-aux-work-flags $aux_work_flags
- printf " Sleep Info Flags:"
- set $ssi_flags = *((Uint32 *) &erts_aligned_scheduler_data[$sched_ix].esd.ssi->flags)
- etp-ssi-flags $ssi_flags
- printf " Pointer: (ErtsSchedulerData *) %p\n", &erts_aligned_scheduler_data[$sched_ix].esd
- printf " - Run Queue -\n"
- if (etp_smp_compiled)
- set $runq = erts_aligned_scheduler_data[$sched_ix].esd.run_queue
- else
- set $runq = &erts_aligned_run_queues[0].runq
- end
- printf " Length: total=%d", *((Uint32 *) &($runq->len))
- printf ", max=%d", *((Uint32 *) &($runq->procs.prio_info[0].len))
- printf ", high=%d", *((Uint32 *) &($runq->procs.prio_info[1].len))
- printf ", normal=%d", *((Uint32 *) &($runq->procs.prio_info[2].len))
- printf ", low=%d", *((Uint32 *) &($runq->procs.prio_info[3].len))
- printf ", port=%d\n", *((Uint32 *) &($runq->ports.info.len))
- if ($runq->misc.start)
- printf " Misc Jobs: yes\n"
- else
- printf " Misc Jobs: no\n"
- end
- set $rq_flags = *((Uint32 *) &($runq->flags))
- etp-rq-flags-int $rq_flags
- printf " Pointer: (ErtsRunQueue *) %p\n", $runq
-
+ etp-scheduler-info-internal
+ etp-run-queue-info-internal
set $sched_ix++
end
- printf "-------------------\n",
+ printf "---------------------\n"
+ if (erts_no_dirty_cpu_schedulers)
+ printf "\n\n"
+ set $sched_type = 1
+ set $sched_ix = 0
+ while $sched_ix < erts_no_dirty_cpu_schedulers
+ etp-scheduler-info-internal
+ set $sched_ix++
+ end
+ etp-run-queue-info-internal
+ printf "---------------------\n"
+ end
+ if (erts_no_dirty_io_schedulers)
+ printf "\n\n"
+ set $sched_type = 2
+ set $sched_ix = 0
+ while $sched_ix < erts_no_dirty_io_schedulers
+ etp-scheduler-info-internal
+ set $sched_ix++
+ end
+ etp-run-queue-info-internal
+ printf "---------------------\n"
+ end
end
end
document etp-schedulers
%---------------------------------------------------------------------------
% etp-schedulers
-%
+%
% Print misc info about all schedulers
%---------------------------------------------------------------------------
end
+define etp-scheduler-info-internal
+ if ($sched_type == 0)
+ printf "--- Scheduler %d ---\n", $sched_ix+1
+ set $sched_data=&erts_aligned_scheduler_data[$sched_ix].esd
+ else
+ if ($sched_type == 1)
+ printf "--- Dirty CPU Scheduler %d ---\n", $sched_ix+1
+ set $sched_data=&erts_aligned_dirty_cpu_scheduler_data[$sched_ix].esd
+ else
+ printf "--- Dirty I/O Scheduler %d ---\n", $sched_ix+1
+ set $sched_data=&erts_aligned_dirty_io_scheduler_data[$sched_ix].esd
+ end
+ end
+ printf " IX: %d\n", $sched_ix
+ if ($sched_data->cpu_id < 0)
+ printf " CPU Binding: unbound\n"
+ else
+ printf " CPU Binding: %d\n", $sched_data->cpu_id
+ end
+ printf " Aux work Flags:"
+ set $aux_work_flags = *((Uint32 *) &$sched_data->ssi->aux_work)
+ etp-aux-work-flags $aux_work_flags
+ printf " Sleep Info Flags:"
+ set $ssi_flags = *((Uint32 *) &$sched_data->ssi->flags)
+ etp-ssi-flags $ssi_flags
+ printf " Pointer: (ErtsSchedulerData *) %p\n", $sched_data
+end
+
+define etp-run-queue-info-internal
+ if ($sched_type == 0)
+ printf " - Run Queue -\n"
+ if (etp_smp_compiled)
+ set $runq = erts_aligned_scheduler_data[$sched_ix].esd.run_queue
+ else
+ set $runq = &erts_aligned_run_queues[0].runq
+ end
+ else
+ if ($sched_type == 1)
+ printf "\n--- Dirty CPU Run Queue ---\n"
+ set $runq = &erts_aligned_run_queues[erts_no_run_queues].runq
+ else
+ printf "\n--- Dirty I/O Run Queue ---\n"
+ set $runq = &erts_aligned_run_queues[erts_no_run_queues+1].runq
+ end
+ end
+ printf " Length: total=%d", *((Uint32 *) &($runq->len))
+ printf ", max=%d", *((Uint32 *) &($runq->procs.prio_info[0].len))
+ printf ", high=%d", *((Uint32 *) &($runq->procs.prio_info[1].len))
+ printf ", normal=%d", *((Uint32 *) &($runq->procs.prio_info[2].len))
+ printf ", low=%d", *((Uint32 *) &($runq->procs.prio_info[3].len))
+ printf ", port=%d\n", *((Uint32 *) &($runq->ports.info.len))
+ if ($runq->misc.start)
+ printf " Misc Jobs: yes\n"
+ else
+ printf " Misc Jobs: no\n"
+ end
+ set $rq_flags = *((Uint32 *) &($runq->flags))
+ etp-rq-flags-int $rq_flags
+ printf " Pointer: (ErtsRunQueue *) %p\n", $runq
+end
+
+define etp-fds
+ if $_exitsignal == -1
+ call erts_check_io_debug(0)
+ else
+ printf "Not yet implemented for core files"
+ end
+end
+
+define etp-disasm-1
+ set $code_ptr = ((BeamInstr*)$arg0)
+ set $addr = *$code_ptr
+ set $i = 0
+ while $i < (sizeof(opc) / sizeof(OpEntry))
+ if $addr == beam_ops[$i]
+ printf "%s %d", opc[$i].name, opc[$i].sz
+ set $next_i = $code_ptr + opc[$i].sz
+ set $i += 4999
+ end
+ set $i++
+ end
+end
+
+define etp-disasm
+ etp-cp-func-info-1 $arg0
+ if $etp_cp_p == 0
+ printf "invalid argument"
+ else
+ etp-mfa-1 $etp_cp_p $cp_cp_p_offset
+ printf ": "
+ etp-disasm-1 $arg0
+ printf "\r\n"
+ while $next_i < ((BeamInstr*)$arg1)
+ set $prev_i = $next_i
+ etp-cp-func-info-1 $next_i
+ etp-mfa-1 $etp_cp_p $cp_cp_p_offset
+ printf ": "
+ etp-disasm-1 $next_i
+ if $prev_i == $next_i
+ # ptr did not advance, we are inside some strange opcode with argument
+ set $next_i++
+ printf "instr argument"
+ end
+ printf "\r\n"
+ end
+ end
+end
+
+############################################################################
+#
+# Timer Wheel
+#
+
+define etp-timer-wheel
+# Args: TimerWheel
+ if (!erts_initialized)
+ printf "System not initialized!\n"
+ else
+ set $tiw = $arg0
+ printf "Number of timers: %d\n", $tiw->nto
+ printf "Min timeout pos: %d\n", $tiw->next_timeout_pos
+ printf "\n--- Soon Wheel ---\n"
+ set $ix = $tiw->pos & etp_tw_soon_wheel_mask
+ printf "Position: %ld (%d)\n", $tiw->pos, $ix
+ printf "Min timeout position: %ld (%d)\n", $tiw->soon.min_tpos, $tiw->soon.min_tpos & etp_tw_soon_wheel_mask
+ printf "Number of timers: %d\n", $tiw->soon.nto
+ set $slots = etp_tw_soon_wheel_size
+ while $slots > 0
+ set $tmr = $tiw->w[$ix]
+ if ($tmr != (ErtsTWheelTimer *) 0x0)
+ printf "---\n"
+ printf "Slot: %d\n", $ix
+ printf "\n"
+ while 1
+ printf "- Timeout pos: %ld\n", $tmr->timeout_pos
+ printf " Pointer: (ErtsTWheelTimer *) %p\n", $tmr
+ set $tmr = $tmr->next
+ if ($tmr == $tiw->w[$ix])
+ loop_break
+ end
+ end
+ end
+ set $ix++
+ if ($ix == (etp_tw_soon_wheel_first_slot + etp_tw_soon_wheel_size))
+ set $ix = etp_tw_soon_wheel_first_slot
+ end
+ set $slots--
+ end
+ printf "\n--- Later Wheel ---\n"
+ set $ix = (($tiw->later.pos >> etp_tw_later_wheel_shift) & etp_tw_later_wheel_mask) + etp_tw_later_wheel_first_slot
+ printf "Position: %ld (%d)\n", $tiw->later.pos, $ix
+ printf "Min timeout position: %ld (%d)\n", $tiw->later.min_tpos, (($tiw->later.min_tpos >> etp_tw_later_wheel_shift) & etp_tw_later_wheel_mask) + etp_tw_later_wheel_first_slot
+ printf "Number of timers: %d\n", $tiw->later.nto
+ set $slots = etp_tw_later_wheel_size
+ set $slot_pos = $tiw->later.pos
+ while $slots > 0
+ set $tmr = $tiw->w[$ix]
+ if ($tmr != (ErtsTWheelTimer *) 0x0)
+ printf "---\n"
+ printf "Slot: %d\n", $ix
+ printf "Slot Range: [%ld, %ld]\n", $slot_pos, $slot_pos + etp_tw_later_wheel_slot_size
+ printf "Pre timeout pos: %ld\n", $slot_pos - etp_tw_later_wheel_slot_size
+ printf "\n"
+ while 1
+ printf "- Timeout pos: %ld\n", $tmr->timeout_pos
+ printf " Pointer: (ErtsTWheelTimer *) %p\n", $tmr
+ set $tmr = $tmr->next
+ if ($tmr == $tiw->w[$ix])
+ loop_break
+ end
+ end
+ end
+ set $ix++
+ if ($ix == (etp_tw_later_wheel_first_slot + etp_tw_later_wheel_size))
+ set $ix = etp_tw_later_wheel_first_slot
+ end
+ set $slot_pos = $slot_pos + etp_tw_later_wheel_slot_size
+ set $slots--
+ end
+ end
+ printf "---\n"
+end
+
+document etp-disasm
+%---------------------------------------------------------------------------
+% etp-disasm StartI EndI
+%
+% Disassemble the code between StartI and EndI
+%---------------------------------------------------------------------------
+end
+
define etp-migration-info
set $minfo = (ErtsMigrationPaths *) *((UWord *) &erts_migration_paths)
set $rq_ix = 0
@@ -2435,18 +3045,16 @@ define etp-system-info
printf "Compile date: %s\n", etp_compile_date
printf "Arch: %s\n", etp_arch
printf "Endianness: "
- if (etp_big_endian)
+ if (etp_endianness > 0)
printf "Big\n"
else
- printf "Little\n"
+ if (etp_endianness < 0)
+ printf "Little\n"
+ else
+ printf "Unknown\n"
+ end
end
printf "Word size: %d-bit\n", etp_arch_bits
- printf "Halfword: "
- if (etp_halfword)
- printf "yes\n"
- else
- printf "no\n"
- end
printf "HiPE support: "
if (etp_hipe)
printf "yes\n"
@@ -3119,7 +3727,7 @@ define etp-chart
# Non-reentrant
etp-chart-start ($arg0)
set ($arg0) = ($arg0)
- etp-msgq (($arg0)->msg)
+ etp-msgq (($arg0)->sig_qs)
etp-stackdump ($arg0)
etp-dictdump (($arg0)->dictionary)
etp-dictdump (($arg0)->debug_dictionary)
@@ -3511,14 +4119,31 @@ document etp-block
%---------------------------------------------------------------------------
end
+define etp-smp-atomic
+ if (etp_smp_compiled)
+ set $arg1 = (($arg0).counter)
+ else
+ set $arg1 = ($arg0)
+ end
+end
+
+document etp-smp-atomic
+%---------------------------------------------------------------------------
+% Read an erts_smp_atomic_t value from $arg0 into $arg1
+%---------------------------------------------------------------------------
+end
+
define etp-carrier-blocks
set $etp_crr = (Carrier_t*) $arg0
- set $etp_alc = (Allctr_t*)($etp_crr->allctr.counter & ~7)
+ etp-smp-atomic $etp_crr->allctr $etp_alc
+ set $etp_alc = (Allctr_t*)($etp_alc & ~7)
+ set $etp_crr_end = ((char*)$etp_crr + ($etp_crr->chdr & ~7) - (sizeof(void*) & ~8))
set $etp_blk = (Block_t*) ((char*)$etp_crr + $etp_alc->mbc_header_size)
set $etp_prev_blk = 0
set $etp_error_cnt = 0
set $etp_ablk_cnt = 0
set $etp_fblk_cnt = 0
+ set $etp_aborted = 0
if $argc == 2
set $etp_be_silent = $arg1
@@ -3565,16 +4190,23 @@ define etp-carrier-blocks
end
set $etp_prev_blk = $etp_blk
set $etp_blk = (Block_t*) ((char*)$etp_blk + $etp_blk_sz)
+ if $etp_blk < (Block_t*) ((char*)$etp_prev_blk + $etp_alc->min_block_size) || $etp_blk >= $etp_crr_end
+ printf "ERROR: Invalid size of block at %#lx. ABORTING\n", $etp_prev_blk
+ set $etp_aborted = 1
+ loop_break
+ end
end
- if ((char*)$etp_blk + $etp_blk_sz) != ((char*)$etp_crr + ($etp_crr->chdr & ~7))
- printf "ERROR: Last block not at end of carrier\n"
- set $etp_error_cnt = $etp_error_cnt + 1
+ if !$etp_aborted
+ if ((char*)$etp_blk + $etp_blk_sz) != $etp_crr_end
+ printf "ERROR: Last block not at end of carrier\n"
+ set $etp_error_cnt = $etp_error_cnt + 1
+ end
+ printf "Allocated blocks: %u\n", $etp_ablk_cnt
+ printf "Free blocks: %u\n", $etp_fblk_cnt
end
- printf "Allocated blocks: %u\n", $etp_ablk_cnt
- printf "Free blocks: %u\n", $etp_fblk_cnt
if $etp_error_cnt
- printf "%u ERRORs reported above\n", $etp-error-cnt
+ printf "%u ERRORs reported above\n", $etp_error_cnt
end
end
@@ -3618,6 +4250,26 @@ document etp-address-to-beam-opcode
%---------------------------------------------------------------------------
end
+define etp-compile-debug
+ shell (cd $ERL_TOP && make emulator FLAVOR=smp TYPE=debug)
+end
+
+document etp-compile-debug
+%---------------------------------------------------------------------------
+% Re-compile the debug erlang emulator
+%---------------------------------------------------------------------------
+end
+
+define etp-compile
+ shell (cd $ERL_TOP && make emulator)
+end
+
+document etp-compile
+%---------------------------------------------------------------------------
+% Re-compile the erlang emulator
+%---------------------------------------------------------------------------
+end
+
############################################################################
# Toolbox parameter handling
@@ -3707,6 +4359,10 @@ document etp-init
%---------------------------------------------------------------------------
end
+define hook-run
+ set $_exitsignal = -1
+end
+
etp-init
help etp-init
etp-show
diff --git a/erts/etc/unix/etp-thr.py b/erts/etc/unix/etp-thr.py
index 64fb858d20..fb82dcaf1f 100644
--- a/erts/etc/unix/etp-thr.py
+++ b/erts/etc/unix/etp-thr.py
@@ -1,18 +1,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2013. All Rights Reserved.
+# Copyright Ericsson AB 2013-2016. 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/.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
#
-# 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.
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
diff --git a/erts/etc/unix/etp_commands.erl b/erts/etc/unix/etp_commands.erl
index 66cb76edbc..fe8f2dd556 100644
--- a/erts/etc/unix/etp_commands.erl
+++ b/erts/etc/unix/etp_commands.erl
@@ -1,18 +1,19 @@
%%
%% %CopyrightBegin%
%%
-%% Copyright Ericsson AB 2005-2009. All Rights Reserved.
+%% Copyright Ericsson AB 2005-2016. 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.
+%% Licensed under the Apache License, Version 2.0 (the "License");
+%% you may not use this file except in compliance with the License.
+%% You may obtain a copy of the License at
+%%
+%% http://www.apache.org/licenses/LICENSE-2.0
+%%
+%% Unless required by applicable law or agreed to in writing, software
+%% distributed under the License is distributed on an "AS IS" BASIS,
+%% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+%% See the License for the specific language governing permissions and
+%% limitations under the License.
%%
%% %CopyrightEnd%
%%
diff --git a/erts/etc/unix/etp_commands.mk b/erts/etc/unix/etp_commands.mk
index 1d9a269b68..983ee9f919 100644
--- a/erts/etc/unix/etp_commands.mk
+++ b/erts/etc/unix/etp_commands.mk
@@ -1,18 +1,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2009. All Rights Reserved.
+# Copyright Ericsson AB 2005-2016. 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.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
diff --git a/erts/etc/unix/format_man_pages b/erts/etc/unix/format_man_pages
index 93dcdcd8fa..0afff13571 100644
--- a/erts/etc/unix/format_man_pages
+++ b/erts/etc/unix/format_man_pages
@@ -3,18 +3,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2010. All Rights Reserved.
+# Copyright Ericsson AB 1996-2016. 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.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
@@ -106,7 +107,7 @@ case :"$TARGET" in
if [ -f $file ]; then
name=`echo $file | sed 's/\.[^.]*$//'`
sec=`echo $file | sed 's/.*\.//'`
- /usr/bin/groff -Tascii -mandoc $ERL_ROOT/man/man$sec/$file \
+ /usr/bin/groff -Tutf8 -mandoc $ERL_ROOT/man/man$sec/$file \
> $ERL_ROOT/man/cat$sec/$file
fi
done
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index 049e83f9e4..bfb3e1bd2c 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -1,18 +1,19 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2017. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
@@ -40,13 +41,16 @@
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
-
#ifdef HAVE_WORKING_POSIX_OPENPT
-#ifndef _XOPEN_SOURCE
-#define _XOPEN_SOURCE 600
-#endif
+# ifndef _XOPEN_SOURCE
+ /* On OS X, BSD and Solaris, we must leave _XOPEN_SOURCE undefined in order
+ * for the prototype of vsyslog() to be included.
+ */
+# if !(defined(__APPLE__) || defined(__FreeBSD__) || defined(__DragonFly__) || defined(__sun))
+# define _XOPEN_SOURCE 600
+# endif
+# endif
#endif
-
#include <sys/types.h>
#include <sys/wait.h>
#include <sys/stat.h>
@@ -64,6 +68,7 @@
#include <dirent.h>
#include <termios.h>
#include <time.h>
+
#ifdef HAVE_SYSLOG_H
# include <syslog.h>
#endif
@@ -73,6 +78,9 @@
#ifdef HAVE_UTMP_H
# include <utmp.h>
#endif
+#ifdef HAVE_LIBUTIL_H
+# include <libutil.h>
+#endif
#ifdef HAVE_UTIL_H
# include <util.h>
#endif
@@ -83,25 +91,81 @@
# include <stropts.h>
#endif
-#include "run_erl_common.h"
+#include "run_erl.h"
#include "safe_string.h" /* sn_printf, strn_cpy, strn_cat, etc */
+#ifdef O_NONBLOCK
+# define DONT_BLOCK_PLEASE O_NONBLOCK
+#else
+# define DONT_BLOCK_PLEASE O_NDELAY
+# ifndef EAGAIN
+# define EAGAIN -3898734
+# endif
+#endif
+
+#define noDEBUG
+
+#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 256
+
+#define PERM 0600
+#define STATUSFILENAME "/run_erl.log"
+#define PIPE_STUBNAME "erlang.pipe"
+#define PIPE_STUBLEN strlen(PIPE_STUBNAME)
+
+#ifndef FILENAME_MAX
+#define FILENAME_MAX 250
+#endif
+
+#ifndef O_SYNC
+#define O_SYNC 0
+#define USE_FSYNC 1
+#endif
+
#define MAX(x,y) ((x) > (y) ? (x) : (y))
+#define FILENAME_BUFSIZ FILENAME_MAX
+
/* prototypes */
static void usage(char *);
+static int create_fifo(char *name, int perm);
static int open_pty_master(char **name, int *sfd);
static int open_pty_slave(char *name);
static void pass_on(pid_t);
static void exec_shell(char **);
+static void status(const char *format,...);
+static void error_logf(int priority, int line, const char *format,...);
static void catch_sigchild(int);
+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);
+static void write_to_log(int* lfd, int* log_num, char* buf, int len);
static void daemon_init(void);
+static char *simple_basename(char *path);
static void init_outbuf(void);
static int outbuf_size(void);
static void clear_outbuf(void);
static char* outbuf_first(void);
static void outbuf_delete(int bytes);
static void outbuf_append(const char* bytes, int n);
+static int write_all(int fd, const char* buf, int len);
+static int extract_ctrl_seq(char* buf, int len);
+static void set_window_size(unsigned col, unsigned row);
+
+static ssize_t sf_write(int fd, const void *buffer, size_t len);
+static ssize_t sf_read(int fd, void *buffer, size_t len);
+static int sf_open(const char *path, int flags, mode_t mode);
+static int sf_close(int fd);
#ifdef DEBUG
static void show_terminal_settings(struct termios *t);
@@ -109,11 +173,20 @@ static void show_terminal_settings(struct termios *t);
/* static data */
static char fifo1[FILENAME_BUFSIZ], fifo2[FILENAME_BUFSIZ];
+static char statusfile[FILENAME_BUFSIZ];
+static char log_dir[FILENAME_BUFSIZ];
static char pipename[FILENAME_BUFSIZ];
static FILE *stdstatus = NULL;
+static int log_generations = DEFAULT_LOG_GENERATIONS;
+static int log_maxsize = DEFAULT_LOG_MAXSIZE;
+static int log_alive_minutes = DEFAULT_LOG_ALIVE_MINUTES;
+static int log_activity_minutes = DEFAULT_LOG_ACTIVITY_MINUTES;
+static int log_alive_in_gmt = 0;
+static char log_alive_format[ALIVE_BUFFSIZ+1];
static int run_daemon = 0;
static char *program_name;
static int mfd; /* master pty fd */
+static unsigned protocol_ver = RUN_ERL_LO_VER; /* assume lowest to begin with */
/*
* Output buffer.
@@ -144,13 +217,30 @@ static char* outbuf_in;
LOG_PID|LOG_CONS|LOG_NOWAIT,LOG_USER)
#endif
+#define ERROR0(Prio,Format) error_logf(Prio,__LINE__,Format"\n")
+#define ERROR1(Prio,Format,A1) error_logf(Prio,__LINE__,Format"\n",A1)
+#define ERROR2(Prio,Format,A1,A2) error_logf(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) error_logf(Prio,__LINE__,ADD_ERRNO(Format))
+#define ERRNO_ERR1(Prio,Format,A1) error_logf(Prio,__LINE__,ADD_ERRNO(Format),A1)
+
+
int main(int argc, char **argv)
{
int childpid;
int sfd = -1;
- char *ptyslave=NULL;
+ int fd;
+ char *p, *ptyslave=NULL;
int i = 1;
int off_argv;
+ int calculated_pipename = 0;
+ int highest_pipe_num = 0;
+ int sleepy_child = 0;
program_name = argv[0];
@@ -161,6 +251,11 @@ int main(int argc, char **argv)
init_outbuf();
+ if (!strcmp(argv[1],"-sleepy-child")) { /* For test purpose only */
+ sleepy_child = 1;
+ ++i;
+ }
+
if (!strcmp(argv[1],"-daemon")) {
daemon_init();
++i;
@@ -168,16 +263,122 @@ int main(int argc, char **argv)
off_argv = i;
strn_cpy(pipename, sizeof(pipename), argv[i++]);
-
- erts_run_erl_log_init(run_daemon,argv[i]);
+ strn_cpy(log_dir, sizeof(log_dir), argv[i]);
+ strn_cpy(statusfile, sizeof(statusfile), log_dir);
+ strn_cat(statusfile, sizeof(statusfile), STATUSFILENAME);
#ifdef DEBUG
- erts_run_erl_log_status("%s: pid is : %d\n", argv[0], getpid());
+ status("%s: pid is : %d\n", argv[0], getpid());
#endif
- /* Open read and write fifo */
- if (erts_run_erl_open_fifo(pipename,fifo1,fifo2))
- exit(1);
+ /* Get values for LOG file handling from the environment */
+ if ((p = getenv("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("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("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("RUN_ERL_LOG_ALIVE_IN_UTC")) && strcmp(p,"0")) {
+ ++log_alive_in_gmt;
+ }
+ if ((p = getenv("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("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);
+ }
+
+ /*
+ * 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);
+ 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), "%s.%d",
+ PIPE_STUBNAME, highest_pipe_num+1);
+ } /* if */
+
+ for(;;) {
+ /* write FIFO - is read FIFO for `to_erl' program */
+ strn_cpy(fifo1, sizeof(fifo1), pipename);
+ strn_cat(fifo1, sizeof(fifo1), ".r");
+ if (create_fifo(fifo1, PERM) < 0) {
+ ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for writing.", fifo1);
+ exit(1);
+ }
+
+ /* read FIFO - is write FIFO for `to_erl' program */
+ strn_cpy(fifo2, sizeof(fifo2), pipename);
+ strn_cat(fifo2, sizeof(fifo2), ".w");
+
+ /* Check that nobody is running run_erl already */
+ if ((fd = sf_open(fifo2, 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, sizeof(pipename), "%s.%d",
+ PIPE_STUBNAME, highest_pipe_num+1);
+ continue;
+ }
+ fprintf(stderr, "Erlang already running on pipe %s.\n", pipename);
+ exit(1);
+ }
+ if (create_fifo(fifo2, PERM) < 0) {
+ ERRNO_ERR1(LOG_ERR,"Cannot create FIFO %s for reading.", fifo2);
+ exit(1);
+ }
+ break;
+ }
/*
* Open master pseudo-terminal
@@ -197,6 +398,9 @@ int main(int argc, char **argv)
exit(1);
}
if (childpid == 0) {
+ if (sleepy_child)
+ sleep(1);
+
/* Child */
sf_close(mfd);
/* disassociate from control terminal */
@@ -249,7 +453,7 @@ int main(int argc, char **argv)
sf_close(2);
if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) {
- erts_run_erl_log_status("Cannot dup\n");
+ status("Cannot dup\n");
}
sf_close(sfd);
exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */
@@ -292,7 +496,9 @@ static void pass_on(pid_t childpid)
struct timeval timeout;
time_t last_activity;
char buf[BUFSIZ];
- int rfd, wfd=0;
+ char log_alive_buffer[ALIVE_BUFFSIZ+1];
+ int lognum;
+ int rfd, wfd=0, lfd=0;
int maxfd;
int ready;
int got_some = 0; /* from to_erl */
@@ -307,12 +513,13 @@ static void pass_on(pid_t childpid)
}
#ifdef DEBUG
- erts_run_erl_log_status("run_erl: %s opened for reading\n", fifo2);
+ status("run_erl: %s opened for reading\n", fifo2);
#endif
/* Open the log file */
- erts_run_erl_log_open();
+ lognum = find_next_log_num();
+ lfd = open_log(lognum, O_RDWR|O_APPEND|O_CREAT|O_SYNC);
/* Enter the work loop */
@@ -331,8 +538,7 @@ static void pass_on(pid_t childpid)
writefds_ptr = &writefds;
}
time(&last_activity);
- /* don't assume old BSD bug */
- timeout.tv_sec = erts_run_erl_log_alive_minutes()*60;
+ timeout.tv_sec = log_alive_minutes*60; /* don't assume old BSD bug */
timeout.tv_usec = 0;
ready = select(maxfd + 1, &readfds, writefds_ptr, NULL, &timeout);
if (ready < 0) {
@@ -347,7 +553,7 @@ static void pass_on(pid_t childpid)
FD_ZERO(&readfds);
FD_ZERO(&writefds);
} else {
- /* Some error occured */
+ /* Some error occurred */
ERRNO_ERR0(LOG_ERR,"Error in select.");
exit(1);
}
@@ -362,7 +568,28 @@ static void pass_on(pid_t childpid)
/* Check how long time we've been inactive */
time(&now);
- erts_run_erl_log_activity(!ready,now,last_activity);
+ if(!ready || 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",
+ ready?"":"ALIVE ", log_alive_buffer);
+ write_to_log(&lfd, &lognum, buf, strlen(buf));
+ }
}
/*
@@ -397,15 +624,17 @@ static void pass_on(pid_t childpid)
*/
if (FD_ISSET(mfd, &readfds)) {
#ifdef DEBUG
- erts_run_erl_log_status("Pty master read; ");
+ status("Pty master read; ");
#endif
if ((len = sf_read(mfd, buf, BUFSIZ)) <= 0) {
+ int saved_errno = errno;
sf_close(rfd);
if(wfd) sf_close(wfd);
sf_close(mfd);
unlink(fifo1);
unlink(fifo2);
if (len < 0) {
+ errno = saved_errno;
if(errno == EIO)
ERROR0(LOG_ERR,"Erlang closed the connection.");
else
@@ -415,7 +644,7 @@ static void pass_on(pid_t childpid)
exit(0);
}
- erts_run_erl_log_write(buf, len);
+ write_to_log(&lfd, &lognum, buf, len);
/*
* Save in the output queue.
@@ -431,7 +660,7 @@ static void pass_on(pid_t childpid)
*/
if (FD_ISSET(rfd, &readfds)) {
#ifdef DEBUG
- erts_run_erl_log_status("FIFO read; ");
+ status("FIFO read; ");
#endif
if ((len = sf_read(rfd, buf, BUFSIZ)) < 0) {
sf_close(rfd);
@@ -460,7 +689,7 @@ static void pass_on(pid_t childpid)
* should succeed. But in case of error, we just ignore it.
*/
if ((wfd = sf_open(fifo1, O_WRONLY|DONT_BLOCK_PLEASE, 0)) < 0) {
- erts_run_erl_log_status("Client expected on FIFO %s, but can't open (len=%d)\n",
+ status("Client expected on FIFO %s, but can't open (len=%d)\n",
fifo1, len);
sf_close(rfd);
rfd = sf_open(fifo2, O_RDONLY|DONT_BLOCK_PLEASE, 0);
@@ -472,7 +701,7 @@ static void pass_on(pid_t childpid)
}
else {
#ifdef DEBUG
- erts_run_erl_log_status("run_erl: %s opened for writing\n", fifo1);
+ status("run_erl: %s opened for writing\n", fifo1);
#endif
}
}
@@ -488,15 +717,14 @@ static void pass_on(pid_t childpid)
/* Write the message */
#ifdef DEBUG
- erts_run_erl_log_status("Pty master write; ");
+ status("Pty master write; ");
#endif
- len = erts_run_erl_extract_ctrl_seq(buf, len, mfd);
+ len = extract_ctrl_seq(buf, len);
if(len==1 && buf[0] == '\003') {
kill(childpid,SIGINT);
- }
- else if (len>0 && erts_run_erl_write_all(mfd, buf, len) != len)
- {
+ }
+ else if (len>0 && write_all(mfd, buf, len) != len) {
ERRNO_ERR0(LOG_ERR,"Error in writing to terminal.");
sf_close(rfd);
if(wfd) sf_close(wfd);
@@ -505,7 +733,7 @@ static void pass_on(pid_t childpid)
}
}
#ifdef DEBUG
- erts_run_erl_log_status("OK\n");
+ status("OK\n");
#endif
}
}
@@ -515,25 +743,204 @@ static void catch_sigchild(int sig)
{
}
+/*
+ * 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() */
+
+/* open_log()
+ * Opens a log file (with given index) for writing. Writing may be
+ * at the end or a trucnating write, according to flags.
+ * A LOGGING STARTED and time stamp message is inserted into the log file
+ */
+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];
+ int lfd;
+
+ /* 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);
+ if((lfd = sf_open(buf, flags, LOG_PERM))<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 (write_all(lfd, buf, strlen(buf)) < 0)
+ status("Error in writing to log.\n");
+
+#ifdef USE_FSYNC
+ fsync(lfd);
+#endif
+
+ return lfd;
+}
+
+/* write_to_log()
+ * Writes a message to a log file. If the current log file is full,
+ * a new log file is opened.
+ */
+static void write_to_log(int* lfd, int* log_num, char* buf, int len)
+{
+ int size;
+
+ /* Decide if new logfile needed, and open if so */
+
+ size = lseek(*lfd,0,SEEK_END);
+ if(size+len > log_maxsize) {
+ sf_close(*lfd);
+ *log_num = next_log(*log_num);
+ *lfd = open_log(*log_num, O_RDWR|O_CREAT|O_TRUNC|O_SYNC);
+ }
+
+ /* Write to log file */
+
+ if (write_all(*lfd, buf, len) < 0) {
+ status("Error in writing to log.\n");
+ }
+
+#ifdef USE_FSYNC
+ fsync(*lfd);
+#endif
+}
+
+/* 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;
+}
+
/* open_pty_master()
* Find a master device, open and return fd and slave device name.
*/
+#ifdef HAVE_WORKING_POSIX_OPENPT
+ /*
+ * Use openpty() on OpenBSD even if we have posix_openpt()
+ * as there is a race when read from master pty returns 0
+ * if child has not yet opened slave pty.
+ * (maybe other BSD's have the same problem?)
+ */
+# if !(defined(__OpenBSD__) && defined(HAVE_OPENPTY))
+# define TRY_POSIX_OPENPT
+# endif
+#endif
+
static int open_pty_master(char **ptyslave, int *sfdp)
{
int mfd;
/* Use the posix_openpt if working, as this guarantees creation of the
slave device properly. */
-#if defined(HAVE_WORKING_POSIX_OPENPT) || (defined(__sun) && defined(__SVR4))
-# ifdef HAVE_WORKING_POSIX_OPENPT
- if ((mfd = posix_openpt(O_RDWR)) >= 0) {
+#if defined(TRY_POSIX_OPENPT) || (defined(__sun) && defined(__SVR4))
+# ifdef TRY_POSIX_OPENPT
+ mfd = posix_openpt(O_RDWR);
# elif defined(__sun) && defined(__SVR4)
mfd = sf_open("/dev/ptmx", O_RDWR, 0);
+# endif
if (mfd >= 0) {
-# endif
if ((*ptyslave = ptsname(mfd)) != NULL &&
grantpt(mfd) == 0 &&
unlockpt(mfd) == 0) {
@@ -711,9 +1118,9 @@ static void exec_shell(char **argv)
else
argv[0] = sh;
argv[1] = "-c";
- erts_run_erl_log_status("Args before exec of shell:\n");
+ status("Args before exec of shell:\n");
for (vp = argv, i = 0; *vp; vp++, i++)
- erts_run_erl_log_status("argv[%d] = %s\n", i, *vp);
+ status("argv[%d] = %s\n", i, *vp);
if (stdstatus) {
fclose(stdstatus);
}
@@ -724,6 +1131,26 @@ static void exec_shell(char **argv)
ERRNO_ERR0(LOG_ERR,"Could not execv");
}
+/* status()
+ * Prints the arguments to a status file
+ * Works like printf (see vfrpintf)
+ */
+static void 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", (int)getpid(), ctime(&now));
+ va_start(args, format);
+ vfprintf(stdstatus, format, args);
+ va_end(args);
+ fflush(stdstatus);
+}
static void daemon_init(void)
/* As R Stevens wants it, to a certain extent anyway... */
@@ -763,10 +1190,47 @@ static void daemon_init(void)
run_daemon = 1;
}
+/* error_logf()
+ * Prints the arguments to stderr or syslog
+ * Works like printf (see vfprintf)
+ */
+static void error_logf(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
+ {
+ time_t now = time(NULL);
+ fprintf(stderr, "run_erl:%d [%d] %s", line, (int)getpid(), ctime(&now));
+ vfprintf(stderr, format, args);
+ }
+ va_end(args);
+}
+
static void usage(char *pname)
{
- fprintf(stderr, "Usage: ");
- fprintf(stderr, RUN_ERL_USAGE, pname);
+ fprintf(stderr, "Usage: %s (pipe_name|pipe_dir/) log_dir \"command [parameters ...]\"\n", pname);
+ fprintf(stderr, "\nYou may also set the environment variables RUN_ERL_LOG_GENERATIONS\n");
+ fprintf(stderr, "and RUN_ERL_LOG_MAXSIZE to the number of log files to use and the\n");
+ fprintf(stderr, "size of the log file when to switch to the next log file\n");
+}
+
+/* Instead of making sure basename exists, we do our own */
+static char *simple_basename(char *path)
+{
+ char *ptr;
+ for (ptr = path; *ptr != '\0'; ++ptr) {
+ if (*ptr == '/') {
+ path = ptr + 1;
+ }
+ }
+ return path;
}
static void init_outbuf(void)
@@ -837,6 +1301,113 @@ static void outbuf_append(const char* buf, int n)
outbuf_in += n;
}
+/* 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;
+ for (;;) {
+ written = sf_write(fd,buf,left);
+ if (written == left) {
+ return len;
+ }
+ if (written < 0) {
+ return -1;
+ }
+ left -= written;
+ buf += written;
+ }
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static 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;
+}
+
+static int sf_close(int fd) {
+ /* "close() should not be retried after an EINTR" */
+ return close(fd);
+}
+
+/* Extract any control sequences that are ment only for run_erl
+ * and should not be forwarded to the pty.
+ */
+static int 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) {
+ set_window_size(col,row);
+ }
+ 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;
+}
+
+static void set_window_size(unsigned col, unsigned row)
+{
+#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
+}
+
+
#ifdef DEBUG
#define S(x) ((x) > 0 ? 1 : 0)
diff --git a/erts/etc/unix/run_erl.h b/erts/etc/unix/run_erl.h
new file mode 100644
index 0000000000..83bdfdfb19
--- /dev/null
+++ b/erts/etc/unix/run_erl.h
@@ -0,0 +1,31 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions 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/unix/safe_string.c b/erts/etc/unix/safe_string.c
new file mode 100644
index 0000000000..666022dc61
--- /dev/null
+++ b/erts/etc/unix/safe_string.c
@@ -0,0 +1,124 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions 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/unix/safe_string.h b/erts/etc/unix/safe_string.h
new file mode 100644
index 0000000000..cafd3fc71a
--- /dev/null
+++ b/erts/etc/unix/safe_string.h
@@ -0,0 +1,66 @@
+/*
+ * %CopyrightBegin%
+ *
+ * Copyright Ericsson AB 2008-2016. All Rights Reserved.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions 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/unix/setuid_socket_wrap.c b/erts/etc/unix/setuid_socket_wrap.c
index 3f0657770c..461c69ee3e 100644
--- a/erts/etc/unix/setuid_socket_wrap.c
+++ b/erts/etc/unix/setuid_socket_wrap.c
@@ -1,18 +1,19 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1999-2009. All Rights Reserved.
+ * Copyright Ericsson AB 1999-2016. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
*
* %CopyrightEnd%
*/
diff --git a/erts/etc/unix/start.src b/erts/etc/unix/start.src
index 8479be0987..bdd146951f 100644
--- a/erts/etc/unix/start.src
+++ b/erts/etc/unix/start.src
@@ -2,18 +2,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1996-2009. All Rights Reserved.
+# Copyright Ericsson AB 1996-2016. 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.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
diff --git a/erts/etc/unix/start_erl.src b/erts/etc/unix/start_erl.src
index ea8022c449..34e0369710 100644
--- a/erts/etc/unix/start_erl.src
+++ b/erts/etc/unix/start_erl.src
@@ -3,18 +3,19 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 1997-2009. All Rights Reserved.
+# Copyright Ericsson AB 1997-2016. 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.
+# Licensed under the Apache License, Version 2.0 (the "License");
+# you may not use this file except in compliance with the License.
+# You may obtain a copy of the License at
+#
+# http://www.apache.org/licenses/LICENSE-2.0
+#
+# Unless required by applicable law or agreed to in writing, software
+# distributed under the License is distributed on an "AS IS" BASIS,
+# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+# See the License for the specific language governing permissions and
+# limitations under the License.
#
# %CopyrightEnd%
#
diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c
index 38a94ed9c3..afff8f7e54 100644
--- a/erts/etc/unix/to_erl.c
+++ b/erts/etc/unix/to_erl.c
@@ -1,24 +1,608 @@
/*
* %CopyrightBegin%
*
- * Copyright Ericsson AB 1996-2013. All Rights Reserved.
+ * Copyright Ericsson AB 1996-2017. 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.
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions 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 <termios.h>
+#include <dirent.h>
+#include <signal.h>
+#include <errno.h>
+#ifdef HAVE_SYS_IOCTL_H
+# include <sys/ioctl.h>
+#endif
+
+#include "run_erl.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
+
+#define PIPE_DIR "/tmp/"
+#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 struct termios tty_smode, tty_rmode;
+static int tty_eof = 0;
+static int recv_sig = 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 window_size_seq(char* buf, size_t bufsz);
+static int version_handshake(char* buf, int len, int wfd);
+#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;
+}
+
+static void usage(char *pname)
+{
+ fprintf(stderr, "Usage: %s [-h|-F] [pipe_name|pipe_dir/]\n", pname);
+ fprintf(stderr, "\t-h\tThis help text.\n");
+ fprintf(stderr, "\t-F\tForce connection even though pipe is locked by other to_erl process.\n");
+}
+
+int main(int argc, char **argv)
+{
+ char FIFO1[FILENAME_MAX], FIFO2[FILENAME_MAX];
+ int i, len, wfd, rfd;
+ fd_set readfds;
+ char buf[BUFSIZ];
+ char pipename[FILENAME_MAX];
+ int pipeIx = 1;
+ int force_lock = 0;
+ int got_some = 0;
+
+ 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)getpid());
+#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);
+
+ /* 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);
+ }
+ }
+
+ 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
+
+ fprintf(stderr, "Attaching to %s (^D to exit)\n\n", pipename);
+
+ /* 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
+ /*
+ * "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");
+ }
+
+ /*
+ * read and write
+ */
+ while (1) {
+ 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 if (FD_ISSET(0, &readfds)) {
+ len = read(0, buf, sizeof(buf));
+ 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 && buf[i] != tty_eof; i++);
+ if (buf[i] == tty_eof) {
+ fprintf(stderr, "[Quit]\n\r");
+ break;
+ }
+ }
+
+ if (len) {
+#ifdef DEBUG
+ (void)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");
+ }
+
+ /*
+ * Read from FIFO, write to terminal.
+ */
+ if (FD_ISSET(rfd, &readfds)) {
+ STATUS("FIFO read: ");
+ len = read(rfd, buf, BUFSIZ);
+ 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;
+ }
+ if (protocol_ver >= 1) {
+ /* Tell run_erl size of terminal window */
+ signal(SIGWINCH, handle_sigwinch);
+ raise(SIGWINCH);
+ }
+ 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");
+ }
+ }
+ }
+
+ /*
+ * Reset terminal characterstics
+ * XXX
+ */
+ tcsetattr(0, TCSADRAIN, &tty_rmode);
+ 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;
+}
+
+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;
+}
+
+/* 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;
+}
+
-#include "to_erl_common.h"
+#ifdef DEBUG
+#define S(x) ((x) > 0 ? 1 : 0)
-int main(int argc,char **argv) {
- return to_erl(argc,argv);
+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