/*
* This file is part of the RootTools Project: http://code.google.com/p/roottools/
*
* Copyright (c) 2012 Stephen Erickson, Chris Ravenscroft, Dominik Schuermann, Adam Shanks
*
* This code is dual-licensed under the terms of the Apache License Version 2.0 and
* the terms of the General Public License (GPL) Version 2.
* You may use this code according to either of these licenses as is most appropriate
* for your project on a case-by-case basis.
*
* The terms of each license can be found in the root directory of this project's repository as well as at:
*
* * http://www.apache.org/licenses/LICENSE-2.0
* * http://www.gnu.org/licenses/gpl-2.0.txt
*
* Unless required by applicable law or agreed to in writing, software
* distributed under these Licenses is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See each License for the specific language governing permissions and
* limitations under that License.
*/
package com.stericson.RootTools;
import com.stericson.RootTools.RootTools.Result;
import java.io.BufferedReader;
import java.io.DataOutputStream;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.LinkedList;
import java.util.List;
import java.util.concurrent.TimeoutException;
class Executer {
protected Process process = null;
protected Result result = null;
// ------------
// # Executer #
// ------------
/**
* Sends several shell command as su (attempts to)
*
* @param commands
* array of commands to send to the shell
*
* @param sleepTime
* time to sleep between each command, delay.
*
* @param result
* injected result object that implements the Result class
*
* @return a <code>LinkedList</code> containing each line that was returned
* by the shell after executing or while trying to execute the given
* commands. You must iterate over this list, it does not allow
* random access, so no specifying an index of an item you want, not
* like you're going to know that anyways.
*
* @throws InterruptedException
*
* @throws IOException
* @throws TimeoutException
*/
synchronized List<String> sendShell(String[] commands, int sleepTime,
Result result, boolean useRoot, int timeout) throws IOException,
RootToolsException, TimeoutException {
RootTools.log("Sending " + commands.length + " shell command" + (commands.length > 1 ? "s" : ""));
Worker worker = new Worker(this, commands, sleepTime, result, useRoot);
worker.start();
try
{
if (timeout == -1)
{
timeout = 300000;
}
worker.join(timeout);
//small pause, let things catch up
Thread.sleep(RootTools.shellDelay);
if (worker.exit != -911)
return worker.finalResponse;
else
throw new TimeoutException();
}
catch(InterruptedException ex)
{
worker.interrupt();
Thread.currentThread().interrupt();
throw new TimeoutException();
}
}
protected static class Worker extends Thread
{
private String[] commands;
private int sleepTime;
private boolean useRoot;
public int exit = -911;
public List<String> finalResponse;
private Executer executer;
private Worker(Executer executer, String[] commands, int sleepTime, Result result, boolean useRoot)
{
this.commands = commands;
this.sleepTime = sleepTime;
this.executer = executer;
this.executer.result = result;
this.useRoot = useRoot;
}
public void run()
{
DataOutputStream os = null;
InputStreamReader osRes = null;
InputStreamReader osErr = null;
try
{
if (executer.process == null)
{
Runtime.getRuntime().gc();
if (RootTools.customShell.equals(""))
{
executer.process = Runtime.getRuntime().exec(useRoot ? "su" : "sh");
RootTools.log(useRoot ? "Using Root" : "Using sh");
}
else
{
executer.process = Runtime.getRuntime().exec(RootTools.customShell);
RootTools.log("Using custom shell: " + RootTools.customShell);
}
if (null != executer.result) {
executer.result.setProcess(executer.process);
}
}
os = new DataOutputStream(executer.process.getOutputStream());
osRes = new InputStreamReader(executer.process.getInputStream());
osErr = new InputStreamReader(executer.process.getErrorStream());
BufferedReader reader = new BufferedReader(osRes);
BufferedReader reader_error = new BufferedReader(osErr);
List<String> response = null;
if (null == executer.result) {
response = new LinkedList<String>();
}
try {
// Doing Stuff ;)
for (String single : commands) {
RootTools.log("Shell command: " + single);
os.writeBytes(single + "\n");
os.flush();
Thread.sleep(sleepTime);
}
os.writeBytes("exit \n");
os.flush();
String line = reader.readLine();
String line_error = reader_error.readLine();
while (line != null) {
if (null == executer.result) {
response.add(line);
} else {
executer.result.process(line);
}
RootTools.log("input stream: " + line);
line = reader.readLine();
}
RootTools.log("Done reading input stream");
while (line_error != null) {
if (null == executer.result) {
response.add(line_error);
} else {
executer.result.processError(line_error);
}
RootTools.log("error stream: " + line_error);
line_error = reader_error.readLine();
}
RootTools.log("Done reading error stream");
}
catch (Exception ex)
{
if (RootTools.debugMode) {
RootTools.log("Error: " + ex.getMessage());
}
if (null != executer.result)
{
executer.result.onFailure(ex);
}
} finally {
RootTools.log("In finally block");
if (executer.process != null) {
RootTools.log("Getting Exit");
finalResponse = response;
exit = -1;
exit = executer.process.waitFor();
RootTools.log("Exit done...");
RootTools.lastExitCode = exit;
if (null != executer.result) {
executer.result.onComplete(exit);
} else {
response.add(Integer.toString(exit));
}
}
}
}
catch (InterruptedException ignore)
{
return;
}
catch (Exception e) {
if (RootTools.debugMode) {
e.printStackTrace();
RootTools.log("Error: " + e.getMessage());
}
} finally {
try {
if (os != null) {
os.writeBytes("exit \n");
os.flush();
os.close();
os = null;
}
if (osRes != null) {
osRes.close();
osRes = null;
}
if (osErr != null) {
osErr.close();
osErr = null;
}
} catch (Exception ignore) {}
executer.closeShell();
}
}
}
public void closeShell()
{
if (this.process != null)
{
try {
//if this fails, ignore it and dont crash.
this.process.destroy();
} catch (Exception ignore) {}
this.process = null;
}
if (this.result != null)
{
this.result = null;
}
}
}