查看源代码 简介

本节描述了在 UNIX 嵌入式系统上运行 Erlang 的特定问题。它描述了与非嵌入式系统相比,安装和启动 Erlang 的差异。

有关如何创建目标系统的详细信息,请参阅系统原则部分中的创建和升级目标系统

在 Windows 上运行时,无需进行特殊考虑。应该通过 erlsrv启动 Erlang。

安装嵌入式系统

本节介绍如何安装嵌入式系统。考虑以下主题:

  • 创建用户和安装目录
  • 安装嵌入式系统
  • 配置启动时自动启动
  • 更改重启权限
  • 设置 TERM 环境变量

本节中的几个步骤需要对操作系统有专业的了解。其中大部分步骤需要超级用户权限。

创建用户和安装目录

建议嵌入式环境由普通用户运行,即不具有超级用户权限的用户。

在本节中,假设用户名是 otpuser,并且该用户的主目录是

/home/otpuser

还假设在 otpuser 的主目录中,有一个名为 otp 的目录,其完整路径为

/home/otpuser/otp

此目录是嵌入式环境的安装目录

安装嵌入式系统

安装嵌入式系统的过程与安装普通系统相同(请参阅安装指南和系统原则部分中的创建和升级目标系统),但以下情况除外:

  • (压缩的)存档文件要解压缩到上面定义的安装目录中。
  • 无需将启动脚本链接到诸如 /usr/local/bin 之类的标准目录。

配置启动时自动启动

真正的嵌入式系统必须在系统启动时启动。本节介绍使用 init.d 启动脚本实现此目的所需的必要配置。

如果以下脚本文件添加到目录 /etc/rc3.d,则嵌入式系统和所有应用程序将自动启动。该文件必须归 root 所有并可由其读取。它的名称不能任意指定;建议使用以下名称

S75otp.system

有关初始化(和终止)脚本及其命名的更多详细信息,请参阅操作系统上的 init.d 文档。

#!/bin/sh
#
#  File name:  S75otp.system
#  Purpose:    Automatically starts Erlang and applications when the
#              system starts
#  Author:     [email protected]
#  Resides in: /etc/rc3.d
#

if [ ! -d /usr/bin ]
then                    # /usr not mounted
        exit
fi

killproc() {            # kill the named process(es)
        pid=`/usr/bin/ps -e |
             /usr/bin/grep -w $1 |
             /usr/bin/sed -e 's/^  *//' -e 's/ .*//'`
        [ "$pid" != "" ] && kill $pid
}

# Start/stop processes required for Erlang

case "$1" in
'start')
        # Start the Erlang emulator
        #
        su - otpuser -c "/home/otpuser/otp/bin/start" &
        ;;
'stop')
        killproc beam
        ;;
*)
        echo "Usage: $0 { start | stop }"
        ;;
esac

上述脚本中引用的文件 /home/otpuser/otp/bin/start 正是启动 Erlang中描述的 start 脚本。该 start 脚本中的脚本变量 $OTPROOT 对应于本节中使用的以下示例路径

/home/otpuser/otp

需要相应地编辑 start 脚本。

上述脚本中 killproc 过程的使用可以与对 erl_call 的调用相结合,例如

$SOME_PATH/erl_call -n Node init stop

要优雅地关闭 Erlang,请参阅 erl_interface 中的 erl_call(1) 手册页,了解有关使用 erl_call 的详细信息。但是,这需要 Erlang 作为分布式节点运行,但情况并非总是如此。

不要删除 killproc 过程。此处的目的是从运行级别 3(具有网络资源的多用户模式)移动到运行级别 2(不具有此类资源的多用户模式),其中 Erlang 不运行。

更改重启权限

如果要启动 Erlang中的 start 脚本中设置 HEART_COMMAND 环境变量,并且要将该值设置为 reboot 命令的路径,即

HEART_COMMAND=/usr/sbin/reboot

然后必须按如下方式更改 /usr/sbin/reboot 的所有权和文件权限

chown 0 /usr/sbin/reboot
chmod 4755 /usr/sbin/reboot

另请参阅 Kernel 中的 heart 手册页。

设置 TERM 环境变量

当 Erlang 运行时系统从 S75otp.system 脚本自动启动时,必须设置 TERM 环境变量。以下是一个最小设置

TERM=dumb

这要添加到 start 脚本中。

启动 Erlang

本节介绍如何启动嵌入式系统。涉及四个程序,它们通常位于目录 <ERL_INSTALL_DIR>/bin 中。唯一的例外是 start 程序,该程序可以位于任何位置,并且也是唯一必须由用户修改的程序。

在嵌入式系统中,通常没有交互式 shell。但是,操作员可以通过命令 to_erl 连接到 Erlang 系统。然后,操作员将连接到 Erlang shell,并可以发出普通的 Erlang 命令。通过此 shell 与系统的所有交互都记录在特殊目录中。

基本上,过程如下:

  • 当机器启动时,调用 start) 程序。
  • 它调用 run_erl,后者设置各项,以便操作员可以连接到系统。
  • 它调用 start_erl,后者使用正确的 bootconfig 文件调用正确版本的 erlexec(位于 <ERL_INSTALL_DIR>/erts-EVsn/bin 中)。

程序

start

当机器启动时,将调用此程序。可以修改或重写它以适应特殊系统。默认情况下,必须将其命名为 start 并驻留在 <ERL_INSTALL_DIR>/bin 中。可以使用应用程序 SASL 中的配置参数 start_prg 来使用另一个启动程序。

