Killing a process through sshj - java

Im using sshj and im trying to tail a file, but my problem is that the remote process is never killed.
In the following example code you can see that i try to tail /var/log/syslog, and then i send a kill signal to the process. However after the application has stopped and i list out all the processes on the server, i can still see an active tail process.
Why will not this code kill the process? and what can i do to remedy that?
SSHClient ssh = new SSHClient();
ssh.addHostKeyVerifier(new PromiscuousVerifier());
try {
ssh.connect("localhost");
ssh.authPassword("xxx", "xxx");
final Session session = ssh.startSession();
try {
final Command cmd = session.exec("tail -f /var/log/syslog");
cmd.signal(Signal.KILL);
System.out.println("\n** exit status: " + cmd.getExitStatus());
} catch (IOException e) {
e.printStackTrace();
}finally{
session.close();
}
} finally{
ssh.disconnect();
}
EDIT
also tried sending all available signals.
for(Signal s : Signal.values()){
cmd.signal(s);
}

Allocating a PTY and sending a Ctrl+C character code did the trick for me:
final Session session = ssh.startSession();
session.allocateDefaultPTY();
try {
final Command cmd = session.exec("tail -f /var/log/syslog");
// Send Ctrl+C (character code is 0x03):
cmd.getOutputStream().write(3);
cmd.getOutputStream().flush();
// Wait some time for the process to exit:
cmd.join(1, TimeUnit.SECONDS);
// If no exception has been raised yet, then the process has exited
// (but the exit status can still be null if the process has been killed).
System.out.println("\n** exit status: " + cmd.getExitStatus());
} catch (IOException e) {
e.printStackTrace();
}finally{
session.close();
}
Of course, being able to send signals would be better, but if even the OpenSSH server does not support it, there's no hope there :/

openssh doesn't support it https://bugzilla.mindrot.org/show_bug.cgi?id=1424
Just use cmd.close(), that should term the process as well

This is most likely a problem with the ssh server implementation, as i have tried using two different ssh clients and getting the same result. My solution ended up being a client-side tail logic, instead of "tail -f" to prevent free roaming processes.

Had a similar issue recently. In my specific case it was the OpenSSH issue mentioned by #shikhar.
My solution was to run start another session (sharing the connection) and run a kill command pgrep mycommand | xargs kill.

Related

How to issue command to server through command line

I am working on an application that starts a minecraft server with one click of a button. I've successfully got the server to startup, but now I am trying to figure out a way to stop the server through the same cmd process.
Here's my code for starting the server...
public static void startServer() {
System.out.println("Starting server...");
try {
server = Runtime.getRuntime().exec(
"java -jar -Xmx1024M -Xms1024M minecraft_server.jar nogui");
output = server.getOutputStream();
input = server.getInputStream();
writer = new BufferedWriter(new OutputStreamWriter(output));
} catch (IOException e) {
e.printStackTrace();
}
}
This tells the runtime to execute a run.bat file that is in the same directory of the application. This method also initialized the OutputStream and InputStream objects that I created at the top of this class.
Here's my code for stopping the server...
public static void stopServer() {
System.out.println("Stopping server...");
// server.destroy();
try {
writer.write("stop\n\r");
} catch (IOException e) {
e.printStackTrace();
}
}
"stop" is a command that I'm trying to issue to the server to stop it, but for some reason the command is never being issued to the server.
More info:
The server is being run in cmd.exe, and therefore all server cmds need to be issued in cmd.
The server is named minecraft_server.jar so I have to use the command line to run the server and get output from the server and write input to it.
The run.bat file contains the text java -Xmx1024M -Xms1024M -jar minecraft_server.jar nogui.
My main goal is to write the command "stop" to the server to stop it.
As #clearlyspam23 stated, you are killing the process the moment you write anything to it.
Second, you are writing to the process' output stream, you want to write in the input stream. Edit: nope
Also, any server command is usually validated with a 'Enter' keystroke, so you might need to add a carriage return ('\r') right after your command to simulate that.

How to run a shell script from Java and have it continue running after JVM shutdown?

I'm writing a plugin in order to restart a server application on Linux (though I'm testing on OSX). The way I'm doing this is using a shell script which commands the application to stop, and then oversees the death of the process, safely starting a new one when the time comes.
My script works when I execute it manually from the command line. However, when I execute it from within the application, the shell process is killed along with the application.
I've tried two different methods of running the process from Java:
String scriptArgs[] = {"sh", "restart.sh", "&"};
try {
Runtime.getRuntime().exec(scriptArgs);
} catch (IOException e) {
e.printStackTrace();
}
and
ProcessBuilder processBuilder = new ProcessBuilder("sh", "restart.sh");
try {
processBuilder.directory(new File(System.getProperty("user.dir")));
processBuilder.redirectErrorStream(false);
processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}
Both of these methods gave the same result: the script was called, it successfully shut down the application, and then it died before it could continue. Is there any method to start a completely independent process from Java?
When you run a process from java you are creating a shell instance which then runs the process. The shell will only exit once this process has finished even if it is being run in the background &
To run a process in headless mode you need to use the nohup command. For details, see here.
A usage could look like this:
ProcessBuilder processBuilder = new ProcessBuilder("nohup", "sh", "restart.sh");
try {
processBuilder.directory(new File(System.getProperty("user.dir")));
processBuilder.redirectErrorStream(false);
processBuilder.start();
} catch (IOException e) {
e.printStackTrace();
}

