QMP/qmp-shell: Introduce HMP mode
In which qmp-shell will exclusively use the HMP passthrough feature,
this is useful for testing.
Example:
    # ./qmp-shell -H qmp-sock
    Welcome to the HMP shell!
    Connected to QEMU 0.13.50
    (QEMU) info network
    VLAN 0 devices:
      user.0: net=10.0.2.0, restricted=n
        e1000.0: model=e1000,macaddr=52:54:00:12:34:56
        Devices not on any VLAN:
    (QEMU)
Signed-off-by: Luiz Capitulino <lcapitulino@redhat.com>
			
			
This commit is contained in:
		
							parent
							
								
									0268d97c51
								
							
						
					
					
						commit
						11217a757e
					
				| 
						 | 
				
			
			@ -145,6 +145,76 @@ class QMPShell(qmp.QEMUMonitorProtocol):
 | 
			
		|||
        else:
 | 
			
		||||
            return self._execute_cmd(cmdline)
 | 
			
		||||
 | 
			
		||||
class HMPShell(QMPShell):
 | 
			
		||||
    def __init__(self, address):
 | 
			
		||||
        QMPShell.__init__(self, address)
 | 
			
		||||
        self.__cpu_index = 0
 | 
			
		||||
 | 
			
		||||
    def __cmd_completion(self):
 | 
			
		||||
        for cmd in self.__cmd_passthrough('help')['return'].split('\r\n'):
 | 
			
		||||
            if cmd and cmd[0] != '[' and cmd[0] != '\t':
 | 
			
		||||
                name = cmd.split()[0] # drop help text
 | 
			
		||||
                if name == 'info':
 | 
			
		||||
                    continue
 | 
			
		||||
                if name.find('|') != -1:
 | 
			
		||||
                    # Command in the form 'foobar|f' or 'f|foobar', take the
 | 
			
		||||
                    # full name
 | 
			
		||||
                    opt = name.split('|')
 | 
			
		||||
                    if len(opt[0]) == 1:
 | 
			
		||||
                        name = opt[1]
 | 
			
		||||
                    else:
 | 
			
		||||
                        name = opt[0]
 | 
			
		||||
                self._completer.append(name)
 | 
			
		||||
                self._completer.append('help ' + name) # help completion
 | 
			
		||||
 | 
			
		||||
    def __info_completion(self):
 | 
			
		||||
        for cmd in self.__cmd_passthrough('info')['return'].split('\r\n'):
 | 
			
		||||
            if cmd:
 | 
			
		||||
                self._completer.append('info ' + cmd.split()[1])
 | 
			
		||||
 | 
			
		||||
    def __other_completion(self):
 | 
			
		||||
        # special cases
 | 
			
		||||
        self._completer.append('help info')
 | 
			
		||||
 | 
			
		||||
    def _fill_completion(self):
 | 
			
		||||
        self.__cmd_completion()
 | 
			
		||||
        self.__info_completion()
 | 
			
		||||
        self.__other_completion()
 | 
			
		||||
 | 
			
		||||
    def __cmd_passthrough(self, cmdline, cpu_index = 0):
 | 
			
		||||
        return self.cmd_obj({ 'execute': 'human-monitor-command', 'arguments':
 | 
			
		||||
                              { 'command-line': cmdline,
 | 
			
		||||
                                'cpu-index': cpu_index } })
 | 
			
		||||
 | 
			
		||||
    def _execute_cmd(self, cmdline):
 | 
			
		||||
        if cmdline.split()[0] == "cpu":
 | 
			
		||||
            # trap the cpu command, it requires special setting
 | 
			
		||||
            try:
 | 
			
		||||
                idx = int(cmdline.split()[1])
 | 
			
		||||
                if not 'return' in self.__cmd_passthrough('info version', idx):
 | 
			
		||||
                    print 'bad CPU index'
 | 
			
		||||
                    return True
 | 
			
		||||
                self.__cpu_index = idx
 | 
			
		||||
            except ValueError:
 | 
			
		||||
                print 'cpu command takes an integer argument'
 | 
			
		||||
                return True
 | 
			
		||||
        resp = self.__cmd_passthrough(cmdline, self.__cpu_index)
 | 
			
		||||
        if resp is None:
 | 
			
		||||
            print 'Disconnected'
 | 
			
		||||
            return False
 | 
			
		||||
        assert 'return' in resp or 'error' in resp
 | 
			
		||||
        if 'return' in resp:
 | 
			
		||||
            # Success
 | 
			
		||||
            if len(resp['return']) > 0:
 | 
			
		||||
                print resp['return'],
 | 
			
		||||
        else:
 | 
			
		||||
            # Error
 | 
			
		||||
            print '%s: %s' % (resp['error']['class'], resp['error']['desc'])
 | 
			
		||||
        return True
 | 
			
		||||
 | 
			
		||||
    def show_banner(self):
 | 
			
		||||
        QMPShell.show_banner(self, msg='Welcome to the HMP shell!')
 | 
			
		||||
 | 
			
		||||
def die(msg):
 | 
			
		||||
    sys.stderr.write('ERROR: %s\n' % msg)
 | 
			
		||||
    sys.exit(1)
 | 
			
		||||
| 
						 | 
				
			
			@ -156,9 +226,16 @@ def fail_cmdline(option=None):
 | 
			
		|||
    sys.exit(1)
 | 
			
		||||
 | 
			
		||||
def main():
 | 
			
		||||
    addr = ''
 | 
			
		||||
    try:
 | 
			
		||||
        if len(sys.argv) == 2:
 | 
			
		||||
            qemu = QMPShell(sys.argv[1])
 | 
			
		||||
            addr = sys.argv[1]
 | 
			
		||||
        elif len(sys.argv) == 3:
 | 
			
		||||
            if sys.argv[1] != '-H':
 | 
			
		||||
                fail_cmdline(sys.argv[1])
 | 
			
		||||
            qemu = HMPShell(sys.argv[2])
 | 
			
		||||
            addr = sys.argv[2]
 | 
			
		||||
        else:
 | 
			
		||||
                fail_cmdline()
 | 
			
		||||
    except QMPShellBadPort:
 | 
			
		||||
| 
						 | 
				
			
			@ -171,7 +248,7 @@ def main():
 | 
			
		|||
    except qmp.QMPCapabilitiesError:
 | 
			
		||||
        die('Could not negotiate capabilities')
 | 
			
		||||
    except qemu.error:
 | 
			
		||||
        die('Could not connect to %s' % sys.argv[1])
 | 
			
		||||
        die('Could not connect to %s' % addr)
 | 
			
		||||
 | 
			
		||||
    qemu.show_banner()
 | 
			
		||||
    while qemu.read_exec_command('(QEMU) '):
 | 
			
		||||
| 
						 | 
				
			
			
 | 
			
		|||
		Loading…
	
		Reference in New Issue