Statistics
| Branch: | Revision:

root / QMP / qmp-shell @ 39bffca2

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