/*
* Copyright (C) 2006 Kustaa Nyholm. All rights reserved. Use is
* subject to license terms.
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the Lesser GNU General Public License as
* published by the Free Software Foundation; either version 2 of the
* License, or (at your option) any later version.
*
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
* USA.
*/
package jApp.jdic;
import java.io.*;
import java.util.*;
/**
* Implements a simple wrapper around the RunTime.exec() method that allows easy
* capture of command results (that is 'stdout' and 'stderr' and feeding the command via
* 'stdin'.
*
* @author Kustaa Nyholm
*
*/
public class Shell {
private boolean m_TraceCommands = true;
private String m_Command;
private int m_EditCode;
private Exception m_Exception;
/**
* Executes a given command line with root rights and default time out of five seconds.
*
* @see #execute(String, String,int)
* @param cmd the command line to execute
* @param input the input to feed to the command via 'stdin', can be null
* @return the combined output of 'stdout' and 'stderr' from the command
* @throws Exception
*/
public String sudoExecute(String cmd, final String input, String password) throws Exception {
return sudoExecute(cmd,input,password,5000);
}
/**
* Executes a given command line with root rights.
*
* @see #execute(String, String,int)
* @param cmd the command line to execute
* @param input the input to feed to the command via 'stdin', can be null
* @return the combined output of 'stdout' and 'stderr' from the command
* @param timeout in milliseconds after which the process is aborted, use zero for no timeout
* @throws Exception
*/
public String sudoExecute(String cmd, final String input, String password, int timeout) throws Exception {
return execute("sudo -S " + cmd, password+input!=null?input:"",5000);
}
/**
* Executes a given command line with default time out of five seconds.
*
* @see #execute(String, String,int)
* @param cmd the command line to execute
* @param input the input to feed to the command via 'stdin', can be null
* @return the combined output of 'stdout' and 'stderr' from the command
*/
public String execute(String cmd, final String input) {
return execute(cmd, input, 5000);
}
/**
* Executes a given command line, aborting after given timeout.
*
* After calling this method you should check for error by calling the getExitCode(). A non zero
* positive value indicates an error, typically Unix/Linux processes can only use values in the
* range 0..255 inclusive.
* If an exception was thrown during the call execute method
* the {@link #getExitCode()} returns -1 and you can get the exception with the {@link #getException()} call
*
* @see #getExitCode
* @see #getCommand
* @see #getException
* @param cmd the command line to execute
* @param input the input to feed to the command via 'stdin', can be null
* @param timeout in milliseconds after which the process is aborted, use zero for no timeout
* @return the combined output of 'stdout' and 'stderr' from the command
*/
public String execute(String cmd, final String input, int timeout) {
m_Exception=null;
OutputStream output = new ByteArrayOutputStream();
m_Command = cmd;
m_EditCode = -1;
try {
if (m_TraceCommands)
System.out.println("execute: " + cmd);
final Process cmdproc = Runtime.getRuntime().exec(cmd);
final PrintStream stdin = new PrintStream(cmdproc.getOutputStream());
InputStream stdout = cmdproc.getInputStream();
createForkedPipe(stdout, m_TraceCommands ? System.out : null, output);
InputStream errout = cmdproc.getErrorStream();
createForkedPipe(errout, m_TraceCommands ? System.err : null, output);
if (input != null) {
stdin.println(input);
stdin.close();
}
java.util.Timer timer = new java.util.Timer();
if (timeout > 0)
timer.schedule(new TimerTask() {
public void run() {
cmdproc.destroy();
}
}, timeout);
int res = cmdproc.waitFor();
timer.cancel();
m_EditCode = res;
} catch (IOException e) {
m_Exception=e;
System.err.println(e.getMessage());
} catch (Exception e) {
m_Exception=e;
e.printStackTrace();
}
if (m_TraceCommands)
System.out.println("exit code: " + m_EditCode);
return output.toString();
}
/**
* Gets the exit code from the last command executed, should be checked after each
* invokation of {@code execute} to verify success. Typically 0 value indicates success,
* no Unix/Linux script/program should not be able to return a code outside 0..255,
* a return code of -1 indicates an exception in attempting to execute the command line
* in other words an exception was thrown before or during execution of the command
* and it was not possible to capture the actual exit code from the command.
*
* @return the exit code
*/
public int getExitCode() {
return m_EditCode;
}
/**
* Gets the last command that has been executed (succesfully or not in other word the command line that
* returned the exit code you can query with getExitCode()
* @return the command line
*/
public String getCommand() {
return m_Command;
}
/**
* Gets the exception that was thrown during, before or after the execution of the command line within
* the execute method, if any. If no exception was thrown, returns null.
* @return the exception or null
*/
public Exception getException() {
return m_Exception;
}
private void createForkedPipe(final InputStream in, final OutputStream out1, final OutputStream out2) {
Thread thread = new Thread() {
@Override
public void run() {
byte b[] = new byte[1];
try {
int n;
while ((n = in.read(b)) > 0) {
if (out1 != null)
out1.write(b);
if (out2 != null)
out2.write(b);
}
} catch (IOException e) {
e.printStackTrace();
m_Exception=e;
}
}
};
thread.start();
}
}
|