Running programs using JSch in the background - java

I am trying to connect to a remote machine using JSch. All my systems are running on ubuntu including my production machines. I am able to successfully connect and run the jar file. But when i close the window the program automatically shuts down. What i'm trying to achieve now is to run this jar file in the background.
I have appended the sudo command with '&' and the server doesn't even start in this case. I have tried using a shell channel but here to the server doesn't startup or closes on stopping my program.
I've also tried the nohup and disown commands to run in the background. When i get the process state using ps ux the STAT column shows T which according to this means the process has stopped. I've been stuck here since 3 days.
Is there anything wrong with the code i've written? why is the server unable to run in the background?
setPty(true) -> what does this do?
is there a way to stop the password from printing to the console when i enter it?
I have been testing this code in my local network. while connecting to our production servers we pass a permissions file along like this: sudo ssh -i permissionFilePath serverName#ipAddress. Will i have to change my approach again for passing this permission file to gain access to production systems?
i am using the following version of JSch:
<dependency>
<groupId>com.jcraft</groupId>
<artifactId>jsch</artifactId>
<version>0.1.53</version>
</dependency>
I am using the following code:
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import javafx.application.Application;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
public class App extends Application {
#Override
public void start(Stage primaryStage) {
Button btn = new Button();
btn.setText("click");
btn.setOnAction(new EventHandler<ActionEvent>() {
public void handle(ActionEvent arg0) {
try {
JSch objJSch = new JSch();
Session objSession;
objSession = objJSch.getSession("userName", "host");
objSession.setPassword("password");
objSession.setConfig("StrictHostKeyChecking", "no");
System.out.println("Establishing Connection...");
objSession.connect();
System.out.println("Connection established.");
Channel objChannel = objSession.openChannel("exec");
((ChannelExec) objChannel).setCommand("cd {{path to my jar file}};sudo java -jar start.jar");
((ChannelExec) objChannel).setErrStream(System.err);
((ChannelExec) objChannel).setPty(true);//why should i use this??
InputStream in = objChannel.getInputStream();
OutputStream out = objChannel.getOutputStream();
objChannel.connect();
out.write(("password" + "\n").getBytes());
out.flush();
BufferedReader br = new BufferedReader(new InputStreamReader(in));
String s;
while ((s = br.readLine()) != null) {
System.out.println(s);
}
while (!objChannel.isClosed()) {
System.out.println("Waiting to close channel");
}
System.out.println("disconnecting...");
objChannel.disconnect();
objSession.disconnect();
System.out.println("disconnected.");
} catch (JSchException e) {
if (e.getMessage().equalsIgnoreCase("Auth fail"))
System.out.println("Authorization failed...");
else
e.printStackTrace();
} catch (IOException e) {
e.printStackTrace();
}
}
});
StackPane root = new StackPane();
root.getChildren().add(btn);
Scene scene = new Scene(root, 300, 250);
primaryStage.setTitle("");
primaryStage.setScene(scene);
primaryStage.show();
}
public static void main(String[] args) {
launch(args);
}
}

Your Code
((ChannelExec) objChannel).setCommand("cd {{path to my jar file}};sudo java -jar start.jar");
Modify it to :
((ChannelExec) objChannel).setCommand("cd {{path to my jar file}};sudo java -jar start.jar > /dev/null 2>&1 &");
Which will resolve your issue.

Related

Show results of SSH command executed with JSch in separate console/cmd window, not in IDE console

