Autopsy  4.15.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 Logger logger = Logger.getLogger(ExecUtil.class.getName());
40  private static final long DEFAULT_CHECK_INTERVAL = 5;
41  private static final TimeUnit DEFAULT_CHECK_INTERVAL_UNITS = TimeUnit.SECONDS;
42 
51  public interface ProcessTerminator {
52 
59  boolean shouldTerminateProcess();
60  }
61 
66  public static class InterruptedThreadProcessTerminator implements ProcessTerminator {
67 
68  @Override
69  public boolean shouldTerminateProcess() {
70  return Thread.currentThread().isInterrupted();
71  }
72  }
73 
78  public static class TimedProcessTerminator implements ProcessTerminator {
79 
80  private final long startTimeInSeconds;
81  private final long maxRunTimeInSeconds;
82 
89  public TimedProcessTerminator(long maxRunTimeInSeconds) {
90  this.maxRunTimeInSeconds = maxRunTimeInSeconds;
91  this.startTimeInSeconds = (new Date().getTime()) / 1000;
92  }
93 
103  // user specified time out
104  this.maxRunTimeInSeconds = UserPreferences.getProcessTimeOutHrs() * 3600;
105  } else {
106  // never time out
107  this.maxRunTimeInSeconds = Long.MAX_VALUE;
108  }
109  this.startTimeInSeconds = (new Date().getTime()) / 1000;
110  }
111 
112  @Override
113  public boolean shouldTerminateProcess() {
114  long currentTimeInSeconds = (new Date().getTime()) / 1000;
115  return (currentTimeInSeconds - this.startTimeInSeconds) > this.maxRunTimeInSeconds;
116  }
117  }
118 
132  public static int execute(ProcessBuilder processBuilder) throws SecurityException, IOException {
133  return ExecUtil.execute(processBuilder, 30, TimeUnit.DAYS, new ProcessTerminator() {
134  @Override
135  public boolean shouldTerminateProcess() {
136  return false;
137  }
138  });
139  }
140 
155  public static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator) throws SecurityException, IOException {
157  }
158 
178  public static int execute(ProcessBuilder processBuilder, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException {
179  return waitForTermination(processBuilder.command().get(0), processBuilder.start(), terminationCheckInterval, units, terminator);
180  }
181 
202  public static int waitForTermination(String processName, Process process, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException {
203  try {
204  do {
205  process.waitFor(terminationCheckInterval, units);
206  if (process.isAlive() && terminator.shouldTerminateProcess()) {
207  killProcess(process);
208  try {
209  process.waitFor();
210  } catch (InterruptedException ex) {
211  logger.log(Level.WARNING, String.format("Thread running %s was interrupted before the process completed", processName), ex);
212  }
213  }
214  } while (process.isAlive());
215  } catch (InterruptedException ex) {
216  if (process.isAlive()) {
217  killProcess(process);
218  }
219  try {
220  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
221  } catch (InterruptedException exx) {
222  logger.log(Level.WARNING, String.format("Thread running %s was interrupted before the process completed", processName), exx);
223  }
224  logger.log(Level.WARNING, String.format("Thread running %s was interrupted before the process completed", processName), ex);
225  Thread.currentThread().interrupt();
226  }
227  return process.exitValue();
228  }
229 
235  public static void killProcess(Process process) {
236  if (process == null) {
237  return;
238  }
239 
240  try {
241  if (PlatformUtil.isWindows()) {
242  Win32Process parentProcess = new Win32Process(process);
243  List<Win32Process> children = parentProcess.getChildren();
244 
245  children.stream().forEach((child) -> {
246  child.terminate();
247  });
248  parentProcess.terminate();
249  } else {
250  process.destroyForcibly();
251  }
252  } catch (Exception ex) {
253  logger.log(Level.WARNING, "Error occurred when attempting to kill process: {0}", ex.getMessage()); // NON-NLS
254  }
255  }
256 
257  /*
258  * Used by deprecated methods.
259  */
260  private Process proc = null;
264  private int exitValue = -100;
265 
279  @Deprecated
280  public synchronized String execute(final String aCommand, final String... params) throws IOException, InterruptedException {
281  // build command array
282  String[] arrayCommand = new String[params.length + 1];
283  arrayCommand[0] = aCommand;
284 
285  StringBuilder arrayCommandToLog = new StringBuilder();
286  arrayCommandToLog.append(aCommand).append(" ");
287 
288  for (int i = 1; i < arrayCommand.length; i++) {
289  arrayCommand[i] = params[i - 1];
290  arrayCommandToLog.append(arrayCommand[i]).append(" ");
291  }
292 
293  final Runtime rt = Runtime.getRuntime();
294  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
295 
296  proc = rt.exec(arrayCommand);
297 
298  //stderr redirect
299  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
300  errorStringRedirect.start();
301 
302  //stdout redirect
303  outputStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getInputStream(), "OUTPUT"); //NON-NLS
304  outputStringRedirect.start();
305 
306  //wait for process to complete and capture error core
307  this.exitValue = proc.waitFor();
308 
309  // wait for output redirectors to finish writing / reading
310  outputStringRedirect.join();
311  errorStringRedirect.join();
312 
313  return outputStringRedirect.getOutput();
314  }
315 
327  @Deprecated
328  public synchronized void execute(final Writer stdoutWriter, final String aCommand, final String... params) throws IOException, InterruptedException {
329 
330  // build command array
331  String[] arrayCommand = new String[params.length + 1];
332  arrayCommand[0] = aCommand;
333 
334  StringBuilder arrayCommandToLog = new StringBuilder();
335  arrayCommandToLog.append(aCommand).append(" ");
336 
337  for (int i = 1; i < arrayCommand.length; i++) {
338  arrayCommand[i] = params[i - 1];
339  arrayCommandToLog.append(arrayCommand[i]).append(" ");
340  }
341 
342  final Runtime rt = Runtime.getRuntime();
343  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
344 
345  proc = rt.exec(arrayCommand);
346 
347  //stderr redirect
348  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
349  errorStringRedirect.start();
350 
351  //stdout redirect
352  outputWriterRedirect = new ExecUtil.StreamToWriterRedirect(proc.getInputStream(), stdoutWriter);
353  outputWriterRedirect.start();
354 
355  //wait for process to complete and capture error core
356  this.exitValue = proc.waitFor();
357  logger.log(Level.INFO, "{0} exit value: {1}", new Object[]{aCommand, exitValue}); //NON-NLS
358 
359  // wait for them to finish writing / reading
360  outputWriterRedirect.join();
361  errorStringRedirect.join();
362 
363  //gc process with its streams
364  //proc = null;
365  }
366 
370  @Deprecated
371  public synchronized void stop() {
372 
373  if (errorStringRedirect != null) {
374  errorStringRedirect.stopRun();
375  errorStringRedirect = null;
376  }
377 
378  if (outputStringRedirect != null) {
379  outputStringRedirect.stopRun();
380  outputStringRedirect = null;
381  }
382 
383  if (outputWriterRedirect != null) {
384  outputWriterRedirect.stopRun();
385  outputWriterRedirect = null;
386  }
387 
388  if (proc != null) {
389  proc.destroy();
390  proc = null;
391  }
392  }
393 
400  @Deprecated
401  synchronized public int getExitValue() {
402  return this.exitValue;
403  }
404 
411  private static class StreamToStringRedirect extends Thread {
412 
413  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
414  private final InputStream is;
415  private final StringBuffer output = new StringBuffer();
416  private volatile boolean doRun = false;
417 
418  StreamToStringRedirect(final InputStream anIs, final String aType) {
419  this.is = anIs;
420  this.doRun = true;
421  }
422 
429  @Override
430  public final void run() {
431  final String SEP = System.getProperty("line.separator");
432  InputStreamReader isr;
433  BufferedReader br = null;
434  try {
435  isr = new InputStreamReader(this.is);
436  br = new BufferedReader(isr);
437  String line = null;
438  while (doRun && (line = br.readLine()) != null) {
439  this.output.append(line).append(SEP);
440  }
441  } catch (final IOException ex) {
442  logger.log(Level.WARNING, "Error redirecting stream to string buffer", ex); //NON-NLS
443  } finally {
444  if (br != null) {
445  try {
446  br.close();
447  } catch (IOException ex) {
448  logger.log(Level.SEVERE, "Error closing stream reader", ex); //NON-NLS
449  }
450  }
451  }
452  }
453 
458  public void stopRun() {
459  doRun = false;
460  }
461 
468  public final String getOutput() {
469  return this.output.toString();
470  }
471  }
472 
481  private static class StreamToWriterRedirect extends Thread {
482 
483  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
484  private final InputStream is;
485  private volatile boolean doRun = false;
486  private Writer writer = null;
487 
488  StreamToWriterRedirect(final InputStream anIs, final Writer writer) {
489  this.is = anIs;
490  this.writer = writer;
491  this.doRun = true;
492  }
493 
500  @Override
501  public final void run() {
502  final String SEP = System.getProperty("line.separator");
503  InputStreamReader isr;
504  BufferedReader br = null;
505  try {
506  isr = new InputStreamReader(this.is);
507  br = new BufferedReader(isr);
508  String line = null;
509  while (doRun && (line = br.readLine()) != null) {
510  writer.append(line).append(SEP);
511  }
512  } catch (final IOException ex) {
513  logger.log(Level.SEVERE, "Error reading output and writing to file writer", ex); //NON-NLS
514  } finally {
515  try {
516  if (doRun) {
517  writer.flush();
518  }
519  if (br != null) {
520  br.close();
521  }
522 
523  } catch (IOException ex) {
524  logger.log(Level.SEVERE, "Error flushing file writer", ex); //NON-NLS
525  }
526  }
527  }
528 
533  public void stopRun() {
534  doRun = false;
535  }
536  }
537 }
ExecUtil.StreamToStringRedirect errorStringRedirect
Definition: ExecUtil.java:261
static int execute(ProcessBuilder processBuilder, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:178
static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator)
Definition: ExecUtil.java:155
ExecUtil.StreamToWriterRedirect outputWriterRedirect
Definition: ExecUtil.java:263
static int execute(ProcessBuilder processBuilder)
Definition: ExecUtil.java:132
synchronized void execute(final Writer stdoutWriter, final String aCommand, final String...params)
Definition: ExecUtil.java:328
static int waitForTermination(String processName, Process process, long terminationCheckInterval, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:202
ExecUtil.StreamToStringRedirect outputStringRedirect
Definition: ExecUtil.java:262
static void killProcess(Process process)
Definition: ExecUtil.java:235
static final TimeUnit DEFAULT_CHECK_INTERVAL_UNITS
Definition: ExecUtil.java:41
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
synchronized String execute(final String aCommand, final String...params)
Definition: ExecUtil.java:280

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