mirror of
https://github.com/alibaba/arthas.git
synced 2024-04-21 10:21:39 +00:00
double check telnet port and pid before attach agent (#1119)
This commit is contained in:
@@ -475,6 +475,34 @@ find_listen_port_process()
|
||||
fi
|
||||
}
|
||||
|
||||
# Status from com.taobao.arthas.client.TelnetConsole
|
||||
# Execute commands timeout
|
||||
STATUS_EXEC_TIMEOUT=100
|
||||
# Execute commands error
|
||||
STATUS_EXEC_ERROR=101
|
||||
|
||||
# find the process pid of target telnet port
|
||||
# maybe another user start an arthas server at the same port, but invisible for current user
|
||||
find_listen_port_process_by_client()
|
||||
{
|
||||
local arthas_lib_dir="${ARTHAS_HOME}"
|
||||
# http://www.inonit.com/cygwin/faq/
|
||||
if [ "${OS_TYPE}" = "Cygwin" ]; then
|
||||
arthas_lib_dir=`cygpath -wp "$arthas_lib_dir"`
|
||||
fi
|
||||
|
||||
"${JAVA_HOME}/bin/java" ${ARTHAS_OPTS} ${JVM_OPTS} \
|
||||
-jar "${arthas_lib_dir}/arthas-client.jar" \
|
||||
${TARGET_IP} \
|
||||
${TELNET_PORT} \
|
||||
-c "session" \
|
||||
--execution-timeout 2000 \
|
||||
2>&1
|
||||
|
||||
# return java process exit status code !
|
||||
return $?
|
||||
}
|
||||
|
||||
parse_arguments()
|
||||
{
|
||||
POSITIONAL=()
|
||||
@@ -699,9 +727,7 @@ 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 with running the 'stop' command."
|
||||
echo "[ERROR] 2. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
|
||||
print_telnet_port_pid_error
|
||||
exit 1
|
||||
fi
|
||||
if [[ ($httpPortPid) && ($TARGET_PID != $httpPortPid) ]]; then
|
||||
@@ -798,6 +824,52 @@ sanity_check() {
|
||||
fi
|
||||
}
|
||||
|
||||
port_pid_check() {
|
||||
if [[ $TELNET_PORT > 0 ]]; then
|
||||
local telnet_output
|
||||
local find_process_status
|
||||
# declare local var before var=$()
|
||||
telnet_output=$(find_listen_port_process_by_client)
|
||||
find_process_status=$?
|
||||
#echo "find_process_status: $find_process_status"
|
||||
#echo "telnet_output: $telnet_output"
|
||||
|
||||
#check return code
|
||||
if [[ $find_process_status -eq $STATUS_EXEC_TIMEOUT ]]; then
|
||||
print_telnet_port_used_error "detection timeout"
|
||||
exit 1
|
||||
elif [[ $find_process_status -eq $STATUS_EXEC_ERROR ]]; then
|
||||
print_telnet_port_used_error "detection error"
|
||||
exit 1
|
||||
fi
|
||||
|
||||
if [[ -n $telnet_output ]]; then
|
||||
# check JAVA_PID
|
||||
telnetPortPid=$(echo "$telnet_output" | grep JAVA_PID | awk '{ print $2 }')
|
||||
#echo "telnetPortPid: $telnetPortPid"
|
||||
# check the process already using telnet port if equals to target pid
|
||||
if [[ -n $telnetPortPid && ($TARGET_PID != $telnetPortPid) ]]; then
|
||||
print_telnet_port_pid_error
|
||||
exit 1
|
||||
fi
|
||||
fi
|
||||
|
||||
fi
|
||||
}
|
||||
|
||||
print_telnet_port_pid_error() {
|
||||
echo "[ERROR] The telnet port $TELNET_PORT is used by process $telnetPortPid instead of target process $TARGET_PID, you will connect to an unexpected process."
|
||||
echo "[ERROR] 1. Try to restart as.sh, select process $telnetPortPid, shutdown it first with running the 'stop' command."
|
||||
echo "[ERROR] 2. Try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 $TELNET_PORT -c \"stop\""
|
||||
echo "[ERROR] 3. Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
|
||||
}
|
||||
|
||||
print_telnet_port_used_error() {
|
||||
local error_msg=$1
|
||||
echo "[ERROR] The telnet port $TELNET_PORT is used, but process $error_msg, you will connect to an unexpected process."
|
||||
echo "[ERROR] Try to use different telnet port, for example: as.sh --telnet-port 9998 --http-port -1"
|
||||
}
|
||||
|
||||
# active console
|
||||
# $1 : arthas_lib_dir
|
||||
active_console()
|
||||
@@ -899,6 +971,8 @@ main()
|
||||
|
||||
sanity_check
|
||||
|
||||
port_pid_check
|
||||
|
||||
echo "Calculating attach execution time..."
|
||||
time (attach_jvm "${ARTHAS_HOME}" || exit 1)
|
||||
|
||||
@@ -915,4 +989,4 @@ main()
|
||||
|
||||
|
||||
|
||||
main "${@}"
|
||||
main "${@}"
|
||||
@@ -1,5 +1,6 @@
|
||||
package com.taobao.arthas.boot;
|
||||
|
||||
import java.io.ByteArrayOutputStream;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.lang.reflect.InvocationTargetException;
|
||||
@@ -11,6 +12,7 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Scanner;
|
||||
import java.util.TimeZone;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
import java.util.logging.Level;
|
||||
@@ -34,6 +36,9 @@ import com.taobao.middleware.cli.annotations.Name;
|
||||
import com.taobao.middleware.cli.annotations.Option;
|
||||
import com.taobao.middleware.cli.annotations.Summary;
|
||||
|
||||
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_ERROR;
|
||||
import static com.taobao.arthas.boot.ProcessUtils.STATUS_EXEC_TIMEOUT;
|
||||
|
||||
/**
|
||||
* @author hengyunabc 2018-10-26
|
||||
*
|
||||
@@ -353,14 +358,7 @@ public class Bootstrap {
|
||||
}
|
||||
}
|
||||
|
||||
if (telnetPortPid > 0 && pid != telnetPortPid) {
|
||||
AnsiLog.error("Target process {} is not the process using port {}, you will connect to an unexpected process.",
|
||||
pid, bootstrap.getTelnetPort());
|
||||
AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
|
||||
telnetPortPid);
|
||||
AnsiLog.error("2. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1");
|
||||
System.exit(1);
|
||||
}
|
||||
checkTelnetPortPid(bootstrap, telnetPortPid, pid);
|
||||
|
||||
if (httpPortPid > 0 && pid != httpPortPid) {
|
||||
AnsiLog.error("Target process {} is not the process using port {}, you will connect to an unexpected process.",
|
||||
@@ -474,6 +472,10 @@ public class Bootstrap {
|
||||
if (telnetPortPid > 0 && pid == telnetPortPid) {
|
||||
AnsiLog.info("The target process already listen port {}, skip attach.", bootstrap.getTelnetPort());
|
||||
} else {
|
||||
//double check telnet port and pid before attach
|
||||
telnetPortPid = findProcessByTelnetClient(arthasHomeDir.getAbsolutePath(), bootstrap.getTelnetPort());
|
||||
checkTelnetPortPid(bootstrap, telnetPortPid, pid);
|
||||
|
||||
// start arthas-core.jar
|
||||
List<String> attachArgs = new ArrayList<String>();
|
||||
attachArgs.add("-jar");
|
||||
@@ -556,6 +558,78 @@ public class Bootstrap {
|
||||
mainMethod.invoke(null, new Object[] { telnetArgs.toArray(new String[0]) });
|
||||
}
|
||||
|
||||
private static void checkTelnetPortPid(Bootstrap bootstrap, long telnetPortPid, long targetPid) {
|
||||
if (telnetPortPid > 0 && targetPid != telnetPortPid) {
|
||||
AnsiLog.error("The telnet port {} is used by process {} instead of target process {}, you will connect to an unexpected process.",
|
||||
bootstrap.getTelnetPort(), telnetPortPid, targetPid);
|
||||
AnsiLog.error("1. Try to restart arthas-boot, select process {}, shutdown it first with running the 'stop' command.",
|
||||
telnetPortPid);
|
||||
AnsiLog.error("2. Or try to stop the existing arthas instance: java -jar arthas-client.jar 127.0.0.1 {} -c \"stop\"", bootstrap.getTelnetPort());
|
||||
AnsiLog.error("3. Or try to use different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1");
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
|
||||
private static long findProcessByTelnetClient(String arthasHomeDir, int telnetPort) {
|
||||
// start java telnet client
|
||||
List<String> telnetArgs = new ArrayList<String>();
|
||||
telnetArgs.add("-c");
|
||||
telnetArgs.add("session");
|
||||
telnetArgs.add("--execution-timeout");
|
||||
telnetArgs.add("2000");
|
||||
// telnet port ,ip
|
||||
telnetArgs.add("127.0.0.1");
|
||||
telnetArgs.add("" + telnetPort);
|
||||
|
||||
try {
|
||||
ByteArrayOutputStream out = new ByteArrayOutputStream(1024);
|
||||
String error = null;
|
||||
int status = ProcessUtils.startArthasClient(arthasHomeDir, telnetArgs, out);
|
||||
if (status == STATUS_EXEC_TIMEOUT) {
|
||||
error = "detection timeout";
|
||||
} else if (status == STATUS_EXEC_ERROR) {
|
||||
error = "detection error";
|
||||
AnsiLog.error("process status: {}", status);
|
||||
AnsiLog.error("process output: {}", out.toString());
|
||||
} else {
|
||||
// ignore connect error
|
||||
}
|
||||
if (error != null) {
|
||||
AnsiLog.error("The telnet port {} is used, but process {}, you will connect to an unexpected process.", telnetPort, error);
|
||||
AnsiLog.error("Try to use a different telnet port, for example: java -jar arthas-boot.jar --telnet-port 9998 --http-port -1");
|
||||
System.exit(1);
|
||||
}
|
||||
|
||||
//parse output, find java pid
|
||||
String output = out.toString("UTF-8");
|
||||
String javaPidLine = null;
|
||||
Scanner scanner = new Scanner(output);
|
||||
while (scanner.hasNextLine()) {
|
||||
String line = scanner.nextLine();
|
||||
if (line.contains("JAVA_PID")) {
|
||||
javaPidLine = line;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (javaPidLine != null) {
|
||||
// JAVA_PID 10473
|
||||
try {
|
||||
String[] strs = javaPidLine.split("JAVA_PID");
|
||||
if (strs.length > 1) {
|
||||
return Long.parseLong(strs[strs.length - 1].trim());
|
||||
}
|
||||
} catch (NumberFormatException e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
} catch (Throwable ex) {
|
||||
AnsiLog.error("Detection telnet port error");
|
||||
AnsiLog.error(ex);
|
||||
}
|
||||
|
||||
return -1;
|
||||
}
|
||||
|
||||
private static String listVersions(String mavenMetaData) {
|
||||
StringBuilder result = new StringBuilder(1024);
|
||||
List<String> versionList = listNames(ARTHAS_LIB_DIR);
|
||||
|
||||
@@ -3,6 +3,11 @@ package com.taobao.arthas.boot;
|
||||
import java.io.File;
|
||||
import java.io.IOException;
|
||||
import java.io.InputStream;
|
||||
import java.io.OutputStream;
|
||||
import java.io.PrintStream;
|
||||
import java.lang.reflect.Method;
|
||||
import java.net.URL;
|
||||
import java.net.URLClassLoader;
|
||||
import java.util.ArrayList;
|
||||
import java.util.Collections;
|
||||
import java.util.Comparator;
|
||||
@@ -28,6 +33,24 @@ import com.taobao.arthas.common.PidUtils;
|
||||
public class ProcessUtils {
|
||||
private static String FOUND_JAVA_HOME = null;
|
||||
|
||||
//status code from com.taobao.arthas.client.TelnetConsole
|
||||
/**
|
||||
* Process success
|
||||
*/
|
||||
public static final int STATUS_OK = 0;
|
||||
/**
|
||||
* Generic error
|
||||
*/
|
||||
public static final int STATUS_ERROR = 1;
|
||||
/**
|
||||
* Execute commands timeout
|
||||
*/
|
||||
public static final int STATUS_EXEC_TIMEOUT = 100;
|
||||
/**
|
||||
* Execute commands error
|
||||
*/
|
||||
public static final int STATUS_EXEC_ERROR = 101;
|
||||
|
||||
@SuppressWarnings("resource")
|
||||
public static long select(boolean v, long telnetPortPid, String select) throws InputMismatchException {
|
||||
Map<Long, String> processMap = listProcessByJps(v);
|
||||
@@ -290,7 +313,52 @@ public class ProcessUtils {
|
||||
} catch (Throwable e) {
|
||||
// ignore
|
||||
}
|
||||
}
|
||||
|
||||
public static int startArthasClient(String arthasHomeDir, List<String> telnetArgs, OutputStream out) throws Throwable {
|
||||
// start java telnet client
|
||||
// find arthas-client.jar
|
||||
URLClassLoader classLoader = new URLClassLoader(
|
||||
new URL[]{new File(arthasHomeDir, "arthas-client.jar").toURI().toURL()});
|
||||
Class<?> telnetConsoleClas = classLoader.loadClass("com.taobao.arthas.client.TelnetConsole");
|
||||
Method processMethod = telnetConsoleClas.getMethod("process", String[].class);
|
||||
|
||||
//redirect System.out/System.err
|
||||
PrintStream originSysOut = System.out;
|
||||
PrintStream originSysErr = System.err;
|
||||
PrintStream newOut = new PrintStream(out);
|
||||
PrintStream newErr = new PrintStream(out);
|
||||
|
||||
// call TelnetConsole.process()
|
||||
// fix https://github.com/alibaba/arthas/issues/833
|
||||
ClassLoader tccl = Thread.currentThread().getContextClassLoader();
|
||||
try {
|
||||
System.setOut(newOut);
|
||||
System.setErr(newErr);
|
||||
Thread.currentThread().setContextClassLoader(classLoader);
|
||||
return (Integer) processMethod.invoke(null, new Object[]{telnetArgs.toArray(new String[0])});
|
||||
} catch (Throwable e) {
|
||||
//java.lang.reflect.InvocationTargetException : java.net.ConnectException
|
||||
e = e.getCause();
|
||||
if (e instanceof IOException || e instanceof InterruptedException) {
|
||||
// ignore connection error and interrupted error
|
||||
return STATUS_ERROR;
|
||||
} else {
|
||||
// process error
|
||||
AnsiLog.error("process error: {}", e.toString());
|
||||
AnsiLog.error(e);
|
||||
return STATUS_EXEC_ERROR;
|
||||
}
|
||||
} finally {
|
||||
Thread.currentThread().setContextClassLoader(tccl);
|
||||
|
||||
//reset System.out/System.err
|
||||
System.setOut(originSysOut);
|
||||
System.setErr(originSysErr);
|
||||
//flush output
|
||||
newOut.flush();
|
||||
newErr.flush();
|
||||
}
|
||||
}
|
||||
|
||||
private static File findJava() {
|
||||
|
||||
@@ -53,7 +53,6 @@ public final class IOUtil {
|
||||
}
|
||||
} catch (IOException e) {
|
||||
e.printStackTrace();
|
||||
System.exit(1);
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -14,6 +14,7 @@ import java.util.Arrays;
|
||||
import java.util.List;
|
||||
import java.util.concurrent.BlockingQueue;
|
||||
import java.util.concurrent.LinkedBlockingQueue;
|
||||
import java.util.concurrent.TimeUnit;
|
||||
|
||||
import org.apache.commons.net.telnet.InvalidTelnetOptionException;
|
||||
import org.apache.commons.net.telnet.TelnetClient;
|
||||
@@ -53,6 +54,25 @@ public class TelnetConsole {
|
||||
|
||||
private static final byte CTRL_C = 0x03;
|
||||
|
||||
// ------- Status codes ------- //
|
||||
/**
|
||||
* Process success
|
||||
*/
|
||||
public static final int STATUS_OK = 0;
|
||||
/**
|
||||
* Generic error
|
||||
*/
|
||||
public static final int STATUS_ERROR = 1;
|
||||
/**
|
||||
* Execute commands timeout
|
||||
*/
|
||||
public static final int STATUS_EXEC_TIMEOUT = 100;
|
||||
/**
|
||||
* Execute commands error
|
||||
*/
|
||||
public static final int STATUS_EXEC_ERROR = 101;
|
||||
|
||||
|
||||
private boolean help = false;
|
||||
|
||||
private String targetIp = "127.0.0.1";
|
||||
@@ -60,6 +80,7 @@ public class TelnetConsole {
|
||||
|
||||
private String command;
|
||||
private String batchFile;
|
||||
private int executionTimeout = -1;
|
||||
|
||||
private Integer width = null;
|
||||
private Integer height = null;
|
||||
@@ -94,6 +115,12 @@ public class TelnetConsole {
|
||||
this.batchFile = batchFile;
|
||||
}
|
||||
|
||||
@Option(shortName = "t", longName = "execution-timeout")
|
||||
@Description("The timeout (ms) of execute commands or batch file ")
|
||||
public void setExecutionTimeout(int executionTimeout) {
|
||||
this.executionTimeout = executionTimeout;
|
||||
}
|
||||
|
||||
@Option(shortName = "w", longName = "width")
|
||||
@Description("The terminal width")
|
||||
public void setWidth(int width) {
|
||||
@@ -133,147 +160,190 @@ public class TelnetConsole {
|
||||
return list;
|
||||
}
|
||||
|
||||
public static void main(String[] args) throws IOException {
|
||||
public static void main(String[] args) throws Exception {
|
||||
|
||||
try {
|
||||
int status = process(args, new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.exit(STATUS_OK);
|
||||
}
|
||||
});
|
||||
System.exit(status);
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
CLI cli = CLIConfigurator.define(TelnetConsole.class);
|
||||
System.out.println(usage(cli));
|
||||
System.exit(STATUS_ERROR);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* 提供给arthas-boot使用的主处理函数
|
||||
*
|
||||
* @param args
|
||||
* @return status code
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static int process(String[] args) throws IOException, InterruptedException {
|
||||
return process(args, null);
|
||||
}
|
||||
|
||||
/**
|
||||
* arthas client 主函数
|
||||
* 注意: process()函数提供给arthas-boot使用,内部不能调用System.exit()结束进程的方法
|
||||
*
|
||||
* @param telnetConsole
|
||||
* @param cli
|
||||
* @param args
|
||||
* @param eotEventCallback Ctrl+D signals an End of Transmission (EOT) event
|
||||
* @return status code
|
||||
* @throws IOException
|
||||
* @throws InterruptedException
|
||||
*/
|
||||
public static int process(String[] args, ActionListener eotEventCallback) throws IOException, InterruptedException {
|
||||
// support mingw/cygw jline color
|
||||
if (OSUtils.isCygwinOrMinGW()) {
|
||||
System.setProperty("jline.terminal", System.getProperty("jline.terminal", "jline.UnixTerminal"));
|
||||
}
|
||||
|
||||
TelnetConsole telnetConsole = new TelnetConsole();
|
||||
|
||||
CLI cli = CLIConfigurator.define(TelnetConsole.class);
|
||||
|
||||
try {
|
||||
CommandLine commandLine = cli.parse(Arrays.asList(args));
|
||||
CommandLine commandLine = cli.parse(Arrays.asList(args));
|
||||
|
||||
CLIConfigurator.inject(commandLine, telnetConsole);
|
||||
CLIConfigurator.inject(commandLine, telnetConsole);
|
||||
|
||||
if (telnetConsole.isHelp()) {
|
||||
System.out.println(usage(cli));
|
||||
System.exit(0);
|
||||
}
|
||||
|
||||
// Try to read cmds
|
||||
List<String> cmds = new ArrayList<String>();
|
||||
if (telnetConsole.getCommand() != null) {
|
||||
for (String c : telnetConsole.getCommand().split(";")) {
|
||||
cmds.add(c.trim());
|
||||
}
|
||||
} else if (telnetConsole.getBatchFile() != null) {
|
||||
File file = new File(telnetConsole.getBatchFile());
|
||||
if (!file.exists()) {
|
||||
throw new IllegalArgumentException("batch file do not exist: " + telnetConsole.getBatchFile());
|
||||
} else {
|
||||
cmds.addAll(readLines(file));
|
||||
}
|
||||
}
|
||||
|
||||
final ConsoleReader consoleReader = new ConsoleReader(System.in, System.out);
|
||||
consoleReader.setHandleUserInterrupt(true);
|
||||
Terminal terminal = consoleReader.getTerminal();
|
||||
|
||||
if (terminal instanceof TerminalSupport) {
|
||||
((TerminalSupport) terminal).disableInterruptCharacter();
|
||||
}
|
||||
|
||||
// support catch ctrl+c event
|
||||
terminal.disableInterruptCharacter();
|
||||
if (terminal instanceof UnixTerminal) {
|
||||
((UnixTerminal) terminal).disableLitteralNextCharacter();
|
||||
}
|
||||
|
||||
int width = TerminalSupport.DEFAULT_WIDTH;
|
||||
int height = TerminalSupport.DEFAULT_HEIGHT;
|
||||
|
||||
if (!cmds.isEmpty()) {
|
||||
// batch mode
|
||||
if (telnetConsole.getWidth() != null) {
|
||||
width = telnetConsole.getWidth();
|
||||
}
|
||||
if (telnetConsole.getheight() != null) {
|
||||
height = telnetConsole.getheight();
|
||||
}
|
||||
} else {
|
||||
// normal telnet client, get current terminal size
|
||||
if (telnetConsole.getWidth() != null) {
|
||||
width = telnetConsole.getWidth();
|
||||
} else {
|
||||
width = terminal.getWidth();
|
||||
// hack for windows dos
|
||||
if (OSUtils.isWindows()) {
|
||||
width--;
|
||||
}
|
||||
}
|
||||
if (telnetConsole.getheight() != null) {
|
||||
height = telnetConsole.getheight();
|
||||
} else {
|
||||
height = terminal.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
final TelnetClient telnet = new TelnetClient();
|
||||
telnet.setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT);
|
||||
|
||||
// send init terminal size
|
||||
TelnetOptionHandler sizeOpt = new WindowSizeOptionHandler(width, height, true, true, false, false);
|
||||
try {
|
||||
telnet.addOptionHandler(sizeOpt);
|
||||
} catch (InvalidTelnetOptionException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// ctrl + c event callback
|
||||
consoleReader.getKeys().bind(new Character((char) CTRL_C).toString(), new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
consoleReader.getCursorBuffer().clear(); // clear current line
|
||||
telnet.getOutputStream().write(CTRL_C);
|
||||
telnet.getOutputStream().flush();
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ctrl + d event call back
|
||||
consoleReader.getKeys().bind(new Character(KeyMap.CTRL_D).toString(), new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
System.exit(0);
|
||||
}
|
||||
});
|
||||
|
||||
try {
|
||||
telnet.connect(telnetConsole.getTargetIp(), telnetConsole.getPort());
|
||||
} catch (IOException e) {
|
||||
System.out.println("Connect to telnet server error: " + telnetConsole.getTargetIp() + " "
|
||||
+ telnetConsole.getPort());
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (cmds.isEmpty()) {
|
||||
IOUtil.readWrite(telnet.getInputStream(), telnet.getOutputStream(), System.in,
|
||||
consoleReader.getOutput());
|
||||
} else {
|
||||
batchModeRun(telnet, cmds);
|
||||
telnet.disconnect();
|
||||
}
|
||||
} catch (Throwable e) {
|
||||
e.printStackTrace();
|
||||
if (telnetConsole.isHelp()) {
|
||||
System.out.println(usage(cli));
|
||||
System.exit(1);
|
||||
return STATUS_ERROR;
|
||||
}
|
||||
|
||||
// Try to read cmds
|
||||
List<String> cmds = new ArrayList<String>();
|
||||
if (telnetConsole.getCommand() != null) {
|
||||
for (String c : telnetConsole.getCommand().split(";")) {
|
||||
cmds.add(c.trim());
|
||||
}
|
||||
} else if (telnetConsole.getBatchFile() != null) {
|
||||
File file = new File(telnetConsole.getBatchFile());
|
||||
if (!file.exists()) {
|
||||
throw new IllegalArgumentException("batch file do not exist: " + telnetConsole.getBatchFile());
|
||||
} else {
|
||||
cmds.addAll(readLines(file));
|
||||
}
|
||||
}
|
||||
|
||||
final ConsoleReader consoleReader = new ConsoleReader(System.in, System.out);
|
||||
consoleReader.setHandleUserInterrupt(true);
|
||||
Terminal terminal = consoleReader.getTerminal();
|
||||
|
||||
if (terminal instanceof TerminalSupport) {
|
||||
((TerminalSupport) terminal).disableInterruptCharacter();
|
||||
}
|
||||
|
||||
// support catch ctrl+c event
|
||||
terminal.disableInterruptCharacter();
|
||||
if (terminal instanceof UnixTerminal) {
|
||||
((UnixTerminal) terminal).disableLitteralNextCharacter();
|
||||
}
|
||||
|
||||
int width = TerminalSupport.DEFAULT_WIDTH;
|
||||
int height = TerminalSupport.DEFAULT_HEIGHT;
|
||||
|
||||
if (!cmds.isEmpty()) {
|
||||
// batch mode
|
||||
if (telnetConsole.getWidth() != null) {
|
||||
width = telnetConsole.getWidth();
|
||||
}
|
||||
if (telnetConsole.getheight() != null) {
|
||||
height = telnetConsole.getheight();
|
||||
}
|
||||
} else {
|
||||
// normal telnet client, get current terminal size
|
||||
if (telnetConsole.getWidth() != null) {
|
||||
width = telnetConsole.getWidth();
|
||||
} else {
|
||||
width = terminal.getWidth();
|
||||
// hack for windows dos
|
||||
if (OSUtils.isWindows()) {
|
||||
width--;
|
||||
}
|
||||
}
|
||||
if (telnetConsole.getheight() != null) {
|
||||
height = telnetConsole.getheight();
|
||||
} else {
|
||||
height = terminal.getHeight();
|
||||
}
|
||||
}
|
||||
|
||||
final TelnetClient telnet = new TelnetClient();
|
||||
telnet.setConnectTimeout(DEFAULT_CONNECTION_TIMEOUT);
|
||||
|
||||
// send init terminal size
|
||||
TelnetOptionHandler sizeOpt = new WindowSizeOptionHandler(width, height, true, true, false, false);
|
||||
try {
|
||||
telnet.addOptionHandler(sizeOpt);
|
||||
} catch (InvalidTelnetOptionException e) {
|
||||
// ignore
|
||||
}
|
||||
|
||||
// ctrl + c event callback
|
||||
consoleReader.getKeys().bind(new Character((char) CTRL_C).toString(), new ActionListener() {
|
||||
@Override
|
||||
public void actionPerformed(ActionEvent e) {
|
||||
try {
|
||||
consoleReader.getCursorBuffer().clear(); // clear current line
|
||||
telnet.getOutputStream().write(CTRL_C);
|
||||
telnet.getOutputStream().flush();
|
||||
} catch (Exception e1) {
|
||||
e1.printStackTrace();
|
||||
}
|
||||
}
|
||||
|
||||
});
|
||||
|
||||
// ctrl + d event call back
|
||||
consoleReader.getKeys().bind(new Character(KeyMap.CTRL_D).toString(), eotEventCallback);
|
||||
|
||||
try {
|
||||
telnet.connect(telnetConsole.getTargetIp(), telnetConsole.getPort());
|
||||
} catch (IOException e) {
|
||||
System.out.println("Connect to telnet server error: " + telnetConsole.getTargetIp() + " "
|
||||
+ telnetConsole.getPort());
|
||||
throw e;
|
||||
}
|
||||
|
||||
if (cmds.isEmpty()) {
|
||||
IOUtil.readWrite(telnet.getInputStream(), telnet.getOutputStream(), System.in,
|
||||
consoleReader.getOutput());
|
||||
} else {
|
||||
try {
|
||||
return batchModeRun(telnet, cmds, telnetConsole.getExecutionTimeout());
|
||||
} catch (Throwable e) {
|
||||
System.out.println("Execute commands error: " + e.getMessage());
|
||||
e.printStackTrace();
|
||||
return STATUS_EXEC_ERROR;
|
||||
} finally {
|
||||
try {
|
||||
telnet.disconnect();
|
||||
} catch (IOException e) {
|
||||
//ignore ex
|
||||
}
|
||||
}
|
||||
}
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
private static void batchModeRun(TelnetClient telnet, List<String> commands)
|
||||
private static int batchModeRun(TelnetClient telnet, List<String> commands, final int executionTimeout)
|
||||
throws IOException, InterruptedException {
|
||||
if (commands.size() == 0) {
|
||||
return;
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
long startTime = System.currentTimeMillis();
|
||||
final InputStream inputStream = telnet.getInputStream();
|
||||
final OutputStream outputStream = telnet.getOutputStream();
|
||||
|
||||
@@ -305,14 +375,22 @@ public class TelnetConsole {
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
printResultThread.start();
|
||||
|
||||
// send commands to arthas server
|
||||
for (String command : commands) {
|
||||
if (command.trim().isEmpty()) {
|
||||
continue;
|
||||
}
|
||||
receviedPromptQueue.take();
|
||||
// try poll prompt and check timeout
|
||||
while (receviedPromptQueue.poll(100, TimeUnit.MILLISECONDS) == null) {
|
||||
if (executionTimeout > 0) {
|
||||
long now = System.currentTimeMillis();
|
||||
if (now - startTime > executionTimeout) {
|
||||
return STATUS_EXEC_TIMEOUT;
|
||||
}
|
||||
}
|
||||
}
|
||||
// send command to server
|
||||
outputStream.write((command + " | plaintext\n").getBytes());
|
||||
outputStream.flush();
|
||||
@@ -323,6 +401,8 @@ public class TelnetConsole {
|
||||
outputStream.write("quit\n".getBytes());
|
||||
outputStream.flush();
|
||||
System.out.println();
|
||||
|
||||
return STATUS_OK;
|
||||
}
|
||||
|
||||
private static String usage(CLI cli) {
|
||||
@@ -349,6 +429,10 @@ public class TelnetConsole {
|
||||
return batchFile;
|
||||
}
|
||||
|
||||
public int getExecutionTimeout() {
|
||||
return executionTimeout;
|
||||
}
|
||||
|
||||
public Integer getWidth() {
|
||||
return width;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user