diff --git a/bob/devtools/bootstrap.py b/bob/devtools/bootstrap.py
index 585f013218dedb9debc790e82c7f2f315841896b..01c415c1790ac0e064d2c0a03802a254876a2ad7 100644
--- a/bob/devtools/bootstrap.py
+++ b/bob/devtools/bootstrap.py
@@ -36,9 +36,12 @@ _INTERVALS = (
 
 import os
 import sys
+import pty
 import glob
 import time
+import errno
 import shutil
+import select
 import platform
 import subprocess
 
@@ -93,6 +96,9 @@ def human_time(seconds, granularity=2):
 def run_cmdline(cmd, env=None):
   '''Runs a command on a environment, logs output and reports status
 
+  Copied from: https://github.com/terminal-labs/cli-passthrough, which is in
+  turn based on https://stackoverflow.com/a/31953436.
+
 
   Parameters:
 
@@ -108,16 +114,43 @@ def run_cmdline(cmd, env=None):
   logger.info('(system) %s' % ' '.join(cmd))
 
   start = time.time()
-  out = b''
-
-  p = subprocess.Popen(cmd, stdout=subprocess.PIPE, stderr=subprocess.STDOUT,
-      env=env, bufsize=1, universal_newlines=True)
 
-  for line in iter(p.stdout.readline, ''):
-    sys.stdout.write(line)
-    sys.stdout.flush()
-
-  if p.wait() != 0:
+  masters, slaves = zip(pty.openpty(), pty.openpty())
+
+  with subprocess.Popen(cmd, stdin=slaves[0], stdout=slaves[0],
+      stderr=slaves[1], env=env) as p:
+
+    for fd in slaves:
+      os.close(fd) # no input
+      readable = {
+          masters[0]: sys.stdout.buffer, # store buffers seperately
+          masters[1]: sys.stderr.buffer,
+          }
+
+    while readable:
+
+      for fd in select.select(readable, [], [])[0]:
+        try:
+          data = os.read(fd, 1024) # read available
+        except OSError as e:
+          if e.errno != errno.EIO:
+            raise #XXX cleanup
+          del readable[fd] # EIO means EOF on some systems
+        else:
+          if not data: # EOF
+            del readable[fd]
+          else:
+            if fd == masters[0]: # We caught stdout
+              utils.echo(data.rstrip())
+            else: # We caught stderr
+              utils.echo(data.rstrip(), err=True)
+
+            readable[fd].flush()
+
+  for fd in masters:
+      os.close(fd)
+
+  if p.returncode != 0:
     raise RuntimeError("command `%s' exited with error state (%d)" % \
         (' '.join(cmd), p.returncode))
 
@@ -126,7 +159,6 @@ def run_cmdline(cmd, env=None):
   logger.info('command took %s' % human_time(total))
 
 
-
 def touch(path):
   '''Python-implementation of the "touch" command-line application'''