Autopsy  4.7.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 2011-2017 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 TimedProcessTerminator implements ProcessTerminator {
66 
67  private final long startTimeInSeconds;
68  private final long maxRunTimeInSeconds;
69 
76  public TimedProcessTerminator(long maxRunTimeInSeconds) {
77  this.maxRunTimeInSeconds = maxRunTimeInSeconds;
78  this.startTimeInSeconds = (new Date().getTime()) / 1000;
79  }
80 
90  // user specified time out
91  this.maxRunTimeInSeconds = UserPreferences.getProcessTimeOutHrs() * 3600;
92  } else {
93  // never time out
94  this.maxRunTimeInSeconds = Long.MAX_VALUE;
95  }
96  this.startTimeInSeconds = (new Date().getTime()) / 1000;
97  }
98 
99  @Override
100  public boolean shouldTerminateProcess() {
101  long currentTimeInSeconds = (new Date().getTime()) / 1000;
102  return (currentTimeInSeconds - this.startTimeInSeconds) > this.maxRunTimeInSeconds;
103  }
104  }
105 
118  public static int execute(ProcessBuilder processBuilder) throws SecurityException, IOException {
119  return ExecUtil.execute(processBuilder, 30, TimeUnit.DAYS, new ProcessTerminator() {
120  @Override
121  public boolean shouldTerminateProcess() {
122  return false;
123  }
124  });
125  }
126 
140  public static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator) throws SecurityException, IOException {
141  return ExecUtil.execute(processBuilder, ExecUtil.DEFAULT_TIMEOUT, ExecUtil.DEFAULT_TIMEOUT_UNITS, terminator);
142  }
143 
159  public static int execute(ProcessBuilder processBuilder, long timeOut, TimeUnit units, ProcessTerminator terminator) throws SecurityException, IOException {
160  Process process = processBuilder.start();
161  try {
162  do {
163  process.waitFor(timeOut, units);
164  if (process.isAlive() && terminator.shouldTerminateProcess()) {
165  killProcess(process);
166  try {
167  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
168  } catch (InterruptedException exx) {
169  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)));
170  }
171  }
172  } while (process.isAlive());
173  } catch (InterruptedException ex) {
174  if (process.isAlive()) {
175  killProcess(process);
176  }
177  try {
178  process.waitFor(); //waiting to help ensure process is shutdown before calling interrupt() or returning
179  } catch (InterruptedException exx) {
180  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)));
181  }
182  Logger.getLogger(ExecUtil.class.getName()).log(Level.INFO, "Thread interrupted while running {0}", processBuilder.command().get(0)); // NON-NLS
183  Thread.currentThread().interrupt();
184  }
185  return process.exitValue();
186  }
187 
193  public static void killProcess(Process process) {
194  if (process == null) {
195  return;
196  }
197 
198  try {
199  if (PlatformUtil.isWindows()) {
200  Win32Process parentProcess = new Win32Process(process);
201  List<Win32Process> children = parentProcess.getChildren();
202 
203  children.stream().forEach((child) -> {
204  child.terminate();
205  });
206  parentProcess.terminate();
207  } else {
208  process.destroyForcibly();
209  }
210  } catch (Exception ex) {
211  logger.log(Level.WARNING, "Error occurred when attempting to kill process: {0}", ex.getMessage()); // NON-NLS
212  }
213  }
214 
218  private static final Logger logger = Logger.getLogger(ExecUtil.class.getName());
219  private Process proc = null;
223  private int exitValue = -100;
224 
235  @Deprecated
236  public synchronized String execute(final String aCommand, final String... params) throws IOException, InterruptedException {
237  // build command array
238  String[] arrayCommand = new String[params.length + 1];
239  arrayCommand[0] = aCommand;
240 
241  StringBuilder arrayCommandToLog = new StringBuilder();
242  arrayCommandToLog.append(aCommand).append(" ");
243 
244  for (int i = 1; i < arrayCommand.length; i++) {
245  arrayCommand[i] = params[i - 1];
246  arrayCommandToLog.append(arrayCommand[i]).append(" ");
247  }
248 
249  final Runtime rt = Runtime.getRuntime();
250  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
251 
252  proc = rt.exec(arrayCommand);
253 
254  //stderr redirect
255  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
256  errorStringRedirect.start();
257 
258  //stdout redirect
259  outputStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getInputStream(), "OUTPUT"); //NON-NLS
260  outputStringRedirect.start();
261 
262  //wait for process to complete and capture error core
263  this.exitValue = proc.waitFor();
264 
265  // wait for output redirectors to finish writing / reading
266  outputStringRedirect.join();
267  errorStringRedirect.join();
268 
269  return outputStringRedirect.getOutput();
270  }
271 
282  @Deprecated
283  public synchronized void execute(final Writer stdoutWriter, final String aCommand, final String... params) throws IOException, InterruptedException {
284 
285  // build command array
286  String[] arrayCommand = new String[params.length + 1];
287  arrayCommand[0] = aCommand;
288 
289  StringBuilder arrayCommandToLog = new StringBuilder();
290  arrayCommandToLog.append(aCommand).append(" ");
291 
292  for (int i = 1; i < arrayCommand.length; i++) {
293  arrayCommand[i] = params[i - 1];
294  arrayCommandToLog.append(arrayCommand[i]).append(" ");
295  }
296 
297  final Runtime rt = Runtime.getRuntime();
298  logger.log(Level.INFO, "Executing {0}", arrayCommandToLog.toString()); //NON-NLS
299 
300  proc = rt.exec(arrayCommand);
301 
302  //stderr redirect
303  errorStringRedirect = new ExecUtil.StreamToStringRedirect(proc.getErrorStream(), "ERROR"); //NON-NLS
304  errorStringRedirect.start();
305 
306  //stdout redirect
307  outputWriterRedirect = new ExecUtil.StreamToWriterRedirect(proc.getInputStream(), stdoutWriter);
308  outputWriterRedirect.start();
309 
310  //wait for process to complete and capture error core
311  this.exitValue = proc.waitFor();
312  logger.log(Level.INFO, "{0} exit value: {1}", new Object[]{aCommand, exitValue}); //NON-NLS
313 
314  // wait for them to finish writing / reading
315  outputWriterRedirect.join();
316  errorStringRedirect.join();
317 
318  //gc process with its streams
319  //proc = null;
320  }
321 
325  @Deprecated
326  public synchronized void stop() {
327 
328  if (errorStringRedirect != null) {
329  errorStringRedirect.stopRun();
330  errorStringRedirect = null;
331  }
332 
333  if (outputStringRedirect != null) {
334  outputStringRedirect.stopRun();
335  outputStringRedirect = null;
336  }
337 
338  if (outputWriterRedirect != null) {
339  outputWriterRedirect.stopRun();
340  outputWriterRedirect = null;
341  }
342 
343  if (proc != null) {
344  proc.destroy();
345  proc = null;
346  }
347  }
348 
355  @Deprecated
356  synchronized public int getExitValue() {
357  return this.exitValue;
358  }
359 
366  private static class StreamToStringRedirect extends Thread {
367 
368  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
369  private final InputStream is;
370  private final StringBuffer output = new StringBuffer();
371  private volatile boolean doRun = false;
372 
373  StreamToStringRedirect(final InputStream anIs, final String aType) {
374  this.is = anIs;
375  this.doRun = true;
376  }
377 
384  @Override
385  public final void run() {
386  final String SEP = System.getProperty("line.separator");
387  InputStreamReader isr;
388  BufferedReader br = null;
389  try {
390  isr = new InputStreamReader(this.is);
391  br = new BufferedReader(isr);
392  String line = null;
393  while (doRun && (line = br.readLine()) != null) {
394  this.output.append(line).append(SEP);
395  }
396  } catch (final IOException ex) {
397  logger.log(Level.WARNING, "Error redirecting stream to string buffer", ex); //NON-NLS
398  } finally {
399  if (br != null) {
400  try {
401  br.close();
402  } catch (IOException ex) {
403  logger.log(Level.SEVERE, "Error closing stream reader", ex); //NON-NLS
404  }
405  }
406  }
407  }
408 
413  public void stopRun() {
414  doRun = false;
415  }
416 
423  public final String getOutput() {
424  return this.output.toString();
425  }
426  }
427 
436  private static class StreamToWriterRedirect extends Thread {
437 
438  private static final Logger logger = Logger.getLogger(StreamToStringRedirect.class.getName());
439  private final InputStream is;
440  private volatile boolean doRun = false;
441  private Writer writer = null;
442 
443  StreamToWriterRedirect(final InputStream anIs, final Writer writer) {
444  this.is = anIs;
445  this.writer = writer;
446  this.doRun = true;
447  }
448 
455  @Override
456  public final void run() {
457  final String SEP = System.getProperty("line.separator");
458  InputStreamReader isr;
459  BufferedReader br = null;
460  try {
461  isr = new InputStreamReader(this.is);
462  br = new BufferedReader(isr);
463  String line = null;
464  while (doRun && (line = br.readLine()) != null) {
465  writer.append(line).append(SEP);
466  }
467  } catch (final IOException ex) {
468  logger.log(Level.SEVERE, "Error reading output and writing to file writer", ex); //NON-NLS
469  } finally {
470  try {
471  if (doRun) {
472  writer.flush();
473  }
474  if (br != null) {
475  br.close();
476  }
477 
478  } catch (IOException ex) {
479  logger.log(Level.SEVERE, "Error flushing file writer", ex); //NON-NLS
480  }
481  }
482  }
483 
488  public void stopRun() {
489  doRun = false;
490  }
491  }
492 }
ExecUtil.StreamToStringRedirect errorStringRedirect
Definition: ExecUtil.java:220
static int execute(ProcessBuilder processBuilder, ProcessTerminator terminator)
Definition: ExecUtil.java:140
ExecUtil.StreamToWriterRedirect outputWriterRedirect
Definition: ExecUtil.java:222
static int execute(ProcessBuilder processBuilder)
Definition: ExecUtil.java:118
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:283
ExecUtil.StreamToStringRedirect outputStringRedirect
Definition: ExecUtil.java:221
static void killProcess(Process process)
Definition: ExecUtil.java:193
synchronized static Logger getLogger(String name)
Definition: Logger.java:124
static int execute(ProcessBuilder processBuilder, long timeOut, TimeUnit units, ProcessTerminator terminator)
Definition: ExecUtil.java:159
synchronized String execute(final String aCommand, final String...params)
Definition: ExecUtil.java:236

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