Statistics
| Branch: | Revision:

root / QMP / qmp-shell @ 1ab516ed

History | View | Annotate | Download (8.2 kB)

1 cedebdac Luiz Capitulino
#!/usr/bin/python
2 cedebdac Luiz Capitulino
#
3 9bed0d0d Luiz Capitulino
# Low-level QEMU shell on top of QMP.
4 cedebdac Luiz Capitulino
#
5 9bed0d0d Luiz Capitulino
# Copyright (C) 2009, 2010 Red Hat Inc.
6 cedebdac Luiz Capitulino
#
7 cedebdac Luiz Capitulino
# Authors:
8 cedebdac Luiz Capitulino
#  Luiz Capitulino <lcapitulino@redhat.com>
9 cedebdac Luiz Capitulino
#
10 cedebdac Luiz Capitulino
# This work is licensed under the terms of the GNU GPL, version 2.  See
11 cedebdac Luiz Capitulino
# the COPYING file in the top-level directory.
12 cedebdac Luiz Capitulino
#
13 cedebdac Luiz Capitulino
# Usage:
14 cedebdac Luiz Capitulino
#
15 cedebdac Luiz Capitulino
# Start QEMU with:
16 cedebdac Luiz Capitulino
#
17 9bed0d0d Luiz Capitulino
# # qemu [...] -qmp unix:./qmp-sock,server
18 cedebdac Luiz Capitulino
#
19 cedebdac Luiz Capitulino
# Run the shell:
20 cedebdac Luiz Capitulino
#
21 9bed0d0d Luiz Capitulino
# $ qmp-shell ./qmp-sock
22 cedebdac Luiz Capitulino
#
23 cedebdac Luiz Capitulino
# Commands have the following format:
24 cedebdac Luiz Capitulino
#
25 9bed0d0d Luiz Capitulino
#    < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
26 cedebdac Luiz Capitulino
#
27 cedebdac Luiz Capitulino
# For example:
28 cedebdac Luiz Capitulino
#
29 9bed0d0d Luiz Capitulino
# (QEMU) device_add driver=e1000 id=net1
30 9bed0d0d Luiz Capitulino
# {u'return': {}}
31 9bed0d0d Luiz Capitulino
# (QEMU)
32 cedebdac Luiz Capitulino
33 cedebdac Luiz Capitulino
import qmp
34 cedebdac Luiz Capitulino
import readline
35 9bed0d0d Luiz Capitulino
import sys
36 fa779b65 Daniel P. Berrange
import pprint
37 cedebdac Luiz Capitulino
38 9bed0d0d Luiz Capitulino
class QMPCompleter(list):
39 9bed0d0d Luiz Capitulino
    def complete(self, text, state):
40 9bed0d0d Luiz Capitulino
        for cmd in self:
41 9bed0d0d Luiz Capitulino
            if cmd.startswith(text):
42 9bed0d0d Luiz Capitulino
                if not state:
43 9bed0d0d Luiz Capitulino
                    return cmd
44 9bed0d0d Luiz Capitulino
                else:
45 9bed0d0d Luiz Capitulino
                    state -= 1
46 cedebdac Luiz Capitulino
47 9bed0d0d Luiz Capitulino
class QMPShellError(Exception):
48 9bed0d0d Luiz Capitulino
    pass
49 9bed0d0d Luiz Capitulino
50 9bed0d0d Luiz Capitulino
class QMPShellBadPort(QMPShellError):
51 9bed0d0d Luiz Capitulino
    pass
52 9bed0d0d Luiz Capitulino
53 9bed0d0d Luiz Capitulino
# TODO: QMPShell's interface is a bit ugly (eg. _fill_completion() and
54 9bed0d0d Luiz Capitulino
#       _execute_cmd()). Let's design a better one.
55 9bed0d0d Luiz Capitulino
class QMPShell(qmp.QEMUMonitorProtocol):
56 fa779b65 Daniel P. Berrange
    def __init__(self, address, pp=None):
57 9bed0d0d Luiz Capitulino
        qmp.QEMUMonitorProtocol.__init__(self, self.__get_address(address))
58 9bed0d0d Luiz Capitulino
        self._greeting = None
59 9bed0d0d Luiz Capitulino
        self._completer = None
60 fa779b65 Daniel P. Berrange
        self._pp = pp
61 9bed0d0d Luiz Capitulino
62 9bed0d0d Luiz Capitulino
    def __get_address(self, arg):
63 9bed0d0d Luiz Capitulino
        """
64 9bed0d0d Luiz Capitulino
        Figure out if the argument is in the port:host form, if it's not it's
65 9bed0d0d Luiz Capitulino
        probably a file path.
66 9bed0d0d Luiz Capitulino
        """
67 9bed0d0d Luiz Capitulino
        addr = arg.split(':')
68 9bed0d0d Luiz Capitulino
        if len(addr) == 2:
69 9bed0d0d Luiz Capitulino
            try:
70 9bed0d0d Luiz Capitulino
                port = int(addr[1])
71 9bed0d0d Luiz Capitulino
            except ValueError:
72 9bed0d0d Luiz Capitulino
                raise QMPShellBadPort
73 9bed0d0d Luiz Capitulino
            return ( addr[0], port )
74 9bed0d0d Luiz Capitulino
        # socket path
75 9bed0d0d Luiz Capitulino
        return arg
76 9bed0d0d Luiz Capitulino
77 9bed0d0d Luiz Capitulino
    def _fill_completion(self):
78 9bed0d0d Luiz Capitulino
        for cmd in self.cmd('query-commands')['return']:
79 9bed0d0d Luiz Capitulino
            self._completer.append(cmd['name'])
80 9bed0d0d Luiz Capitulino
81 9bed0d0d Luiz Capitulino
    def __completer_setup(self):
82 9bed0d0d Luiz Capitulino
        self._completer = QMPCompleter()
83 9bed0d0d Luiz Capitulino
        self._fill_completion()
84 9bed0d0d Luiz Capitulino
        readline.set_completer(self._completer.complete)
85 9bed0d0d Luiz Capitulino
        readline.parse_and_bind("tab: complete")
86 9bed0d0d Luiz Capitulino
        # XXX: default delimiters conflict with some command names (eg. query-),
87 9bed0d0d Luiz Capitulino
        # clearing everything as it doesn't seem to matter
88 9bed0d0d Luiz Capitulino
        readline.set_completer_delims('')
89 9bed0d0d Luiz Capitulino
90 9bed0d0d Luiz Capitulino
    def __build_cmd(self, cmdline):
91 9bed0d0d Luiz Capitulino
        """
92 9bed0d0d Luiz Capitulino
        Build a QMP input object from a user provided command-line in the
93 9bed0d0d Luiz Capitulino
        following format:
94 9bed0d0d Luiz Capitulino
    
95 9bed0d0d Luiz Capitulino
            < command-name > [ arg-name1=arg1 ] ... [ arg-nameN=argN ]
96 9bed0d0d Luiz Capitulino
        """
97 9bed0d0d Luiz Capitulino
        cmdargs = cmdline.split()
98 9bed0d0d Luiz Capitulino
        qmpcmd = { 'execute': cmdargs[0], 'arguments': {} }
99 9bed0d0d Luiz Capitulino
        for arg in cmdargs[1:]:
100 9bed0d0d Luiz Capitulino
            opt = arg.split('=')
101 9bed0d0d Luiz Capitulino
            try:
102 9bed0d0d Luiz Capitulino
                value = int(opt[1])
103 9bed0d0d Luiz Capitulino
            except ValueError:
104 9bed0d0d Luiz Capitulino
                value = opt[1]
105 9bed0d0d Luiz Capitulino
            qmpcmd['arguments'][opt[0]] = value
106 9bed0d0d Luiz Capitulino
        return qmpcmd
107 9bed0d0d Luiz Capitulino
108 9bed0d0d Luiz Capitulino
    def _execute_cmd(self, cmdline):
