diff --git a/common/source/java/ch/systemsx/cisd/common/process/ProcessExecutionHelper.java b/common/source/java/ch/systemsx/cisd/common/process/ProcessExecutionHelper.java
index 631e12f5859b9d3057b19171ba15cd8466d217a6..7ebf724961587731baecdbc8616aea6cc8b8c979 100644
--- a/common/source/java/ch/systemsx/cisd/common/process/ProcessExecutionHelper.java
+++ b/common/source/java/ch/systemsx/cisd/common/process/ProcessExecutionHelper.java
@@ -17,9 +17,12 @@
 package ch.systemsx.cisd.common.process;
 
 import java.io.BufferedReader;
+import java.io.ByteArrayOutputStream;
 import java.io.File;
 import java.io.IOException;
+import java.io.InputStream;
 import java.io.InputStreamReader;
+import java.io.OutputStream;
 import java.util.ArrayList;
 import java.util.Collections;
 import java.util.List;
@@ -32,10 +35,10 @@ import org.apache.commons.io.IOUtils;
 import org.apache.commons.lang.StringUtils;
 import org.apache.log4j.Logger;
 
+import ch.systemsx.cisd.base.exceptions.CheckedExceptionTunnel;
 import ch.systemsx.cisd.base.exceptions.InterruptedExceptionUnchecked;
 import ch.systemsx.cisd.base.namedthread.NamedCallable;
 import ch.systemsx.cisd.base.namedthread.NamingThreadPoolExecutor;
-import ch.systemsx.cisd.base.utilities.OSUtilities;
 import ch.systemsx.cisd.common.concurrent.ConcurrencyUtilities;
 import ch.systemsx.cisd.common.concurrent.ExecutionResult;
 import ch.systemsx.cisd.common.concurrent.ExecutionStatus;
@@ -49,6 +52,8 @@ import ch.systemsx.cisd.common.utilities.ITerminable;
 public final class ProcessExecutionHelper
 {
 
+    private static final int BUFFER_SIZE = 4096;
+
     /**
      * Strategy on whether to read the process output or not.
      */
@@ -67,6 +72,19 @@ public final class ProcessExecutionHelper
         ALWAYS;
     }
 
+    /**
+     * Role for handling the process I/O.
+     */
+    public interface IProcessIOHandler
+    {
+        /**
+         * Method that gets the process' <code>stdin</code>, <code>stdout</code> and
+         * <code>stderr</code> and is expected to handlt the I/O of the process.
+         */
+        public void handle(OutputStream stdin, InputStream stdout, InputStream stderr)
+                throws IOException;
+    }
+
     /**
      * Record to store process and its output.
      */
@@ -74,12 +92,26 @@ public final class ProcessExecutionHelper
     {
         private final Process process;
 
-        private final List<String> processOutput;
+        private final List<String> processTextOutput;
+
+        private final List<String> processErrorOutput;
+
+        private final ByteArrayOutputStream processBinaryOutput;
 
         ProcessRecord(final Process process)
         {
             this.process = process;
-            this.processOutput = Collections.synchronizedList(new ArrayList<String>());
+            if (binaryOutput)
+            {
+                this.processTextOutput = null;
+                this.processErrorOutput = new ArrayList<String>();
+                this.processBinaryOutput = new ByteArrayOutputStream();
+            } else
+            {
+                this.processTextOutput = new ArrayList<String>();
+                this.processErrorOutput = null;
+                this.processBinaryOutput = null;
+            }
         }
 
         Process getProcess()
@@ -87,9 +119,19 @@ public final class ProcessExecutionHelper
             return process;
         }
 
-        List<String> getProcessOutput()
+        List<String> getTextProcessOutput()
         {
-            return processOutput;
+            return processTextOutput;
+        }
+
+        ByteArrayOutputStream getBinaryProcessOutput()
+        {
+            return processBinaryOutput;
+        }
+
+        List<String> getErrorProcessOutput()
+        {
+            return processErrorOutput;
         }
     }
 
@@ -123,6 +165,10 @@ public final class ProcessExecutionHelper
 
     private final OutputReadingStrategy outputReadingStrategy;
 
