Hello World in Qemu

This is the second post in the series “HOWTO: Add libvirt support for a qemu command”

This first patch shows the implementation of the ‘hello’ monitor command in qemu. The command is simple — merely printing a greeting in English or Spanish and with punctuation if requested. The command synopsis looks like this:

hello [-e] [language]

  • if -e is specified, the greeting will be punctuated with exclamation marks
  • language may be specified as either ‘english or ‘spanish’. If ommitted, english is used.

Next we will walk through the patch to explain the implementation. You can view the patch here.

commit 468da14f29552f415413864ea848310c9ad6efe9
Author: Adam Litke <agl@us.ibm.com>
Date:   Thu Apr 7 08:25:58 2011 -0500

    hello: Add a simple hello world monitor command to qemu
    
    Signed-off-by: Adam Litke <agl@us.ibm.com>

diff --git a/hmp-commands.hx b/hmp-commands.hx
index 372bef4..dd2ad7d 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -10,6 +10,21 @@ STEXI
 ETEXI
 
     {
+        .name       = "hello",
+        .args_type  = "exclaim:-e,lang:s?",
+        .params     = "[-e] [language]",
+        .help       = "Say hello",
+        .user_print = monitor_print_hello,
+        .mhandler.cmd_new = do_hello,
+    },
+
+STEXI
+@item hello
+@findex hello
+Say hello to QEMU.
+ETEXI
+
+    {
         .name       = "help|?",
         .args_type  = "name:s?",
         .params     = "[cmd]",

This first part of the patch declares the command for the human monitor. hmp_commands.hx contains a list of these command declarations. Here you set the command name, argument synopsis, help text, command handler, and a function that will be called to print the results.

diff --git a/monitor.c b/monitor.c
index 7fc311d..957ea01 100644
--- a/monitor.c
+++ b/monitor.c
@@ -360,6 +360,7 @@ static void monitor_json_emitter(Monitor *mon, const QObject *data)
     qstring_append_chr(json, '\n');
     monitor_puts(mon, qstring_get_str(json));
 
+    printf("-> %s\n", qstring_get_str(json));
     QDECREF(json);
 }
 

I included this bit of debugging code for convenience. This will echo all JSON responses from the qmp monitor to standard out. I found this very helpful when debugging libvirt/qemu interactions.

@@ -1004,6 +1005,47 @@ static void do_info_trace_events(Monitor *mon)
 }
 #endif
 
+static void monitor_print_hello(Monitor *mon, const QObject *data)
+{
+    QDict *qdict;
+
+    qdict = qobject_to_qdict(data);
+    if (!qdict_haskey(qdict, "response"))
+        return;
+
+    monitor_printf(mon, "%s\n", qdict_get_str(qdict, "response"));
+}
+
+/**
+ * do_hello(): Implement the sample hello command
+ */
+static int do_hello(Monitor *mon, const QDict *qdict, QObject **ret_data)
+{
+    int exclaim = qdict_get_try_bool(qdict, "exclaim", 0);
+    const char *lang = qdict_get_try_str(qdict, "lang");
+    char *resp;
+    int rc;
+
+    if (!lang || !strcmp(lang, "english"))
+	    rc = asprintf(&resp, "%s%s", "Hello world", exclaim ? "!" : "");
+    else if (!strcmp(lang, "spanish"))
+        rc = asprintf(&resp, "%s%s%s", exclaim ? "¡" : "",
+                 "Hola mundo", exclaim ? "!" : "");
+    else {
+        qerror_report(QERR_INVALID_PARAMETER, "lang");
+        return -1;
+    }
+
+    if (rc == -1) {
+        qerror_report(QERR_UNDEFINED_ERROR);
+        return -1;
+    }
+
+    *ret_data = qobject_from_jsonf("{ 'response': %s }", resp);
+    free(resp);
+    return 0;
+}
+
 /**
  * do_quit(): Quit QEMU execution
  */

Shown above are the print handler and command handler. The print handler takes the command result (as a QObject) and emits it as a human readable string to the monitor. The command handler is where the command itself is implemented. Most commands will do something interesting and virtualization-related here. Our command simply parses its arguments and builds a return object based on them.

@@ -4396,6 +4438,8 @@ static void handle_user_command(Monitor *mon, const char *cmdline)
 
     qdict = qdict_new();
 
+    printf("Got command: %s\n", cmdline);
+
     cmd = monitor_parse_command(mon, cmdline, qdict);
     if (!cmd)
         goto out;

This is more debugging code. The line above causes all commands received via the ‘hmp’ monitor to be echoed to standard out.

@@ -5024,6 +5068,7 @@ static void monitor_control_read(void *opaque, const uint8_t *buf, int size)
 
     cur_mon = opaque;
 
+    printf("%*c", size, (char)*buf);
     json_message_parser_feed(&cur_mon->mc->parser, (const char *) buf, size);
 
     cur_mon = old_mon;

Debug statememt similar to the one above, but commands received via the ‘qmp’ monitor are echoed.

diff --git a/qmp-commands.hx b/qmp-commands.hx
index df40a3d..e60aec8 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -61,6 +61,37 @@ refer to the QMP specification for more details on error responses.
 EQMP
 
     {
+        .name       = "hello",
+        .args_type  = "exclaim:-e,lang:s?",
+        .params     = "[-e] [language]",
+        .help       = "Say hello",
+        .mhandler.cmd_new = do_hello,
+    },
+
+SQMP
+hello
+-----
+
+Say hello.
+
+Arguments:
+
+- exclaim: Greet with more enthusiasm (json-bool, optional)
+- lang: Select greeting language (json-string, optional)
+
+Note: The lang argument defaults to english
+
+Returns a JSON object containing:
+- response: A greeting/response (json-string)
+
+Example:
+
+-> { "execute": "hello", "arguments": { "lang": "spanish" } }
+<- { "return": { "response": "Hola Mundo" } }
+
+EQMP
+
+    {
         .name       = "quit",
         .args_type  = "",
         .params     = "",

This block of code declares the hello command in the qmp monitor. Similar to the definition in hmp-commands.hx, this specifies the command name, arguments synopsis, documentation, and the actual command handler. Notice that both the hmp and qmp version use the same handler. This is good.

This concludes the code walkthrough for the ‘hello’ qemu monitor command. In the next installment, we will begin extending libvirt to support this command.

Up next… Define hello API function and data types

Advertisements

About aglitke

I am a software engineer working on Linux, open source software, and virtualization. I am proud to work at Red Hat on oVirt and Red Hat Virtualization with a focus on software defined storage. Other notable projects I have been involved in include: The Linux ppc64 architecture, Linux kernel crash dumps (kdump), Linux huge pages and libhugetlbfs, qemu, libvirt, and the Memory Overcommitment Manager.
This entry was posted in Uncategorized. Bookmark the permalink.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s