/* * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package com.addthis.hydra.minion; import java.io.File; import java.io.IOException; import java.util.Scanner; import com.addthis.basis.util.LessBytes; import com.addthis.basis.util.LessFiles; import com.addthis.basis.util.SimpleExec; import org.slf4j.Logger; import org.slf4j.LoggerFactory; final class ProcessUtils { private static final Logger log = LoggerFactory.getLogger(ProcessUtils.class); private ProcessUtils() {} public static int shell(String cmd, File directory) { try { File tmp = File.createTempFile(".minion", "shell", directory); try { LessFiles.write(tmp, LessBytes.toBytes("#!/bin/sh\n" + cmd + "\n"), false); Process process = Runtime.getRuntime().exec("sh " + tmp); int exit = waitForUninterruptibly(process); log.debug("[shell] ({}) exited with {}", cmd, exit); return exit; } finally { tmp.delete(); } } catch (Exception ex) { log.warn("", ex); } return -1; } public static int waitForUninterruptibly(Process toWaitFor) { boolean interrupted = false; try { while (true) { try { return toWaitFor.waitFor(); } catch (InterruptedException ignored) { interrupted = true; } } } finally { if (interrupted) { Thread.currentThread().interrupt(); } } } static String getTaskBaseDir(String baseDir, String id, int node) { return new StringBuilder().append(baseDir).append("/").append(id).append("/").append(node).toString(); } public static Integer getPID(File pidFile) { try { if (pidFile != null) { log.debug("[getpid] {} --> {}", pidFile, pidFile.exists()); } else { log.debug("[getpid] pidFile is null"); } if ((pidFile != null) && pidFile.exists()) { return Integer.parseInt(LessBytes.toString(LessFiles.read(pidFile)).trim()); } else { return null; } } catch (Exception ex) { log.warn("", ex); return null; } } private static String execCommandReturnStdOut(String cmd) throws InterruptedException, IOException { SimpleExec command = new SimpleExec(cmd).join(); return command.stdoutString(); } // Sorry Illumos port... public static String getCmdLine(int pid) { try { String cmd; if (MacUtils.useMacFriendlyPSCommands) { cmd = execCommandReturnStdOut("ps -f " + pid); } else { File cmdFile = new File("/proc/" + pid + "/cmdline"); cmd = LessBytes.toString(LessFiles.read(cmdFile)).trim().replace('\0', ' '); } log.warn("found cmd {} for pid: {}", cmd, pid); return cmd; } catch (Exception ex) { log.warn("error searching for pidfile for pid: {}", pid, ex); return null; } } static boolean activeProcessExistsWithPid(Integer pid, File directory) { return shell("ps " + pid, directory) == 0; } static Integer findActiveRsync(String id, int node) { return findActiveProcessWithTokens(new String[]{id + "/" + node + "/", Minion.rsyncCommand}, new String[]{"server"}); } private static Integer findActiveProcessWithTokens(String[] requireTokens, String[] omitTokens) { StringBuilder command = new StringBuilder("ps ax | grep -v grep"); for (String requireToken : requireTokens) { command.append("| grep " + requireToken); } for (String excludeToken : omitTokens) { command.append("| grep -v " + excludeToken); } command.append("| cut -c -5"); try { SimpleExec exec = new SimpleExec(new String[]{"/bin/sh", "-c", command.toString()}).join(); if (exec.exitCode() == 0) { return new Scanner(exec.stdoutString()).nextInt(); } else { return null; } } catch (Exception e) { // No PID found return null; } } }