+    private final boolean binaryOutput;
+
+    private final IProcessIOHandler processIOHandlerOrNull;
+
     /** The number used in thread names to distinguish the process. */
     private final int processNumber;
 
@@ -165,7 +211,8 @@ public final class ProcessExecutionHelper
             final Logger machineLog, boolean stopOnInterrupt) throws InterruptedExceptionUnchecked
     {
         return new ProcessExecutionHelper(cmd, ConcurrencyUtilities.NO_TIMEOUT,
-                DEFAULT_OUTPUT_READING_STRATEGY, operationLog, machineLog).run(stopOnInterrupt);
+                DEFAULT_OUTPUT_READING_STRATEGY, null, false, operationLog, machineLog)
+                .run(stopOnInterrupt);
     }
 
     /**
@@ -241,7 +288,8 @@ public final class ProcessExecutionHelper
             final long millisToWaitForCompletion) throws InterruptedExceptionUnchecked
     {
         return new ProcessExecutionHelper(cmd, millisToWaitForCompletion,
-                DEFAULT_OUTPUT_READING_STRATEGY, operationLog, machineLog).run(stopOnInterrupt);
+                DEFAULT_OUTPUT_READING_STRATEGY, null, false, operationLog, machineLog)
+                .run(stopOnInterrupt);
     }
 
     /**
@@ -309,7 +357,65 @@ public final class ProcessExecutionHelper
             throws InterruptedExceptionUnchecked
     {
         return new ProcessExecutionHelper(cmd, millisToWaitForCompletion, outputReadingStrategy,
-                operationLog, machineLog).run(stopOnInterrupt);
+                null, false, operationLog, machineLog).run(stopOnInterrupt);
+    }
+
+    /**
+     * Runs an Operating System process, specified by <var>cmd</var>.
+     * 
+     * @param cmd The command line to run.
+     * @param operationLog The {@link Logger} to use for all message on the higher level.
+     * @param machineLog The {@link Logger} to use for all message on the lower (machine) level.
+     * @param millisToWaitForCompletion The time to wait for the process to complete in milli
+     *            seconds. If the process is not finished after that time, it will be terminated by
+     *            a watch dog.
+     * @param outputReadingStrategy The strategy for when to read the output (both
+     *            <code>stdout</code> and <code>sterr</code>) of the process.
+     * @param binaryOutput If <code>true</code>, the process is expected to produce binary output on
+     *            <code>stdout</code>.
+     * @param stopOnInterrupt If <code>true</code>, throw a {@link InterruptedExceptionUnchecked} if
+     *            the thread gets interrupted while waiting on the future.
+     * @return The process result.
+     * @throws InterruptedExceptionUnchecked If the thread got interrupted and
+     *             <var>stopOnInterrupt</var> is <code>true</code>.
+     */
+    public static ProcessResult run(final List<String> cmd, final Logger operationLog,
+            final Logger machineLog, final long millisToWaitForCompletion,
+            final OutputReadingStrategy outputReadingStrategy, final boolean binaryOutput,
+            final boolean stopOnInterrupt) throws InterruptedExceptionUnchecked
+    {
+        return new ProcessExecutionHelper(cmd, millisToWaitForCompletion, outputReadingStrategy,
+                null, binaryOutput, operationLog, machineLog).run(stopOnInterrupt);
+    }
+
+    /**
+     * Runs an Operating System process, specified by <var>cmd</var>.
+     * 
+     * @param cmd The command line to run.
+     * @param operationLog The {@link Logger} to use for all message on the higher level.
+     * @param machineLog The {@link Logger} to use for all message on the lower (machine) level.
+     * @param millisToWaitForCompletion The time to wait for the process to complete in milli
+     *            seconds. If the process is not finished after that time, it will be terminated by
+     *            a watch dog.
+     * @param outputReadingStrategy The strategy for when to read the output (both
+     *            <code>stdout</code> and <code>sterr</code>) of the process.
+     * @param processIOHandler The handler in charge of dealing with the process input and output.
+     *            Beware that if the process reaches the I/O buffer limit and this handler doesn't
+     *            read the output, the process may hang indefinitely.
+     * @param stopOnInterrupt If <code>true</code>, throw a {@link InterruptedExceptionUnchecked} if
+     *            the thread gets interrupted while waiting on the future.
+     * @return The process result.
+     * @throws InterruptedExceptionUnchecked If the thread got interrupted and
+     *             <var>stopOnInterrupt</var> is <code>true</code>.
+     */
+    public static ProcessResult run(final List<String> cmd, final Logger operationLog,
+            final Logger machineLog, final long millisToWaitForCompletion,
+            final OutputReadingStrategy outputReadingStrategy,
+            final IProcessIOHandler processIOHandler, final boolean stopOnInterrupt)
+            throws InterruptedExceptionUnchecked
+    {
+        return new ProcessExecutionHelper(cmd, millisToWaitForCompletion, outputReadingStrategy,
+                processIOHandler, false, operationLog, machineLog).run(stopOnInterrupt);
     }
 
     /** Handler to a running process. Allows to wait for the result and stop the process. */