109 9bed0d0d Luiz Capitulino
        try:
110 9bed0d0d Luiz Capitulino
            qmpcmd = self.__build_cmd(cmdline)
111 9bed0d0d Luiz Capitulino
        except:
112 9bed0d0d Luiz Capitulino
            print 'command format: <command-name> ',
113 9bed0d0d Luiz Capitulino
            print '[arg-name1=arg1] ... [arg-nameN=argN]'
114 9bed0d0d Luiz Capitulino
            return True
115 9bed0d0d Luiz Capitulino
        resp = self.cmd_obj(qmpcmd)
116 9bed0d0d Luiz Capitulino
        if resp is None:
117 9bed0d0d Luiz Capitulino
            print 'Disconnected'
118 9bed0d0d Luiz Capitulino
            return False
119 fa779b65 Daniel P. Berrange
120 fa779b65 Daniel P. Berrange
        if self._pp is not None:
121 fa779b65 Daniel P. Berrange
            self._pp.pprint(resp)
122 fa779b65 Daniel P. Berrange
        else:
123 fa779b65 Daniel P. Berrange
            print resp
124 9bed0d0d Luiz Capitulino
        return True
125 9bed0d0d Luiz Capitulino
126 9bed0d0d Luiz Capitulino
    def connect(self):
127 9bed0d0d Luiz Capitulino
        self._greeting = qmp.QEMUMonitorProtocol.connect(self)
128 9bed0d0d Luiz Capitulino
        self.__completer_setup()
129 cedebdac Luiz Capitulino
130 9bed0d0d Luiz Capitulino
    def show_banner(self, msg='Welcome to the QMP low-level shell!'):
131 9bed0d0d Luiz Capitulino
        print msg
132 9bed0d0d Luiz Capitulino
        version = self._greeting['QMP']['version']['qemu']
133 9bed0d0d Luiz Capitulino
        print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro'])
134 cedebdac Luiz Capitulino
135 9bed0d0d Luiz Capitulino
    def read_exec_command(self, prompt):
136 9bed0d0d Luiz Capitulino
        """
137 9bed0d0d Luiz Capitulino
        Read and execute a command.
138 cedebdac Luiz Capitulino
139 9bed0d0d Luiz Capitulino
        @return True if execution was ok, return False if disconnected.
140 9bed0d0d Luiz Capitulino
        """
141 cedebdac Luiz Capitulino
        try:
142 9bed0d0d Luiz Capitulino
            cmdline = raw_input(prompt)
143 cedebdac Luiz Capitulino
        except EOFError:
144 cedebdac Luiz Capitulino
            print
145 9bed0d0d Luiz Capitulino
            return False
146 9bed0d0d Luiz Capitulino
        if cmdline == '':
147 9bed0d0d Luiz Capitulino
            for ev in self.get_events():
148 9bed0d0d Luiz Capitulino
                print ev
149 9bed0d0d Luiz Capitulino
            self.clear_events()
150 9bed0d0d Luiz Capitulino
            return True
151 cedebdac Luiz Capitulino
        else:
152 9bed0d0d Luiz Capitulino
            return self._execute_cmd(cmdline)
153 9bed0d0d Luiz Capitulino
154 11217a75 Luiz Capitulino
class HMPShell(QMPShell):
155 11217a75 Luiz Capitulino
    def __init__(self, address):
156 11217a75 Luiz Capitulino
        QMPShell.__init__(self, address)
157 11217a75 Luiz Capitulino
        self.__cpu_index = 0
158 11217a75 Luiz Capitulino
159 11217a75 Luiz Capitulino
    def __cmd_completion(self):
160 11217a75 Luiz Capitulino
        for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
161 11217a75 Luiz Capitulino
            if cmd and cmd[0] != '[' and cmd[0] != '\t':
162 11217a75 Luiz Capitulino
                name = cmd.split()[0] # drop help text
163 11217a75 Luiz Capitulino
                if name == 'info':
164 11217a75 Luiz Capitulino
                    continue