Java Process InputStream in Linux machine

I'm using Java Process as below :
Runtime rt = Runtime.getRuntime();
try {
Process pr = rt.exec(cmd);
response = IOUtils.toString(pr.getInputStream(), "UTF-8");
response = response.substring(2, response.length()-4);
logger.debug("response :" + response);
} catch (IOException e) {
logger.error(e);
e.printStackTrace();
}
I can see the loggers in my local machine(Mac OSX). But when I run the same program in a Redhat Linux machine, I'm having problem seeing the logs. I don't have any clue whats happening after pr.getInputStream(). Having a logger before that statement is working fine. I want to see the response of the exec(cmd). How can I achieve this. I suspect something is wrong when I'm trying to read the InputStream.
Try reading input stream and error stream in two threads other than the one that launched the process.
I have seen processes gets stuck writing to error or output streams if no one is reading what they are writing.

Automatically close and disconnect a java sshj session

I am using the sshj library for java.
I need to open an ssh session on a remote server, execute a command which could run for many minutes, and then continue on executing in my java code. Once the command running on the remote server is finished, i would like the ssh session to close, and the sshclient to disconnect.
I have seen the following code example:
public class Exec {
public static void main(String... args) throws IOException {
final SSHClient ssh = new SSHClient();
ssh.loadKnownHosts();
ssh.connect("localhost");
try {
ssh.authPublickey(System.getProperty("user.name"));
final Session session = ssh.startSession();
try {
final Command cmd = session.exec("ping -c 1 google.com");
System.out.println(IOUtils.readFully(cmd.getInputStream()).toString());
cmd.join(5, TimeUnit.SECONDS);
System.out.println("\n** exit status: " + cmd.getExitStatus());
} finally {
session.close();
}
} finally {
ssh.disconnect();
}
}
}
Basically I don't want to wait for the command to finish (no cmd.join call) and I need the session.close() and ssh.disconnect() to be called automatically once the command has exited. Is this possible?
I may not be able to exactly answer my question, but maybe provide help for others trying to do something similar to what I was doing. When I posted, I was under the impression that the ssh session had to stay open for the command to finish, but I don't think that is the case.
So what I was trying to do was start a remote ssh session via java, and run a shell script on the remote machine. The shell script could take up to 10-15 mins to complete. I tested a short timeout (5 secs) and the script continued to run after the session was disconnected... which is what I wanted.

How to tell Java run this Runtime.getRuntime().exec, without waiting what ever command it has to run, simply run it in backend?

How to let the Runtime.getRuntime().exec(p) run without waiting for the sleep 10??
Currently its wrong, its waiting until the exec gets complete and then moves to next. Where i need to on the fly let the exec running so that after 10 second later it can kill the PresentationInProjector.jpg.
Example:
Runtime.getRuntime().exec("(sleep 10; echo '09|00|CC|01|83|88' | nc localhost 58888) &");
PlayThisSlideShow("PresentationInProjector.jpg");
According to the docs exec():
Executes the specified string command in a separate process.
So any call to exec() should not block unless you used waitFor() on the returned process of the Runtime .
Here is a small example(Exception handling omitted):
Process p=Runtime.getRuntime().exec("cmd.exe /c ping 127.0.0.1 -n 10");
System.out.println("Here 1");//this will execute immediately
try {
p.waitFor();
System.out.println("Here 2");//this will only be seen after +- 10 seconds and process has finished
} catch (InterruptedException ex) {
ex.printStackTrace();
}
exec() is not making thread wait until spawned process ends by default. You need to call process.waitFor() explicitly to make current process wait.
I guess that PlayThisSlideShow("PresentationInProjector.jpg"); is being called immediately after exec(). What you see is system making JVM process be running as long as child process is running. I guess there is no way to overcome this easily, to have parent process killed while child process still running.
Why can't you kill presentation projector from Java?
   Runtime.getRuntime().exec("(sleep 10; echo '09|00|CC|01|83|88' | nc localhost 58888) &");
will not do what you expect. Runtime.exec is not a shell and doesn't understand things like () grouping, ; or |. But the actions you're trying to perform can be done purely in Java, you don't need to exec an external process. For example (exception handling omitted):
new Thread(new Runnable() {
public void run() {
Thread.sleep(10000); //sleep 10
Socket s = new Socket("localhost", 58888); // nc
PrintWriter pw = new PrintWriter(s.getOutputStream());
pw.print("09|00|CC|01|83|88\n"); // echo
pw.close();
s.close();
}
}).start();

Categories