简体   繁体   中英

Change System.in and read System.out programmly on the fly (Jsch)

In my code I am trying to run some commands on a remote server via SSH. The commands must build on each other, but with a logic behind it. This means something like: When the output of command a contains “retcode 0”, then do command b. Else do command c

I found no way to implement this logic into several “exec” commands. It seems like every “exec” has its own process, so I can't continue where I was before. And with one “exec” I just can pass a list of commands where all of them will be executed, so no logic there. So, I decided to use “shell” for Jsch. (If there is a way to use exec for it, I would be happy with that)

Based on the example from jcraft , I wrote this code:

import com.jcraft.jsch.*;
import java.io.ByteArrayInputStream;
import java.io.InputStream;

public class Main {
    public static void main(String[] args) {
        try {
            JSch jsch = new JSch();
            String user = "sshuser";
            String host = "localhost";
            Session session = jsch.getSession(user, host, 22);
            String passwd = "password";
            session.setPassword(passwd);
            session.setConfig("StrictHostKeyChecking", "no");

            //session.connect();
            session.connect(30000);   // making a connection with timeout.
            Channel channel = session.openChannel("shell");

            // Enable agent-forwarding.
            ((ChannelShell)channel).setAgentForwarding(true);


            // Set Streams
            channel.setInputStream(System.in);
            channel.setOutputStream(System.out);

            channel.connect(3 * 1000);
        } catch (Exception e) {
            System.out.println(e);
        }
    }
}

Basically, this gives me as a human exact the possibility to do what I want to do. I can enter commands in System.in, the return is printed to System.out. I can read it, decide what I want to do with it and then enter the next command. The command will be executed exact at the point where I was earlier, so everything is fine.

Now I have to find a way to do it via java. I found a way to enter the first command through a fix string:

[...]
InputStream testInput = new ByteArrayInputStream( "dir \n".getBytes("UTF-8") );
// Set Streams
channel.setInputStream(testInput);
[...]

But after that I find no way to send the next one (as a first step even without reading the output).

So, my question is, is there a way to set the System.in via Java code which will directly send this via Jsch (System.setIn() doesn't work for me) or another way to change the input string on the fly, so that it gets transmitted via Jsch?

Thanks for your time!

Thanks to the comments from Martin Prikryl I found a solution. I created a little example with Telnet instead of my real application. The basics are the same and i think it is more helpfull because more people can try it out and play with it when it is not based on a specific software.

import com.jcraft.jsch.*;
import java.io.*;

public class Main {
    public static void main(String[] args) {
        OutputStream out = null;
        Session session = null;
        try {
            JSch jsch = new JSch();
            String user = "sshuser";
            String host = "localhost";
            session = jsch.getSession(user, host, 22);
            String passwd = "password";
            session.setPassword(passwd);
            session.setConfig("StrictHostKeyChecking", "no");

            // vars and objects used later
            String lineSeperator = System.getProperty("line.separator");
            StringBuilder sb = new StringBuilder();
            Main main = new Main();

            //session.connect();
            session.connect(30000);   // making a connection with timeout.
            ChannelExec channel = (ChannelExec) session.openChannel("exec");
            InputStream in = channel.getInputStream();
            BufferedReader reader = new BufferedReader(new InputStreamReader(in));

            // start telnet session
            channel.setCommand("telnet 192.168.222.128 -l sshuser");
            out = channel.getOutputStream();
            channel.connect();
            // wait a little bit for telnet to be ready to take the input
            Thread.sleep(500);
            // pass the password
            out.write(("password\n").getBytes());
            out.write(("\n").getBytes());
            Thread.sleep(500);
            // flush reader, very important!
            out.flush();

            // Read from Bufferreader until the current line contains a specific string
            // For my real application it would be "---       END", for this example i
            // used something from the last line my machine returns. Very important that this string
            // appears on every possible output, or you will stuck in a while loop!
            //
            // Tried it with while((reader.readline())!=null) but this ends in a infinity loop too.
            // Since in my application there is an String that always get returned i didn't look it further up
            String responeFromLogin = main.readOutput("security updates.", reader, lineSeperator, sb);

            // Working with the response, in this example a simple fail-->Exception, success --> progress
            if (responeFromLogin.contains("Login incorrect")) {
                throw new Exception("Failed: Login");
            }
            System.out.println("Login Successfull");

            // Log in was successful, so lets do the next command, basiclly the same routine again
            out.write(("dir\n").getBytes());
            Thread.sleep(500);
            out.flush();
            // Again, not bulletproofed in this example
            String responseFromHelp = main.readOutput("examples.desktop", reader, lineSeperator, sb);
            if (!responseFromHelp.contains("test")) {
                throw new Exception("Failed: Help");
            }
            System.out.println("Folder Found");



        } catch (InterruptedException e1) {
            e1.printStackTrace();
        } catch (IOException e1) {
            e1.printStackTrace();
        } catch (JSchException e1) {
            e1.printStackTrace();
        } catch (Exception e1) {
            e1.printStackTrace();
        } finally {
            try {
                if (out != null) {
                    out.flush();
                }
            } catch (IOException e1) {
                e1.printStackTrace();
            }
            System.out.println("_________________________");
            System.out.println("I am done");
            if (session != null) {
                session.disconnect();
            }
        }
    }

    public String readOutput(String endString, BufferedReader reader, String lineSeperator, StringBuilder sb) {
        String line;
        String returnString = "Error";

        while (true) {
            try {
                line = reader.readLine();
                if (line.contains(endString)) {
                    sb.append(line).append(lineSeperator);
                    returnString = sb.toString();
                    break;
                } else {
                    sb.append(line).append(lineSeperator);
                }
            } catch (IOException e) {
                returnString = "Error";
                e.printStackTrace();
            }
        }
        return returnString;
    }
}

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM