|
|
|
@ -8,12 +8,74 @@
|
|
|
|
|
|
|
|
|
|
# program : Arthas
|
|
|
|
|
# author : Core Engine @ Taobao.com
|
|
|
|
|
# date : 2019-05-15
|
|
|
|
|
# date : 2019-09-09
|
|
|
|
|
|
|
|
|
|
# current arthas script version
|
|
|
|
|
ARTHAS_SCRIPT_VERSION=3.1.1
|
|
|
|
|
ARTHAS_SCRIPT_VERSION=3.1.2
|
|
|
|
|
|
|
|
|
|
DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"
|
|
|
|
|
# SYNOPSIS
|
|
|
|
|
# rreadlink <fileOrDirPath>
|
|
|
|
|
# DESCRIPTION
|
|
|
|
|
# Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and
|
|
|
|
|
# prints its canonical path. If it is not a symlink, its own canonical path
|
|
|
|
|
# is printed.
|
|
|
|
|
# A broken symlink causes an error that reports the non-existent target.
|
|
|
|
|
# LIMITATIONS
|
|
|
|
|
# - Won't work with filenames with embedded newlines or filenames containing
|
|
|
|
|
# the string ' -> '.
|
|
|
|
|
# COMPATIBILITY
|
|
|
|
|
# This is a fully POSIX-compliant implementation of what GNU readlink's
|
|
|
|
|
# -e option does.
|
|
|
|
|
# EXAMPLE
|
|
|
|
|
# In a shell script, use the following to get that script's true directory of origin:
|
|
|
|
|
# trueScriptDir=$(dirname -- "$(rreadlink "$0")")
|
|
|
|
|
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.
|
|
|
|
|
|
|
|
|
|
target=$1 fname= targetDir= CDPATH=
|
|
|
|
|
|
|
|
|
|
# Try to make the execution environment as predictable as possible:
|
|
|
|
|
# All commands below are invoked via `command`, so we must make sure that
|
|
|
|
|
# `command` itself is not redefined as an alias or shell function.
|
|
|
|
|
# (Note that command is too inconsistent across shells, so we don't use it.)
|
|
|
|
|
# `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not
|
|
|
|
|
# even have an external utility version of it (e.g, Ubuntu).
|
|
|
|
|
# `command` bypasses aliases and shell functions and also finds builtins
|
|
|
|
|
# in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for
|
|
|
|
|
# that to happen.
|
|
|
|
|
{ \unalias command; \unset -f command; } >/dev/null 2>&1
|
|
|
|
|
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.
|
|
|
|
|
|
|
|
|
|
while :; do # Resolve potential symlinks until the ultimate target is found.
|
|
|
|
|
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
|
|
|
|
|
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
|
|
|
|
|
fname=$(command basename -- "$target") # Extract filename.
|
|
|
|
|
[ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
|
|
|
|
|
if [ -L "$fname" ]; then
|
|
|
|
|
# Extract [next] target path, which may be defined
|
|
|
|
|
# *relative* to the symlink's own directory.
|
|
|
|
|
# Note: We parse `ls -l` output to find the symlink target
|
|
|
|
|
# which is the only POSIX-compliant, albeit somewhat fragile, way.
|
|
|
|
|
target=$(command ls -l "$fname")
|
|
|
|
|
target=${target#* -> }
|
|
|
|
|
continue # Resolve [next] symlink target.
|
|
|
|
|
fi
|
|
|
|
|
break # Ultimate target reached.
|
|
|
|
|
done
|
|
|
|
|
targetDir=$(command pwd -P) # Get canonical dir. path
|
|
|
|
|
# Output the ultimate target's canonical path.
|
|
|
|
|
# Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
|
|
|
|
|
if [ "$fname" = '.' ]; then
|
|
|
|
|
command printf '%s\n' "${targetDir%/}"
|
|
|
|
|
elif [ "$fname" = '..' ]; then
|
|
|
|
|
# Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
|
|
|
|
|
# AFTER canonicalization.
|
|
|
|
|
command printf '%s\n' "$(command dirname -- "${targetDir}")"
|
|
|
|
|
else
|
|
|
|
|
command printf '%s\n' "${targetDir%/}/$fname"
|
|
|
|
|
fi
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
DIR=$(dirname -- "$(rreadlink "${BASH_SOURCE[0]}")")
|
|
|
|
|
|
|
|
|
|
############ Command Arguments ############
|
|
|
|
|
|
|
|
|
@ -66,6 +128,11 @@ COMMAND=
|
|
|
|
|
# batch file to execute
|
|
|
|
|
BATCH_FILE=
|
|
|
|
|
|
|
|
|
|
# tunnel server url
|
|
|
|
|
TUNNEL_SERVER=
|
|
|
|
|
# agent id
|
|
|
|
|
AGENT_ID=
|
|
|
|
|
|
|
|
|
|
############ Command Arguments ############
|
|
|
|
|
|
|
|
|
|
# if arguments contains -c/--command or -f/--batch-file, BATCH_MODE will be true
|
|
|
|
@ -150,68 +217,6 @@ check_permission()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# SYNOPSIS
|
|
|
|
|
# rreadlink <fileOrDirPath>
|
|
|
|
|
# DESCRIPTION
|
|
|
|
|
# Resolves <fileOrDirPath> to its ultimate target, if it is a symlink, and
|
|
|
|
|
# prints its canonical path. If it is not a symlink, its own canonical path
|
|
|
|
|
# is printed.
|
|
|
|
|
# A broken symlink causes an error that reports the non-existent target.
|
|
|
|
|
# LIMITATIONS
|
|
|
|
|
# - Won't work with filenames with embedded newlines or filenames containing
|
|
|
|
|
# the string ' -> '.
|
|
|
|
|
# COMPATIBILITY
|
|
|
|
|
# This is a fully POSIX-compliant implementation of what GNU readlink's
|
|
|
|
|
# -e option does.
|
|
|
|
|
# EXAMPLE
|
|
|
|
|
# In a shell script, use the following to get that script's true directory of origin:
|
|
|
|
|
# trueScriptDir=$(dirname -- "$(rreadlink "$0")")
|
|
|
|
|
rreadlink() ( # Execute the function in a *subshell* to localize variables and the effect of `cd`.
|
|
|
|
|
|
|
|
|
|
target=$1 fname= targetDir= CDPATH=
|
|
|
|
|
|
|
|
|
|
# Try to make the execution environment as predictable as possible:
|
|
|
|
|
# All commands below are invoked via `command`, so we must make sure that
|
|
|
|
|
# `command` itself is not redefined as an alias or shell function.
|
|
|
|
|
# (Note that command is too inconsistent across shells, so we don't use it.)
|
|
|
|
|
# `command` is a *builtin* in bash, dash, ksh, zsh, and some platforms do not
|
|
|
|
|
# even have an external utility version of it (e.g, Ubuntu).
|
|
|
|
|
# `command` bypasses aliases and shell functions and also finds builtins
|
|
|
|
|
# in bash, dash, and ksh. In zsh, option POSIX_BUILTINS must be turned on for
|
|
|
|
|
# that to happen.
|
|
|
|
|
{ \unalias command; \unset -f command; } >/dev/null 2>&1
|
|
|
|
|
[ -n "$ZSH_VERSION" ] && options[POSIX_BUILTINS]=on # make zsh find *builtins* with `command` too.
|
|
|
|
|
|
|
|
|
|
while :; do # Resolve potential symlinks until the ultimate target is found.
|
|
|
|
|
[ -L "$target" ] || [ -e "$target" ] || { command printf '%s\n' "ERROR: '$target' does not exist." >&2; return 1; }
|
|
|
|
|
command cd "$(command dirname -- "$target")" # Change to target dir; necessary for correct resolution of target path.
|
|
|
|
|
fname=$(command basename -- "$target") # Extract filename.
|
|
|
|
|
[ "$fname" = '/' ] && fname='' # !! curiously, `basename /` returns '/'
|
|
|
|
|
if [ -L "$fname" ]; then
|
|
|
|
|
# Extract [next] target path, which may be defined
|
|
|
|
|
# *relative* to the symlink's own directory.
|
|
|
|
|
# Note: We parse `ls -l` output to find the symlink target
|
|
|
|
|
# which is the only POSIX-compliant, albeit somewhat fragile, way.
|
|
|
|
|
target=$(command ls -l "$fname")
|
|
|
|
|
target=${target#* -> }
|
|
|
|
|
continue # Resolve [next] symlink target.
|
|
|
|
|
fi
|
|
|
|
|
break # Ultimate target reached.
|
|
|
|
|
done
|
|
|
|
|
targetDir=$(command pwd -P) # Get canonical dir. path
|
|
|
|
|
# Output the ultimate target's canonical path.
|
|
|
|
|
# Note that we manually resolve paths ending in /. and /.. to make sure we have a normalized path.
|
|
|
|
|
if [ "$fname" = '.' ]; then
|
|
|
|
|
command printf '%s\n' "${targetDir%/}"
|
|
|
|
|
elif [ "$fname" = '..' ]; then
|
|
|
|
|
# Caveat: something like /var/.. will resolve to /private (assuming /var@ -> /private/var), i.e. the '..' is applied
|
|
|
|
|
# AFTER canonicalization.
|
|
|
|
|
command printf '%s\n' "$(command dirname -- "${targetDir}")"
|
|
|
|
|
else
|
|
|
|
|
command printf '%s\n' "${targetDir%/}/$fname"
|
|
|
|
|
fi
|
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
# reset arthas work environment
|
|
|
|
|
# reset some options for env
|
|
|
|
|
reset_for_env()
|
|
|
|
@ -395,6 +400,7 @@ usage()
|
|
|
|
|
Usage:
|
|
|
|
|
$0 [-h] [--target-ip <value>] [--telnet-port <value>]
|
|
|
|
|
[--http-port <value>] [--session-timeout <value>] [--arthas-home <value>]
|
|
|
|
|
[--tunnel-server <value>] [--agent-id <value>]
|
|
|
|
|
[--use-version <value>] [--repo-mirror <value>] [--versions] [--use-http]
|
|
|
|
|
[--attach-only] [-c <value>] [-f <value>] [-v] [pid]
|
|
|
|
|
|
|
|
|
@ -412,6 +418,8 @@ Options and Arguments:
|
|
|
|
|
--use-http Enforce use http to download, default use https
|
|
|
|
|
--attach-only Attach target process only, do not connect
|
|
|
|
|
--debug-attach Debug attach agent
|
|
|
|
|
--tunnel-server Remote tunnel server url
|
|
|
|
|
--agent-id Special agent id
|
|
|
|
|
-c,--command <value> Command to execute, multiple commands separated
|
|
|
|
|
by ;
|
|
|
|
|
-f,--batch-file <value> The batch file to execute
|
|
|
|
@ -424,9 +432,11 @@ EXAMPLES:
|
|
|
|
|
./as.sh <pid>
|
|
|
|
|
./as.sh --target-ip 0.0.0.0
|
|
|
|
|
./as.sh --telnet-port 9999 --http-port -1
|
|
|
|
|
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws'
|
|
|
|
|
./as.sh --tunnel-server 'ws://192.168.10.11:7777/ws' --agent-id bvDOe8XbTM2pQWjF4cfw
|
|
|
|
|
./as.sh -c 'sysprop; thread' <pid>
|
|
|
|
|
./as.sh -f batch.as <pid>
|
|
|
|
|
./as.sh --use-version 3.1.1
|
|
|
|
|
./as.sh --use-version 3.1.2
|
|
|
|
|
./as.sh --session-timeout 3600
|
|
|
|
|
./as.sh --attach-only
|
|
|
|
|
./as.sh --repo-mirror aliyun --use-http
|
|
|
|
@ -519,6 +529,16 @@ parse_arguments()
|
|
|
|
|
shift # past argument
|
|
|
|
|
shift # past value
|
|
|
|
|
;;
|
|
|
|
|
--tunnel-server)
|
|
|
|
|
TUNNEL_SERVER="$2"
|
|
|
|
|
shift # past argument
|
|
|
|
|
shift # past value
|
|
|
|
|
;;
|
|
|
|
|
--agent-id)
|
|
|
|
|
AGENT_ID="$2"
|
|
|
|
|
shift # past argument
|
|
|
|
|
shift # past value
|
|
|
|
|
;;
|
|
|
|
|
--use-http)
|
|
|
|
|
USE_HTTP=true
|
|
|
|
|
shift # past argument
|
|
|
|
@ -652,13 +672,13 @@ parse_arguments()
|
|
|
|
|
# check the process already using telnet port if equals to target pid
|
|
|
|
|
if [[ ($telnetPortPid) && ($TARGET_PID != $telnetPortPid) ]]; then
|
|
|
|
|
echo "[ERROR] Target process $TARGET_PID is not the process using port $TELNET_PORT, you will connect to an unexpected process."
|
|
|
|
|
echo "[ERROR] 1. Try to restart as.sh, select process $telnetPortPid, shutdown it first."
|
|
|
|
|
echo "[ERROR] 1. Try to restart as.sh, select process $telnetPortPid, shutdown it first with running the 'shutdown' command."
|
|
|
|
|
echo "[ERROR] 2. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
|
if [[ ($httpPortPid) && ($TARGET_PID != $httpPortPid) ]]; then
|
|
|
|
|
echo "Target process $TARGET_PID is not the process using port $HTTP_PORT, you will connect to an unexpected process."
|
|
|
|
|
echo "1. Try to restart as.sh, select process $httpPortPid, shutdown it first."
|
|
|
|
|
echo "1. Try to restart as.sh, select process $httpPortPid, shutdown it first with running the 'shutdown' command."
|
|
|
|
|
echo "2. Try to use different http port, for example: as.sh --telnet-port 9998 --http-port 9999"
|
|
|
|
|
exit 1
|
|
|
|
|
fi
|
|
|
|
@ -685,6 +705,16 @@ attach_jvm()
|
|
|
|
|
java_command+=("${BOOT_CLASSPATH}")
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
local tempArgs=()
|
|
|
|
|
if [ "${TUNNEL_SERVER}" ]; then
|
|
|
|
|
tempArgs+=("-tunnel-server")
|
|
|
|
|
tempArgs+=("${TUNNEL_SERVER}")
|
|
|
|
|
fi
|
|
|
|
|
if [ "${AGENT_ID}" ]; then
|
|
|
|
|
tempArgs+=("-agent-id")
|
|
|
|
|
tempArgs+=("${AGENT_ID}")
|
|
|
|
|
fi
|
|
|
|
|
|
|
|
|
|
"${java_command[@]}" \
|
|
|
|
|
${ARTHAS_OPTS} ${JVM_OPTS} \
|
|
|
|
|
-jar "${arthas_lib_dir}/arthas-core.jar" \
|
|
|
|
@ -693,6 +723,7 @@ attach_jvm()
|
|
|
|
|
-telnet-port ${TELNET_PORT} \
|
|
|
|
|
-http-port ${HTTP_PORT} \
|
|
|
|
|
-session-timeout ${SESSION_TIMEOUT} \
|
|
|
|
|
"${tempArgs[@]}" \
|
|
|
|
|
-core "${arthas_lib_dir}/arthas-core.jar" \
|
|
|
|
|
-agent "${arthas_lib_dir}/arthas-agent.jar"
|
|
|
|
|
|
|
|
|
|