From 0c8cd90f4e0bcd1d6bc8d70b5cfd3f1e0a47b752 Mon Sep 17 00:00:00 2001 From: Fredrik Fornwall Date: Sun, 20 Nov 2016 16:43:27 +0100 Subject: [PATCH] Use $PREFIX/bin/sh for script file without shebang Also try to handle #!(/usr)/bin/foo shebangs. --- .../java/com/termux/app/BackgroundJob.java | 84 +++++++++++++++---- 1 file changed, 68 insertions(+), 16 deletions(-) diff --git a/app/src/main/java/com/termux/app/BackgroundJob.java b/app/src/main/java/com/termux/app/BackgroundJob.java index fd54b5bc..956c2c8d 100644 --- a/app/src/main/java/com/termux/app/BackgroundJob.java +++ b/app/src/main/java/com/termux/app/BackgroundJob.java @@ -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); - f.setAccessible(false); + try { + return f.getInt(p); + } finally { + f.setAccessible(false); + } } catch (Throwable e) { - pid = -1; + return -1; } - return pid; + } + + 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 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()]); } }