johnsam
johnsam

Reputation: 4582

Input to a process in JAVA always hung

Following this I have a JAVA code to do sudo -l, but it always hung. Btw, regardless if I use

Reader stdOut = new InputStreamReader (p.getInputStream ())

or

Reader stdOut = new InputStreamReader (p.getErrorStream ())

The output "[sudo] password for john" seems wasn't read by my code. Where did come from?

Here is my code

     Process p= Runtime.getRuntime ().exec (new String[] {"sudo", "-l"});

     Reader stdOut = new InputStreamReader (p.getErrorStream ());
     BufferedReader reader = new BufferedReader(stdOut);

     StringBuffer output = new StringBuffer();
     String line = "";           
     while ((line = reader.readLine())!= null) {
         System.out.println("$$" + line);
         if (line.contains ("password"))  {
               break;
         }
     }

    OutputStream stdIn = p.getOutputStream ();
    stdIn.write ("<my password>\n".getBytes ("US-ASCII"));
    stdIn.flush ();

     while ((line = reader.readLine())!= null) {
         System.out.println(line);
     }

Upvotes: 2

Views: 245

Answers (2)

Gren
Gren

Reputation: 1854

readLine blocks until end of line or end of stream is reached, but sudo does not print a line feed or carriage return after password.

So you should read the stream char by char like so:

String line;
char c;
do {
    line = null;
    while ((c = (char) p.getInputStream().read()) != -1) {
      if(c == '\r' || c == '\n') {
          break;
      }
      if(line==null){
          line="";
      }
      line+=String.valueOf(c);
        if (line != null) { 
            if(line.contains("password")) {//Attention: Ask for the very last word,
                                          //including ':' if sudo prints that out
                break;
            }
        }
    }
    if (line != null) { 
        System.out.println("$$" + line);
        if(line.contains("password")) {//Attention: Ask for the very last word,
                                       //including ':' if sudo prints that out
            break;
        }
    }
}while(c != -1);

I think this will work, but also I am sure that the code could written clearer.
Also you should think about using ProcessBuilder, than you are able to merge the output and the error stream

ProcessBuilder.redirectErrorStream(true)

Upvotes: 1

Kenster
Kenster

Reputation: 25438

Sudo normally opens /dev/tty to prompt for and read a password. Redirecting standard input or standard output doesn't affect the tty associated with the process.

Try running sudo with the -S parameter. It causes sudo to write the prompt to standard error and read the password from standard input. See the sudo manual.

Upvotes: 1

Related Questions