Autopsy  4.12.0
Graphical digital forensics platform for The Sleuth Kit and other tools.
ExecUtil.java
Go to the documentation of this file.
1 /*
2  * Autopsy Forensic Browser
3  *
4  * Copyright 2013-2019 Basis Technology Corp.
5  * Contact: carrier <at> sleuthkit <dot> org
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  * http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  */
19 package org.sleuthkit.autopsy.coreutils;
20 
21 import com.sun.javafx.PlatformUtil;
22 import java.io.BufferedReader;
23 import java.io.IOException;
24 import java.io.InputStream;
25 import java.io.InputStreamReader;
26 import java.io.Writer;
27 import java.util.Date;
28 import java.util.List;
29 import java.util.concurrent.TimeUnit;
30 import java.util.logging.Level;
32 
37 public final class ExecUtil {
38 
39  private static final long DEFAULT_TIMEOUT = 5;
40  private static final TimeUnit DEFAULT_TIMEOUT_UNITS = TimeUnit.SECONDS;
41 
50  public interface ProcessTerminator {
51 
58  boolean shouldTerminateProcess();
59  }
60 
65  public static class InterruptedThreadProcessTerminator implements ProcessTerminator {
66 
67  @Override
68  public boolean shouldTerminateProcess() {
69  return Thread.currentThread().isInterrupted();
70  }
71  }
72 
77  public static class TimedProcessTerminator implements ProcessTerminator {
78 
79  private final long startTimeInSeconds;
80  private final long maxRunTimeInSeconds;
81 
88  public TimedProcessTerminator(long maxRunTimeInSeconds) {
89  this.maxRunTimeInSeconds = maxRunTimeInSeconds;
90  this.startTimeInSeconds = (new Date().getTime()) / 1000;
91  }
92 
102  // user specified time out
103  this.maxRunTimeInSeconds = UserPreferences.getProcessTimeOutHrs() * 3600;
104  } else {
105  // never time out
106  this.maxRunTimeInSeconds = Long.MAX_VALUE;
107  }
108  this.startTimeInSeconds = (new Date().getTime()) / 1000;
109  }
110 
111  @Override
112  public boolean shouldTerminateProcess() {
113  long currentTimeInSeconds = (new Date().getTime()) / 1000;
114  return (currentTimeInSeconds - this.startTimeInSeconds) > this.maxRunTimeInSeconds;
115  }
116  }
117 
130  public static int execute(ProcessBuilder processBuilder) throws SecurityException, IOException {
131  return ExecUtil.execute(processBuilder, 30, TimeUnit.DAYS, new ProcessTerminator() {
132  @Override
133  public boolean shouldTerminateProcess() {
134  return false;
135  }
136  });
137  }
138 
152  public static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator) throws SecurityException, IOException {
153  return ExecUtil.execute(processBuilder, ExecUtil.DEFAULT_TIMEOUT, ExecUtil.DEFAULT_TIMEOUT_UNITS, terminator);
154  }
155 
171  public static int execute(ProcessBuilder processBuilder, long timeOut, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException {
172  Process process = processBuilder.start();
173  try {
174  do {
175  process.waitFor(timeOut, units);
176  if (process.isAlive() && terminator.shouldTerminateProcess()) {
177  killProcess(process);
178  try {
179  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
180  } catch (InterruptedException exx) {
181  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, String.format("Wait for process termination following killProcess was interrupted for command %s", processBuilder.command().get(0)));
182  }
183  }
184  } while (process.isAlive());
185  } catch (InterruptedException ex) {
186  if (process.isAlive()) {
187  killProcess(process);
188  }
189  try {
190  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
191  } catch (InterruptedException exx) {
192  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, String.format("Wait for process termination following killProcess was interrupted for command %s", processBuilder.command().get(0)));
193  }
194  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, "Thread interrupted while running {0}", processBuilder.command().get(0)); // NON-NLS
195  Thread.currentThread().interrupt();
196  }
197  return process.exitValue();
198  }
199 
215  public static int waitForTermination(String command, Process process, ProcessTerminator terminator) throws SecurityException, IOException {
216  return ExecUtil.waitForTermination(command, process, ExecUtil.DEFAULT_TIMEOUT, ExecUtil.DEFAULT_TIMEOUT_UNITS, terminator);
217  }
218 
219  private static int waitForTermination(String command, Process process, long timeOut, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException {
220  try {
221  do {
222  process.waitFor(timeOut, units);
223  if (process.isAlive() && terminator.shouldTerminateProcess()) {
224  killProcess(process);
225  try {
226  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
227  } catch (InterruptedException exx) {
228  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, String.format("Wait for process termination following killProcess was interrupted for command %s", command));
229  }
230  }
231  } while (process.isAlive());
232  } catch (InterruptedException ex) {
233  if (process.isAlive()) {
234  killProcess(process);
235  }
236  try {
237  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
238  } catch (InterruptedException exx) {
239  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, String.format("Wait for process termination following killProcess was interrupted for command %s", command));
240  }
241  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, "Thread interrupted while running {0}", command); // NON-NLS
242  Thread.currentThread().interrupt();
243  }
244  return process.exitValue();
245  }
246 
252  public static void killProcess(Process process) {
253  if (process == null) {
254  return;
255  }
256 
257  try {
258  if (PlatformUtil.isWindows()) {
259  Win32Process parentProcess = new Win32Process(process);
260  List<Win32Process> children = parentProcess.getChildren();
261 
262  children.stream().forEach((child) -> {
263  child.terminate();
264  });
265  parentProcess.terminate();
266  } else {
267  process.destroyForcibly();
268  }
269  } catch (Exception ex) {
270  logger.log(Level.WARNING, "Error occurred when attempting to kill process: {0}", ex.getMessage()); // NON-NLS
271  }
272  }
273 
274  private static final Logger logger = Logger.getLogger(ExecUtil.class.getName());
275  private Process proc = null;
279  private int exitValue = -100;
280 
291  @Deprecated
292  public synchronized String execute(final String aCommand, final String... params) throws IOException, InterruptedException {
293  // build command array
294  String[] arrayCommand = new String[params.length + 1];
295  arrayCommand[0] = aCommand;
296 
297  StringBuilder arrayCommandToLog = new StringBuilder();
298  arrayCommandToLog.append(aCommand).append(" ");
299 
300  for (int i = 1; i < arrayCommand.length; i++) {
301  arrayCommand[i] = params[i - 1];
302  arrayCommandToLog.append(arrayCommand[i]).append(" ");
303  }
304 
305  final Runtime rt = Runtime.getRuntime();
306  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
307 
308  proc = rt.exec(arrayCommand);
309 
310  //stderr redirect
311  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
312  errorStringRedirect.start();
313 
314  //stdout redirect
315  outputStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getInputStream(), "OUTPUT"); //NON-NLS
316  outputStringRedirect.start();
317 
318  //wait for process to complete and capture error core
319  this.exitValue = proc.waitFor();
320 
321  // wait for output redirectors to finish writing / reading
322  outputStringRedirect.join();
323  errorStringRedirect.join();
324 
325  return outputStringRedirect.getOutput();
326  }
327 
338  @Deprecated
339  public synchronized void execute(final Writer stdoutWriter, final String aCommand, final String... params) throws IOException, InterruptedException {
340 
341  // build command array
342  String[] arrayCommand = new String[params.length + 1];
343  arrayCommand[0] = aCommand;
344 
345  StringBuilder arrayCommandToLog = new StringBuilder();
346  arrayCommandToLog.append(aCommand).append(" ");
347 
348  for (int i = 1; i < arrayCommand.length; i++) {
349  arrayCommand[i] = params[i - 1];
350  arrayCommandToLog.append(arrayCommand[i]).append(" ");
351  }
352 
353  final Runtime rt = Runtime.getRuntime();
354  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
355 
356  proc = rt.exec(arrayCommand);
357 
358  //stderr redirect
359  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
360  errorStringRedirect.start();
361 
362  //stdout redirect
363  outputWriterRedirect = new ExecUtil.StreamToWriterRedirect(proc.getInputStream(), stdoutWriter);
364  outputWriterRedirect.start();
365 
366  //wait for process to complete and capture error core
367  this.exitValue = proc.waitFor();
368  logger.log(Level.INFO, "{0} exit value: {1}", new Object[]{aCommand, exitValue}); //NON-NLS
369 
370  // wait for them to finish writing / reading
371  outputWriterRedirect.join();
372  errorStringRedirect.join();
373 
374  //gc process with its streams
375  //proc = null;
376  }
377 
381  @Deprecated
382  public synchronized void stop() {
383 
384  if (errorStringRedirect != null) {
385  errorStringRedirect.stopRun();
386  errorStringRedirect = null;
387  }
388 
389  if (outputStringRedirect != null) {
390  outputStringRedirect.stopRun();
391  outputStringRedirect = null;
392  }
393 
394  if (outputWriterRedirect != null) {
395  outputWriterRedirect.stopRun();
396  outputWriterRedirect = null;
397  }
398 
399  if (proc != null) {
400  proc.destroy();
401  proc = null;
402  }
403  }
404 
411  @Deprecated
412  synchronized public int getExitValue() {
413  return this.exitValue;
414  }
415 
422  private static class StreamToStringRedirect extends Thread {
423 
424  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
425  private final InputStream is;
426  private final StringBuffer output = new StringBuffer();
427  private volatile boolean doRun = false;
428 
429  StreamToStringRedirect(final InputStream anIs, final String aType) {
430  this.is = anIs;
431  this.doRun = true;
432  }
433 
440  @Override
441  public final void run() {
442  final String SEP = System.getProperty("line.separator");
443  InputStreamReader isr;
444  BufferedReader br = null;
445  try {
446  isr = new InputStreamReader(this.is);
447  br = new BufferedReader(isr);
448  String line = null;
449  while (doRun && (line = br.readLine()) != null) {
450  this.output.append(line).append(SEP);
451  }
452  } catch (final IOException ex) {
453  logger.log(Level.WARNING, "Error redirecting stream to string buffer", ex); //NON-NLS
454  } finally {
455  if (br != null) {
456  try {
457  br.close();
458  } catch (IOException ex) {
459  logger.log(Level.SEVERE, "Error closing stream reader", ex); //NON-NLS
460  }
461  }
462  }
463  }
464 
469  public void stopRun() {
470  doRun = false;
471  }
472 
479  public final String getOutput() {
480  return this.output.toString();
481  }
482  }
483 
492  private static class StreamToWriterRedirect extends Thread {
493 
494  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
495  private final InputStream is;
496  private volatile boolean doRun = false;
497  private Writer writer = null;
498 
499  StreamToWriterRedirect(final InputStream anIs, final Writer writer) {
500  this.is = anIs;
501  this.writer = writer;
502  this.doRun = true;
503  }
504 
511  @Override
512  public final void run() {
513  final String SEP = System.getProperty("line.separator");
514  InputStreamReader isr;
515  BufferedReader br = null;
516  try {
517  isr = new InputStreamReader(this.is);
518  br = new BufferedReader(isr);
519  String line = null;
520  while (doRun && (line = br.readLine()) != null) {
521  writer.append(line).append(SEP);
522  }
523  } catch (final IOException ex) {
524  logger.log(Level.SEVERE, "Error reading output and writing to file writer", ex); //NON-NLS
525  } finally {
526  try {
527  if (doRun) {
528  writer.flush();
529  }
530  if (br != null) {
531  br.close();
532  }
533 
534  } catch (IOException ex) {
535  logger.log(Level.SEVERE, "Error flushing file writer", ex); //NON-NLS
536  }
537  }
538  }
539 
544  public void stopRun() {
545  doRun = false;
546  }
547  }
548 }
ExecUtil.StreamToStringRedirect errorStringRedirect
Definition: ExecUtil.java:276
static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator)
Definition: ExecUtil.java:152
static int waitForTermination(String command, Process process, long timeOut, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:219
ExecUtil.StreamToWriterRedirect outputWriterRedirect
Definition: ExecUtil.java:278
static int execute(ProcessBuilder processBuilder)
Definition: ExecUtil.java:130
static final TimeUnit DEFAULT_TIMEOUT_UNITS
Definition: ExecUtil.java:40
synchronized void execute(final Writer stdoutWriter, final String aCommand, final String...params)
Definition: ExecUtil.java:339
static int waitForTermination(String command, Process process, ProcessTerminator terminator)
Definition: ExecUtil.java:215
ExecUtil.StreamToStringRedirect outputStringRedirect
Definition: ExecUtil.java:277
static void killProcess(Process process)
Definition: ExecUtil.java:252
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static int execute(ProcessBuilder processBuilder, long timeOut, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:171
synchronized String execute(final String aCommand, final String...params)
Definition: ExecUtil.java:292

Copyright © 2012-2018 Basis Technology. Generated on: Wed Sep 18 2019
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.