summaryrefslogtreecommitdiff
path: root/xspice
blob: 8e739956d1c45e12062612e8ffdc4a09626619d5 (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
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
#!/usr/bin/env python

"""
Xspice launcher and tester. Either run as "xspice" and it launches Xspice :10.0,
then icewm, then gimp, and then remote-viewer, or run with "xspice test" and it
will quit after two seconds from launching remote-viewer, and return a non 0
exit code for any problem (Xspice not loading).
"""

import sys
import os
import subprocess
import time
import atexit
import argparse

processes = []
def launch(*args, **kw):
    p = subprocess.Popen(*args, **kw)
    processes.append(p)
    return p

def cleanup(*args):
    for p in reversed(processes):
        print "terminating %d" % p.pid
        try:
            p.terminate()
        except OSError:
            pass
    time.sleep(0.5)
    for p in reversed(processes):
        try:
            p.kill()
        except OSError:
            pass

atexit.register(cleanup)

VALGRIND=None
#VALGRIND="valgrind --leak-check=full --track-origins=yes --log-file=/tmp/xspice.valgrind.log".split()
#--trace-children=yes --tool=callgrind

def which(x):
    return subprocess.check_output(['which', x]).strip()

###################################
os.system("xspice-local-xkbcomp")

def launch_xspice(dnum, port, args):
    display = ":%(dnum)s.0" % locals()
    which_python = which('python')
    which_Xspice = which('Xspice')

    cmd = [x % locals() for x in ["%(which_python)s",
        "%(which_Xspice)s", display, "--port", "%(port)s", "--disable-ticketing",
        ]] + args
    TLS_PORT_PARAMS = ["--tls-port", "0"]
    if VALGRIND:
        cmd = VALGRIND + cmd
    print ' '.join(cmd)
    logfile = open(os.path.expanduser('~/.Xspice.%(dnum)s.log' % locals()), 'w+')

    Xspice = launch(cmd, stdout=logfile, stderr=logfile)
    #$VALGRIND `which python` `which Xspice` :$DNUM.0 --port $PORT --disable-ticketing --tls-port 0 $* >

    spiceqxl = None
    with open('/proc/%s/maps' % Xspice.pid) as fd:
        spiceqxl_cand = [l.strip().split()[-1] for l in fd.readlines() if 'spiceqxl' in l]
        if len(spiceqxl_cand) == 1:
            spiceqxl = spiceqxl_cand[0]

    if not spiceqxl:
        # Cannot read /proc/Xspice.pid/maps since it's running as root, go the
        # second route
        for lib in ['lib', 'lib64']:
            spiceqxl = os.path.join(which_Xspice.rsplit('/', 2)[0],
                            lib, 'xorg/modules/drivers/spiceqxl_drv.so')
            if os.path.exists(spiceqxl):
                break
        print spiceqxl
        assert(os.path.exists(spiceqxl))
    Xspice.display = display
    Xspice.spiceqxl = spiceqxl
    Xspice.dnum = dnum
    return Xspice

def port_available_via_netstat(port):
    """
    (Not all processes could be identified, non-owned process info
             will not be shown, you would have to be root to see it all.)
    tcp        0      0 0.0.0.0:5900            0.0.0.0:*               LISTEN      23216/Xorg           off (0.00/0/0)
    tcp        0      0 0.0.0.0:6010            0.0.0.0:*               LISTEN      23216/Xorg           off (0.00/0/0)
    tcp6       0      0 :::6010                 :::*                    LISTEN      23216/Xorg           off (0.00/0/0)
    """
    lines = subprocess.check_output(['netstat', '-ltUnop']).split('\n')
    port_lines = [l for l in lines if str(port) in l]
    return len(port_lines) > 0

def wait_for_xspice_load(xspice):
    expected = 6000 + xspice.dnum
    while True:
        if port_available_via_netstat(expected):
            return
        time.sleep(0.5)
        print "."
        if xspice.poll() is not None:
            # process has quit
            raise Exception("Xspice died")

def test_xspice():
    spiceqxl, Xspice = launch_xspice(':10.0', args = [])

def main(wait=True):
    parser = argparse.ArgumentParser()
    parser.add_argument('--num', type=int, default=10)
    args, rest = parser.parse_known_args(sys.argv[1:])
    DNUM = args.num
    PORT = 15000 + DNUM
    print "%s %s" % (DNUM, PORT)

    Xspice = launch_xspice(dnum=DNUM, port=PORT, args=rest)
    spiceqxl = Xspice.spiceqxl
    display = Xspice.display
    seconds_ago = time.time() - os.stat(spiceqxl).st_ctime
    print "age: %d:%2d:%2d old (%s)" % (seconds_ago // 3600,
                (seconds_ago // 60) % 60, seconds_ago % 60, spiceqxl)

    #time.sleep(3)
    wait_for_xspice_load(Xspice)

    client_display = os.environ['DISPLAY']
    os.environ['DISPLAY'] = display
    icewm = launch(['icewm'])
    #DISPLAY=:$DNUM.0 firefox --no-remote -P spice_xpi_test &
    red = launch(['test-red'])
    gimp = launch(['gimp'])
    os.environ['DISPLAY'] = client_display
    remote_viewer = launch(['remote-viewer', 'spice://localhost:%s' % PORT])
    if wait:
        remote_viewer.wait()
    else:
        time.sleep(2.0)
        # and quit

if __name__ == '__main__':
    main()