165 11217a75 Luiz Capitulino
                if name.find('|') != -1:
166 11217a75 Luiz Capitulino
                    # Command in the form 'foobar|f' or 'f|foobar', take the
167 11217a75 Luiz Capitulino
                    # full name
168 11217a75 Luiz Capitulino
                    opt = name.split('|')
169 11217a75 Luiz Capitulino
                    if len(opt[0]) == 1:
170 11217a75 Luiz Capitulino
                        name = opt[1]
171 11217a75 Luiz Capitulino
                    else:
172 11217a75 Luiz Capitulino
                        name = opt[0]
173 11217a75 Luiz Capitulino
                self._completer.append(name)
174 11217a75 Luiz Capitulino
                self._completer.append('help ' + name) # help completion
175 11217a75 Luiz Capitulino
176 11217a75 Luiz Capitulino
    def __info_completion(self):
177 11217a75 Luiz Capitulino
        for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
178 11217a75 Luiz Capitulino
            if cmd:
179 11217a75 Luiz Capitulino
                self._completer.append('info ' + cmd.split()[1])
180 11217a75 Luiz Capitulino
181 11217a75 Luiz Capitulino
    def __other_completion(self):
182 11217a75 Luiz Capitulino
        # special cases
183 11217a75 Luiz Capitulino
        self._completer.append('help info')
184 11217a75 Luiz Capitulino
185 11217a75 Luiz Capitulino
    def _fill_completion(self):
186 11217a75 Luiz Capitulino
        self.__cmd_completion()
187 11217a75 Luiz Capitulino
        self.__info_completion()
188 11217a75 Luiz Capitulino
        self.__other_completion()
189 11217a75 Luiz Capitulino
190 11217a75 Luiz Capitulino
    def __cmd_passthrough(self, cmdline, cpu_index = 0):
191 11217a75 Luiz Capitulino
        return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
192 11217a75 Luiz Capitulino
                              { 'command-line': cmdline,
193 11217a75 Luiz Capitulino
                                'cpu-index': cpu_index } })
194 11217a75 Luiz Capitulino
195 11217a75 Luiz Capitulino
    def _execute_cmd(self, cmdline):
196 11217a75 Luiz Capitulino
        if cmdline.split()[0] == "cpu":
197 11217a75 Luiz Capitulino
            # trap the cpu command, it requires special setting
198 11217a75 Luiz Capitulino
            try:
199 11217a75 Luiz Capitulino
                idx = int(cmdline.split()[1])
200 11217a75 Luiz Capitulino
                if not 'return' in self.__cmd_passthrough('info version', idx):
201 11217a75 Luiz Capitulino
                    print 'bad CPU index'
202 11217a75 Luiz Capitulino
                    return True
203 11217a75 Luiz Capitulino
                self.__cpu_index = idx
204 11217a75 Luiz Capitulino
            except ValueError:
205 11217a75 Luiz Capitulino
                print 'cpu command takes an integer argument'
206 11217a75 Luiz Capitulino
                return True
207 11217a75 Luiz Capitulino
        resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
208 11217a75 Luiz Capitulino
        if resp is None:
209 11217a75 Luiz Capitulino
            print 'Disconnected'
210 11217a75 Luiz Capitulino
            return False
211 11217a75 Luiz Capitulino
        assert 'return' in resp or 'error' in resp
212 11217a75 Luiz Capitulino
        if 'return' in resp:
213 11217a75 Luiz Capitulino
            # Success
214 11217a75 Luiz Capitulino
            if len(resp['return']) > 0:
215 11217a75 Luiz Capitulino
                print resp['return'],
216 11217a75 Luiz Capitulino
        else:
217 11217a75 Luiz Capitulino
            # Error
218 11217a75 Luiz Capitulino
            print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
219 11217a75 Luiz Capitulino
        return True
220 11217a75 Luiz Capitulino
221 11217a75 Luiz Capitulino
    def show_banner(self):
222 11217a75 Luiz Capitulino
        QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