@@ -346,7 +452,7 @@ public final class ProcessExecutionHelper
             final Logger machineLog)
     {
         return new ProcessExecutionHelper(cmd, ConcurrencyUtilities.NO_TIMEOUT,
-                outputReadingStrategy, operationLog, machineLog).runUnblocking();
+                outputReadingStrategy, null, false, operationLog, machineLog).runUnblocking();
     }
 
     /**
@@ -380,6 +486,67 @@ public final class ProcessExecutionHelper
         }
     }
 
+    /**
+     * Reads the <code>stdout</code> and <code>stderr</code> of <var>process</var>.
+     */
+    private final void readProcessOutput(final ProcessRecord processRecord, final boolean discard)
+    {
+        readProcessOutput(processRecord, -1, discard);
+    }
+
+    /**
+     * Reads the <code>stdout</code> and <code>stderr</code> of <var>process</var>. If
+     * <code>maxBytes > 0</code>, read not more than so many bytes.
+     */
+    private final void readProcessOutput(final ProcessRecord processRecord, final long maxBytes,
+            final boolean discard)
+    {
+        assert processRecord != null;
+        assert machineLog != null;
+
+        final Process process = processRecord.getProcess();
+        if (binaryOutput)
+        {
+            try
+            {
+                copy(process, processRecord, maxBytes, discard);
+            } catch (final IOException e)
+            {
+                machineLog.warn(String.format("IOException when reading stdout/stderr, msg='%s'.",
+                        e.getMessage()));
+            }
+            final List<String> errorOutput = processRecord.getErrorProcessOutput();
+            final BufferedReader errorReader =
+                    new BufferedReader(new InputStreamReader(process.getErrorStream()));
+            readProcessOutputLines(errorOutput, errorReader, discard);
+        } else
+        {
+            final List<String> processOutput = processRecord.getTextProcessOutput();
+            final BufferedReader reader =
+                    new BufferedReader(new InputStreamReader(process.getInputStream()));
+            readProcessOutputLines(processOutput, reader, discard);
+        }
+    }
+
+    protected void copy(final Process process, final ProcessRecord processRecord,
+            final long maxBytes, final boolean discard) throws IOException
+    {
+        final InputStream input = process.getInputStream();
+        final OutputStream output = processRecord.getBinaryProcessOutput();
+        final byte[] buffer = new byte[BUFFER_SIZE];
+        long count = 0;
+        int n = 0;
+        while ((maxBytes <= 0 || count < maxBytes) && input.available() > 0
+                && -1 != (n = input.read(buffer)))
+        {
+            if (discard == false)
+            {
+                output.write(buffer, 0, n);
+            }
+            count += n;
+        }
+    }
+
     /**
      * Returns the <code>stdout</code> and <code>stderr</code> of the <var>process</var> in
      * <var>processRecord.getProcessOutput()</var>.
@@ -413,13 +580,11 @@ public final class ProcessExecutionHelper
     }
 
     /**
-     * On Windows it is necessary to read the output stream during the process is running in order
-     * not to get dead-locked. This is less efficient (due to the limited interface of
-     * {@link Process}), so we don't do it if we don't have to.
+     * Returns <code>true</code>, if an I/O handler for the process I/O is available.
      */