启动程序必须调用 run_erl,如下所示。它还必须采用一个可选参数,该参数默认为 <ERL_INSTALL_DIR>/releases/start_erl.data

此程序用于设置静态参数和环境变量,例如 -sname NameHEART_COMMAND 以重新启动机器。

<RELDIR> 目录是安装新发行包的位置,以及发行处理程序保留有关发行版信息的位置。有关更多信息,请参阅 SASL 中的 release_handler 手册页。

以下脚本说明了该程序的默认行为

#!/bin/sh
# Usage: start [DataFile]
#
ROOTDIR=/usr/local/otp

if [ -z "$RELDIR" ]
then
   RELDIR=$ROOTDIR/releases
fi

START_ERL_DATA=${1:-$RELDIR/start_erl.data}

$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl \
                     $ROOTDIR $RELDIR $START_ERL_DATA" > /dev/null 2>&1 &

以下脚本说明了一个修改,其中节点被赋予名称 cp1,并且已将环境变量 HEART_COMMANDTERM 添加到之前的脚本中

#!/bin/sh
# Usage: start [DataFile]
#
HEART_COMMAND=/usr/sbin/reboot
TERM=dumb
export HEART_COMMAND TERM

ROOTDIR=/usr/local/otp

if [ -z "$RELDIR" ]
then
   RELDIR=$ROOTDIR/releases
fi

START_ERL_DATA=${1:-$RELDIR/start_erl.data}

$ROOTDIR/bin/run_erl /tmp/ $ROOTDIR/log "exec $ROOTDIR/bin/start_erl \
      $ROOTDIR $RELDIR $START_ERL_DATA -heart -sname cp1" > /dev/null 2>&1 &

如果要启动无盘和/或只读客户端节点,则文件 start_erl.data 位于主节点的客户端目录中。因此,START_ERL_DATA 行应如下所示

CLIENTDIR=$ROOTDIR/clients/clientname
START_ERL_DATA=${1:-$CLIENTDIR/bin/start_erl.data}

run_erl

此程序用于启动模拟器,但您不会连接到 shell。 to_erl 用于连接到 Erlang shell。

Usage: run_erl pipe_dir/ log_dir "exec command [parameters ...]"

这里

  • pipe_dir/ 应为 /tmp/to_erl 默认使用此名称)。
  • log_dir 是写入日志文件的位置。
  • 执行 command [parameters]
  • 写入 stdinstdout 的所有内容都记录在 log_dir 中。

日志文件写入 log_dir 中。每个日志文件的名称格式为 erlang.log.N,其中 N 是一个生成编号,范围从 1 到 5。每个日志文件最多可保存 100 kB 的文本。随着时间的推移,在日志文件目录中找到以下日志文件

erlang.log.1
erlang.log.1, erlang.log.2
erlang.log.1, erlang.log.2, erlang.log.3
erlang.log.1, erlang.log.2, erlang.log.3, erlang.log.4
erlang.log.2, erlang.log.3, erlang.log.4, erlang.log.5
erlang.log.3, erlang.log.4, erlang.log.5, erlang.log.1
...

最近的日志文件是每行中最右边的文件。也就是说,最近的文件是编号最高的那个,或者如果已经有四个文件,则是跳过之前的那个。

当打开日志文件(用于追加或创建)时,会将时间戳写入该文件。如果 15 分钟内没有写入任何日志文件,则会插入一条记录,表明我们仍然处于活动状态。

有关更多详细信息,请参阅 ERTS 文档中的 run_erl

to_erl

此程序用于连接到使用 run_erl 启动的正在运行的 Erlang 运行时系统。

Usage: to_erl [pipe_name | pipe_dir]

此处,pipe_name 默认为 /tmp/erlang.pipe.N

要断开与 shell 的连接而不退出 Erlang 系统,请键入 Ctrl-D

start_erl

此程序使用设置的参数 -boot-config 启动 Erlang 模拟器。它从名为 start_erl.data 的文件中读取有关这些文件位置的数据,该文件位于 <RELDIR> 中。每个新发行版都会引入一个新的数据文件。此文件由 Erlang 中的发行处理程序自动生成。

以下脚本说明了该程序的行为

#!/bin/sh
#
# This program is called by run_erl. It starts
# the Erlang emulator and sets -boot and -config parameters.
# It should only be used at an embedded target system.
#
# Usage: start_erl RootDir RelDir DataFile [ErlFlags ...]
#
ROOTDIR=$1
shift
RELDIR=$1
shift
DataFile=$1
shift

ERTS_VSN=`awk '{print $1}' $DataFile`
VSN=`awk '{print $2}' $DataFile`

BINDIR=$ROOTDIR/erts-$ERTS_VSN/bin
EMU=beam
PROGNAME=`echo $0 | sed 's/.*\///'`
export EMU
export ROOTDIR
export BINDIR
export PROGNAME
export RELDIR

exec $BINDIR/erlexec -boot $RELDIR/$VSN/start -config $RELDIR/$VSN/sys $*

如果要启动 SASL 配置参数 static_emulator 设置为 true 的无盘和/或只读客户端节点,则必须更改 -boot-config 标志。

由于此类客户端无法读取新的 start_erl.data 文件(无法动态更改该文件)。引导文件和配置文件始终从同一位置获取(但如果安装了新版本,则内容会发生更改)。

每当新版本变为永久版本时,release_handler 都会将这些文件复制到主节点客户端目录中的 bin 目录。

假设使用与上述相同的 CLIENTDIR,最后一行应如下所示

exec $BINDIR/erlexec -boot $CLIENTDIR/bin/start \
     -config $CLIENTDIR/bin/sys $*