From aa3b167f21588a87e7783ac29aa54b0c721eb37a Mon Sep 17 00:00:00 2001 From: John Snow Date: Thu, 27 Apr 2017 18:36:28 -0400 Subject: qmp-shell: add persistent command history Use the existing readline history function we are utilizing to provide persistent command history across instances of qmp-shell. This assists entering debug commands across sessions that may be interrupted by QEMU sessions terminating, where the qmp-shell has to be relaunched. Signed-off-by: John Snow Message-Id: <20170427223628.20893-1-jsnow@redhat.com> Reviewed-by: Stefan Hajnoczi Reviewed-by: Kashyap Chamarthy Tested-by: Kashyap Chamarthy Signed-off-by: Markus Armbruster --- scripts/qmp/qmp-shell | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) (limited to 'scripts/qmp') diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index eccb88a4e8..6ece6e7c81 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -70,6 +70,9 @@ import json import ast import readline import sys +import os +import errno +import atexit class QMPCompleter(list): def complete(self, text, state): @@ -109,6 +112,8 @@ class QMPShell(qmp.QEMUMonitorProtocol): self._pretty = pretty self._transmode = False self._actions = list() + self._histfile = os.path.join(os.path.expanduser('~'), + '.qmp-shell_history') def __get_address(self, arg): """ @@ -132,11 +137,27 @@ class QMPShell(qmp.QEMUMonitorProtocol): def __completer_setup(self): self._completer = QMPCompleter() self._fill_completion() + readline.set_history_length(1024) readline.set_completer(self._completer.complete) readline.parse_and_bind("tab: complete") # XXX: default delimiters conflict with some command names (eg. query-), # clearing everything as it doesn't seem to matter readline.set_completer_delims('') + try: + readline.read_history_file(self._histfile) + except Exception as e: + if isinstance(e, IOError) and e.errno == errno.ENOENT: + # File not found. No problem. + pass + else: + print "Failed to read history '%s'; %s" % (self._histfile, e) + atexit.register(self.__save_history) + + def __save_history(self): + try: + readline.write_history_file(self._histfile) + except Exception as e: + print "Failed to save history file '%s'; %s" % (self._histfile, e) def __parse_value(self, val): try: -- cgit v1.2.3-55-g7522 From c5e397df9e247bff2398400864cde94d1b40317c Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 4 May 2017 16:54:29 +0400 Subject: qmp-shell: add -N option to skip negotiate qemu-ga doesn't have negotiate phase. Signed-off-by: Marc-André Lureau Message-Id: <20170504125432.21653-2-marcandre.lureau@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qmp/qmp-shell | 11 +++++++---- 1 file changed, 7 insertions(+), 4 deletions(-) (limited to 'scripts/qmp') diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 6ece6e7c81..b4d2dbd292 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -277,8 +277,8 @@ class QMPShell(qmp.QEMUMonitorProtocol): self._print(resp) return True - def connect(self): - self._greeting = qmp.QEMUMonitorProtocol.connect(self) + def connect(self, negotiate): + self._greeting = qmp.QEMUMonitorProtocol.connect(self, negotiate) self.__completer_setup() def show_banner(self, msg='Welcome to the QMP low-level shell!'): @@ -390,7 +390,7 @@ def die(msg): def fail_cmdline(option=None): if option: sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option) - sys.stderr.write('qemu-shell [ -v ] [ -p ] [ -H ] < UNIX socket path> | < TCP address:port >\n') + sys.stderr.write('qemu-shell [ -v ] [ -p ] [ -H ] [ -N ] < UNIX socket path> | < TCP address:port >\n') sys.exit(1) def main(): @@ -399,6 +399,7 @@ def main(): hmp = False pretty = False verbose = False + negotiate = True try: for arg in sys.argv[1:]: @@ -408,6 +409,8 @@ def main(): hmp = True elif arg == "-p": pretty = True + elif arg == "-N": + negotiate = False elif arg == "-v": verbose = True else: @@ -425,7 +428,7 @@ def main(): die('bad port number in command-line') try: - qemu.connect() + qemu.connect(negotiate) except qmp.QMPConnectError: die('Didn\'t get QMP greeting message') except qmp.QMPCapabilitiesError: -- cgit v1.2.3-55-g7522 From daa5a72ebab20345da474ee2f6148a8dacd2cb17 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 4 May 2017 16:54:30 +0400 Subject: qmp-shell: Cope with query-commands error qemu-ga doesn't implement it. Signed-off-by: Marc-André Lureau Message-Id: <20170504125432.21653-3-marcandre.lureau@redhat.com> Reviewed-by: Eric Blake [Commit message tweaked] Signed-off-by: Markus Armbruster --- scripts/qmp/qmp-shell | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) (limited to 'scripts/qmp') diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index b4d2dbd292..1182f823ef 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -131,7 +131,10 @@ class QMPShell(qmp.QEMUMonitorProtocol): return arg def _fill_completion(self): - for cmd in self.cmd('query-commands')['return']: + cmds = self.cmd('query-commands') + if cmds.has_key('error'): + return + for cmd in cmds['return']: self._completer.append(cmd['name']) def __completer_setup(self): -- cgit v1.2.3-55-g7522 From b13d2ff3de2d1f79107a376e883bcb8336f75d4d Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 4 May 2017 16:54:31 +0400 Subject: qmp-shell: don't show version greeting if unavailable qemu-ga doesn't have greeting. Signed-off-by: Marc-André Lureau Message-Id: <20170504125432.21653-4-marcandre.lureau@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qmp/qmp-shell | 3 +++ 1 file changed, 3 insertions(+) (limited to 'scripts/qmp') diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 1182f823ef..5986e3740c 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -286,6 +286,9 @@ class QMPShell(qmp.QEMUMonitorProtocol): def show_banner(self, msg='Welcome to the QMP low-level shell!'): print msg + if not self._greeting: + print 'Connected' + return version = self._greeting['QMP']['version']['qemu'] print 'Connected to QEMU %d.%d.%d\n' % (version['major'],version['minor'],version['micro']) -- cgit v1.2.3-55-g7522 From dcd3b25d656d346205dc0f2254723fccf0264e45 Mon Sep 17 00:00:00 2001 From: Marc-André Lureau Date: Thu, 4 May 2017 16:54:32 +0400 Subject: qmp-shell: improve help Describe the arguments & fix the tool name. Signed-off-by: Marc-André Lureau Message-Id: <20170504125432.21653-5-marcandre.lureau@redhat.com> Reviewed-by: Eric Blake Signed-off-by: Markus Armbruster --- scripts/qmp/qmp-shell | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) (limited to 'scripts/qmp') diff --git a/scripts/qmp/qmp-shell b/scripts/qmp/qmp-shell index 5986e3740c..860ffb27f2 100755 --- a/scripts/qmp/qmp-shell +++ b/scripts/qmp/qmp-shell @@ -396,7 +396,11 @@ def die(msg): def fail_cmdline(option=None): if option: sys.stderr.write('ERROR: bad command-line option \'%s\'\n' % option) - sys.stderr.write('qemu-shell [ -v ] [ -p ] [ -H ] [ -N ] < UNIX socket path> | < TCP address:port >\n') + sys.stderr.write('qmp-shell [ -v ] [ -p ] [ -H ] [ -N ] < UNIX socket path> | < TCP address:port >\n') + sys.stderr.write(' -v Verbose (echo command sent and received)\n') + sys.stderr.write(' -p Pretty-print JSON\n') + sys.stderr.write(' -H Use HMP interface\n') + sys.stderr.write(' -N Skip negotiate (for qemu-ga)\n') sys.exit(1) def main(): -- cgit v1.2.3-55-g7522