-    private boolean hasLimitedOutputBuffer()
+    private boolean hasIOHandler()
     {
-        return OSUtilities.isWindows();
+        return processIOHandlerOrNull != null;
     }
 
     /**
@@ -432,7 +597,10 @@ public final class ProcessExecutionHelper
         private final Process launch() throws IOException
         {
             final ProcessBuilder processBuilder = new ProcessBuilder(commandLine);
-            processBuilder.redirectErrorStream(true);
+            if (binaryOutput == false && processIOHandlerOrNull == null)
+            {
+                processBuilder.redirectErrorStream(true);
+            }
             if (operationLog.isDebugEnabled())
             {
                 operationLog.debug("Running command: " + getCommand(commandLine));
@@ -453,18 +621,15 @@ public final class ProcessExecutionHelper
                 {
                     ProcessRecord processRecord = new ProcessRecord(process);
                     processWrapper.set(processRecord);
-                    final List<String> processOutput = processRecord.getProcessOutput();
-                    final BufferedReader reader =
-                            new BufferedReader(new InputStreamReader(process.getInputStream()));
 
                     int exitValue = ProcessResult.NO_EXIT_VALUE;
-                    if (hasLimitedOutputBuffer())
+                    if (hasIOHandler() == false)
                     {
                         final boolean discardOutput =
                                 (outputReadingStrategy == OutputReadingStrategy.NEVER);
                         while (exitValue == ProcessResult.NO_EXIT_VALUE)
                         {
-                            readProcessOutputLines(processOutput, reader, discardOutput);
+                            readProcessOutput(processRecord, discardOutput);
                             exitValue = getExitValue(process);
                             if (exitValue == ProcessResult.NO_EXIT_VALUE)
                             {
@@ -472,23 +637,67 @@ public final class ProcessExecutionHelper
                             }
                         }
                         processWrapper.set(null);
-                        readProcessOutputLines(processOutput, reader, discardOutput);
+                        readProcessOutput(processRecord, discardOutput);
+                        if (binaryOutput)
+                        {
+                            return new ProcessResult(commandLine, processNumber,
+                                    ExecutionStatus.COMPLETE, "", exitValue, processRecord
+                                            .getBinaryProcessOutput().toByteArray(),
+                                    processRecord.getErrorProcessOutput(), operationLog, machineLog);
+                        } else
+                        {
+                            return new ProcessResult(commandLine, processNumber,
+                                    ExecutionStatus.COMPLETE, "", exitValue,
+                                    processRecord.getTextProcessOutput(), operationLog, machineLog);
+                        }
                     } else
                     {
+                        final Future<?> future = executor.submit(new Runnable()
+                            {
+                                public void run()
+                                {
+                                    try
+                                    {
+                                        processIOHandlerOrNull.handle(process.getOutputStream(),
+                                                process.getInputStream(), process.getErrorStream());
+                                    } catch (IOException ex)
+                                    {
+                                        throw CheckedExceptionTunnel.wrapIfNecessary(ex);
+                                    }
+                                }
+                            });
                         exitValue = process.waitFor();
-                        final boolean stillInCharge = (processWrapper.getAndSet(null) != null);
-
-                        if (stillInCharge
-                                && (OutputReadingStrategy.ALWAYS.equals(outputReadingStrategy) || (OutputReadingStrategy.ON_ERROR
-                                        .equals(outputReadingStrategy) && ProcessResult
-                                        .isProcessOK(exitValue) == false)))
+                        processWrapper.set(null);
+                        final ExecutionResult<?> result =
+                                ConcurrencyUtilities.getResult(future, SHORT_TIMEOUT);
+                        switch (result.getStatus())
                         {
-                            readProcessOutputLines(processOutput, reader, false);
+                            case COMPLETE:
+                                break;
+                            case EXCEPTION:
+                                final Throwable th = result.tryGetException();
+                                final Throwable cause =
+                                        (th == null) ? new RuntimeException("Unknown exception.")
+                                                : (th instanceof Error) ? (Error) th
+                                                        : CheckedExceptionTunnel
+                                                                .unwrapIfNecessary((Exception) th);
+                                machineLog
+                                        .warn(String
+                                                .format("Exception when reading stdout/stderr, type='%s', msg='%s'.",
+                                                        cause.getClass().getSimpleName(),
+                                                        cause.getMessage()));
+                                break;
+                            case INTERRUPTED:
+                                machineLog.warn("Interrupted when reading stdout/stderr.");
+                                break;
+                            case TIMED_OUT:
+                                machineLog.warn("Timeout when reading stdout/stderr.");
+                                break;
                         }
+                        return new ProcessResult(commandLine, processNumber,
+                                ExecutionStatus.COMPLETE, "", exitValue, null, operationLog,
+                                machineLog);
                     }
-                    return new ProcessResult(commandLine, processNumber, ExecutionStatus.COMPLETE,
-                            "", exitValue, processRecord.getProcessOutput(), operationLog,
-                            machineLog);
                 } finally
                 {
                     IOUtils.closeQuietly(process.getErrorStream());
@@ -536,22 +745,22 @@ public final class ProcessExecutionHelper
             if (processRecord != null)
             {
                 final Process process = processRecord.getProcess();
-                if (hasLimitedOutputBuffer() == false
-                        && OutputReadingStrategy.NEVER.equals(outputReadingStrategy) == false)
-                {
-                    final List<String> processOutput = processRecord.getProcessOutput();
-                    final BufferedReader reader =
-                            new BufferedReader(new InputStreamReader(process.getInputStream()));
-                    readProcessOutputLines(processOutput, reader, false);
-                }
                 process.destroy(); // Note: this also closes the I/O streams.
                 if (machineLog.isInfoEnabled())
                 {
                     machineLog.info(String.format("Killed '%s'.", getCommand(commandLine)));
                 }
                 final int exitValue = getExitValue(processRecord.getProcess());
-                return new ProcessResult(commandLine, processNumber, status, "", exitValue,
-                        processRecord.getProcessOutput(), operationLog, machineLog);
+                if (binaryOutput)
+                {
+                    return new ProcessResult(commandLine, processNumber, status, "", exitValue,
+                            processRecord.getBinaryProcessOutput().toByteArray(),
+                            processRecord.getErrorProcessOutput(), operationLog, machineLog);
+                } else
+                {
+                    return new ProcessResult(commandLine, processNumber, status, "", exitValue,
+                            processRecord.getTextProcessOutput(), operationLog, machineLog);
+                }
             } else
             {
                 return null; // Value signals that the ProcessRunner got us.
@@ -567,8 +776,9 @@ public final class ProcessExecutionHelper
 
     private ProcessExecutionHelper(final List<String> commandLine,
             final long millisToWaitForCompletion,
-            final OutputReadingStrategy outputReadingStrategy, final Logger operationLog,
-            final Logger machineLog)
+            final OutputReadingStrategy outputReadingStrategy,
+            final IProcessIOHandler processIOHandlerOrNull, final boolean binaryOutput,
+            final Logger operationLog, final Logger machineLog)
     {
         this.processNumber = processCounter.getAndIncrement();
         this.callingThreadName = Thread.currentThread().getName();
@@ -583,6 +793,8 @@ public final class ProcessExecutionHelper
             this.millisToWaitForCompletion = millisToWaitForCompletion;
         }
         this.outputReadingStrategy = outputReadingStrategy;
+        this.processIOHandlerOrNull = processIOHandlerOrNull;
+        this.binaryOutput = binaryOutput;
         this.commandLine = Collections.unmodifiableList(commandLine);
         this.processWrapper = new AtomicReference<ProcessRecord>();
     }
@@ -656,9 +868,17 @@ public final class ProcessExecutionHelper
                 // see the note above about termination from other thread
                 status = ExecutionStatus.INTERRUPTED;
             }
-            return new ProcessResult(commandLine, processNumber, status,
-                    tryGetStartupFailureMessage(executionResult.tryGetException()),
-                    ProcessResult.NO_EXIT_VALUE, null, operationLog, machineLog);
+            if (binaryOutput)
+            {
+                return new ProcessResult(commandLine, processNumber, status,
+                        tryGetStartupFailureMessage(executionResult.tryGetException()),
+                        ProcessResult.NO_EXIT_VALUE, null, null, operationLog, machineLog);
+            } else
+            {
+                return new ProcessResult(commandLine, processNumber, status,
+                        tryGetStartupFailureMessage(executionResult.tryGetException()),
+                        ProcessResult.NO_EXIT_VALUE, null, operationLog, machineLog);
+            }
         }
     }
 
diff --git a/common/source/java/ch/systemsx/cisd/common/process/ProcessResult.java b/common/source/java/ch/systemsx/cisd/common/process/ProcessResult.java
index 4d8adb63b3f22b90ef948c0c2ae330f4e4edd9b3..604e8249799730495a25caebb0ae10f4beeae056 100644
--- a/common/source/java/ch/systemsx/cisd/common/process/ProcessResult.java
+++ b/common/source/java/ch/systemsx/cisd/common/process/ProcessResult.java
@@ -76,6 +76,12 @@ public final class ProcessResult
 
     private final List<String> output;
 
+    private final byte[] binaryOutput;
+
+    private final List<String> errorOutput;
+
+    private final boolean isBinaryOutput;
+
     /**
      * Returns <code>true</code> if the <var>exitValue</var> indicates that the process has been
      * terminated on the Operating System level.
@@ -108,6 +114,7 @@ public final class ProcessResult
         this.startupFailureMessage =
                 (startupFailureMessageOrNull == null) ? "" : startupFailureMessageOrNull;
         this.exitValue = exitValue;
+        this.isBinaryOutput = false;
         this.outputAvailable = (processOutputOrNull != null);
         if (outputAvailable)
         {
@@ -118,6 +125,41 @@ public final class ProcessResult
             this.output = Collections.emptyList();
 
         }
+        this.errorOutput = null;
+        this.binaryOutput = null;
+        this.operationLog = operationLog;
+        this.machineLog = machineLog;
+    }
+
+    public ProcessResult(final List<String> commandLine, final int processNumber,
+            final ExecutionStatus status, final String startupFailureMessageOrNull,
+            final int exitValue, final byte[] processBinaryOutputOrNull,
+            final List<String> processErrorOutputOrNull, final Logger operationLog,
+            final Logger machineLog)
+    {
+        this.commandLine = commandLine;
+        this.commandName = ProcessExecutionHelper.getCommandName(commandLine);
+        this.processNumber = processNumber;
+        this.status = status;
+        this.startupFailureMessage =
+                (startupFailureMessageOrNull == null) ? "" : startupFailureMessageOrNull;
+        this.exitValue = exitValue;
+        this.isBinaryOutput = true;
+        this.outputAvailable = (processBinaryOutputOrNull != null);
+        if (outputAvailable)
+        {
+            this.errorOutput =
+                    (processErrorOutputOrNull == null) ? Collections.<String> emptyList()
+                            : Collections.unmodifiableList(processErrorOutputOrNull);
+            this.binaryOutput = processBinaryOutputOrNull;
+
+        } else
+        {
+            this.errorOutput = Collections.emptyList();
+            binaryOutput = new byte[0];
+
+        }
+        this.output = null;
         this.operationLog = operationLog;
         this.machineLog = machineLog;
     }
@@ -156,8 +198,49 @@ public final class ProcessResult
     }
 
     /**
-     * Returns the output of the process (<code>stdout</code> and <code>stderr</code>). If it not
-     * available (see {@link #isOutputAvailable()}, an empty list is returned.
+     * Returns <code>true</code>, if the output of the method is binary and <code>false</code>, if
+     * it is text. If the output is binary, the error output is available separately, otherwise it
+     * is merged with the regular output.
+     * <p>
+     * If this method returns <code>true</code>, you are supposed to call {@link #getBinaryOutput()}
+     * and {@link #getErrorOutput()}. If it is <code>false</code>, you are supposed to call
+     * {@link #getOutput()}.
+     */
+    public boolean isBinaryOutput()
+    {
+        return isBinaryOutput;
+    }
+
+    /**
+     * Returns the binary output of the process (<code>stdout</code>). If it not available (see
+     * {@link #isOutputAvailable()}, an empty array is returned.
+     * <p>
+     * <i>Only call this method, if {@link #isBinaryOutput()} is <code>true</code>. Otherwise this
+     * method will return <code>null</code></i>.
+     */
+    public byte[] getBinaryOutput()
+    {
+        return binaryOutput;
+    }
+
+    /**
+     * Returns the text error output of the process (<code>stderr</code>). If it not available (see
+     * {@link #isOutputAvailable()}, an empty array is returned.
+     * <p>
+     * <i>Only call this method, if {@link #isBinaryOutput()} is <code>true</code>. Otherwise this
+     * method will return <code>null</code></i>.
+     */
+    public List<String> getErrorOutput()
+    {
+        return errorOutput;
+    }
+
+    /**
+     * Returns the text output of the process (<code>stdout</code> and <code>stderr</code>). If it
+     * not available (see {@link #isOutputAvailable()}, an empty list is returned.
+     * <p>
+     * <i>Only call this method, if {@link #isBinaryOutput()} is <code>false</code>. Otherwise this
+     * method will return <code>null</code></i>.
      */
     public List<String> getOutput()
     {
@@ -255,16 +338,16 @@ public final class ProcessResult
                     processNumber, commandName, startupFailureMessage));
         } else if (isTimedOut())
         {
-            operationLog.log(logLevel, String.format("P%d-{%s} process has timed out.",
-                    processNumber, commandName));
+            operationLog.log(logLevel,
+                    String.format("P%d-{%s} process has timed out.", processNumber, commandName));
         } else if (isInterruped())
         {
-            operationLog.log(logLevel, String.format("P%d-{%s} thread was interrupted.",
-                    processNumber, commandName));
+            operationLog.log(logLevel,
+                    String.format("P%d-{%s} thread was interrupted.", processNumber, commandName));
         } else if (isTerminated())
         {
-            operationLog.log(logLevel, String.format("P%d-{%s} process was terminated.",
-                    processNumber, commandName));
+            operationLog.log(logLevel,
+                    String.format("P%d-{%s} process was terminated.", processNumber, commandName));
         } else
         {
             operationLog.log(logLevel, String.format(
@@ -277,17 +360,40 @@ public final class ProcessResult
     {
         assert logLevel != null;
 
-        final List<String> processOutputLines = getOutput();
-        if (processOutputLines.size() == 0)
+        if (isBinaryOutput)
         {
-            return;
-        }
-        machineLog.log(logLevel, String.format("[%s] output:", commandName));
-        for (final String ln : processOutputLines)
+            if (getBinaryOutput().length != 0)
+            {
+                machineLog.log(logLevel, String.format("[%s] output: %d bytes", commandName,
+                        getBinaryOutput().length));
+            }
+            final List<String> processErrorOutputLines = getErrorOutput();
+            if (processErrorOutputLines.size() > 0)
+            {
+                machineLog.log(logLevel, String.format("[%s] error output:", commandName));
+                for (final String ln : processErrorOutputLines)
+                {
+                    if (ln.trim().length() > 0)
+                    {
+                        machineLog.log(logLevel, String.format("\"%s\"", ln));
+                    }
+                }
+            }
+
+        } else
         {
-            if (ln.trim().length() > 0)
+            final List<String> processOutputLines = getOutput();
+            if (processOutputLines.size() == 0)
+            {
+                return;
+            }
+            machineLog.log(logLevel, String.format("[%s] output:", commandName));
+            for (final String ln : processOutputLines)
             {
-                machineLog.log(logLevel, String.format("\"%s\"", ln));
+                if (ln.trim().length() > 0)
+                {
+                    machineLog.log(logLevel, String.format("\"%s\"", ln));
+                }
             }
         }
     }
diff --git a/common/sourceTest/java/ch/systemsx/cisd/common/process/ProcessExecutionHelperTest.java b/common/sourceTest/java/ch/systemsx/cisd/common/process/ProcessExecutionHelperTest.java
index ddb10a18313af0089b6bb0cf97765042b60b165e..7c6e726348453577da280d186d6ea17e9ca47a4f 100644
--- a/common/sourceTest/java/ch/systemsx/cisd/common/process/ProcessExecutionHelperTest.java
+++ b/common/sourceTest/java/ch/systemsx/cisd/common/process/ProcessExecutionHelperTest.java
@@ -98,6 +98,12 @@ public class ProcessExecutionHelperTest
                 "n=1; while [ 1 ]; do echo $n; n=$(($n+1)); done");
     }
 