I am connecting to SSH in Java with JSch jar. And need to show result in cmd not in IDE console view. Any guidance for this, it is possible to open a command prompt with the result?
Why we need result in cmd means we need to take screenshot of the Command prompt window and send to client.
import java.io.InputStream;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.ThreadLocalRandom;
import com.jcraft.jsch.Channel;
import com.jcraft.jsch.ChannelExec;
import com.jcraft.jsch.JSch;
import com.jcraft.jsch.JSchException;
import com.jcraft.jsch.Session;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
public class Putty1 {
public static String txt;
/**
* #param args the command line arguments
*/
public static void main(String[] args) throws JSchException, FileNotFoundException {
// TODO code application logic here
String host="HostName";
String user="xxxx";
String password="xxxx";
String command1="ls -ltr";
try{
java.util.Properties config = new java.util.Properties();
config.put("StrictHostKeyChecking", "no");
JSch jsch = new JSch();
Session session=jsch.getSession(user, host, 22);
session.setPassword(password);
session.setConfig(config);
session.connect();
System.out.println("Connected");
Channel channel=session.openChannel("exec");
((ChannelExec)channel).setCommand(command1);
channel.setInputStream(null);
((ChannelExec)channel).setErrStream(System.err);
InputStream in=channel.getInputStream();
channel.connect();
byte[] tmp=new byte[1024];
while(true){
while(in.available()>0){
int i=in.read(tmp, 0, 1024);
if(i<0)break;
txt = new String(tmp, 0, i);
System.out.print(txt);
}
if(channel.isClosed()){
System.out.println("exit-status: "+channel.getExitStatus());
break;
}
try{Thread.sleep(1000);}catch(Exception ee){}
}
channel.disconnect();
session.disconnect();
System.out.println("DONE");
}catch(Exception e){
e.printStackTrace();
}
//System.out.println(txt);
try (PrintWriter out = new PrintWriter("C:\\Documents and Settings\\arahman9\\My Documents\\Downloads\\jpp\\prs72760.txt"))
{
out.println(txt);
}
}
}
Output:
Connected
total 12
drwxrwxrwt 2 arahman9 arahman9 4096 Jul 10 14:30 tmp
drwxr-xr-x 2 arahman9 arahman9 4096 Jul 10 14:30 public_html
drwxr-xr-x 2 arahman9 arahman9 4096 Jul 10 14:30 Documents
exit-status: 0
DONE
BUILD SUCCESSFUL (total time: 2 seconds)
When you execute a console application in IDE (Eclipse/Netbeans/etc), IDE redirects console application output to Console view.
But if you run your application in cmd.exe it will use cmd.exe console.
And if you run your application directly (via java.exe), e.g. from Windows Run box, it will create its own console window.
That's just how console application behave. It has nothing to do with your code.
Also, here's some trick that can be used to make Eclipse not redirect console application output to Console view:
https://www.reddit.com/r/eclipse/comments/1bk7a1/how_do_i_run_programs_in_a_separate_console_window/

Program will not run when turned into .jar

