Autopsy  4.11.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 
205  public static void killProcess(Process process) {
206  if (process == null) {
207  return;
208  }
209 
210  try {
211  if (PlatformUtil.isWindows()) {
212  Win32Process parentProcess = new Win32Process(process);
213  List<Win32Process> children = parentProcess.getChildren();
214 
215  children.stream().forEach((child) -> {
216  child.terminate();
217  });
218  parentProcess.terminate();
219  } else {
220  process.destroyForcibly();
221  }
222  } catch (Exception ex) {
223  logger.log(Level.WARNING, "Error occurred when attempting to kill process: {0}", ex.getMessage()); // NON-NLS
224  }
225  }
226 
227  private static final Logger logger = Logger.getLogger(ExecUtil.class.getName());
228  private Process proc = null;
232  private int exitValue = -100;
233 
244  @Deprecated
245  public synchronized String execute(final String aCommand, final String... params) throws IOException, InterruptedException {
246  // build command array
247  String[] arrayCommand = new String[params.length + 1];
248  arrayCommand[0] = aCommand;
249 
250  StringBuilder arrayCommandToLog = new StringBuilder();
251  arrayCommandToLog.append(aCommand).append(" ");
252 
253  for (int i = 1; i < arrayCommand.length; i++) {
254  arrayCommand[i] = params[i - 1];
255  arrayCommandToLog.append(arrayCommand[i]).append(" ");
256  }
257 
258  final Runtime rt = Runtime.getRuntime();
259  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
260 
261  proc = rt.exec(arrayCommand);
262 
263  //stderr redirect
264  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
265  errorStringRedirect.start();
266 
267  //stdout redirect
268  outputStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getInputStream(), "OUTPUT"); //NON-NLS
269  outputStringRedirect.start();
270 
271  //wait for process to complete and capture error core
272  this.exitValue = proc.waitFor();
273 
274  // wait for output redirectors to finish writing / reading
275  outputStringRedirect.join();
276  errorStringRedirect.join();
277 
278  return outputStringRedirect.getOutput();
279  }
280 
291  @Deprecated
292  public synchronized void execute(final Writer stdoutWriter, final String aCommand, final String... params) throws IOException, InterruptedException {
293 
294  // build command array
295  String[] arrayCommand = new String[params.length + 1];
296  arrayCommand[0] = aCommand;
297 
298  StringBuilder arrayCommandToLog = new StringBuilder();
299  arrayCommandToLog.append(aCommand).append(" ");
300 
301  for (int i = 1; i < arrayCommand.length; i++) {
302  arrayCommand[i] = params[i - 1];
303  arrayCommandToLog.append(arrayCommand[i]).append(" ");
304  }
305 
306  final Runtime rt = Runtime.getRuntime();
307  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
308 
309  proc = rt.exec(arrayCommand);
310 
311  //stderr redirect
312  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
313  errorStringRedirect.start();
314 
315  //stdout redirect
316  outputWriterRedirect = new ExecUtil.StreamToWriterRedirect(proc.getInputStream(), stdoutWriter);
317  outputWriterRedirect.start();
318 
319  //wait for process to complete and capture error core
320  this.exitValue = proc.waitFor();
321  logger.log(Level.INFO, "{0} exit value: {1}", new Object[]{aCommand, exitValue}); //NON-NLS
322 
323  // wait for them to finish writing / reading
324  outputWriterRedirect.join();
325  errorStringRedirect.join();
326 
327  //gc process with its streams
328  //proc = null;
329  }
330 
334  @Deprecated
335  public synchronized void stop() {
336 
337  if (errorStringRedirect != null) {
338  errorStringRedirect.stopRun();
339  errorStringRedirect = null;
340  }
341 
342  if (outputStringRedirect != null) {
343  outputStringRedirect.stopRun();
344  outputStringRedirect = null;
345  }
346 
347  if (outputWriterRedirect != null) {
348  outputWriterRedirect.stopRun();
349  outputWriterRedirect = null;
350  }
351 
352  if (proc != null) {
353  proc.destroy();
354  proc = null;
355  }
356  }
357 
364  @Deprecated
365  synchronized public int getExitValue() {
366  return this.exitValue;
367  }
368 
375  private static class StreamToStringRedirect extends Thread {
376 
377  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
378  private final InputStream is;
379  private final StringBuffer output = new StringBuffer();
380  private volatile boolean doRun = false;
381 
382  StreamToStringRedirect(final InputStream anIs, final String aType) {
383  this.is = anIs;
384  this.doRun = true;
385  }
386 
393  @Override
394  public final void run() {
395  final String SEP = System.getProperty("line.separator");
396  InputStreamReader isr;
397  BufferedReader br = null;
398  try {
399  isr = new InputStreamReader(this.is);
400  br = new BufferedReader(isr);
401  String line = null;
402  while (doRun && (line = br.readLine()) != null) {
403  this.output.append(line).append(SEP);
404  }
405  } catch (final IOException ex) {
406  logger.log(Level.WARNING, "Error redirecting stream to string buffer", ex); //NON-NLS
407  } finally {
408  if (br != null) {
409  try {
410  br.close();
411  } catch (IOException ex) {
412  logger.log(Level.SEVERE, "Error closing stream reader", ex); //NON-NLS
413  }
414  }
415  }
416  }
417 
422  public void stopRun() {
423  doRun = false;
424  }
425 
432  public final String getOutput() {
433  return this.output.toString();
434  }
435  }
436 
445  private static class StreamToWriterRedirect extends Thread {
446 
447  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
448  private final InputStream is;
449  private volatile boolean doRun = false;
450  private Writer writer = null;
451 
452  StreamToWriterRedirect(final InputStream anIs, final Writer writer) {
453  this.is = anIs;
454  this.writer = writer;
455  this.doRun = true;
456  }
457 
464  @Override
465  public final void run() {
466  final String SEP = System.getProperty("line.separator");
467  InputStreamReader isr;
468  BufferedReader br = null;
469  try {
470  isr = new InputStreamReader(this.is);
471  br = new BufferedReader(isr);
472  String line = null;
473  while (doRun && (line = br.readLine()) != null) {
474  writer.append(line).append(SEP);
475  }
476  } catch (final IOException ex) {
477  logger.log(Level.SEVERE, "Error reading output and writing to file writer", ex); //NON-NLS
478  } finally {
479  try {
480  if (doRun) {
481  writer.flush();
482  }
483  if (br != null) {
484  br.close();
485  }
486 
487  } catch (IOException ex) {
488  logger.log(Level.SEVERE, "Error flushing file writer", ex); //NON-NLS
489  }
490  }
491  }
492 
497  public void stopRun() {
498  doRun = false;
499  }
500  }
501 }
ExecUtil.StreamToStringRedirect errorStringRedirect
Definition: ExecUtil.java:229
static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator)
Definition: ExecUtil.java:152
ExecUtil.StreamToWriterRedirect outputWriterRedirect
Definition: ExecUtil.java:231
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:292
ExecUtil.StreamToStringRedirect outputStringRedirect
Definition: ExecUtil.java:230
static void killProcess(Process process)
Definition: ExecUtil.java:205
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:245

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