Use $PREFIX/bin/sh for script file without shebang

Also try to handle #!(/usr)/bin/foo shebangs.
This commit is contained in:
Fredrik Fornwall
2016-11-20 16:43:27 +01:00
parent e1ea68913f
commit 0c8cd90f4e

View File

@@ -4,12 +4,15 @@ import android.util.Log;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.lang.reflect.Field;
import java.nio.charset.StandardCharsets;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
/**
* A background job launched by Termux.
@@ -24,16 +27,7 @@ public final class BackgroundJob {
String[] env = buildEnvironment(false, cwd);
if (cwd == null) cwd = TermuxService.HOME_PATH;
String[] modifiedArgs;
if (args == null) {
modifiedArgs = new String[]{fileToExecute};
} else {
modifiedArgs = new String[args.length + 1];
modifiedArgs[0] = fileToExecute;
System.arraycopy(args, 0, modifiedArgs, 1, args.length);
}
final String[] progArray = modifiedArgs;
final String[] progArray = setupProcessArgs(fileToExecute, args);
final String processDescription = Arrays.toString(progArray);
Process process;
@@ -45,6 +39,7 @@ public final class BackgroundJob {
Log.e(LOG_TAG, "Failed running background job: " + processDescription, e);
return;
}
mProcess = process;
final int pid = getPid(mProcess);
@@ -126,17 +121,74 @@ public final class BackgroundJob {
}
public static int getPid(Process p) {
int pid = -1;
try {
Field f = p.getClass().getDeclaredField("pid");
f.setAccessible(true);
pid = f.getInt(p);
try {
return f.getInt(p);
} finally {
f.setAccessible(false);
} catch (Throwable e) {
pid = -1;
}
return pid;
} catch (Throwable e) {
return -1;
}
}
static String[] setupProcessArgs(String fileToExecute, String[] args) {
// The file to execute may either be:
// - An elf file, in which we execute it directly.
// - A script file without shebang, which we execute with our standard shell $PREFIX/bin/sh instead of the
// system /system/bin/sh. The system shell may vary and may not work at all due to LD_LIBRARY_PATH.
// - A file with shebang, which we try to handle with e.g. /bin/foo -> $PREFIX/bin/foo.
String interpreter = null;
try {
File file = new File(fileToExecute);
try (FileInputStream in = new FileInputStream(file)) {
byte[] buffer = new byte[256];
int bytesRead = in.read(buffer);
if (bytesRead > 4) {
if (buffer[0] == 0x7F && buffer[1] == 'E' && buffer[2] == 'L' && buffer[3] == 'F') {
// Elf file, do nothing.
} else if (buffer[0] == '#' && buffer[1] == '!') {
// Try to parse shebang.
StringBuilder builder = new StringBuilder();
for (int i = 2; i < bytesRead; i++) {
char c = (char) buffer[i];
if (c == ' ' || c == '\n') {
if (builder.length() == 0) {
// Skip whitespace after shebang.
continue;
} else {
// End of shebang.
String executable = builder.toString();
if (executable.startsWith("/usr") || executable.startsWith("/bin")) {
String[] parts = executable.split("/");
String binary = parts[parts.length - 1];
interpreter = TermuxService.PREFIX_PATH + "/bin/" + binary;
}
break;
}
} else {
builder.append(c);
}
}
} else {
// No shebang and no ELF, use standard shell.
interpreter = TermuxService.PREFIX_PATH + "/bin/sh";
}
}
}
} catch (IOException e) {
// Ignore.
}
List<String> result = new ArrayList<>();
if (interpreter != null) result.add(interpreter);
result.add(fileToExecute);
if (args != null) {
for (String arg : args) result.add(arg);
}
return result.toArray(new String[result.size()]);
}
}