I have tried many methods over the last few days with no success...I've trawled through various Stackoverflow entries and to no avail...I must be missing something.
I have tried across three different IDEs...IntelliJ, Eclispe and Netbeans.
The problem is when trying to turn my program into an executable jar it is unable to run (either by double clicking or running through command).
When executing the following on command:
java -jar D:\Computing\Programming\Java\Projects\JavaFXGameMenu\out\artifacts\JavaFXGameMenu_jar\JavaFXGameMenu.jar
I get: Error: Could not find or load main class root.Main
When i run the same but with javaw instead.. i get not error message, but nothing happens either.
I am predominately using IntelliJ as its a JavaFX application that I am building.
This is the project hierarchy:
When creating the Artifact I choose the following based upon other threads:
I then re run this using: Java -jar D:\Computing\Executables\JavaFXGameMenu.jar
I get the following issue:
I have put the relevant environment variables into my system and Path and I am using jre1.8.0_144.
Any help with tracking down what the problem could be is greatly appreciated
Code below...but this fully compiles and runs within IDE without errors...the problem is when its turned into a .jar and ran from command.
package root;
import javafx.application.Application;
import javafx.application.Platform;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.geometry.Pos;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.CheckBox;
import javafx.scene.control.Label;
import javafx.scene.effect.DropShadow;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.Pane;
import javafx.scene.layout.StackPane;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.paint.CycleMethod;
import javafx.scene.paint.LinearGradient;
import javafx.scene.paint.Stop;
import javafx.scene.shape.Line;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.scene.text.FontWeight;
import javafx.scene.text.Text;
import javafx.stage.Screen;
import javafx.stage.Stage;
import javafx.stage.StageStyle;
import javafx.stage.Window;
import java.io.IOException;
import java.io.InputStream;
import java.nio.file.Files;
import java.nio.file.Paths;
public class Main extends Application {
private double width = 1920;
private double height = 1080;
private Parent createContent(){
Pane root = new Pane();
root.setPrefSize(width, height); //W:860 H:600
ImageView imgLogo = null;
ImageView bottomlogo = null;
MenuItem newGame = new MenuItem("NEW GAME");
MenuItem continueGame = new MenuItem("CONTINUE");
MenuItem friends = new MenuItem("FRIENDS");
MenuItem settings = new MenuItem("SETTINGS");
MenuItem store = new MenuItem("STORE");
MenuItem exit = new MenuItem("EXIT");
try(InputStream is = Files.newInputStream(Paths.get("src/resources/Images/dark.jpg"))) {
ImageView img = new ImageView(new Image(is));
img.setFitWidth(width);
img.setFitHeight(height);
root.getChildren().add(img);
} catch (IOException e){
System.out.println("Couldn't Load Image");
}
try(InputStream is = Files.newInputStream(Paths.get("src/resources/Images/logo.png"))) {
imgLogo = new ImageView(new Image(is));
imgLogo.setX(1000);
imgLogo.setY(100);
imgLogo.setFitWidth(600);
imgLogo.setFitHeight(300);
} catch (IOException e){
System.out.println("Couldn't Load Image");
}
try(InputStream is = Files.newInputStream(Paths.get("src/resources/Images/SteamAgony.png"))) {
bottomlogo = new ImageView(new Image(is));
bottomlogo.setX(100);
bottomlogo.setY(800);
bottomlogo.setFitHeight(200);
bottomlogo.setFitWidth(200);
bottomlogo.setOpacity(0.7);
} catch (IOException e){
System.out.println("Couldn't Load Image");
}
MenuBox menu = new MenuBox(
newGame,
continueGame,
friends,
settings,
store,
exit);
menu.setTranslateX(width / 3.4);
menu.setTranslateY(height / 2.5);
settings.setOnMouseClicked(event -> new SceneCreator().createScene(200,300));
exit.setOnMouseClicked( event -> Platform.exit());
root.getChildren().addAll(menu, imgLogo, bottomlogo);
return root;
}
#Override
public void start(Stage primaryStage) throws Exception{
Scene scene = new Scene(createContent());
primaryStage.setScene(scene);
primaryStage.initStyle(StageStyle.UNDECORATED);
primaryStage.show();
}
#Override
public void stop(){
//TODO
}
public static void main(String[] args) {
launch(args);
}
}
The error is at Main.createContent line 102. Maybe you forgot to initialize the child node (I'm not really familiar with JavaFX).
As #cedrikk mentioned, the problem is related to your code in Main.createContent.
You said the problem is when trying to run the jar as an executable -
did you try to run it within the IDE? If not - you should try to, and while at it - debug it to help you find the problem. Just right click your Main class and choose debug.
Regarding running it with javaw, the reason you got no error messages is because javaw executes java programs without a console - where you would normally get error messages unless using some logging solution.
You are adding a null element as a child of a Pane, causing the null pointer issue you are facing, if you use the debugger you'll be able to find where the variable that shouldn't be null is being set to null.
Edit - after code added
You are seeing 2 fields in try catches (imageLogo, bottomLogo), and adding them even if they fail, which adds nulls, causing the error.
You use a relative path for the images, this is probably the issue, are you running the jar from the project root? If not you could put the absolute path, but using resources would be more reliable, and allow the jar to run on different computers.
The problem was down to declaring inputStreams.
This works for both in IDE and running from jar:
String bgImg = "root/resources/dark.jpg";
URL bgImgPath = Main.class.getClassLoader().getResource(bgImg);
ImageView img = new ImageView(new Image(bgImgPath.toExternalForm()));
img.setFitWidth(width);
img.setFitHeight(height);
root.getChildren().add(img);
Compared to what I had before:
try(InputStream is = Files.newInputStream(Paths.get("src/resources/Images/dark.jpg"))){
ImageView img = new ImageView(new Image(is));
img.setFitWidth(width);
img.setFitHeight(height);
root.getChildren().add(img);
}catch (IOException e) {
System.out.println("Could not load");
}
The changes to the paths, were from where I tried adding the resource folder to the root folder instead of within src.

JavaFX2.2 (stable) ignores set properties for "socksProxyHost" and "socksProxyPort"?

First, I would like to mention that I also had this problem when 2.2 was still beta (forced me to revert back to 2.1.1).
Installed JavaSE 7u6 today (comes bundled with JavaFX 2.2 stable). NetBeans was
able to automatically detect the Default JavaFX Platform.
Created a new JavaFX Application project (tried the FXML derivative with the same result as well). Tried this piece of code:
package javafxapplication;
import java.io.BufferedReader;
import java.io.InputStreamReader;
import java.net.URL;
import java.net.URLConnection;
import javafx.application.Application;
import javafx.stage.Stage;
public class JavaFXApplication extends Application
{
public static void main(String[] args)
{
launch(args);
}
#Override
public void start(Stage primaryStage)
{
System.setProperty("socksProxyHost", "127.0.0.1");
System.setProperty("socksProxyPort", "9050");
try
{
URLConnection conn = new URL("http://www.wikipedia.org").openConnection();
BufferedReader br = new BufferedReader(new InputStreamReader(conn.getInputStream()));
String line;
while ((line = br.readLine()) != null)
{
System.out.println(line);
}
}
catch (Exception e) { e.printStackTrace(); }
System.exit(0);
}
}
And it works. Without spewing an error that no connection could be made due to bad socks proxy settings (there is nothing running on that port on my machine). These properties are silently ignored and the connection occurs directly. Is this a bug? I've tested this on 2 machines running Win7 x64. Does not happen on 2.1.1.
JavaFX 2.2 introduced support for system proxy (see http://javafx-jira.kenai.com/browse/RT-21705).
It may interfere with socks proxy settings. You can try remove your system proxy or try to add next to JVM options: -Djavafx.autoproxy.disable=true

how to automate sending commands using SSH factory

I am using ssh factory to automate the logins. I have to automate logins till 4 gateways and send commands and get output's of it. I have successfully automated till 3 gateways. Now i have to fire command "telnet remote_ip" to get into the 4th gateway. Where i am using telnet sessions for this 4th gateway alone since i need to fire "telnet ip", since it is using telnet protocol over here. But for the previous 3 gateway's i've used ssh sessions. But it is not firing this "telnet ip" command. Can some1 help me regarding this?.
Below is the code, where i am trying to automate it.
import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileInputStream;
import java.io.FileWriter;
import java.io.IOException;
import java.io.InputStreamReader;
import java.io.PrintWriter;
import java.util.Scanner;
import com.jscape.inet.ssh.Ssh;
import com.jscape.inet.ssh.SshAdapter;
import com.jscape.inet.ssh.SshConnectedEvent;
import com.jscape.inet.ssh.SshDataReceivedEvent;
import com.jscape.inet.ssh.SshDisconnectedEvent;
import com.jscape.inet.ssh.SshException;
import com.jscape.inet.ssh.SshScript;
import com.jscape.inet.ssh.SshSession;
import com.jscape.inet.ssh.SshTask;
import com.jscape.inet.ssh.connection.channels.SessionClient;
import com.jscape.inet.ssh.connection.channels.SessionRequests;
import com.jscape.inet.ssh.util.SshParameters;
import com.jscape.inet.telnet.Telnet;
import com.jscape.inet.telnet.TelnetException;
import com.jscape.inet.telnet.TelnetListener;
import com.jscape.inet.telnet.TelnetScript;
import com.jscape.inet.telnet.TelnetSession;
import com.jscape.inet.telnet.TelnetTask;
public class SshScriptTutorial extends SshAdapter {
public SshScriptTutorial() {}
public void executeSshScript(String hostname, String username, String password)
throws SshException, IOException, InterruptedException, TelnetException
{
// assumes that SSH shell prompt is ">" .. this MUST match exactly
String shellPrompt = ">";
String shellPrompt1 = ":";
// initialize and create new Ssh instance
SshParameters sshParams = new SshParameters(hostname,username,password);
Ssh ssh = new Ssh(sshParams);
// register this class to receive Ssh events
ssh.addSshListener(this);
// create new script object and bind to the given ssh object
SshScript script = new SshScript(ssh);
// add tasks to script object
script.addTask(new SshTask(shellPrompt, "show host", shellPrompt));
script.addTask(new SshTask(shellPrompt, "ssh ssgpun", shellPrompt1)); // 2nd g/w
script.addTask(new SshTask(shellPrompt1, "password", shellPrompt));
script.addTask(new SshTask(shellPrompt, "net ip", shellPrompt1)); // 3rd gateway
script.addTask(new SshTask(shellPrompt1, "username", shellPrompt1));
script.addTask(new SshTask(shellPrompt1, "password", shellPrompt));
// till this it is working
// connect to SSH server and execute script
ssh.connect();
// wait until last task is complete
while(!script.isComplete()) {
try {
Thread.sleep(500);
} catch(Exception e) {
System.err.println(e.getMessage());
}
}
// disconnect from server
// ssh.disconnect();
//**
Here i am trying to get into the last remote server using command "telnet ip" using telnet session since it is involving telnet protocol. But it is not firing this command itself. So, can anybody help me regarding this. How to do?... I have even tried using ssh sessions for this "telnet ip" and for username and pass. If i use ssh session for this 4th gateway, i am able to automate only "telnet ip" and it is asking for login name, and login name is not automated. So, i have tried both ssh sessions and telnet sessions. I dont know what is the prob or how to solve it.
Kindly help...
//**
// create new Telnet instance
Telnet telnet = new Telnet("10.228.128.33");
// create new TelnetScript instance and bind to Telnet instance
TelnetScript script_t = new TelnetScript(telnet);
// create a task that waits for login prompt and submits username
TelnetTask username_t = new TelnetTask(shellPrompt1,"switchind", shellPrompt1);
// create task that waits for password prompt and submits password
TelnetTask password_t = new TelnetTask(shellPrompt1, "Indore123", shellPrompt);
// add tasks to script
script_t.addTask(username_t);
script_t.addTask(password_t);
// connect to telnet server … script is executed automatically
telnet.connect();
}
public void connected(SshConnectedEvent event) {
System.out.println("Connected to host: " + event.getHost());
}
public void disconnected(SshDisconnectedEvent event) {
System.out.println("Disconnected from host: " + event.getHost());
}
public void dataReceived(SshDataReceivedEvent event) {
System.out.print(event.getData());
}
public static void main(String[] args)
{
try
{
BufferedReader reader = new BufferedReader(new InputStreamReader(System.in));
String hostname = "host_ip";
String username = "username";
System.out.print("Enter password: ");
String password = reader.readLine();
SshScriptTutorial tutorial = new SshScriptTutorial();
tutorial.executeSshScript(hostname, username, password);
} catch(Exception e) {
e.printStackTrace();
}
}
}

Write an executable .sh file with Java for OSX

So I am trying to write an .sh file that will be executable, this is how I'm currently writing it:
Writer output = null;
try {
output = new BufferedWriter(new FileWriter(file2));
output.write(shellScriptContent);
output.close();
} catch (IOException ex) {
Logger.getLogger(PunchGUI.class.getName()).log(Level.SEVERE, null, ex);
}
So that writes the file just fine, but it is not executable. Is there a way to change the executable status when I write it?
Edit: To further clarify, I am trying to make it execute by default, so that for instance, if you double clicked the generated file, it would automatically execute.
You can call File.setExecutable() to set the owner's executable bit for the file, which might be sufficient for your case. Or you can just chmod it yourself with a system call with Process.
Alas, full-powered programmatic alteration of file permissions isn't available until Java 7. It'll be part of the New IO feature set, which you can read more about here.
You'd need to chmod it, and you can probably do it by exec'ing a system command like such:
Really all you'd need is to fire off something like this:
Runtime.getRuntime().exec("chmod u+x "+FILENAME);
But if you want to keep track of it more explicitly can capture stdin / stderr then something more like:
Process p = Runtime.getRuntime().exec("chmod u+x "+FILENAME);
BufferedReader stdInput = new BufferedReader(new InputStreamReader(p.getInputStream()));
BufferedReader stdError = new BufferedReader(new InputStreamReader(p.getErrorStream()));
Which I got from here:
http://www.devdaily.com/java/edu/pj/pj010016/pj010016.shtml
Update:
Test program:
package junk;
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
public class Main{
private String scriptContent = '#!/bin/bash \n echo "yeah toast!" > /tmp/toast.txt';
public void doIt(){
try{
Writer output = new BufferedWriter(new FileWriter("/tmp/toast.sh"));
output.write(scriptContent);
output.close();
Runtime.getRuntime().exec("chmod u+x /tmp/toast.sh");
}catch (IOException ex){}
}
public static void main(String[] args){
Main m = new Main();
m.doIt();
}
}
On linux if you open up a file browser and double click on /tmp/toast.sh and choose to run it, it should generate a text file /tmp/toast.txt with the words 'yeah toast'. I assume Mac would do the same since it's BSD under the hood.
In Java 7 you can call Files.setPosixFilePermissions. Here is an example:
import java.io.IOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.attribute.PosixFilePermission;
import java.util.Set;
class FilePermissionExample {
public static void main(String[] args) throws IOException {
final Path filepath = Paths.get("path", "to", "file.txt");
final Set<PosixFilePermission> permissions = Files.getPosixFilePermissions(filepath);
permissions.add(PosixFilePermission.OWNER_EXECUTE);
Files.setPosixFilePermissions(filepath, permissions);
}
}
On Mac OS X, besides chmod +x, you have to give a .command extension to your shell script if you want to launch it with a double-click.
This answer I wrote for the question how do I programmatically change file permissions shows a chmod example via a native call using jna, which should work on Mac OS X.

Categories