Autopsy  4.16.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-2020 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 Logger logger = Logger.getLogger(ExecUtil.class.getName());
40  private static final long DEFAULT_TERMINATION_CHECK_INTERVAL = 5;
41  private static final TimeUnit DEFAULT_TERMINATION_CHECK_INTERVAL_UNITS = TimeUnit.SECONDS;
42  private static final long MAX_WAIT_FOR_TERMINATION = 1;
43  private static final TimeUnit MAX_WAIT_FOR_TERMINATION_UNITS = TimeUnit.MINUTES;
44 
54  public interface ProcessTerminator {
55 
62  boolean shouldTerminateProcess();
63  }
64 
69  public static class InterruptedThreadProcessTerminator implements ProcessTerminator {
70 
71  @Override
72  public boolean shouldTerminateProcess() {
73  return Thread.currentThread().isInterrupted();
74  }
75  }
76 
81  public static class TimedProcessTerminator implements ProcessTerminator {
82 
83  private final long startTimeInSeconds;
84  private final Long maxRunTimeInSeconds;
85 
92  public TimedProcessTerminator(long maxRunTimeInSeconds) {
93  this.maxRunTimeInSeconds = maxRunTimeInSeconds;
94  this.startTimeInSeconds = (new Date().getTime()) / 1000;
95  }
96 
105  this.maxRunTimeInSeconds = (long) UserPreferences.getProcessTimeOutHrs() * 3600;
106  } else {
107  this.maxRunTimeInSeconds = null;
108  }
109  this.startTimeInSeconds = (new Date().getTime()) / 1000;
110  }
111 
112  @Override
113  public boolean shouldTerminateProcess() {
114  if (maxRunTimeInSeconds != null) {
115  long currentTimeInSeconds = (new Date().getTime()) / 1000;
116  return (currentTimeInSeconds - this.startTimeInSeconds) > this.maxRunTimeInSeconds;
117  } else {
118  return false;
119  }
120  }
121  }
122 
145  public static int execute(ProcessBuilder processBuilder) throws SecurityException, IOException {
146  return ExecUtil.execute(processBuilder, 30, TimeUnit.DAYS, new ProcessTerminator() {
147  @Override
148  public boolean shouldTerminateProcess() {
149  return false;
150  }
151  });
152  }
153 
176  public static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator) throws SecurityException, IOException {
178  }
179 
207  public static int execute(ProcessBuilder processBuilder, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException {
208  return waitForTermination(processBuilder.command().get(0), processBuilder.start(), terminationCheckInterval, units, terminator);
209  }
210 
237  public static int waitForTermination(String processName, Process process, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator) throws IOException {
238  try {
239  return waitForProcess(processName, process, terminationCheckInterval, units, terminator);
240  } catch (InterruptedException ex) {
241  /*
242  * Reset the interrupted flag and wrap the exception in an
243  * IOException for backwards compatibility.
244  */
245  Thread.currentThread().interrupt();
246  throw new IOException(String.format("Interrupted executing %s", processName), ex); //NON-NLS
247  }
248  }
249 
271  private static int waitForProcess(String processName, Process process, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator) throws IOException, InterruptedException {
272  do {
273  try {
274  process.waitFor(terminationCheckInterval, units);
275  } catch (InterruptedException ex) {
276  logger.log(Level.WARNING, String.format("Interrupted executing %s", processName), ex); //NON-NLS
277  Thread.currentThread().interrupt();
278  terminateProcess(processName, process);
279  /*
280  * Note that if the preceding call to terminateProcess() throws
281  * an IOException, the caller will get that exception instead of
282  * this InterruptedException, which is arguably preferable. If
283  * terminateProcess() does not throw an IOException, then its
284  * call to waitFor() will throw a fresh InterruptedException,
285  * which is fine.
286  */
287  throw ex;
288  }
289  if (process.isAlive() && terminator.shouldTerminateProcess()) {
290  terminateProcess(processName, process);
291  }
292  } while (process.isAlive());
293 
294  /*
295  * Careful: Process.exitValue() throws an IllegalStateException if the
296  * process is still alive when the method is called. This code is set up
297  * so that the only way Process.exitValue() can be called is when it has
298  * not been bypassed by an exception and the preceding loop has
299  * terminated with Process.isAlive == false.
300  */
301  return process.exitValue();
302  }
303 
317  public static void killProcess(Process process) {
318  String processName = process.toString();
319  try {
320  terminateProcess(processName, process);
321  } catch (IOException ex) {
322  logger.log(Level.WARNING, String.format("Error occured executing %s", processName), ex); //NON-NLS
323  } catch (InterruptedException ex) {
324  logger.log(Level.WARNING, String.format("Interrupted executing %s", processName), ex); //NON-NLS
325  Thread.currentThread().interrupt();
326  }
327  }
328 
342  private static void terminateProcess(String processName, Process process) throws IOException, InterruptedException {
343  if (process == null || !process.isAlive()) {
344  return;
345  }
346 
347  if (PlatformUtil.isWindows()) {
348  try {
349  Win32Process parentProcess = new Win32Process(process);
350  List<Win32Process> children = parentProcess.getChildren();
351  children.stream().forEach((child) -> {
352  child.terminate();
353  });
354  parentProcess.terminate();
355  } catch (Exception ex) {
356  /*
357  * Wrap whatever exception was thrown from Windows in an
358  * exception that is appropriate for this API.
359  */
360  throw new IOException(String.format("Error occured terminating %s", processName), ex); //NON-NLS
361  }
362  } else {
363  process.destroyForcibly();
364  }
365 
366  if (!process.waitFor(MAX_WAIT_FOR_TERMINATION, MAX_WAIT_FOR_TERMINATION_UNITS)) {
367  throw new IOException(String.format("Failed to terminate %s after %d %s", processName, MAX_WAIT_FOR_TERMINATION, MAX_WAIT_FOR_TERMINATION_UNITS)); //NON-NLS
368  }
369  }
370 
371  /*
372  * Fields used by deprecated methods that require instantiation of an
373  * ExecUtil object.
374  */
375  private Process proc = null;
379  private int exitValue = -100;
380 
394  @Deprecated
395  public synchronized String execute(final String aCommand, final String... params) throws IOException, InterruptedException {
396  // build command array
397  String[] arrayCommand = new String[params.length + 1];
398  arrayCommand[0] = aCommand;
399 
400  StringBuilder arrayCommandToLog = new StringBuilder();
401  arrayCommandToLog.append(aCommand).append(" ");
402 
403  for (int i = 1; i < arrayCommand.length; i++) {
404  arrayCommand[i] = params[i - 1];
405  arrayCommandToLog.append(arrayCommand[i]).append(" ");
406  }
407 
408  final Runtime rt = Runtime.getRuntime();
409  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
410 
411  proc = rt.exec(arrayCommand);
412 
413  //stderr redirect
414  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
415  errorStringRedirect.start();
416 
417  //stdout redirect
418  outputStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getInputStream(), "OUTPUT"); //NON-NLS
419  outputStringRedirect.start();
420 
421  //wait for process to complete and capture error core
422  this.exitValue = proc.waitFor();
423 
424  // wait for output redirectors to finish writing / reading
425  outputStringRedirect.join();
426  errorStringRedirect.join();
427 
428  return outputStringRedirect.getOutput();
429  }
430 
442  @Deprecated
443  public synchronized void execute(final Writer stdoutWriter, final String aCommand, final String... params) throws IOException, InterruptedException {
444 
445  // build command array
446  String[] arrayCommand = new String[params.length + 1];
447  arrayCommand[0] = aCommand;
448 
449  StringBuilder arrayCommandToLog = new StringBuilder();
450  arrayCommandToLog.append(aCommand).append(" ");
451 
452  for (int i = 1; i < arrayCommand.length; i++) {
453  arrayCommand[i] = params[i - 1];
454  arrayCommandToLog.append(arrayCommand[i]).append(" ");
455  }
456 
457  final Runtime rt = Runtime.getRuntime();
458  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
459 
460  proc = rt.exec(arrayCommand);
461 
462  //stderr redirect
463  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
464  errorStringRedirect.start();
465 
466  //stdout redirect
467  outputWriterRedirect = new ExecUtil.StreamToWriterRedirect(proc.getInputStream(), stdoutWriter);
468  outputWriterRedirect.start();
469 
470  //wait for process to complete and capture error core
471  this.exitValue = proc.waitFor();
472  logger.log(Level.INFO, "{0} exit value: {1}", new Object[]{aCommand, exitValue}); //NON-NLS
473 
474  // wait for them to finish writing / reading
475  outputWriterRedirect.join();
476  errorStringRedirect.join();
477 
478  //gc process with its streams
479  //proc = null;
480  }
481 
485  @Deprecated
486  public synchronized void stop() {
487 
488  if (errorStringRedirect != null) {
489  errorStringRedirect.stopRun();
490  errorStringRedirect = null;
491  }
492 
493  if (outputStringRedirect != null) {
494  outputStringRedirect.stopRun();
495  outputStringRedirect = null;
496  }
497 
498  if (outputWriterRedirect != null) {
499  outputWriterRedirect.stopRun();
500  outputWriterRedirect = null;
501  }
502 
503  if (proc != null) {
504  proc.destroy();
505  proc = null;
506  }
507  }
508 
515  @Deprecated
516  synchronized public int getExitValue() {
517  return this.exitValue;
518  }
519 
526  private static class StreamToStringRedirect extends Thread {
527 
528  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
529  private final InputStream is;
530  private final StringBuffer output = new StringBuffer();
531  private volatile boolean doRun = false;
532 
533  StreamToStringRedirect(final InputStream anIs, final String aType) {
534  this.is = anIs;
535  this.doRun = true;
536  }
537 
544  @Override
545  public final void run() {
546  final String SEP = System.getProperty("line.separator");
547  InputStreamReader isr;
548  BufferedReader br = null;
549  try {
550  isr = new InputStreamReader(this.is);
551  br = new BufferedReader(isr);
552  String line = null;
553  while (doRun && (line = br.readLine()) != null) {
554  this.output.append(line).append(SEP);
555  }
556  } catch (final IOException ex) {
557  logger.log(Level.WARNING, "Error redirecting stream to string buffer", ex); //NON-NLS
558  } finally {
559  if (br != null) {
560  try {
561  br.close();
562  } catch (IOException ex) {
563  logger.log(Level.SEVERE, "Error closing stream reader", ex); //NON-NLS
564  }
565  }
566  }
567  }
568 
573  public void stopRun() {
574  doRun = false;
575  }
576 
583  public final String getOutput() {
584  return this.output.toString();
585  }
586  }
587 
596  private static class StreamToWriterRedirect extends Thread {
597 
598  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
599  private final InputStream is;
600  private volatile boolean doRun = false;
601  private Writer writer = null;
602 
603  StreamToWriterRedirect(final InputStream anIs, final Writer writer) {
604  this.is = anIs;
605  this.writer = writer;
606  this.doRun = true;
607  }
608 
615  @Override
616  public final void run() {
617  final String SEP = System.getProperty("line.separator");
618  InputStreamReader isr;
619  BufferedReader br = null;
620  try {
621  isr = new InputStreamReader(this.is);
622  br = new BufferedReader(isr);
623  String line = null;
624  while (doRun && (line = br.readLine()) != null) {
625  writer.append(line).append(SEP);
626  }
627  } catch (final IOException ex) {
628  logger.log(Level.SEVERE, "Error reading output and writing to file writer", ex); //NON-NLS
629  } finally {
630  try {
631  if (doRun) {
632  writer.flush();
633  }
634  if (br != null) {
635  br.close();
636  }
637 
638  } catch (IOException ex) {
639  logger.log(Level.SEVERE, "Error flushing file writer", ex); //NON-NLS
640  }
641  }
642  }
643 
648  public void stopRun() {
649  doRun = false;
650  }
651  }
652 }
ExecUtil.StreamToStringRedirect errorStringRedirect
Definition: ExecUtil.java:376
static int execute(ProcessBuilder processBuilder, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:207
static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator)
Definition: ExecUtil.java:176
ExecUtil.StreamToWriterRedirect outputWriterRedirect
Definition: ExecUtil.java:378
static int execute(ProcessBuilder processBuilder)
Definition: ExecUtil.java:145
synchronized void execute(final Writer stdoutWriter, final String aCommand, final String...params)
Definition: ExecUtil.java:443
static int waitForTermination(String processName, Process process, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:237
static void terminateProcess(String processName, Process process)
Definition: ExecUtil.java:342
ExecUtil.StreamToStringRedirect outputStringRedirect
Definition: ExecUtil.java:377
static void killProcess(Process process)
Definition: ExecUtil.java:317
static final TimeUnit MAX_WAIT_FOR_TERMINATION_UNITS
Definition: ExecUtil.java:43
static int waitForProcess(String processName, Process process, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:271
static final long MAX_WAIT_FOR_TERMINATION
Definition: ExecUtil.java:42
static final long DEFAULT_TERMINATION_CHECK_INTERVAL
Definition: ExecUtil.java:40
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static final TimeUnit DEFAULT_TERMINATION_CHECK_INTERVAL_UNITS
Definition: ExecUtil.java:41
synchronized String execute(final String aCommand, final String...params)
Definition: ExecUtil.java:395

Copyright © 2012-2020 Basis Technology. Generated on: Tue Sep 22 2020
This work is licensed under a Creative Commons Attribution-Share Alike 3.0 United States License.