qvm-run: color untrusted stderr even when stdout is redirected

When stdout is redirected to some file or command two things will
happen:
 - qvm-run will not automatically color the output as stdout is not a
 TTY
 - even when coloring is forced, it will not work, as the control
 sequence (on stdout) will be redirected anyway

Fix this by handling stdout and stderr independently and output color
switching sequence to each of them.

Fixes QubesOS/qubes-issues#2190
This commit is contained in:
Marek Marczykowski-Górecki 2016-07-29 11:20:21 +02:00
parent 6a516caee2
commit 86a14b53fb
No known key found for this signature in database
GPG Key ID: 063938BA42CFA724

View File

@ -47,7 +47,9 @@ def vm_run_cmd(vm, cmd, options):
if options.verbose: if options.verbose:
print >> sys.stderr, "Running command on VM: '{0}'...".format(vm.name) print >> sys.stderr, "Running command on VM: '{0}'...".format(vm.name)
if options.passio and options.color_output is not None: if options.passio and options.color_output is not None:
print "\033[0;%dm" % options.color_output, sys.stdout.write("\033[0;{}m".format(options.color_output))
if options.passio and options.color_stderr is not None:
sys.stderr.write("\033[0;{}m".format(options.color_stderr))
try: try:
def tray_notify_generic(level, str): def tray_notify_generic(level, str):
@ -65,6 +67,8 @@ def vm_run_cmd(vm, cmd, options):
except QubesException as err: except QubesException as err:
if options.passio and options.color_output is not None: if options.passio and options.color_output is not None:
sys.stdout.write("\033[0m") sys.stdout.write("\033[0m")
if options.passio and options.color_stderr is not None:
sys.stderr.write("\033[0m")
if options.tray: if options.tray:
tray_notify_error(str(err)) tray_notify_error(str(err))
notify_error_qubes_manager(vm.name, str(err)) notify_error_qubes_manager(vm.name, str(err))
@ -73,6 +77,8 @@ def vm_run_cmd(vm, cmd, options):
finally: finally:
if options.passio and options.color_output is not None: if options.passio and options.color_output is not None:
sys.stdout.write("\033[0m") sys.stdout.write("\033[0m")
if options.passio and options.color_stderr is not None:
sys.stderr.write("\033[0m")
def main(): def main():
usage = "usage: %prog [options] [<vm-name>] [<cmd>]" usage = "usage: %prog [options] [<vm-name>] [<cmd>]"
@ -122,11 +128,20 @@ def main():
dest="color_output", default=None, dest="color_output", default=None,
help="Disable marking VM output with red color") help="Disable marking VM output with red color")
parser.add_option("--no-color-stderr", action="store_false",
dest="color_stderr", default=None,
help="Disable marking VM stderr with red color")
parser.add_option("--color-output", action="store", type="int", parser.add_option("--color-output", action="store", type="int",
dest="color_output", dest="color_output",
help="Force marking VM output with given ANSI style (" help="Force marking VM output with given ANSI style ("
"use 31 for red)") "use 31 for red)")
parser.add_option("--color-stderr", action="store", type="int",
dest="color_stderr",
help="Force marking VM stderr with given ANSI style ("
"use 31 for red)")
(options, args) = parser.parse_args () (options, args) = parser.parse_args ()
if (options.passio and not options.localcmd) and options.run_on_all_running: if (options.passio and not options.localcmd) and options.run_on_all_running:
@ -145,6 +160,12 @@ def main():
elif options.color_output is False: elif options.color_output is False:
options.color_output = None options.color_output = None
if options.color_stderr is None:
if os.isatty(sys.stderr.fileno()) and not options.localcmd:
options.color_stderr = 31
elif options.color_stderr is False:
options.color_stderr = None
if (options.pause or options.unpause): if (options.pause or options.unpause):
takes_cmd_argument = False takes_cmd_argument = False
else: else: