diff --git a/as.sh b/as.sh index 0efe49040..ca87e7df5 100755 --- a/as.sh +++ b/as.sh @@ -8,10 +8,10 @@ # program : Arthas # author : Core Engine @ Taobao.com -# date : 2018-11-12 +# date : 2018-11-19 # current arthas script version -ARTHAS_SCRIPT_VERSION=3.0.4.1 +ARTHAS_SCRIPT_VERSION=3.0.4.2 # define arthas's home ARTHAS_HOME=${HOME}/.arthas @@ -111,6 +111,68 @@ check_permission() } +# SYNOPSIS +# rreadlink +# DESCRIPTION +# Resolves 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() @@ -122,19 +184,36 @@ reset_for_env() # if env define the JAVA_HOME, use it first # if is alibaba opts, use alibaba ops's default JAVA_HOME - [ -z "${JAVA_HOME}" ] && JAVA_HOME=/opt/taobao/java + [ -z "${JAVA_HOME}" ] && [ -d /opt/taobao/java ] && JAVA_HOME=/opt/taobao/java + + if [[ (-z "${JAVA_HOME}") && ( -e "/usr/libexec/java_home") ]]; then + # for mac + JAVA_HOME=`/usr/libexec/java_home` + fi + + if [ -z "${JAVA_HOME}" ]; then + # try to find JAVA_HOME from java command + local JAVA_COMMAND_PATH=$( rreadlink $(type -p java) ) + JAVA_HOME=$(echo "$JAVA_COMMAND_PATH" | sed -n 's/\/bin\/java$//p') + fi # iterater throught candidates to find a proper JAVA_HOME at least contains tools.jar which is required by arthas. if [ ! -d "${JAVA_HOME}" ]; then JAVA_HOME_CANDIDATES=($(ps aux | grep java | grep -v 'grep java' | awk '{print $11}' | sed -n 's/\/bin\/java$//p')) for JAVA_HOME_TEMP in ${JAVA_HOME_CANDIDATES[@]}; do if [ -f "${JAVA_HOME_TEMP}/lib/tools.jar" ]; then - JAVA_HOME=${JAVA_HOME_TEMP} + JAVA_HOME=`rreadlink "${JAVA_HOME_TEMP}"` break fi done fi + if [ -z "${JAVA_HOME}" ]; then + exit_on_err 1 "Can not find JAVA_HOME, please set \$JAVA_HOME bash env first." + fi + + echo "JAVA_HOME: ${JAVA_HOME}" + # maybe 1.8.0_162 , 11-ea local JAVA_VERSION @@ -484,7 +563,7 @@ active_console() # Windows/system32/telnet.exe can not run in Cygwin/MinGw echo "It seems that current bash is under Windows. $(command -v telnet) can not run under bash." echo "Please start cmd.exe from Windows start menu, and then run telnet ${TARGET_IP} ${TELNET_PORT} to connect to target process." - echo "Or visit http://localhost:8563/ to connect to target process." + echo "Or visit http://127.0.0.1:8563/ to connect to target process." return 1 fi echo "telnet connecting to arthas server... current timestamp is `date +%s`"