package org.jboss.as.process; import org.jboss.as.process.logging.ProcessLogger; import org.jboss.as.process.protocol.StreamUtils; import java.io.BufferedReader; import java.io.File; import java.io.IOException; import java.io.InputStreamReader; import java.nio.charset.StandardCharsets; import java.util.ArrayList; import java.util.List; import org.wildfly.security.manager.WildFlySecurityManager; /** * Process utilities to kill a process. */ abstract class ProcessUtils { private static final ProcessUtils processUtils; private static final String modulesJar = "jboss-modules.jar"; static { if (File.pathSeparatorChar == ':'){ processUtils = new UnixProcessUtils(); } else { processUtils = new WindowsProcessUtils(); } } /** * Try to kill a given process. * * @param processName the process name * @return {@code true} if the command succeeded, {@code false} otherwise */ static boolean killProcess(final String processName) { int pid; try { pid = processUtils.resolveProcessId(processName); if(pid > 0) { try { Runtime.getRuntime().exec(processUtils.getKillCommand(pid)); return true; } catch (Throwable t) { ProcessLogger.ROOT_LOGGER.debugf(t, "failed to kill process '%s' with pid '%s'", processName, pid); } } } catch (Throwable t) { ProcessLogger.ROOT_LOGGER.debugf(t, "failed to resolve pid of process '%s'", processName); } return false; } /** * Resolve the java home. * * @return the java home */ protected String getJavaHome() { return WildFlySecurityManager.getPropertyPrivileged("java.home", "."); } /** * Get the jps command. * * @return the jps command, {@code null} if not found */ abstract String getJpsCommand(); /** * Get the kill command. * * @param processId the process id to kill * @return the kill command */ abstract String getKillCommand(int processId); /** * Iterate through all java processes and try to find the one matching to the given process id. * This will return the resolved process-id or {@code -1} if not resolvable. * * @param processName the process name * @return the process id * @throws IOException */ private int resolveProcessId(final String processName) throws IOException { final String jpsCommand = getJpsCommand(); if(jpsCommand == null) { ProcessLogger.ROOT_LOGGER.debugf("jps command not found'"); return -1; } final Process p = Runtime.getRuntime().exec(jpsCommand); final List<String> processes = new ArrayList<>(); final BufferedReader input = new BufferedReader(new InputStreamReader(p.getInputStream(), StandardCharsets.UTF_8)); try { String line; // See if the process contains "jboss-modules.jar" and "-D[Server:server-one]" final String process = "-D[" + processName + "]"; while ((line = input.readLine()) != null) { if (line.contains(modulesJar) && line.contains(process)){ processes.add(line); } } } finally { StreamUtils.safeClose(input); } if(processes.size() == 1) { final String proc = processes.get(0); final int i = proc.indexOf(' '); return Integer.parseInt(proc.substring(0, i)); } if(processes.isEmpty()) { ProcessLogger.ROOT_LOGGER.debugf("process not found '%s'", processName); } else { ProcessLogger.ROOT_LOGGER.debugf("ambiguous result. multiple processes found for '%s'", processName); } return -1; } private static class UnixProcessUtils extends ProcessUtils { @Override String getJpsCommand() { final File jreHome = new File(getJavaHome()); File jpsExe = new File(jreHome, "bin/jps"); if (!jpsExe.exists()) { jpsExe = new File(jreHome, "../bin/jps"); } if(jpsExe.exists()) { return String.format("%s -vl", jpsExe.getAbsolutePath()); } return null; } @Override String getKillCommand(int process) { return "kill -9 " + process; } } private static class WindowsProcessUtils extends ProcessUtils { @Override String getJpsCommand() { final File jreHome = new File(getJavaHome()); File jpsExe = new File(jreHome, "bin/jps.exe"); if (!jpsExe.exists()) { jpsExe = new File(jreHome, "../bin/jps.exe"); } if(jpsExe.exists()) { return String.format("%s -vl", jpsExe.getAbsolutePath()); } return null; } @Override String getKillCommand(int process) { return "taskkill /f /pid " + process; } } }