aboutsummaryrefslogtreecommitdiffstats
path: root/erts/etc/unix
diff options
context:
space:
mode:
Diffstat (limited to 'erts/etc/unix')
-rw-r--r--erts/etc/unix/cerl.src7
-rw-r--r--erts/etc/unix/etp-commands.in844
-rw-r--r--erts/etc/unix/run_erl.c601
-rw-r--r--erts/etc/unix/run_erl.h30
-rw-r--r--erts/etc/unix/safe_string.c123
-rw-r--r--erts/etc/unix/safe_string.h65
-rw-r--r--erts/etc/unix/to_erl.c589
7 files changed, 858 insertions, 1401 deletions
diff --git a/erts/etc/unix/cerl.src b/erts/etc/unix/cerl.src
index be8343e87e..78fefbea55 100644
--- a/erts/etc/unix/cerl.src
+++ b/erts/etc/unix/cerl.src
@@ -86,6 +86,7 @@ run_valgrind=no
# Default rootdir
ROOTDIR=%SRC_ROOTDIR%
BINDIR="$ROOTDIR/bin/`$ROOTDIR/erts/autoconf/config.guess`"
+TARGET=%TARGET%
#BINDIR="$ROOTDIR/bin/%TARGET%"
PROGNAME=$ROOTDIR/bin/cerl
EMU=beam
@@ -248,6 +249,12 @@ while [ $# -gt 0 ]; do
done
+if [ ! -f $BINDIR/erlexec -a -f $ROOTDIR/bin/$TARGET/erlexec ]; then
+ # We are in a strange target (I'm looking at you openbsd) where
+ # TARGET != config.guess
+ BINDIR=$ROOTDIR/bin/$TARGET
+fi
+
PATH=$BINDIR:$ROOTDIR/bin:$PATH
EXEC=$BINDIR/erlexec
diff --git a/erts/etc/unix/etp-commands.in b/erts/etc/unix/etp-commands.in
index 54ff7b3e3a..bf6eb00314 100644
--- a/erts/etc/unix/etp-commands.in
+++ b/erts/etc/unix/etp-commands.in
@@ -1,7 +1,7 @@
#
# %CopyrightBegin%
#
-# Copyright Ericsson AB 2005-2012. All Rights Reserved.
+# Copyright Ericsson AB 2005-2014. All Rights Reserved.
#
# The contents of this file are subject to the Erlang Public License,
# Version 1.1, (the "License"); you may not use this file except in
@@ -54,13 +54,23 @@ document etp-help
% etp-mfa, etp-cp,
% etp-msgq, etpf-msgq,
% etp-stacktrace, etp-stackdump, etpf-stackdump, etp-dictdump
-% etp-offheapdump, etpf-offheapdump,
-% etp-print-procs, etp-search-heaps, etp-search-alloc,
+% etp-process-info, etp-process-memory-info
+% etp-port-info, etp-port-state, etp-port-sched-flags
+% etp-heapdump, etp-offheapdump, etpf-offheapdump,
+% etp-search-heaps, etp-search-alloc,
% etp-ets-tables, etp-ets-tabledump
%
% Complex commands that use the Erlang support module.
% etp-overlapped-heaps, etp-chart, etp-chart-start, etp-chart-end
-%
+%
+% System inspection
+% etp-system-info, etp-schedulers, etp-process, etp-ports, etp-lc-dump,
+% etp-migration-info, etp-processes-memory,
+% etp-compile-info, etp-config-h-info
+%
+% Platform specific (when gdb fails you)
+% etp-ppc-stacktrace
+%
% Erlang support module handling commands:
% etp-run
%
@@ -652,7 +662,7 @@ end
define etp-ct-atom-1
# Args: int
#
-# Determines if integer is a atom first character
+# Determines if integer is an atom first character
#
# Non-reentrant
# Returns: $etp_ct_atom
@@ -1055,7 +1065,9 @@ define etp-cp-1
set $etp_cp_mid = $etp_cp_low + ($etp_cp_high-$etp_cp_low)/2
end
if $etp_cp_p
- set $etp_cp_low = (Eterm**)($etp_cp_p->start + 8)
+ # 12 = MI_FUNCTIONS
+ set $etp_cp_low = (Eterm**)($etp_cp_p->start + 12)
+ # 0 = MI_NUM_FUNCTIONS
set $etp_cp_high = $etp_cp_low +$etp_cp_p->start[0]
set $etp_cp_p = 0
while $etp_cp_low < $etp_cp_high
@@ -1278,6 +1290,250 @@ document etpf-stackdump
%---------------------------------------------------------------------------
end
+define etp-heapdump
+# Args: Process*
+#
+# Non-reentrant
+ etp-heapdump-1 ($arg0)->heap ($arg0)->htop
+end
+
+document etp-heapdump
+%---------------------------------------------------------------------------
+% etp-heapdump Process*
+%
+% Take an Process* and print a heapdump for the process heap.
+%---------------------------------------------------------------------------
+end
+
+define etp-heapdump-old
+# Args: Process*
+#
+# Non-reentrant
+ etp-heapdump-1 ($arg0)->old_heap ($arg0)->old_htop
+end
+
+document etp-heapdump
+%---------------------------------------------------------------------------
+% etp-heapdump-old Process*
+%
+% Take an Process* and print a heapdump for the process old heap (gen-heap).
+%---------------------------------------------------------------------------
+end
+
+
+define etp-heapdump-1
+# Args: Eterm* heap, Eterm* htop
+#
+# Non-reentrant
+ set $etp_heapdump_heap = (Eterm*)($arg0)
+ set $etp_heapdump_p = (Eterm*)($arg0)
+ set $etp_heapdump_end = (Eterm*)($arg1)
+ set $etp_heapdump_skips = 0
+ printf "%% heapdump (%u):\n", $etp_heapdump_end-$etp_heapdump_p
+ while $etp_heapdump_p < $etp_heapdump_end
+ set $etp_heapdump_ix = 0
+ printf " %p: ", $etp_heapdump_p
+ while $etp_heapdump_p < $etp_heapdump_end && $etp_heapdump_ix < 8
+ if ($etp_heapdump_skips > 0)
+ printf "| 0x%08x ", ($etp_heapdump_p)
+ set $etp_heapdump_skips--
+ else
+ etp-term-dump $etp_heapdump_p[0]
+ end
+ set $etp_heapdump_p++
+ set $etp_heapdump_ix++
+ end
+ printf "\n"
+ end
+end
+
+
+define etp-term-dump
+# Args: Eterm
+ if (($arg0) & 0x3) == 0
+ etp-term-dump-header ($arg0)
+ else
+ if (($arg0) & 0x3) == 1
+ # Cons pointer
+ set $etp_term_dump_cons_p = ((Eterm*)(($arg0) & ~0x3))
+ if $etp_term_dump_cons_p > $etp_heapdump_heap && $etp_term_dump_cons_p < $etp_heapdump_end
+ printf "| C:0x%08x ", $etp_term_dump_cons_p
+ #printf "| C: --> %5d ", $etp_heapdump_p - $etp_term_dump_cons_p - 1
+ else
+ printf "| C:0x%08x ", $etp_term_dump_cons_p
+ end
+ else
+ if (($arg0) & 0x3) == 2
+ # Box pointer
+ printf "| B:0x%08x ", ($arg0)
+ else
+ if (($arg0) & 0x3) == 3
+ # immediate
+ etp-term-dump-immediate ($arg0)
+ else
+ printf "| U:0x%08x ", ($arg0)
+ end
+ end
+ end
+ end
+end
+
+define etp-term-dump-immediate
+# Args: immediate term
+ if (($arg0) & 0xF) == 0xf
+ # Fixnum
+ etp-ct-printable-1 ((long)((Sint)($arg0)>>4))
+ if $etp_ct_printable
+ if $etp_ct_printable < 0
+ printf "| I: %c (%3ld) ", (long)((Sint)($arg0)>>4), (long)((Sint)($arg0)>>4)
+ else
+ printf "| I: \\%c (%3ld) ", (long)((Sint)($arg0)>>4), (long)((Sint)($arg0)>>4)
+ end
+ else
+ printf "| I:%10ld ", (long)((Sint)($arg0)>>4)
+ end
+ else
+ if (($arg0) & 0xF) == 0x3
+ etp-term-dump-pid ($arg0)
+ else
+ if (($arg0) & 0xF) == 0x7
+ printf "| port:0x%05x ", ($arg0)
+ else
+ # Immediate2 - 0xB
+ if (($arg0) & 0x3f) == 0x0b
+ etp-term-dump-atom ($arg0)
+ else
+ if (($arg0) & 0x3f) == 0x1b
+ printf "| #Catch<%06d> ", ($arg0)>>6
+ else
+ if (($arg0) == $etp_nil)
+ printf "| [] (NIL) "
+ else
+ printf "| I:0x%08x ", ($arg0)
+ end
+ end
+ end
+ end
+ end
+ end
+end
+
+define etp-term-dump-atom
+# Args: atom term
+ set $etp_atom_1_ap = (Atom*)erts_atom_table.seg_table[(Eterm)($arg0)>>16][((Eterm)($arg0)>>6)&0x3FF]
+ set $etp_atom_1_i = ($etp_atom_1_ap)->len
+ set $etp_atom_1_p = ($etp_atom_1_ap)->name
+ set $etp_atom_1_quote = 1
+ set $etp_atom_indent = 13
+
+ if ($etp_atom_1_i < 11)
+ if ($etp_atom_1_i > 0)
+ etp-ct-atom-1 (*$etp_atom_1_p)
+ if $etp_ct_atom
+ set $etp_atom_indent = 13
+ else
+ set $etp_atom_indent = 11
+ end
+ end
+ # perform indentation
+ printf "|"
+ while ($etp_atom_1_i < $etp_atom_indent)
+ printf " "
+ set $etp_atom_1_i++
+ end
+ set $etp_atom_1_i = ($etp_atom_1_ap)->len
+ # Check if atom has to be quoted
+ if ($etp_atom_1_i > 0)
+ etp-ct-atom-1 (*$etp_atom_1_p)
+ if $etp_ct_atom
+ # Atom start character
+ set $etp_atom_1_p++
+ set $etp_atom_1_i--
+ set $etp_atom_1_quote = 0
+ else
+ set $etp_atom_1_i = 0
+ end
+ end
+ while $etp_atom_1_i > 0
+ etp-ct-name-1 (*$etp_atom_1_p)
+ if $etp_ct_name
+ # Name character
+ set $etp_atom_1_p++
+ set $etp_atom_1_i--
+ else
+ set $etp_atom_1_quote = 1
+ set $etp_atom_1_i = 0
+ end
+ end
+ # Print the atom
+ if $etp_atom_1_quote
+ printf "'"
+ end
+ set $etp_atom_1_i = ($etp_atom_1_ap)->len
+ set $etp_atom_1_p = ($etp_atom_1_ap)->name
+ while $etp_atom_1_i > 0
+ etp-char-1 (*$etp_atom_1_p) '\''
+ set $etp_atom_1_p++
+ set $etp_atom_1_i--
+ end
+ if $etp_atom_1_quote
+ printf "'"
+ end
+ printf " "
+ else
+ printf "| A:0x%08x ", ($arg0)
+ end
+end
+
+define etp-term-dump-pid
+# Args: Eterm pid
+#
+# Non-reentrant
+#
+ 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)
+ else
+ set $etp_pid_data = (unsigned) ((((Uint64) $etp_pid_1) >> 4) & 0x0fffffff)
+ end
+ else
+ set $etp_pid_data = (unsigned) (((((Uint32) $etp_pid_1) >> 4) & ~erts_proc.r.o.pix_mask) | ((((Uint32) $etp_pid_1) >> (erts_proc.r.o.pix_cl_shift + 4)) & erts_proc.r.o.pix_cl_mask) | (((((Uint32) $etp_pid_1) >> 4) & erts_proc.r.o.pix_cli_mask) << erts_proc.r.o.pix_cli_shift))
+ end
+ # Internal pid
+ printf "| <0.%04u.%03u> ", $etp_pid_data & 0x7fff, ($etp_pid_data >> 15) & 0x1fff
+ else
+ printf "| #NotPid<%#x> ", ($arg0)
+ end
+end
+
+define etp-term-dump-header
+# Args: Header term
+ if (($arg0) & 0x3f) == 0
+ printf "| H:%4d-tuple ", ($arg0) >> 6
+ else
+ set $etp_heapdump_skips = ($arg0) >> 6
+ if ((($arg0) & 0x3f) == 0x18)
+ printf "| H: float %3d ", ($arg0) >> 6
+ else
+ if ((($arg0) & 0x3f) == 0x28)
+ # sub-binary
+ printf "| H: sub-bin "
+ else
+ if ((($arg0) & 0x3f) == 0x8)
+ # pos-bignum
+ printf "| H:bignum %3u ", ($arg0) >> 6
+ else
+ printf "| header %5d ", ($arg0) >> 6
+ end
+ end
+ end
+ end
+end
+
+
+
define etp-pid2pix-1
# Args: Eterm
#
@@ -1316,49 +1572,102 @@ end
define etp-proc-state-int
# Args: int
#
- if ($arg0 & 0xfffff000)
+ if ($arg0 & 0xff000000)
printf "GARBAGE | "
end
- if ($arg0 & 0x800)
+ if ($arg0 & 0x800000)
+ printf "delayed-sys | "
+ end
+ if ($arg0 & 0x400000)
+ printf "proxy | "
+ set $proxy_process = 1
+ else
+ set $proxy_process = 0
+ end
+ if ($arg0 & 0x200000)
+ printf "running-sys | "
+ end
+ if ($arg0 & 0x100000)
+ printf "active-sys | "
+ end
+ if ($arg0 & 0x80000)
printf "trapping-exit | "
end
- if ($arg0 & 0x400)
+ if ($arg0 & 0x40000)
printf "bound | "
end
- if ($arg0 & 0x200)
+ if ($arg0 & 0x20000)
printf "garbage-collecting | "
end
- if ($arg0 & 0x100)
+ if ($arg0 & 0x10000)
printf "suspended | "
end
- if ($arg0 & 0x80)
+ if ($arg0 & 0x8000)
printf "running | "
end
- if ($arg0 & 0x40)
+ if ($arg0 & 0x4000)
printf "in-run-queue | "
end
- if ($arg0 & 0x20)
+ if ($arg0 & 0x2000)
printf "active | "
end
- if ($arg0 & 0x10)
+ if ($arg0 & 0x1000)
printf "pending-exit | "
end
- if ($arg0 & 0x8)
+ if ($arg0 & 0x800)
printf "exiting | "
end
- if ($arg0 & 0x4)
+ if ($arg0 & 0x400)
printf "free | "
end
- if ($arg0 & 0x3) == 0
- printf "prio-max\n"
+ if ($arg0 & 0x200)
+ printf "in-prq-low | "
+ end
+ if ($arg0 & 0x100)
+ printf "in-prq-normal | "
+ end
+ if ($arg0 & 0x80)
+ printf "in-prq-high | "
+ end
+ if ($arg0 & 0x40)
+ printf "in-prq-max | "
+ end
+ if ($arg0 & 0x30) == 0x0
+ printf "prq-prio-max | "
+ else
+ if ($arg0 & 0x30) == 0x10
+ printf "prq-prio-high | "
+ else
+ if ($arg0 & 0x30) == 0x20
+ printf "prq-prio-normal | "
+ else
+ printf "prq-prio-low | "
+ end
+ end
+ end
+ if ($arg0 & 0xc) == 0x0
+ printf "usr-prio-max | "
else
- if ($arg0 & 0x3) == 1
- printf "prio-high\n"
+ if ($arg0 & 0xc) == 0x4
+ printf "usr-prio-high | "
else
- if ($arg0 & 0x3) == 2
- printf "prio-normal\n"
+ if ($arg0 & 0xc) == 0x8
+ printf "usr-prio-normal | "
else
- printf "prio-low\n"
+ printf "usr-prio-low | "
+ end
+ end
+ end
+ if ($arg0 & 0x3) == 0x0
+ printf "act-prio-max\n"
+ else
+ if ($arg0 & 0x3) == 0x1
+ printf "act-prio-high\n"
+ else
+ if ($arg0 & 0x3) == 0x2
+ printf "act-prio-normal\n"
+ else
+ printf "act-prio-low\n"
end
end
end
@@ -1392,9 +1701,15 @@ define etp-process-info
# Args: Process*
#
printf " Pid: "
- etp-1 $arg0->common.id
+ etp-1 ($arg0)->common.id
printf "\n State: "
etp-proc-state $arg0
+ if $proxy_process != 0
+ printf " Pointer: (Process *) %p\n", $arg0
+ printf " *** PROXY process struct *** refer to: \n"
+ etp-pid2proc-1 $arg0->common.id
+ etp-process-info $proc
+ else
if (*(((Uint32 *) &(((Process *) $arg0)->state))) & 0x4) == 0
if ($arg0->common.u.alive.reg)
printf " Registered name: "
@@ -1432,6 +1747,7 @@ define etp-process-info
printf " Parent: "
etp-1 $arg0->parent
printf "\n Pointer: (Process *) %p\n", $arg0
+ end
end
document etp-process-info
@@ -1463,11 +1779,104 @@ end
document etp-processes
%---------------------------------------------------------------------------
% etp-processes
-%
+%
% Print misc info about all processes
%---------------------------------------------------------------------------
end
+define etp-processes-memory
+ if (!erts_initialized)
+ printf "No processes, since system isn't initialized!\n"
+ else
+ set $proc_ix = 0
+ printf "--- (%ld processes in wheel)\n", erts_proc.r.o.max
+ 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)
+ etp-process-memory-info $proc
+ end
+ set $proc_ix++
+ end
+ printf "---\n",
+ end
+end
+
+document etp-processes-memory
+%---------------------------------------------------------------------------
+% etp-processes-memory
+%
+% Print memory info about all processes
+%---------------------------------------------------------------------------
+end
+
+define etp-process-memory-info
+# Args: Process*
+#
+ if ((*(((Uint32 *) &(((Process *) $arg0)->state)))) & 0x400000)
+ set $proxy_process = 1
+ else
+ set $proxy_process = 0
+ end
+ printf " "
+ etp-1 $arg0->common.id
+ printf ": (Process *) %p ", $arg0
+ if $proxy_process != 0
+ printf "(Process *) %p ", $arg0
+ printf " *** PROXY process struct *** refer to next: \n"
+ etp-pid2proc-1 $arg0->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
+ else
+ printf " | none "
+ end
+ printf "] [Mbuf: %5ld", $arg0->mbuf_sz
+ if (etp_smp_compiled)
+ printf " | %3ld (%3ld | %3ld)", ($arg0->msg.len + $arg0->msg_inq.len), $arg0->msg.len, $arg0->msg_inq.len
+ else
+ printf " | %3ld", $arg0->msg.len
+ end
+ printf "] "
+ if ($arg0->i)
+ printf " I: "
+ etp-cp-1 $arg0->i
+ printf " "
+ end
+
+ if ($arg0->current)
+ etp-1 $arg0->current[0]
+ printf ":"
+ etp-1 $arg0->current[1]
+ printf "/%d ", $arg0->current[2]
+ end
+
+ if (*(((Uint32 *) &(((Process *) $arg0)->state))) & 0x4) == 0
+ if ($arg0->common.u.alive.reg)
+ etp-1 $arg0->common.u.alive.reg->name
+ printf " "
+ end
+ end
+
+ if ($arg0->cp)
+ printf " CP: "
+ etp-cp-1 $arg0->cp
+ printf " "
+ end
+ printf "\n"
+ end
+end
+
+document etp-process-memory-info
+%---------------------------------------------------------------------------
+% etp-process-memory-info Process*
+%
+% Print memory info about process
+%---------------------------------------------------------------------------
+end
+
define etp-port-id2pix-1
# Args: Eterm
#
@@ -2433,6 +2842,152 @@ document etp-search-alloc
end
+define etp-alloc-stats
+ printf "\nIx Name Inst. Blocks Bytes Carriers Crr.bytes Util\n"
+ set $etp_tot_block_no = 0
+ set $etp_tot_block_sz = 0
+ set $etp_tot_crr_no = 0
+ set $etp_tot_crr_sz = 0
+ set $etp_ERTS_ALC_A_MIN = 1
+ set $etp_ERTS_ALC_A_MAX = (sizeof(erts_allctrs) / sizeof(*erts_allctrs)) - 1
+
+ set $etp_ix = $etp_ERTS_ALC_A_MIN
+ while $etp_ix <= $etp_ERTS_ALC_A_MAX
+ set $etp_allctr = 0
+ set $etp_alloc = erts_allctrs[$etp_ix].alloc
+ if $etp_alloc != erts_sys_alloc
+ if $etp_alloc == erts_alcu_alloc_thr_spec || \
+ $etp_alloc == erts_alcu_alloc_thr_pref
+ set $etp_instance = 0
+ set $etp_block_no = 0
+ set $etp_block_sz = 0
+ set $etp_crr_no = 0
+ set $etp_crr_sz = 0
+ set $etp_tspec = (ErtsAllocatorThrSpec_t *) erts_allctrs[$etp_ix].extra
+ if $etp_tspec->enabled
+ while $etp_instance < $etp_tspec->size
+ set $etp_allctr = $etp_tspec->allctr[$etp_instance]
+ set $etp_block_no = $etp_block_no + $etp_allctr->mbcs.blocks.curr.no \
+ + $etp_allctr->sbcs.blocks.curr.no
+ set $etp_block_sz = $etp_block_sz + $etp_allctr->mbcs.blocks.curr.size \
+ + $etp_allctr->sbcs.blocks.curr.size
+ set $etp_crr_no = $etp_crr_no + $etp_allctr->mbcs.curr.norm.mseg.no \
+ + $etp_allctr->sbcs.curr.norm.mseg.no \
+ + $etp_allctr->mbcs.curr.norm.sys_alloc.no \
+ + $etp_allctr->sbcs.curr.norm.sys_alloc.no
+ set $etp_crr_sz = $etp_crr_sz + $etp_allctr->mbcs.curr.norm.mseg.size \
+ + $etp_allctr->sbcs.curr.norm.mseg.size \
+ + $etp_allctr->mbcs.curr.norm.sys_alloc.size \
+ + $etp_allctr->sbcs.curr.norm.sys_alloc.size
+ set $etp_instance = $etp_instance + 1
+ end
+ else
+ printf "erts_allctr[%d]: Disabled (thread specific)\n", $etp_ix
+ end
+ else
+ if $etp_alloc == erts_alcu_alloc_ts || $etp_alloc == erts_alcu_alloc
+ set $etp_allctr = (Allctr_t*) erts_allctrs[$etp_ix].extra
+ set $etp_block_no = $etp_allctr->mbcs.blocks.curr.no \
+ + $etp_allctr->sbcs.blocks.curr.no
+ set $etp_block_sz = $etp_allctr->mbcs.blocks.curr.size \
+ + $etp_allctr->sbcs.blocks.curr.size
+ set $etp_crr_no = $etp_allctr->mbcs.curr.norm.mseg.no \
+ + $etp_allctr->sbcs.curr.norm.mseg.no \
+ + $etp_allctr->mbcs.curr.norm.sys_alloc.no \
+ + $etp_allctr->sbcs.curr.norm.sys_alloc.no
+ set $etp_crr_sz = $etp_allctr->mbcs.curr.norm.mseg.size \
+ + $etp_allctr->sbcs.curr.norm.mseg.size \
+ + $etp_allctr->mbcs.curr.norm.sys_alloc.size \
+ + $etp_allctr->sbcs.curr.norm.sys_alloc.size
+ set $etp_instance = 1
+ else
+ printf "erts_allctr[%d]: Unknown allocation function: ", $etp_ix
+ p $etp_alloc
+ end
+ end
+ end
+ if $etp_allctr != 0
+ printf "%2d %-8s%2d%12lu%13lu%12lu%13lu", $etp_ix, $etp_allctr->name_prefix, \
+ $etp_instance, \
+ $etp_block_no, $etp_block_sz, $etp_crr_no, $etp_crr_sz
+ if $etp_crr_sz != 0
+ printf "%5lu%%", ($etp_block_sz * 100) / $etp_crr_sz
+ end
+ printf "\n"
+ set $etp_tot_block_no = $etp_tot_block_no + $etp_block_no
+ set $etp_tot_block_sz = $etp_tot_block_sz + $etp_block_sz
+ set $etp_tot_crr_no = $etp_tot_crr_no + $etp_crr_no
+ set $etp_tot_crr_sz = $etp_tot_crr_sz + $etp_crr_sz
+ end
+ set $etp_ix = $etp_ix + 1
+ end
+ printf "\nTotal: %12lu%13lu%12lu%13lu", $etp_tot_block_no, $etp_tot_block_sz, \
+ $etp_tot_crr_no, $etp_tot_crr_sz
+ if $etp_tot_crr_sz != 0
+ printf "%5lu%%", ($etp_tot_block_sz * 100) / $etp_tot_crr_sz
+ end
+ printf "\n"
+end
+
+document etp-alloc-stats
+%---------------------------------------------------------------------------
+% etp-alloc-stats
+%
+% Combine and print allocator statistics
+%---------------------------------------------------------------------------
+end
+
+
+define etp-alloc-instances
+ set $etp_ERTS_ALC_A_MIN = 1
+ set $etp_ERTS_ALC_A_MAX = (sizeof(erts_allctrs) / sizeof(*erts_allctrs)) - 1
+
+ set $etp_ix = $arg0
+ if $etp_ix >= $etp_ERTS_ALC_A_MIN && $etp_ix <= $etp_ERTS_ALC_A_MAX
+ set $etp_allctr = 0
+ set $etp_alloc = erts_allctrs[$etp_ix].alloc
+ if $etp_alloc == erts_sys_alloc
+ printf "Allocator %d is sys_alloc\n", $etp_ix
+ else
+ if $etp_alloc == erts_alcu_alloc_thr_spec || \
+ $etp_alloc == erts_alcu_alloc_thr_pref
+ set $etp_instance = 0
+ set $etp_tspec = (ErtsAllocatorThrSpec_t *) erts_allctrs[$etp_ix].extra
+ if $etp_tspec->enabled
+ printf "All instances for allocator '%s'\n", $etp_tspec->allctr[0]->name_prefix
+ while $etp_instance < $etp_tspec->size
+ p $etp_tspec->allctr[$etp_instance]
+ set $etp_instance = $etp_instance + 1
+ end
+ else
+ printf "erts_allctr[%d]: Disabled (thread specific)\n", $etp_ix
+ end
+ else
+ if $etp_alloc == erts_alcu_alloc_ts || $etp_alloc == erts_alcu_alloc
+ set $etp_allctr = (Allctr_t*) erts_allctrs[$etp_ix].extra
+ printf "Single instances for allocator '%s'\n", $etp_allctr->name_prefix
+ p $etp_allctr
+ else
+ printf "erts_allctr[%d]: Unknown allocation function: ", $etp_ix
+ p $etp_alloc
+ end
+ end
+ end
+ else
+ printf "Allocator type not between %d and %d\n", $etp_ERTS_ALC_A_MIN, $etp_ERTS_ALC_A_MAX
+ end
+end
+
+document etp-alloc-instances
+%---------------------------------------------------------------------------
+% etp-alloc-instances
+%
+% Print pointers to all allocator instances for a specific type (Ix)
+%---------------------------------------------------------------------------
+end
+
+
+
define etp-overlapped-heaps
# Args:
@@ -2736,6 +3291,95 @@ document etp-ets-tabledump
%---------------------------------------------------------------------------
end
+define etp-lc-dump
+# Non-reentrant
+ set $etp_lc_dump_thread = erts_locked_locks
+ while $etp_lc_dump_thread
+ printf "Thread %s\n", $etp_lc_dump_thread->thread_name
+ set $etp_lc_dump_thread_locked = $etp_lc_dump_thread->locked.first
+ while $etp_lc_dump_thread_locked
+ if 0 <= $etp_lc_dump_thread_locked->id && $etp_lc_dump_thread_locked->id < sizeof(erts_lock_order)/sizeof(erts_lc_lock_order_t)
+ printf " %s:", erts_lock_order[$etp_lc_dump_thread_locked->id].name
+ else
+ printf " unkown:"
+ end
+ if ($etp_lc_dump_thread_locked->extra & 0x3) == 0x3
+ etp-1 $etp_lc_dump_thread_locked->extra
+ else
+ printf "%p", $etp_lc_dump_thread_locked->extra
+ end
+ if ($etp_lc_dump_thread_locked->flags & (0x1f)) == (1 << 0)
+ printf "[spinlock]"
+ end
+ if ($etp_lc_dump_thread_locked->flags & (0x1f)) == (1 << 1)
+ printf "[rw(spin)lock]"
+ end
+ if ($etp_lc_dump_thread_locked->flags & (0x1f)) == (1 << 2)
+ printf "[mutex]"
+ end
+ if ($etp_lc_dump_thread_locked->flags & (0x1f)) == (1 << 3)
+ printf "[rwmutex]"
+ end
+ if ($etp_lc_dump_thread_locked->flags & (0x1f)) == (1 << 4)
+ printf "[proclock]"
+ end
+ printf "(%s:%d)", $etp_lc_dump_thread_locked->file, $etp_lc_dump_thread_locked->line
+ if ($etp_lc_dump_thread_locked->flags & (0x60)) == (1 << 5)
+ printf "(r)"
+ end
+ if ($etp_lc_dump_thread_locked->flags & (0x60)) == ((1 << 5) | (1 << 6))
+ printf "(rw)"
+ end
+ printf "\n"
+ set $etp_lc_dump_thread_locked = $etp_lc_dump_thread_locked->next
+ end
+ set $etp_lc_dump_thread = $etp_lc_dump_thread->next
+ end
+end
+
+document etp-lc-dump
+%---------------------------------------------------------------------------
+% etp-lc-dump
+%
+% Dump all info about locks in the lock checker
+%---------------------------------------------------------------------------
+end
+
+define etp-ppc-stacktrace
+# Args: R1
+# Non-reentrant
+ set $etp_ppc_st_fp = ($arg0)
+ while $etp_ppc_st_fp
+ info symbol ((void**)$etp_ppc_st_fp)[1]
+ set $etp_ppc_st_fp = ((void**)$etp_ppc_st_fp)[0]
+ end
+end
+
+document etp-ppc-stacktrace
+%---------------------------------------------------------------------------
+% etp-ppc-stacktrace R1
+%
+% Dump stacktrace from given $r1 frame pointer
+%---------------------------------------------------------------------------
+end
+
+############################################################################
+# OSE support
+#
+define etp-ose-attach
+ target ose $arg0:21768
+ attach block start_beam start_beam
+end
+
+document etp-ose-attach
+%---------------------------------------------------------------------------
+% etp-ose-attach Host
+%
+% Connect and attach to erlang vm at Host.
+%---------------------------------------------------------------------------
+end
+
+
############################################################################
# Erlang support module handling
#
@@ -2762,6 +3406,154 @@ define etp-thr
end
############################################################################
+# erl_alloc_util (blocks and carriers)
+#
+
+define etp-block-size-1
+#
+# In: (Block_t*) in $arg0
+# Out: Byte size in $etp_blk_sz
+#
+ if ($arg0)->bhdr & 1
+ # Free block
+ set $etp_blk_sz = ($arg0)->bhdr & ~7
+ else
+ # Allocated block
+ if !$etp_MBC_ABLK_SZ_MASK
+ if etp_arch_bits == 64
+ set $etp_MBC_ABLK_OFFSET_SHIFT = (64 - 24)
+ else
+ set $etp_MBC_ABLK_OFFSET_SHIFT = (32 - 9)
+ end
+ set $etp_MBC_ABLK_SZ_MASK = ((UWord)1 << $etp_MBC_ABLK_OFFSET_SHIFT) - 1 - 7
+ end
+ set $etp_blk_sz = ($arg0)->bhdr & $etp_MBC_ABLK_SZ_MASK
+ end
+end
+
+define etp-block2mbc-1
+#
+# In: (Block_t*) in $arg0
+# Out: (Carrier_t*) in $etp-mbc
+#
+ if (($arg0)->bhdr) & 1
+ # Free block
+ set $etp_mbc = ($arg0)->u.carrier
+ else
+ # Allocated block
+ if !$etp_MBC_ABLK_OFFSET_SHIFT
+ if etp_arch_bits == 64
+ set $etp_MBC_ABLK_OFFSET_SHIFT = (64 - 24)
+ else
+ set $etp_MBC_ABLK_OFFSET_SHIFT = (32 - 9)
+ end
+ end
+ set $etp_mbc = (Carrier_t*) ((((UWord)($arg0) >> 18) - (($arg0)->bhdr >> $etp_MBC_ABLK_OFFSET_SHIFT)) << 18)
+ end
+end
+
+define etp-block2mbc
+ etp-block2mbc-1 ((Block_t*)$arg0)
+ print $etp_mbc
+end
+
+document etp-block2mbc
+%---------------------------------------------------------------------------
+% Print pointer to multiblock carrier containing the argument (Block_t*)
+%---------------------------------------------------------------------------
+end
+
+define etp-block
+ etp-block-size-1 ((Block_t*)$arg0)
+ if ((Block_t*)$arg0)->bhdr & 1
+ printf "%#lx: FREE sz=%#x\n", ($arg0), $etp_blk_sz
+ else
+ printf "%#lx: ALLOCATED sz=%#x\n", ($arg0), $etp_blk_sz
+ end
+end
+
+document etp-block
+%---------------------------------------------------------------------------
+% Print memory block (Block_t*)
+%---------------------------------------------------------------------------
+end
+
+define etp-carrier-blocks
+ set $etp_crr = (Carrier_t*) $arg0
+ set $etp_alc = (Allctr_t*)($etp_crr->allctr.counter & ~7)
+ 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
+
+ if $argc == 2
+ set $etp_be_silent = $arg1
+ else
+ set $etp_be_silent = 0
+ end
+
+ while 1
+ if !$etp_be_silent
+ etp-block $etp_blk
+ else
+ etp-block-size-1 $etp_blk
+ end
+ etp-block2mbc-1 $etp_blk
+ if $etp_mbc != $etp_crr
+ printf "ERROR: Invalid carrier pointer %#lx in block at %#lx\n", $etp_mbc, $etp_blk
+ set $etp_error_cnt = $etp_error_cnt + 1
+ end
+ if $etp_prev_blk
+ if ($etp_prev_blk->bhdr & 1)
+ # Prev is FREE
+ if ($etp_blk->bhdr & 1)
+ printf "ERROR: Adjacent FREE blocks at %#lx and %#lx\n", $etp_prev_blk, $etp_blk
+ set $etp_error_cnt = $etp_error_cnt + 1
+ end
+ if !($etp_blk->bhdr & 2)
+ printf "ERROR: Missing PREV_FREE_BLK_HDR_FLG (2) in block at %#lx\n", $etp_blk
+ set $etp_error_cnt = $etp_error_cnt + 1
+ end
+ end
+ end
+ if $etp_blk->bhdr & 1
+ set $etp_fblk_cnt = $etp_fblk_cnt + 1
+ else
+ set $etp_ablk_cnt = $etp_ablk_cnt + 1
+ end
+ if $etp_blk->bhdr & 4
+ # Last block
+ loop_break
+ end
+ # All free blocks except the last have a footer
+ if ($etp_blk->bhdr & 1) && ((UWord*)((char*)$etp_blk + $etp_blk_sz))[-1] != $etp_blk_sz
+ printf "ERROR: Invalid footer of free block at %#lx\n", $etp_blk
+ end
+ set $etp_prev_blk = $etp_blk
+ set $etp_blk = (Block_t*) ((char*)$etp_blk + $etp_blk_sz)
+ 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
+ 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
+ end
+end
+
+document etp-carrier-blocks
+%---------------------------------------------------------------------------
+% Check and (maybe) print all memory blocks in carrier
+% Args: (Carrier_t*) [1=be_silent]
+%---------------------------------------------------------------------------
+end
+
+
+############################################################################
# Toolbox parameter handling
#
diff --git a/erts/etc/unix/run_erl.c b/erts/etc/unix/run_erl.c
index 2018bc007c..a6fc4c2bf5 100644
--- a/erts/etc/unix/run_erl.c
+++ b/erts/etc/unix/run_erl.c
@@ -79,81 +79,25 @@
# include <stropts.h>
#endif
-#include "run_erl.h"
+#include "run_erl_common.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);
@@ -161,20 +105,11 @@ 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.
@@ -205,29 +140,13 @@ 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;
- int fd;
- char *p, *ptyslave=NULL;
+ char *ptyslave=NULL;
int i = 1;
int off_argv;
- int calculated_pipename = 0;
- int highest_pipe_num = 0;
program_name = argv[0];
@@ -245,122 +164,16 @@ int main(int argc, char **argv)
off_argv = i;
strn_cpy(pipename, sizeof(pipename), argv[i++]);
- strn_cpy(log_dir, sizeof(log_dir), argv[i]);
- strn_cpy(statusfile, sizeof(statusfile), log_dir);
- strn_cat(statusfile, sizeof(statusfile), STATUSFILENAME);
+
+ erts_run_erl_log_init(run_daemon,argv[i]);
#ifdef DEBUG
- status("%s: pid is : %d\n", argv[0], getpid());
+ erts_run_erl_log_status("%s: pid is : %d\n", argv[0], getpid());
#endif
- /* 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 read and write fifo */
+ if (erts_run_erl_open_fifo(pipename,fifo1,fifo2))
+ exit(1);
/*
* Open master pseudo-terminal
@@ -432,7 +245,7 @@ int main(int argc, char **argv)
sf_close(2);
if (dup(sfd) != 0 || dup(sfd) != 1 || dup(sfd) != 2) {
- status("Cannot dup\n");
+ erts_run_erl_log_status("Cannot dup\n");
}
sf_close(sfd);
exec_shell(argv+off_argv); /* exec_shell expects argv[2] to be */
@@ -475,9 +288,7 @@ static void pass_on(pid_t childpid)
struct timeval timeout;
time_t last_activity;
char buf[BUFSIZ];
- char log_alive_buffer[ALIVE_BUFFSIZ+1];
- int lognum;
- int rfd, wfd=0, lfd=0;
+ int rfd, wfd=0;
int maxfd;
int ready;
int got_some = 0; /* from to_erl */
@@ -492,13 +303,12 @@ static void pass_on(pid_t childpid)
}
#ifdef DEBUG
- status("run_erl: %s opened for reading\n", fifo2);
+ erts_run_erl_log_status("run_erl: %s opened for reading\n", fifo2);
#endif
/* Open the log file */
- lognum = find_next_log_num();
- lfd = open_log(lognum, O_RDWR|O_APPEND|O_CREAT|O_SYNC);
+ erts_run_erl_log_open();
/* Enter the work loop */
@@ -517,7 +327,8 @@ static void pass_on(pid_t childpid)
writefds_ptr = &writefds;
}
time(&last_activity);
- timeout.tv_sec = log_alive_minutes*60; /* don't assume old BSD bug */
+ /* don't assume old BSD bug */
+ timeout.tv_sec = erts_run_erl_log_alive_minutes()*60;
timeout.tv_usec = 0;
ready = select(maxfd + 1, &readfds, writefds_ptr, NULL, &timeout);
if (ready < 0) {
@@ -547,28 +358,7 @@ static void pass_on(pid_t childpid)
/* Check how long time we've been inactive */
time(&now);
- 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));
- }
+ erts_run_erl_log_activity(!ready,now,last_activity);
}
/*
@@ -603,7 +393,7 @@ static void pass_on(pid_t childpid)
*/
if (FD_ISSET(mfd, &readfds)) {
#ifdef DEBUG
- status("Pty master read; ");
+ erts_run_erl_log_status("Pty master read; ");
#endif
if ((len = sf_read(mfd, buf, BUFSIZ)) <= 0) {
sf_close(rfd);
@@ -621,7 +411,7 @@ static void pass_on(pid_t childpid)
exit(0);
}
- write_to_log(&lfd, &lognum, buf, len);
+ erts_run_erl_log_write(buf, len);
/*
* Save in the output queue.
@@ -637,7 +427,7 @@ static void pass_on(pid_t childpid)
*/
if (FD_ISSET(rfd, &readfds)) {
#ifdef DEBUG
- status("FIFO read; ");
+ erts_run_erl_log_status("FIFO read; ");
#endif
if ((len = sf_read(rfd, buf, BUFSIZ)) < 0) {
sf_close(rfd);
@@ -666,7 +456,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) {
- status("Client expected on FIFO %s, but can't open (len=%d)\n",
+ erts_run_erl_log_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);
@@ -678,7 +468,7 @@ static void pass_on(pid_t childpid)
}
else {
#ifdef DEBUG
- status("run_erl: %s opened for writing\n", fifo1);
+ erts_run_erl_log_status("run_erl: %s opened for writing\n", fifo1);
#endif
}
}
@@ -694,14 +484,15 @@ static void pass_on(pid_t childpid)
/* Write the message */
#ifdef DEBUG
- status("Pty master write; ");
+ erts_run_erl_log_status("Pty master write; ");
#endif
- len = extract_ctrl_seq(buf, len);
+ len = erts_run_erl_extract_ctrl_seq(buf, len);
if(len==1 && buf[0] == '\003') {
kill(childpid,SIGINT);
- }
- else if (len>0 && write_all(mfd, buf, len) != len) {
+ }
+ else if (len>0 && erts_run_erl_write_all(mfd, buf, len) != len)
+ {
ERRNO_ERR0(LOG_ERR,"Error in writing to terminal.");
sf_close(rfd);
if(wfd) sf_close(wfd);
@@ -710,7 +501,7 @@ static void pass_on(pid_t childpid)
}
}
#ifdef DEBUG
- status("OK\n");
+ erts_run_erl_log_status("OK\n");
#endif
}
}
@@ -720,173 +511,6 @@ 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");
-
-#if 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");
- }
-
-#if 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.
@@ -1083,9 +707,9 @@ static void exec_shell(char **argv)
else
argv[0] = sh;
argv[1] = "-c";
- status("Args before exec of shell:\n");
+ erts_run_erl_log_status("Args before exec of shell:\n");
for (vp = argv, i = 0; *vp; vp++, i++)
- status("argv[%d] = %s\n", i, *vp);
+ erts_run_erl_log_status("argv[%d] = %s\n", i, *vp);
if (stdstatus) {
fclose(stdstatus);
}
@@ -1096,26 +720,6 @@ 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... */
@@ -1155,47 +759,10 @@ 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: %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;
+ fprintf(stderr, "Usage: ");
+ fprintf(stderr, RUN_ERL_USAGE, pname);
}
static void init_outbuf(void)
@@ -1266,114 +833,6 @@ 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) {
- int res = 0;
-
- do { res = close(fd); } while(fd < 0 && errno == EINTR);
-
- return res;
-}
-/* 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
deleted file mode 100644
index 843cda680c..0000000000
--- a/erts/etc/unix/run_erl.h
+++ /dev/null
@@ -1,30 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-
-/*
- * The protocol version number used between to_erl and run_erl.
- */
-#define RUN_ERL_HI_VER 1 /* My preferred protocol version */
-#define RUN_ERL_LO_VER 0 /* The lowest version I accept to talk with */
-
-/* Version history:
- * 0: Older, without version handshake
- * 1: R12B-3, version handshake + window size ctrl
- */
-
diff --git a/erts/etc/unix/safe_string.c b/erts/etc/unix/safe_string.c
deleted file mode 100644
index a77d9c5456..0000000000
--- a/erts/etc/unix/safe_string.c
+++ /dev/null
@@ -1,123 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-/*
- * Module: safe_string.c
- *
- * This is a bunch of generic string operation
- * that are safe regarding buffer overflow.
- *
- * All string functions terminate the process with an error message
- * on buffer overflow.
- */
-
-#ifdef HAVE_CONFIG_H
-# include "config.h"
-#endif
-#include "safe_string.h"
-#include <stdio.h>
-#include <string.h>
-#include <stdarg.h>
-#include <stdlib.h>
-
-
-static void string_overflow_handler(const char* format, ...)
-{
- va_list args;
- va_start(args, format);
- vfprintf(stderr,format,args);
- va_end(args);
- exit(1);
-}
-
-int vsn_printf(char* dst, size_t size, const char* format, va_list args)
-{
- int ret = vsnprintf(dst, size, format, args);
- if (ret >= size || ret < 0) {
- string_overflow_handler("Buffer truncated '%s'\n",dst);
- }
- return ret;
-}
-
-int sn_printf(char* dst, size_t size, const char* format, ...)
-{
- va_list args;
- int ret;
- va_start(args, format);
- ret = vsn_printf(dst,size,format,args);
- va_end(args);
- return ret;
-}
-
-int strn_cpy(char* dst, size_t size, const char* src)
-{
- return sn_printf(dst,size,"%s",src);
-}
-
-int strn_cat(char* dst, size_t size, const char* src)
-{
- return strn_catf(dst,size,"%s",src);
-}
-
-int strn_catf(char* dst, size_t size, const char* format, ...)
-{
- int ret;
- va_list args;
-#ifdef _GNU_SOURCE
- int len = strnlen(dst,size);
-#else
- int len = strlen(dst);
-#endif
-
- if (len >= size) {
- string_overflow_handler("Buffer already overflowed '%.*s'\n",
- size, dst);
- }
- va_start(args, format);
- ret = vsn_printf(dst+len, size-len, format, args);
- va_end(args);
- return len+ret;
-}
-
-char* find_str(const char* haystack, int hsize, const char* needle)
-{
- int i = 0;
- int nsize = strlen(needle);
- hsize -= nsize - 1;
- for (i=0; i<hsize; i++) {
- if (haystack[i]==needle[0] && strncmp(haystack+i,needle,nsize)==0) {
- return (char*)(haystack+i);
- }
- }
- return NULL;
-}
-
-#ifndef HAVE_MEMMOVE
-void* memmove(void *dest, const void *src, size_t n)
-{
- int i;
- if (src > dest) {
- for (i=0; i<n; i++) ((char*)dest)[i] = ((char*)src)[i];
- }
- else {
- for (i=(int)(n-1); i>=0; i--) ((char*)dest)[i] = ((char*)src)[i];
- }
- return dest;
-}
-#endif /* HAVE_MEMMOVE */
-
diff --git a/erts/etc/unix/safe_string.h b/erts/etc/unix/safe_string.h
deleted file mode 100644
index c70e528814..0000000000
--- a/erts/etc/unix/safe_string.h
+++ /dev/null
@@ -1,65 +0,0 @@
-/*
- * %CopyrightBegin%
- *
- * Copyright Ericsson AB 2008-2009. All Rights Reserved.
- *
- * The contents of this file are subject to the Erlang Public License,
- * Version 1.1, (the "License"); you may not use this file except in
- * compliance with the License. You should have received a copy of the
- * Erlang Public License along with this software. If not, it can be
- * retrieved online at http://www.erlang.org/.
- *
- * Software distributed under the License is distributed on an "AS IS"
- * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
- * the License for the specific language governing rights and limitations
- * under the License.
- *
- * %CopyrightEnd%
- */
-/*
- * Module: safe_string.h
- *
- * This is an interface to a bunch of generic string operation
- * that are safe regarding buffer overflow.
- *
- * All string functions terminate the process with an error message
- * on buffer overflow.
- */
-
-#include <stdio.h>
-#include <stdarg.h>
-
-/* Like vsnprintf()
- */
-int vsn_printf(char* dst, size_t size, const char* format, va_list args);
-
-/* Like snprintf()
- */
-int sn_printf(char* dst, size_t size, const char* format, ...);
-
-/* Like strncpy()
- * Returns length of copied string.
- */
-int strn_cpy(char* dst, size_t size, const char* src);
-
-/* Almost like strncat()
- * size is sizeof entire dst buffer.
- * Returns length of resulting string.
- */
-int strn_cat(char* dst, size_t size, const char* src);
-
-/* Combination of strncat() and snprintf()
- * size is sizeof entire dst buffer.
- * Returns length of resulting string.
- */
-int strn_catf(char* dst, size_t size, const char* format, ...);
-
-/* Simular to strstr() but search size bytes of haystack
- * without regard to '\0' characters.
- */
-char* find_str(const char* haystack, int size, const char* needle);
-
-#ifndef HAVE_MEMMOVE
-void* memmove(void *dest, const void *src, size_t n);
-#endif
-
diff --git a/erts/etc/unix/to_erl.c b/erts/etc/unix/to_erl.c
index b9e397cbf2..38a94ed9c3 100644
--- a/erts/etc/unix/to_erl.c
+++ b/erts/etc/unix/to_erl.c
@@ -16,592 +16,9 @@
*
* %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 ^R 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 ^R 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
- if(write(1, buf, len));
-#endif
- if (write_all(wfd, buf, len) != len) {
- fprintf(stderr, "Error in writing to FIFO.\n");
- close(rfd);
- close(wfd);
- break;
- }
- STATUS("\" OK\r\n");
- }
-
- /*
- * 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
- * | |
- * |---------- '\022' -------->| (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;
-}
-
-#ifdef DEBUG
-#define S(x) ((x) > 0 ? 1 : 0)
+#include "to_erl_common.h"
-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]);
+int main(int argc,char **argv) {
+ return to_erl(argc,argv);
}
-#endif