summaryrefslogtreecommitdiff
path: root/scripts/xspice
blob: f41161977c0d6acabc9339e58964ff528e348c03 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
#!/usr/bin/python

"""
xspice

xspice is a standard X server that is also a Spice server.

It is implemented as a module with video, mouse and keyboard drivers.

The video driver is mostly the same code as the qxl guest driver, hence
xspice is kept in the same repository. It can also be used to debug the qxl
driver.

xspice (this executable) will set a bunch of environment variables that are
used by spiceqxl_drv.so, and then exec Xorg, giving it the default config file,
which can be overridden as well.
"""

import argparse
import os
import sys

def which(x):
    for p in os.environ['PATH'].split(':'):
        candidate = os.path.join(p, x)
        if os.path.exists(candidate):
            return candidate
    return None

cgdb = which('cgdb') if os.path.exists(
    os.path.join(os.path.dirname(sys.modules[__name__].__file__),
                 'Makefile.am')) else None

def add_boolean(flag, *args, **kw):
    parser.add_argument(flag, action='store_const', const='1', default='0',
                        *args, **kw)

wan_compression_options = ['auto', 'never', 'always']
parser = argparse.ArgumentParser("xspice",
    description="X and Spice server. example usage: xspice --port 5900 --disable-ticketing :1.0",
    usage="xspice [xspice and Xorg options intermixed]",
    epilog="Any options not parsed by xspice get passed to Xorg as is.")
parser.add_argument('--xorg', default=which('Xorg'))
parser.add_argument('--config', default='spiceqxl.xorg.conf')
# Don't use any options that are already used by Xorg (unless we must)
# specifically, don't use -p and -s.
parser.add_argument('--port', type=int, help='standard spice port')
parser.add_argument('--tls-port', type=int, help='spice tls port')
add_boolean('--disable-ticketing', help="do not require a client password")
add_boolean('--sasl', help="enable sasl")
parser.add_argument('--x509-dir', help="x509 directory for tls", default='.')
parser.add_argument('--cacert-file', help="ca certificate file for tls")
parser.add_argument('--x509-cert-file', help="server certificate file for tls")
parser.add_argument('--x509-key-file', help="server key file for tls")
parser.add_argument('--x509-key-password', help="key file password for tls")
parser.add_argument('--tls-ciphers')
parser.add_argument('--dh-file')
parser.add_argument('--password', help="set password required to connect to server")
parser.add_argument('--image-compression',
                    choices = ['off', 'auto_glz', 'auto_lz', 'quic',
                               'glz', 'lz'],
                    default='auto_glz', help='auto_glz by default')
parser.add_argument('--jpeg-wan-compression',
                    choices=wan_compression_options,
                    default='auto', help='auto by default')
parser.add_argument('--zlib-glz-wan-compression',
                    choices=wan_compression_options,
                    default='auto', help='auto by default')
# TODO - sound support
#parser.add_argument('--playback-compression', choices=['0', '1'], default='1', help='enabled by default')
parser.add_argument('--streaming-video', choices=['off', 'all', 'filter'],
                    default='filter', help='filter by default')
add_boolean('--ipv4-only')
add_boolean('--ipv6-only')

if cgdb:
    parser.add_argument('--cgdb', action='store_true', default=False)
# TODO:
#add_boolean(parser, '--agent-mouse')

args, xorg_args = parser.parse_known_args(sys.argv[1:])

def tls_files(args):
    if args.tls_port == 0:
        return {}
    files = {}
    for k, var in [('ca-cert', 'cacert_file'),
                   ('server-key', 'x509_key_file'),
                   ('server-cert', 'x509_cert_file')]:
        files[k] = os.path.join(args.x509_dir, k + '.pem')
        if getattr(args, var):
            files[k] = getattr(args, var)
    return files

# XXX spice-server aborts if it can't find the certificates - avoid by checking
# ourselves. This isn't exhaustive - if the server key requires a password
# and it isn't supplied spice will still abort, and Xorg with it.
for key, filename in tls_files(args).items():
    if not os.path.exists(filename):
        print "missing %s - %s does not exist" % (key, filename)
        sys.exit(1)

def error(msg, exit_code=1):
    print "xspice: %s" % msg
    sys.exit(exit_code)

if not args.xorg:
    error("Xorg missing")

var_args = ['port', 'tls_port', 'disable_ticketing',
    'x509_dir', 'sasl', 'cacert_file', 'x509_cert_file',
    'x509_key_file', 'x509_key_password',
    'tls_ciphers', 'dh_file', 'password', 'image_compression',
    'jpeg_wan_compression', 'zlib_glz_wan_compression',
    'streaming_video']
for arg in var_args:
    if getattr(args, arg):
        os.environ['XSPICE_' + arg.upper()] = str(getattr(args, arg))

exec_args = [args.xorg, '-config', args.config]
if cgdb and args.cgdb:
    exec_args = [cgdb, '--args'] + exec_args
    args.xorg = cgdb

os.execv(args.xorg, exec_args + xorg_args)