+    private File createExecutableEndlessDevURandom(String name) throws IOException,
+            InterruptedException
+    {
+        return createExecutable(name, "#! /bin/sh", "cat < /dev/urandom");
+    }
+
     @BeforeClass
     public void init()
     {
@@ -294,7 +300,8 @@ public class ProcessExecutionHelperTest
                         operationLog, machineLog, WATCHDOG_WAIT_MILLIS);
         assertTrue(result.isTimedOut());
         assertFalse(result.isOK());
-        assertTrue(Integer.toString(result.getOutput().size()), result.getOutput().size() > 100);
+        assertTrue(Integer.toString(result.getOutput().size()),
+                result.getOutput().size() > 100);
         assertEquals(Integer.toString(result.getOutput().size()),
                 result.getOutput().get(result.getOutput().size() - 1));
     }
@@ -308,8 +315,8 @@ public class ProcessExecutionHelperTest
         final String stderr1 = "This goes to stderr, 1";
         final String stderr2 = "This goes to stderr, 2";
         final File dummyExec =
-                createExecutable("dummy.sh", "echo " + stdout1, "echo " + stderr1, "echo "
-                        + stdout2, "echo " + stderr2);
+                createExecutable("dummy.sh", "echo " + stdout1, "echo " + stderr1
+                        + " > /dev/stderr", "echo " + stdout2, "echo " + stderr2 + " > /dev/stderr");
         final ProcessResult result =
                 ProcessExecutionHelper.run(Arrays.asList(dummyExec.getAbsolutePath()),
                         operationLog, machineLog, ConcurrencyUtilities.NO_TIMEOUT,
@@ -318,6 +325,7 @@ public class ProcessExecutionHelperTest
         assertEquals(0, exitValue);
         result.log();
         assertTrue(result.isOutputAvailable());
+        assertFalse(result.isBinaryOutput());
         assertEquals(4, result.getOutput().size());
         assertEquals(stdout1, result.getOutput().get(0));
         assertEquals(stderr1, result.getOutput().get(1));
@@ -325,6 +333,47 @@ public class ProcessExecutionHelperTest
         assertEquals(stderr2, result.getOutput().get(3));
     }
 
