From 42c0d49c3e4c0fc55a498bc63d0db78308271883 Mon Sep 17 00:00:00 2001 From: nuex Date: Tue, 11 Mar 2014 11:22:46 -0400 Subject: Give release scripts ability to handle directories with spaces --- priv/templates/bin.dtl | 60 ++++++----- priv/templates/extended_bin.dtl | 222 ++++++++++++++++++++++++---------------- priv/templates/nodetool.dtl | 2 +- 3 files changed, 168 insertions(+), 116 deletions(-) diff --git a/priv/templates/bin.dtl b/priv/templates/bin.dtl index 8f8b048..4434552 100755 --- a/priv/templates/bin.dtl +++ b/priv/templates/bin.dtl @@ -2,51 +2,61 @@ set -e -SCRIPT_DIR=`dirname $0` -RELEASE_ROOT_DIR=`cd $SCRIPT_DIR/.. && pwd` -REL_NAME={{ rel_name }} -REL_VSN={{ rel_vsn }} -ERTS_VSN={{ erts_vsn }} -REL_DIR=$RELEASE_ROOT_DIR/releases/$REL_VSN -ERL_OPTS={{ erl_opts }} +SCRIPT_DIR="$(dirname "$0")" +RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +REL_NAME="{{ rel_name }}" +REL_VSN="{{ rel_vsn }}" +ERTS_VSN="{{ erts_vsn }}" +REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN" +ERL_OPTS="{{ erl_opts }}" find_erts_dir() { - local erts_dir=$RELEASE_ROOT_DIR/erts-$ERTS_VSN + local erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN" if [ -d "$erts_dir" ]; then - ERTS_DIR=$erts_dir; - ROOTDIR=$RELEASE_ROOT_DIR + ERTS_DIR="$erts_dir"; + ROOTDIR="$RELEASE_ROOT_DIR" else - local erl=`which erl` - local erl_root=`$erl -noshell -eval "io:format(\\"~s\\", [code:root_dir()])." -s init stop` - ERTS_DIR=$erl_root/erts-$ERTS_VSN - ROOTDIR=$erl_root + local erl="$(which erl)" + local erl_root="$("$erl" -noshell -eval "io:format(\\"~s\\", [code:root_dir()])." -s init stop)" + ERTS_DIR="$erl_root/erts-$ERTS_VSN" + ROOTDIR="$erl_root" fi } find_sys_config() { - local possible_sys=$REL_DIR/sys.config + local possible_sys="$REL_DIR/sys.config" if [ -f "$possible_sys" ]; then - SYS_CONFIG="-config $possible_sys" + SYS_CONFIG="$possible_sys" fi } find_vm_args() { - local possible_vm_args=$REL_DIR/vm.args + local possible_vm_args="$REL_DIR/vm.args" if [ -f "$possible_vm_args" ]; then - VM_ARGS="-args_file $possible_vm_args" + VM_ARGS="$possible_vm_args" fi } find_erts_dir find_sys_config find_vm_args -export ROOTDIR=$RELEASE_ROOT_DIR -export BINDIR=$ERTS_DIR/bin -export EMU=beam -export PROGNAME=erl -export LD_LIBRARY_PATH=$ERTS_DIR/lib:$LD_LIBRARY_PATH +export ROOTDIR="$RELEASE_ROOT_DIR" +export BINDIR="$ERTS_DIR/bin" +export EMU="beam" +export PROGNAME="erl" +export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH" -cd $ROOTDIR +cd "$ROOTDIR" -$BINDIR/erlexec $ERL_OPTS $SYS_CONFIG $VM_ARGS -boot $REL_DIR/$REL_NAME $@ +# Save extra arguments +ARGS="$@" + +# Build arguments for erlexec +set -- "$ERL_OPTS" +[ "$SYS_CONFIG" ] && set -- "$@" -config "$SYS_CONFIG" +[ "$VM_ARGS" ] && set -- "$@" -args_file "$VM_ARGS" +set -- "$@" -boot "$REL_DIR/$REL_NAME" "$ARGS" + +# Boot the release +"$BINDIR/erlexec" "$@" diff --git a/priv/templates/extended_bin.dtl b/priv/templates/extended_bin.dtl index 75f3859..59cf692 100644 --- a/priv/templates/extended_bin.dtl +++ b/priv/templates/extended_bin.dtl @@ -2,44 +2,60 @@ set -e -SCRIPT_DIR=`dirname $0` -RELEASE_ROOT_DIR=`cd $SCRIPT_DIR/.. && pwd` -REL_NAME={{ rel_name }} -REL_VSN={{ rel_vsn }} -ERTS_VSN={{ erts_vsn }} -REL_DIR=$RELEASE_ROOT_DIR/releases/$REL_VSN -ERL_OPTS={{ erl_opts }} -PIPE_DIR=/tmp/erl_pipes/{{ rel_name }}/ -RUNNER_LOG_DIR=${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log} +SCRIPT_DIR="$(dirname "$0")" +RELEASE_ROOT_DIR="$(cd "$SCRIPT_DIR/.." && pwd)" +REL_NAME="{{ rel_name }}" +REL_VSN="{{ rel_vsn }}" +ERTS_VSN="{{ erts_vsn }}" +REL_DIR="$RELEASE_ROOT_DIR/releases/$REL_VSN" +ERL_OPTS="{{ erl_opts }}" +PIPE_DIR="/tmp/erl_pipes/{{ rel_name }}/" +RUNNER_LOG_DIR="${RUNNER_LOG_DIR:-$RELEASE_ROOT_DIR/log}" find_erts_dir() { - local erts_dir=$RELEASE_ROOT_DIR/erts-$ERTS_VSN + local erts_dir="$RELEASE_ROOT_DIR/erts-$ERTS_VSN" if [ -d "$erts_dir" ]; then - ERTS_DIR=$erts_dir; - ROOTDIR=$RELEASE_ROOT_DIR + ERTS_DIR="$erts_dir"; + ROOTDIR="$RELEASE_ROOT_DIR" else - local erl=`which erl` - local erl_root=`$erl -noshell -eval "io:format(\\"~s\\", [code:root_dir()])." -s init stop` - ERTS_DIR=$erl_root/erts-$ERTS_VSN - ROOTDIR=$erl_root + local erl="$(which erl)" + local erl_root="$("$erl" -noshell -eval "io:format(\\"~s\\", [code:root_dir()])." -s init stop)" + ERTS_DIR="$erl_root/erts-$ERTS_VSN" + ROOTDIR="$erl_root" fi +} + +# Connect to a remote node +relx_rem_sh() { + # Generate a unique id used to allow multiple remsh to the same node + # transparently + id="remsh$(date +%s`@`echo "$NAME" | awk -F@ '{print $2}')" + # Setup remote shell command to control node + exec "$BINDIR/erl" "$NAME_TYPE" "$id" -remsh "$NAME" -boot start_clean \ + -setcookie "$COOKIE" } -find_sys_config() { - local possible_sys=$REL_DIR/sys.config - if [ -f "$possible_sys" ]; then - SYS_CONFIG="-config $possible_sys" - fi +# Control a node +relx_nodetool() { + command="$1"; shift + "erts-$ERTS_VSN/bin/escript" "$ROOTDIR/bin/nodetool" "$NAME_TYPE" "$NAME" \ + -setcookie "$COOKIE" "$command" +} + +# Output a start command for the last argument of run_erl +relx_start_command() { + printf "exec \"%s\" \"%s\"" "$RELEASE_ROOT_DIR/bin/$REL_NAME" \ + "$START_OPTION" } # Use $CWD/vm.args if exists, otherwise releases/APP_VSN/vm.args, or else etc/vm.args if [ -z "$VMARGS_PATH" ]; then if [ -e "$RELEASE_ROOT_DIR/vm.args" ]; then - VMARGS_PATH=$RELEASE_ROOT_DIR/vm.args - USE_DIR=$RELEASE_ROOT_DIR + VMARGS_PATH="$RELEASE_ROOT_DIR/vm.args" + USE_DIR="$RELEASE_ROOT_DIR" else - USE_DIR=$REL_DIR + USE_DIR="$REL_DIR" if [ -e "$REL_DIR/vm.args" ]; then VMARGS_PATH="$REL_DIR/vm.args" else @@ -49,7 +65,7 @@ if [ -z "$VMARGS_PATH" ]; then fi # Make sure log directory exists -mkdir -p $RUNNER_LOG_DIR +mkdir -p "$RUNNER_LOG_DIR" # Use releases/VSN/sys.config if it exists otherwise use etc/app.config if [ -z "$CONFIG_PATH" ]; then @@ -65,42 +81,34 @@ if [ -z "$CONFIG_PATH" ]; then fi # Extract the target node name from node.args -NAME_ARG=`egrep '^-s?name' $VMARGS_PATH` +NAME_ARG=$(egrep '^-s?name' "$VMARGS_PATH") if [ -z "$NAME_ARG" ]; then echo "vm.args needs to have either -name or -sname parameter." exit 1 fi # Extract the name type and name from the NAME_ARG for REMSH -REMSH_TYPE=`echo $NAME_ARG | awk '{print $1}'` -REMSH_NAME=`echo $NAME_ARG | awk '{print $2}'` - -# Note the `date +%s`, used to allow multiple remsh to the same node transparently -REMSH_NAME_ARG="$REMSH_TYPE remsh`date +%s`@`echo $REMSH_NAME | awk -F@ '{print $2}'`" -REMSH_REMSH_ARG="-remsh $REMSH_NAME -boot start_clean" +NAME_TYPE="$(echo "$NAME_ARG" | awk '{print $1}')" +NAME="$(echo "$NAME_ARG" | awk '{print $2}')" # Extract the target cookie -COOKIE_ARG=`grep '^-setcookie' $VMARGS_PATH` +COOKIE_ARG="$(grep '^-setcookie' "$VMARGS_PATH")" if [ -z "$COOKIE_ARG" ]; then echo "vm.args needs to have a -setcookie parameter." exit 1 fi -find_erts_dir -find_sys_config -export ROOTDIR=$RELEASE_ROOT_DIR -export BINDIR=$ERTS_DIR/bin -export EMU=beam -export PROGNAME=erl -export LD_LIBRARY_PATH=$ERTS_DIR/lib:$LD_LIBRARY_PATH - -cd $ROOTDIR +# Extract cookie name from COOKIE_ARG +COOKIE="$(echo "$COOKIE_ARG" | awk '{print $2}')" -# Setup remote shell command to control node -REMSH="$BINDIR/erl $REMSH_NAME_ARG $REMSH_REMSH_ARG $COOKIE_ARG" +find_erts_dir +export ROOTDIR="$RELEASE_ROOT_DIR" +export BINDIR="$ERTS_DIR/bin" +export EMU="beam" +export PROGNAME="erl" +export LD_LIBRARY_PATH="$ERTS_DIR/lib:$LD_LIBRARY_PATH" -# Setup command to control the node -NODETOOL="$BINDIR/escript $ROOTDIR/bin/nodetool $NAME_ARG $COOKIE_ARG" +cd "$ROOTDIR" # Check the first argument for instructions case "$1" in @@ -124,37 +132,46 @@ case "$1" in HEART_OPTION="start_boot" ;; esac - RUN_PARAM=$(printf "'%s' " "$@") - HEART_COMMAND="$SCRIPT_DIR/bin/$REL_NAME $HEART_OPTION $RUN_PARAM" + RUN_PARAM="$@" + + # Set arguments for the heart command + set -- "$SCRIPT_DIR/$REL_NAME" "$HEART_OPTION" + [ "$RUN_PARAM" ] && set -- "$@" "$RUN_PARAM" + + # Export the HEART_COMMAND + HEART_COMMAND="$@" export HEART_COMMAND - mkdir -p $PIPE_DIR - $BINDIR/run_erl -daemon $PIPE_DIR $RUNNER_LOG_DIR "exec $RELEASE_ROOT_DIR/bin/$REL_NAME $START_OPTION $RUN_PARAM" 2>&1 + + mkdir -p "$PIPE_DIR" + + "$BINDIR/run_erl" -daemon "$PIPE_DIR" "$RUNNER_LOG_DIR" \ + "$(relx_start_command)" ;; stop) # Wait for the node to completely stop... - case `uname -s` in + case $(uname -s) in Linux|Darwin|FreeBSD|DragonFly|NetBSD|OpenBSD) # PID COMMAND - PID=`ps ax -o pid= -o command=| - grep "$SCRIPT_DIR/.*/[b]eam"|awk '{print $1}'` + PID=$(ps ax -o pid= -o command=| + grep "$SCRIPT_DIR/.*/[b]eam"|awk '{print $1}') ;; SunOS) # PID COMMAND - PID=`ps -ef -o pid= -o args=| - grep "$SCRIPT_DIR/.*/[b]eam"|awk '{print $1}'` + PID=$(ps -ef -o pid= -o args=| + grep "$SCRIPT_DIR/.*/[b]eam"|awk '{print $1}') ;; CYGWIN*) # UID PID PPID TTY STIME COMMAND - PID=`ps -efW|grep "$SCRIPT_DIR/.*/[b]eam"|awk '{print $2}'` + PID=$(ps -efw|grep "$SCRIPT_DIR/.*/[b]eam"|awk '{print $2}') ;; esac - $NODETOOL stop - ES=$? + relx_nodetool "stop" + ES="$?" if [ "$ES" -ne 0 ]; then - exit $ES + exit "$ES" fi - while `kill -0 $PID 2>/dev/null`; + while $(kill -0 "$PID" 2>/dev/null); do sleep 1 done @@ -162,8 +179,8 @@ case "$1" in restart) ## Restart the VM without exiting the process - $NODETOOL restart - ES=$? + relx_nodetool "restart" + ES="$?" if [ "$ES" -ne 0 ]; then exit $ES fi @@ -171,8 +188,8 @@ case "$1" in reboot) ## Restart the VM completely (uses heart to restart it) - $NODETOOL reboot - ES=$? + relx_nodetool "reboot" + ES="$?" if [ "$ES" -ne 0 ]; then exit $ES fi @@ -180,8 +197,8 @@ case "$1" in ping) ## See if the VM is alive - $NODETOOL ping - ES=$? + relx_nodetool "ping" + ES="$?" if [ "$ES" -ne 0 ]; then exit $ES fi @@ -189,28 +206,28 @@ case "$1" in attach) # Make sure a node IS running - RES=`$NODETOOL ping` - ES=$? + RES="$(relx_nodetool "ping")" + ES="$?" if [ "$ES" -ne 0 ]; then echo "Node is not running!" exit $ES fi shift - exec $BINDIR/to_erl $PIPE_DIR + exec "$BINDIR/to_erl" "$PIPE_DIR" ;; remote_console) # Make sure a node IS running - RES=`$NODETOOL ping` - ES=$? + RES="$(relx_nodetool "ping")" + ES="$?" if [ "$ES" -ne 0 ]; then echo "Node is not running!" exit $ES fi shift - exec $REMSH + relx_rem_sh ;; upgrade|downgrade|install) @@ -222,17 +239,15 @@ case "$1" in fi # Make sure a node IS running - RES=`$NODETOOL ping` - ES=$? + RES="$(relx_nodetool "ping")" + ES="$?" if [ "$ES" -ne 0 ]; then echo "Node is not running!" exit $ES fi - node_name=`echo $NAME_ARG | awk '{print $2}'` - erlang_cookie=`echo $COOKIE_ARG | awk '{print $2}'` - - exec $BINDIR/escript $ROOTDIR/bin/install_upgrade.escript $REL_NAME $node_name $erlang_cookie $2 + exec "$BINDIR/escript" "$ROOTDIR/bin/install_upgrade.escript" \ + "$REL_NAME" "$NAME" "$COOKIE" "$2" ;; console|console_clean|console_boot) @@ -240,8 +255,16 @@ case "$1" in # however, for debugging, sometimes start_clean.boot is useful. # For e.g. 'setup', one may even want to name another boot script. case "$1" in - console) [ -f $REL_DIR/$REL_NAME.boot ] && BOOTFILE=$REL_DIR/$REL_NAME || BOOTFILE=$REL_DIR/start ;; - console_clean) BOOTFILE=$ROOTDIR/bin/start_clean ;; + console) + if [ "$REL_DIR/$REL_NAME.boot" ]; then + BOOTFILE="$REL_DIR/$REL_NAME" + else + BOOTFILE="$REL_DIR/start" + fi + ;; + console_clean) + BOOTFILE="$ROOTDIR/bin/start_clean" + ;; console_boot) shift BOOTFILE="$1" @@ -249,43 +272,62 @@ case "$1" in ;; esac # Setup beam-required vars - EMU=beam - PROGNAME=`echo $0 | sed 's/.*\\///'` - CMD="$BINDIR/erlexec -boot $BOOTFILE -env ERL_LIBS $REL_DIR/lib -config $CONFIG_PATH -args_file $VMARGS_PATH" + EMU="beam" + PROGNAME="${0#*/}" + export EMU export PROGNAME + # Store passed arguments since they will be erased by `set` + ARGS="$@" + + # Build an array of arguments to pass to exec later on + # Build it here because this command will be used for logging. + set -- "$BINDIR/erlexec" -boot "$BOOTFILE" \ + -env ERL_LIBS "$REL_DIR/lib" -config "$CONFIG_PATH" \ + -args_file "$VMARGS_PATH" + # Dump environment info for logging purposes - echo "Exec: $CMD" -- ${1+"$@"} + echo "Exec: $@ -- ${1+$ARGS}" echo "Root: $ROOTDIR" # Log the startup + echo "$RELEASE_ROOT_DIR" logger -t "$REL_NAME[$$]" "Starting up" # Start the VM - exec $CMD -- ${1+"$@"} + exec "$@" -- "${1+$ARGS}" ;; foreground) # start up the release in the foreground for use by runit # or other supervision services - [ -f $REL_DIR/$REL_NAME.boot ] && BOOTFILE=$REL_NAME || BOOTFILE=start + [ -f "$REL_DIR/$REL_NAME.boot" ] && BOOTFILE="$REL_NAME" || BOOTFILE=start FOREGROUNDOPTIONS="-noinput +Bd" # Setup beam-required vars EMU=beam - PROGNAME=`echo $0 | sed 's/.*\\///'` - CMD="$BINDIR/erlexec $FOREGROUNDOPTIONS -boot $REL_DIR/$BOOTFILE -mode embedded -config $CONFIG_PATH -args_file $VMARGS_PATH" + PROGNAME="${0#*/}" + export EMU export PROGNAME + # Store passed arguments since they will be erased by `set` + ARGS="$@" + + # Build an array of arguments to pass to exec later on + # Build it here because this command will be used for logging. + set -- "$BINDIR/erlexec" "$FOREGROUNDOPTIONS" \ + -boot "$REL_DIR/$BOOTFILE" -mode embedded -config "$CONFIG_PATH" \ + -args_file "$VMARGS_PATH" + # Dump environment info for logging purposes - echo "Exec: $CMD" -- ${1+"$@"} + echo "Exec: $@" -- "${1+$ARGS}" echo "Root: $ROOTDIR" # Start the VM - exec $CMD -- ${1+"$@"} + exec "$@" -- "${1+$ARGS}" ;; *) echo "Usage: $REL_NAME {start|start_boot |foreground|stop|restart|reboot|ping|console|console_clean|console_boot |attach|remote_console|upgrade}" diff --git a/priv/templates/nodetool.dtl b/priv/templates/nodetool.dtl index a6faad5..80f1965 100644 --- a/priv/templates/nodetool.dtl +++ b/priv/templates/nodetool.dtl @@ -75,7 +75,7 @@ process_args([Arg | Rest], Acc, Opts) -> start_epmd() -> - [] = os:cmd(epmd_path() ++ " -daemon"), + [] = os:cmd("\"" ++ epmd_path() ++ "\" -daemon"), ok. epmd_path() -> -- cgit v1.2.3