From 9cb499c4ec296b82a318dac6fe1fbccfc4e1ca24 Mon Sep 17 00:00:00 2001 From: ME1312 Date: Fri, 4 Jan 2019 18:32:01 -0500 Subject: [PATCH] Properly terminate child processes on windows This applies to both SubCreator and SubServers. Only works on Java 9+ because Java 8 lacks a way to get the PIDs. --- .../ME1312/SubServers/Bungee/Host/Executable.java | 6 +++--- .../Bungee/Host/Internal/InternalSubCreator.java | 15 +++++++++++++-- .../Bungee/Host/Internal/InternalSubServer.java | 6 ++++++ .../SubServers/Host/Executable/Executable.java | 6 +++--- .../SubServers/Host/Executable/SubCreator.java | 15 +++++++++++++-- .../SubServers/Host/Executable/SubServer.java | 5 +++++ 6 files changed, 43 insertions(+), 10 deletions(-) diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java index 538de737..348bb79e 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Executable.java @@ -17,13 +17,13 @@ public class Executable { */ public static String[] parse(String gitbash, String exec) { String[] cmd; - if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) { + if (System.getProperty("os.name").toLowerCase().startsWith("windows")) { if (gitbash != null && (exec.startsWith("bash ") || exec.startsWith("sh "))) - exec = "\"" + gitbash + ((gitbash.endsWith(File.separator))?"":File.separator) + "bin" + File.separatorChar + "sh.exe\" -lic \"" + + exec = "\"" + gitbash + ((gitbash.endsWith(File.separator))?"":File.separator) + "bin" + File.separatorChar + "sh.exe\" -lc \"" + exec.replace("\\", "/\\").replace("\"", "\\\"").replace("^", "^^").replace("%", "^%").replace("&", "^&").replace("<", "^<").replace(">", "^>").replace("|", "^|") + "\""; cmd = new String[]{"cmd.exe", "/q", "/c", '"'+exec+'"'}; } else { - cmd = new String[]{"sh", "-lic", exec}; + cmd = new String[]{"sh", "-lc", exec}; } return cmd; } diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java index b13a519e..8a3c9edb 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubCreator.java @@ -128,7 +128,7 @@ public class InternalSubCreator extends SubCreator { String command = "bash \"" + template.getBuildOptions().getRawString("Shell-Location") + '\"'; for (String arg : args) command += ' ' + arg; - if (System.getProperty("os.name").toLowerCase().indexOf("win") < 0 && template.getBuildOptions().contains("Permission")) { + if (!System.getProperty("os.name").toLowerCase().startsWith("windows") && template.getBuildOptions().contains("Permission")) { try { Process process = Runtime.getRuntime().exec("chmod " + template.getBuildOptions().getRawString("Permission") + ' ' + template.getBuildOptions().getRawString("Shell-Location"), null, dir); Thread.sleep(500); @@ -347,9 +347,20 @@ public class InternalSubCreator extends SubCreator { @Override public void terminate(String name) { if (this.thread.keySet().contains(name.toLowerCase())) { + boolean success = false; + if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { + Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(this.thread.get(name.toLowerCase()).process))}); + terminator.waitFor(); + if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); + success = true; + } catch (Exception e) {} + if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive()) { this.thread.get(name.toLowerCase()).process.destroyForcibly(); - } else if (this.thread.get(name.toLowerCase()).isAlive()) { + success = true; + } + + if (!success && this.thread.get(name.toLowerCase()).isAlive()) { this.thread.get(name.toLowerCase()).interrupt(); this.thread.remove(name.toLowerCase()); } diff --git a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java index 1ae7852b..029daf2d 100644 --- a/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java +++ b/SubServers.Bungee/src/net/ME1312/SubServers/Bungee/Host/Internal/InternalSubServer.java @@ -15,6 +15,7 @@ import net.md_5.bungee.BungeeServerInfo; import java.io.*; import java.lang.reflect.Field; +import java.lang.reflect.Method; import java.util.ArrayList; import java.util.LinkedList; import java.util.List; @@ -220,6 +221,11 @@ public class InternalSubServer extends SubServerContainer { host.plugin.getPluginManager().callEvent(event); if (!event.isCancelled()) { allowrestart = false; + if (process != null && process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { + Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(process))}); + terminator.waitFor(); + if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); + } catch (Exception e) {} if (process != null && process.isAlive()) process.destroyForcibly(); return true; } else return false; diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java index a3350ed0..8675a574 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/Executable.java @@ -17,13 +17,13 @@ public class Executable { */ public static String[] parse(String gitbash, String exec) { String[] cmd; - if (System.getProperty("os.name").toLowerCase().indexOf("win") >= 0) { + if (System.getProperty("os.name").toLowerCase().startsWith("windows")) { if (gitbash != null && (exec.startsWith("bash ") || exec.startsWith("sh "))) - exec = "\"" + gitbash + ((gitbash.endsWith(File.separator))?"":File.separator) + "bin" + File.separatorChar + "sh.exe\" -lic \"" + + exec = "\"" + gitbash + ((gitbash.endsWith(File.separator))?"":File.separator) + "bin" + File.separatorChar + "sh.exe\" -lc \"" + exec.replace("\\", "/\\").replace("\"", "\\\"").replace("^", "^^").replace("%", "^%").replace("&", "^&").replace("<", "^<").replace(">", "^>").replace("|", "^|") + "\""; cmd = new String[]{"cmd.exe", "/q", "/c", '"'+exec+'"'}; } else { - cmd = new String[]{"sh", "-lic", exec}; + cmd = new String[]{"sh", "-lc", exec}; } return cmd; } diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java index 1f991155..b7e5cd25 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubCreator.java @@ -278,7 +278,7 @@ public class SubCreator { String command = "bash \"" + template.getBuildOptions().getRawString("Shell-Location") + '\"'; for (String arg : args) command += ' ' + arg; - if (System.getProperty("os.name").toLowerCase().indexOf("win") < 0 && template.getBuildOptions().contains("Permission")) { + if (!System.getProperty("os.name").toLowerCase().startsWith("windows") && template.getBuildOptions().contains("Permission")) { try { Process process = Runtime.getRuntime().exec("chmod " + template.getBuildOptions().getRawString("Permission") + ' ' + template.getBuildOptions().getRawString("Shell-Location"), null, dir); Thread.sleep(500); @@ -380,9 +380,20 @@ public class SubCreator { public void terminate(String name) { if (this.thread.keySet().contains(name.toLowerCase())) { + boolean success = false; + if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { + Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(this.thread.get(name.toLowerCase()).process))}); + terminator.waitFor(); + if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); + success = true; + } catch (Exception e) {} + if (this.thread.get(name.toLowerCase()).process != null && this.thread.get(name.toLowerCase()).process.isAlive()) { this.thread.get(name.toLowerCase()).process.destroyForcibly(); - } else if (this.thread.get(name.toLowerCase()).isAlive()) { + success = true; + } + + if (!success && this.thread.get(name.toLowerCase()).isAlive()) { this.thread.get(name.toLowerCase()).interrupt(); this.thread.remove(name.toLowerCase()); } diff --git a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java index 4f24ccba..61014040 100644 --- a/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java +++ b/SubServers.Host/src/net/ME1312/SubServers/Host/Executable/SubServer.java @@ -167,6 +167,11 @@ public class SubServer { */ public void terminate() { allowrestart = false; + if (process != null && process.isAlive() && System.getProperty("os.name").toLowerCase().startsWith("windows")) try { + Process terminator = Runtime.getRuntime().exec(new String[]{"taskkill", "/T", "/F", "/PID", Long.toString((long) Process.class.getDeclaredMethod("pid").invoke(process))}); + terminator.waitFor(); + if (terminator.exitValue() != 0) throw new IllegalStateException("taskkill exited with code " + terminator.exitValue()); + } catch (Exception e) {} if (process != null && process.isAlive()) process.destroyForcibly(); }