+    @Test(groups =
+        { "requires_unix", "slow" })
+    public void testTryExecutionReadBinaryProcessOutput() throws Exception
+    {
+        final String stdout1 = "This goes to stdout, 1";
+        final String stdout2 = "This goes to stdout, 2";
+        final String stderr1 = "This goes to stderr, 1";
+        final String stderr2 = "This goes to stderr, 2";
+        final File dummyExec =
+                createExecutable("dummy.sh", "echo " + stdout1, "echo " + stderr1
+                        + " > /dev/stderr", "echo " + stdout2, "echo " + stderr2 + " > /dev/stderr");
+        final ProcessResult result =
+                ProcessExecutionHelper.run(Arrays.asList(dummyExec.getAbsolutePath()),
+                        operationLog, machineLog, ConcurrencyUtilities.NO_TIMEOUT,
+                        OutputReadingStrategy.ALWAYS, true, false);
+        final int exitValue = result.getExitValue();
+        assertEquals(0, exitValue);
+        result.log();
+        assertTrue(result.isOutputAvailable());
+        assertTrue(result.isBinaryOutput());
+        assertEquals(2, result.getErrorOutput().size());
+        assertEquals(stderr1, result.getErrorOutput().get(0));
+        assertEquals(stderr2, result.getErrorOutput().get(1));
+        final String stdout = new String(result.getBinaryOutput());
+        assertEquals(stdout1 + "\n" + stdout2 + "\n", stdout);
+    }
+
+    @Test(groups =
+        { "requires_unix", "slow" })
+    public void testHangingExecLotsOfBinaryOutputOnStdOut() throws Exception
+    {
+        final File dummyExec = createExecutableEndlessDevURandom("iHangOnUrandom.sh");
+        final ProcessResult result =
+                ProcessExecutionHelper.run(Arrays.asList(dummyExec.getAbsolutePath()),
+                        operationLog, machineLog, WATCHDOG_WAIT_MILLIS,
+                        OutputReadingStrategy.ON_ERROR, true, false);
+        assertTrue(result.isTimedOut());
+        assertFalse(result.isOK());
+        assertTrue(result.getBinaryOutput().length > 1000);
+    }
+
     @Test(groups = "requires_unix")
     public void testStartupFailed()
     {