Coverage for /home/antoine/projects/xpra-git/dist/python3/lib64/python/xpra/server/source/shell_mixin.py : 95%
Hot-keys on this page
r m x p toggle line displays
j k next/prev highlighted chunk
0 (zero) top of page
1 (one) first highlighted chunk
1# -*- coding: utf-8 -*-
2# This file is part of Xpra.
3# Copyright (C) 2020 Antoine Martin <antoine@xpra.org>
4# Xpra is released under the terms of the GNU GPL v2, or, at your option, any
5# later version. See the file COPYING for details.
7import io
8from contextlib import redirect_stdout, redirect_stderr
10from xpra.util import typedict
11from xpra.scripts.config import TRUE_OPTIONS
12from xpra.server.source.stub_source_mixin import StubSourceMixin
13from xpra.log import Logger
15log = Logger("exec")
18class ShellMixin(StubSourceMixin):
20 @classmethod
21 def is_needed(cls, caps : typedict) -> bool:
22 return caps.boolget("shell", False)
24 def __init__(self, *_args):
25 self._server = None
26 self.shell_enabled = False
27 self.saved_logging_handler = None
28 self.log_records = []
29 self.log_thread = None
31 def init_from(self, protocol, server):
32 self._server = server
33 try:
34 options = protocol._conn.options
35 shell = options.get("shell", "")
36 self.shell_enabled = shell.lower() in TRUE_OPTIONS
37 except AttributeError:
38 options = {}
39 self.shell_enabled = False
40 log("init_from(%s, %s) shell_enabled(%s)=%s", protocol, server, options, self.shell_enabled)
42 def get_caps(self) -> dict:
43 return {"shell" : self.shell_enabled}
45 def get_info(self) -> dict:
46 return {"shell" : self.shell_enabled}
48 def shell_exec(self, code):
49 stdout, stderr = self.do_shell_exec(code)
50 log("shell_exec(%s) stdout=%r", code, stdout)
51 log("shell_exec(%s) stderr=%r", code, stderr)
52 if stdout is not None:
53 self.send("shell-reply", 1, stdout)
54 if stderr:
55 self.send("shell-reply", 2, stderr)
56 return stdout, stderr
58 def do_shell_exec(self, code):
59 log("shell_exec(%r)", code)
60 try:
61 assert self.shell_enabled, "shell support is not available with this connection"
62 _globals = {
63 "connection" : self,
64 "server" : self._server,
65 "log" : log,
66 }
67 stdout = io.StringIO()
68 stderr = io.StringIO()
69 with redirect_stdout(stdout):
70 with redirect_stderr(stderr):
71 exec(code, _globals, {})
72 return stdout.getvalue().encode("utf8"), stderr.getvalue().encode("utf8")
73 except Exception as e:
74 log("shell_exec(..)", exc_info=True)
75 log.error("Error running %r:", code)
76 log.error(" %s", e)
77 return None, str(e)