/* (C) 2012 Pragmatic Software This Source Code Form is subject to the terms of the Mozilla Public License, v. 2.0. If a copy of the MPL was not distributed with this file, You can obtain one at http://mozilla.org/MPL/2.0/ */ package com.googlecode.networklog; import java.util.ArrayList; import java.util.Iterator; import java.util.List; import android.util.Log; public class InteractiveShell { ShellCommand command; String shell; String tag; int exitval; public static final int IGNORE_OUTPUT = (1 << 0); public static final int BACKGROUND = (1 << 1); public InteractiveShell() { this("sh", "InteractiveShell"); } public InteractiveShell(String shell) { this(shell, "InteractiveShell"); } public InteractiveShell(String shell, String tag) { MyLog.d("Creating new InteractiveShell [" + tag + "]"); this.shell = shell; this.tag = tag; } public ShellCommand getShell() { return command; } public void start() { MyLog.d("Starting InteractiveShell [" + tag + "]"); command = new ShellCommand(new String[] { shell }, tag); command.start(false); } public int close() { MyLog.d("Closing InteractiveShell [" + tag + "]"); if(command == null) { MyLog.d("No active ShellCommand for InteractiveShell [" + tag + "]"); return -1; } command.sendCommand("exit\n"); return command.waitForExit(); } public boolean hasError() { return command.hasError(); } public String getError(boolean clearError) { return command.getError(clearError); } public boolean checkForExit() { if(command.checkForExit()) { exitval = command.exitval; return true; } else { return false; } } public boolean checkForExit(boolean ignoreStdout) { if(command.checkForExit(ignoreStdout)) { exitval = command.exitval; return true; } else { return false; } } public int waitForExit() { exitval = command.waitForExit(); return exitval; } public boolean sendCommand(String cmd) { return sendCommand(cmd, 0); } public boolean sendCommand(String cmd, int flags) { try { if(command == null || !command.sendCommand(cmd)) { Log.w("NetworkLog", "[" + tag + "] shell not running, starting new shell"); getError(true); // clear the error start(); if(!command.sendCommand(cmd)) { Log.e("NetworkLog", "[" + tag + "] Unable to execute command [" + cmd.trim() + "]: " + getError(false)); return false; } } if((flags & BACKGROUND) != BACKGROUND) { command.sendCommand("echo;echo ..EOF..$?\n"); } if((flags & IGNORE_OUTPUT) == IGNORE_OUTPUT) { waitForCommandExit(null); } return true; } catch (Exception e) { e.printStackTrace(); return false; } } public int waitForCommandExit(List<String> output) { String line; while((line = readLine()) != null) { if(output != null) { output.add(line); } else { if(MyLog.enabled) { MyLog.d("Discarding output: [" + line.trim() + "]"); } } } return exitval; } public Integer peekAtCommandExitValue() { return peekAtCommandExitValue(Integer.MAX_VALUE); } public Integer peekAtCommandExitValue(int maxLines) { Iterator<String> iterator = command.stdout.buffer.iterator(); int lines = 0; while(iterator.hasNext() && lines < maxLines) { String line = iterator.next(); lines++; if(line.startsWith("..EOF..")) { try { return Integer.valueOf(line.substring(7, line.length())); } catch (Exception e) { Log.w("NetworkLog", "PeekAtCommandExitValue [" + tag + "] encountered EOF without valid exit value [" + line.trim() + "]"); continue; } } } return null; } public boolean stdoutAvailable() { return command.stdout.lineAvailable(); } public String readLine() { String line = command.stdout.readLine(); if(line == null) { return null; } else if(line.startsWith("..EOF..")) { exitval = Integer.parseInt(line.substring(7, line.length())); if(MyLog.enabled) { MyLog.d("InteractiveShell [" + tag + "] command exited " + exitval); } return null; } else { return line; } } }