223 11217a75 Luiz Capitulino
224 9bed0d0d Luiz Capitulino
def die(msg):
225 9bed0d0d Luiz Capitulino
    sys.stderr.write('ERROR: %s\n' % msg)
226 9bed0d0d Luiz Capitulino
    sys.exit(1)
227 9bed0d0d Luiz Capitulino
228 9bed0d0d Luiz Capitulino
def fail_cmdline(option=None):
229 9bed0d0d Luiz Capitulino
    if option:
230 9bed0d0d Luiz Capitulino
        sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option)
231 fa779b65 Daniel P. Berrange
    sys.stderr.write('qemu-shell [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n')
232 9bed0d0d Luiz Capitulino
    sys.exit(1)
233 9bed0d0d Luiz Capitulino
234 9bed0d0d Luiz Capitulino
def main():
235 11217a75 Luiz Capitulino
    addr = ''
236 fa779b65 Daniel P. Berrange
    qemu = None
237 fa779b65 Daniel P. Berrange
    hmp = False
238 fa779b65 Daniel P. Berrange
    pp = None
239 fa779b65 Daniel P. Berrange
240 9bed0d0d Luiz Capitulino
    try:
241 fa779b65 Daniel P. Berrange
        for arg in sys.argv[1:]:
242 fa779b65 Daniel P. Berrange
            if arg == "-H":
243 fa779b65 Daniel P. Berrange
                if qemu is not None:
244 fa779b65 Daniel P. Berrange
                    fail_cmdline(arg)
245 fa779b65 Daniel P. Berrange
                hmp = True
246 fa779b65 Daniel P. Berrange
            elif arg == "-p":
247 fa779b65 Daniel P. Berrange
                if pp is not None:
248 fa779b65 Daniel P. Berrange
                    fail_cmdline(arg)
249 fa779b65 Daniel P. Berrange
                pp = pprint.PrettyPrinter(indent=4)
250 fa779b65 Daniel P. Berrange
            else:
251 fa779b65 Daniel P. Berrange
                if qemu is not None:
252 fa779b65 Daniel P. Berrange
                    fail_cmdline(arg)
253 fa779b65 Daniel P. Berrange
                if hmp:
254 fa779b65 Daniel P. Berrange
                    qemu = HMPShell(arg)
255 fa779b65 Daniel P. Berrange
                else:
256 fa779b65 Daniel P. Berrange
                    qemu = QMPShell(arg, pp)
257 fa779b65 Daniel P. Berrange
                addr = arg
258 fa779b65 Daniel P. Berrange
259 fa779b65 Daniel P. Berrange
        if qemu is None:
260 fa779b65 Daniel P. Berrange
            fail_cmdline()
261 9bed0d0d Luiz Capitulino
    except QMPShellBadPort:
262 9bed0d0d Luiz Capitulino
        die('bad port number in command-line')
263 9bed0d0d Luiz Capitulino
264 9bed0d0d Luiz Capitulino
    try:
265 9bed0d0d Luiz Capitulino
        qemu.connect()
266 9bed0d0d Luiz Capitulino
    except qmp.QMPConnectError:
267 9bed0d0d Luiz Capitulino
        die('Didn\'t get QMP greeting message')
268 9bed0d0d Luiz Capitulino
    except qmp.QMPCapabilitiesError:
269 9bed0d0d Luiz Capitulino
        die('Could not negotiate capabilities')
270 9bed0d0d Luiz Capitulino
    except qemu.error:
271 11217a75 Luiz Capitulino
        die('Could not connect to %s' % addr)
272 9bed0d0d Luiz Capitulino
273 9bed0d0d Luiz Capitulino
    qemu.show_banner()
274 9bed0d0d Luiz Capitulino
    while qemu.read_exec_command('(QEMU) '):
275 9bed0d0d Luiz Capitulino
        pass
276 9bed0d0d Luiz Capitulino
    qemu.close()
277 cedebdac Luiz Capitulino
278 cedebdac Luiz Capitulino
if __name__ == '__main__':
279 cedebdac Luiz Capitulino
    main()