commit 7012548e0d761bf365f17bd39cd551753eb8e652
Author: Juergen Gross <jgross@suse.com>
Date:   Fri Feb 24 07:21:42 2017 +0100

    xenstore: enhance control command support
    
    The Xenstore protocol supports the XS_CONTROL command for triggering
    various actions in the Xenstore daemon. Enhance that support by using
    a command table and adding a help function.
    
    Support multiple control commands in the associated xenstore-control
    program used to issue XS_CONTROL commands.
    
    Signed-off-by: Juergen Gross <jgross@suse.com>
    Reviewed-by: Wei Liu <wei.liu2@citrix.com>

diff --git a/tools/xenstore/xenstore_control.c b/tools/xenstore/xenstore_control.c
index 0a108df..afa0449 100644
--- a/tools/xenstore/xenstore_control.c
+++ b/tools/xenstore/xenstore_control.c
@@ -7,29 +7,61 @@
 
 int main(int argc, char **argv)
 {
-  struct xs_handle * xsh;
+    struct xs_handle *xsh;
+    char *par = NULL;
+    char *ret;
+    unsigned int p, len = 0;
+    int rc = 0;
 
-  if (argc < 2 ||
-      strcmp(argv[1], "check"))
-  {
-    fprintf(stderr,
-            "Usage:\n"
-            "\n"
-            "       %s check\n"
-            "\n", argv[0]);
-    return 2;
-  }
+    if (argc < 2) {
+        fprintf(stderr, "Usage:\n"
+                "%s <command> [<arg>...]\n", argv[0]);
+        rc = 2;
+        goto out;
+    }
 
-  xsh = xs_daemon_open();
+    for (p = 2; p < argc; p++)
+        len += strlen(argv[p]) + 1;
+    if (len) {
+        par = malloc(len);
+        if (!par) {
+            fprintf(stderr, "Allocation error.\n");
+            rc = 1;
+            goto out;
+        }
+        len = 0;
+        for (p = 2; p < argc; p++) {
+            memcpy(par + len, argv[p], strlen(argv[p]) + 1);
+            len += strlen(argv[p]) + 1;
+        }
+    }
 
-  if (xsh == NULL) {
-    fprintf(stderr, "Failed to contact Xenstored.\n");
-    return 1;
-  }
+    xsh = xs_open(0);
+    if (xsh == NULL) {
+        fprintf(stderr, "Failed to contact Xenstored.\n");
+        rc = 1;
+        goto out;
+    }
 
-  xs_debug_command(xsh, argv[1], NULL, 0);
+    ret = xs_control_command(xsh, argv[1], par, len);
+    if (!ret) {
+        rc = 3;
+        if (errno == EINVAL) {
+            ret = xs_control_command(xsh, "help", NULL, 0);
+            if (ret)
+                fprintf(stderr, "Command not supported. Valid commands are:\n"
+                                "%s\n", ret);
+            else
+                fprintf(stderr, "Error when executing command.\n");
+        } else
+            fprintf(stderr, "Error %d when trying to execute command.\n",
+                    errno);
+    } else if (strlen(ret) > 0)
+        printf("%s\n", ret);
 
-  xs_daemon_close(xsh);
+    xs_close(xsh);
 
-  return 0;
+ out:
+    free(par);
+    return rc;
 }
diff --git a/tools/xenstore/xenstored_control.c b/tools/xenstore/xenstored_control.c
index f169d23..3080e47 100644
--- a/tools/xenstore/xenstored_control.c
+++ b/tools/xenstore/xenstored_control.c
@@ -17,30 +17,108 @@
 */
 
 #include <errno.h>
+#include <stdarg.h>
+#include <stdio.h>
+#include <string.h>
 
 #include "utils.h"
+#include "talloc.h"
 #include "xenstored_core.h"
 #include "xenstored_control.h"
 
+struct cmd_s {
+	char *cmd;
+	int (*func)(void *, struct connection *, char **, int);
+	char *pars;
+};
+
+static int do_control_check(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num)
+		return EINVAL;
+
+	check_store();
+
+	send_ack(conn, XS_CONTROL);
+	return 0;
+}
+
+static int do_control_print(void *ctx, struct connection *conn,
+			    char **vec, int num)
+{
+	if (num != 1)
+		return EINVAL;
+
+	xprintf("control: %s", vec[0]);
+
+	send_ack(conn, XS_CONTROL);
+	return 0;
+}
+
+static int do_control_help(void *, struct connection *, char **, int);
+
+static struct cmd_s cmds[] = {
+	{ "check", do_control_check, "" },
+	{ "print", do_control_print, "<string>" },
+	{ "help", do_control_help, "" },
+};
+
+static int do_control_help(void *ctx, struct connection *conn,
+			   char **vec, int num)
+{
+	int cmd, len = 0;
+	char *resp;
+
+	if (num)
+		return EINVAL;
+
+	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++) {
+		len += strlen(cmds[cmd].cmd) + 1;
+		len += strlen(cmds[cmd].pars) + 1;
+	}
+	len++;
+
+	resp = talloc_array(ctx, char, len);
+	if (!resp)
+		return ENOMEM;
+
+	len = 0;
+	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++) {
+		strcpy(resp + len, cmds[cmd].cmd);
+		len += strlen(cmds[cmd].cmd);
+		resp[len] = '\t';
+		len++;
+		strcpy(resp + len, cmds[cmd].pars);
+		len += strlen(cmds[cmd].pars);
+		resp[len] = '\n';
+		len++;
+	}
+	resp[len] = 0;
+
+	send_reply(conn, XS_CONTROL, resp, len);
+	return 0;
+}
+
 int do_control(struct connection *conn, struct buffered_data *in)
 {
 	int num;
+	int cmd;
+	char **vec;
 
 	if (conn->id != 0)
 		return EACCES;
 
 	num = xs_count_strings(in->buffer, in->used);
+	vec = talloc_array(in, char *, num);
+	if (!vec)
+		return ENOMEM;
+	if (get_strings(in, vec, num) != num)
+		return EIO;
 
-	if (streq(in->buffer, "print")) {
-		if (num < 2)
-			return EINVAL;
-		xprintf("control: %s", in->buffer + strlen(in->buffer) + 1);
-	}
+	for (cmd = 0; cmd < ARRAY_SIZE(cmds); cmd++)
+		if (streq(vec[0], cmds[cmd].cmd))
+			return cmds[cmd].func(in, conn, vec + 1, num - 1);
 
-	if (streq(in->buffer, "check"))
-		check_store();
-
-	send_ack(conn, XS_CONTROL);
-
-	return 0;
+	return EINVAL;
 }
