package de.fun2code.android.piratebox.util;
import java.io.BufferedInputStream;
import java.io.BufferedReader;
import java.io.DataInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.io.OutputStream;
import android.util.Log;
import de.fun2code.android.pawserver.util.Utils;
import de.fun2code.android.piratebox.Constants;
/**
* Support class to execute shell commands
*
* @author joschi
*
*/
public class ShellUtil {
public static String SH_BIN = "sh";
public static String SU_BIN = "su";
public static String MOUNT_BIN = "mount";
public static String SYSTEM_MOUNT_POINT = "/system";
/**
* Execute shell command with normal shell
*
* @param commands command to execute
* @return {@code true} if the operation succeeded
*/
public boolean execShell(String[] commands) {
return execShell(commands , false);
}
/**
* Executes commands by using the root shell (su)
*
* @param commands command to execute
* @return {@code true} if the operation succeeded
*/
public boolean execRootShell(String[] commands) {
return execShell(commands , true);
}
/**
* Executes shell command with standard or su shell
*
* @param commands commands to execute
* @param root {@code true} if root shell should be used otherwise {@code false}
* @return {@code true} if the operation succeeded
*/
private boolean execShell(String[] commands, boolean root) {
try {
String shellCmd = root ? SU_BIN + " -c sh" : SH_BIN;
Process sh = Runtime.getRuntime().exec(shellCmd);
OutputStream os = sh.getOutputStream();
for (String cmd : commands) {
os.write((cmd + "\n").getBytes());
}
os.write(("exit\n").getBytes());
os.flush();
sh.waitFor();
return true;
} catch (Exception e) {
e.printStackTrace();
return false;
}
}
/**
* Checks if a command is available
*
* @param command command to check
* @return {@code true} if command is available, otherwise {@code false}
*/
public boolean isCommandAvailable(String command) {
try {
Process proc = Runtime.getRuntime().exec(command);
proc.destroy();
return true;
} catch (Exception e) {
return false;
}
}
/**
* Returns the PID of a process
*
* @param processName process to retrieve PID from
* @return PID or -1 if process was not found
*/
public int getProcessPid(String processName) {
try {
int pid = -1;
Process ps = Runtime.getRuntime().exec("ps");
InputStream is = ps.getInputStream();
BufferedReader stdout = new BufferedReader(
new InputStreamReader(is));
int lines = 0;
int pidCol = 0;
int procCol = 4;
String line;
while ((line = stdout.readLine()) != null) {
lines++;
/* There seem to be two versions of ps commands */
if (lines == 1) {
if (line.startsWith("USER")) {
pidCol = 1;
procCol = 8;
}
continue;
}
line = line.replaceAll("^\\s+", "");
String[] processInfo = line.split("\\s+");
if (processInfo[procCol].equals(processName)) {
pid = Integer.parseInt(processInfo[pidCol]);
break;
}
}
is.close();
return pid;
} catch (Exception e) {
return -1;
}
}
/**
* Kill process with a given name
*
* @param processName process to kill
* @return PID of killed process, if process could not be killed -1
*/
public int killProcessByName(String processName) {
int pid = getProcessPid(processName);
if (pid != -1) {
String[] killCmd = new String[] { "kill " + pid,
};
execRootShell(killCmd);
return pid;
} else {
return -1;
}
}
/**
* Remounts /system ({@code SYSTEM_MOUNT_POINT})
*
* @param options option to use, nomally {@code rw} of {@code ro}
*/
public void remountSystem(String options) {
/*
* Try to get device name, if not found try without.
* This might fix issue #5.
*/
String device = getMountDeviceName(SYSTEM_MOUNT_POINT);
device = device != null ? device : "";
Log.i(Constants.TAG, "Device for " + SYSTEM_MOUNT_POINT + ": " + device);
String[] cmd = new String[] { "mount -o " + options + ",remount " + device + " " + SYSTEM_MOUNT_POINT};
execRootShell(cmd);
}
/**
* Wait for a process with the given process name
*
* @param processName name of process to wait for
* @param timeout timeout in millis
* @return returns the process id or {@code -1} if no process was found
*/
public int waitForProcess(String processName, long timeout) {
long until = System.currentTimeMillis() + timeout;
int id;
while((id = getProcessPid(processName)) == -1 && System.currentTimeMillis() < until) {
try {
Thread.sleep(100);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
return id;
}
/**
* Returns the device for the given file system mount point
*
* @param fileSystem file system to retrieve device
* @return name of device, may be {@code null} if device was
* not found
*/
public String getMountDeviceName(String fileSystem) {
String device = null;
BufferedReader bis = null;
try {
Process proc = Runtime.getRuntime().exec(MOUNT_BIN);
//BufferedInputStream bis = new BufferedInputStream(new InputStreamReader(proc.getInputStream()));
InputStreamReader isr = new InputStreamReader(proc.getInputStream());
bis = new BufferedReader(isr);
String line;
while( (line = bis.readLine()) != null ) {
if(line.matches("^/dev/.*?\\s+" + fileSystem + "\\s+.*$")) {
device = line.split("\\s+")[0];
break;
}
}
}
catch(Exception e) {
e.printStackTrace();
device = null;
}
finally {
if(bis != null) {
try {
bis.close();
} catch (IOException e) {
e.printStackTrace();
}
}
}
return device;
}
}