qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Qemu-devel] [PATCH 3/3] Sample server that opens image files for QEMU


From: Corey Bryant
Subject: [Qemu-devel] [PATCH 3/3] Sample server that opens image files for QEMU
Date: Mon, 4 Jun 2012 09:10:10 -0400

This sample server opens image files and passes the fds to QEMU.  The
paths for two image files are passed as parameters, the first being
the boot image, and the second being an image to be hot-attached.  The
server will open the files and pass the fds to QEMU in one of two ways:

  1) Over the command line (using -drive file=/dev/fd/X) or
  2) Via the QMP monitor with the getfd command (using SCM_RIGHTS)
     followed by drive_add (using file=/dev/fd/X) and then
     device_add.

Usage:
  gcc -Wall -o test-fd-passing test-fd-passing.c -L/usr/local/lib -ljson
  ./test-fd-passing /path/hda.img /path/hdb.img

Note: This requires json-c and json-c-devel packages.

Signed-off-by: Corey Bryant <address@hidden>
---
 test-fd-passing.c |  321 +++++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 321 insertions(+)
 create mode 100644 test-fd-passing.c

diff --git a/test-fd-passing.c b/test-fd-passing.c
new file mode 100644
index 0000000..f3f06e6
--- /dev/null
+++ b/test-fd-passing.c
@@ -0,0 +1,321 @@
+/*
+ * QEMU fd passing test server
+ *
+ * Copyright IBM, Corp. 2012
+ *
+ * Authors:
+ *  Corey Bryant      <address@hidden>
+ *  Stefan Hajnoczi   <address@hidden>
+ *
+ * This work is licensed under the terms of the GNU LGPL, version 2 or later.
+ * See the COPYING.LIB file in the top-level directory.
+ *
+ * gcc -Wall -o test-fd-passing test-fd-passing.c -L/usr/local/lib -ljson
+ * ./test-fd-passing /path/hda.img /path/hdb.img
+ *
+ * Note: This requires json-c and json-c-devel packages.
+ *
+ */
+
+#define _GNU_SOURCE
+#include <stdlib.h>
+#include <stdio.h>
+#include <errno.h>
+#include <sys/stat.h>
+#include <sys/socket.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <spawn.h>
+#include <sys/un.h>
+#include <json/json.h>
+
+static int openMonitor(const char *mon_path)
+{
+    int i;
+    int rc;
+    struct sockaddr_un addr;
+    int fd = 0;
+
+    if ((fd = socket(AF_UNIX, SOCK_STREAM, 0)) < 0) {
+        perror("socket");
+        goto error;
+    }
+
+    memset(&addr, 0, sizeof(addr));
+    addr.sun_family = AF_UNIX;
+    strcpy(addr.sun_path, mon_path);
+
+    for (i = 0; i < 100; i++) {
+        rc = connect(fd, (struct sockaddr *) &addr, sizeof(addr));
+        if (rc == 0) {
+            break;
+        }
+        sleep(1);
+    }
+
+    if (rc != 0) {
+        fprintf(stderr, "unable to connect to monitor socket\n");
+        goto error;
+    }
+
+    return fd;
+
+error:
+    close(fd);
+    return -1;
+}
+
+static int writeQMPfd(int qmpfd, int fd, const char *str)
+{
+    int rc;
+    char *json_str = NULL;
+    struct json_object *json_obj;
+    struct msghdr msg;
+    struct iovec iov[1];
+    char control[CMSG_SPACE(sizeof(int))];
+    struct cmsghdr *cmsg;
+
+    fprintf(stderr, "write (fd=%d) %s\n", fd, str);
+
+    memset(&msg, 0, sizeof(msg));
+
+    json_obj = json_tokener_parse(str);
+    asprintf(&json_str, "%s\r\n", json_object_to_json_string(json_obj));
+    json_object_put(json_obj);
+
+    iov[0].iov_base = (void *)json_str;
+    iov[0].iov_len = strlen(json_str);
+
+    msg.msg_iov = iov;
+    msg.msg_iovlen = 1;
+
+    msg.msg_control = control;
+    msg.msg_controllen = sizeof(control);
+
+    cmsg = CMSG_FIRSTHDR(&msg);
+    cmsg->cmsg_len = CMSG_LEN(sizeof(int));
+    cmsg->cmsg_level = SOL_SOCKET;
+    cmsg->cmsg_type = SCM_RIGHTS;
+    memcpy(CMSG_DATA(cmsg), &fd, sizeof(int));
+
+    do {
+        rc = sendmsg(qmpfd, &msg, 0);
+    } while (rc < 0 && errno == EINTR);
+
+    if (rc < 0) {
+        perror("sendmsg");
+    }
+
+    return rc;
+}
+
+static int writeQMP(int qmpfd, const char *str) {
+    int rc;
+    char *json_str = NULL;
+    struct json_object *json_obj;
+
+    fprintf(stderr, "write %s\n", str);
+
+    json_obj = json_tokener_parse(str);
+    asprintf(&json_str, "%s\r\n", json_object_to_json_string(json_obj));
+    json_object_put(json_obj);
+
+    rc = write(qmpfd, json_str, strlen(json_str));
+    if (rc < 0) {
+        perror("write");
+    }
+
+    return rc;
+}
+
+static char *readQMP(int qmpfd) {
+    int rc;
+    int i;
+    char *json_str;
+
+    json_str = calloc(1024, sizeof(char));
+    if (json_str == NULL) {
+        return NULL;
+    }
+
+    i = 0;
+    do {
+        sleep(1);
+        rc = read(qmpfd, json_str, 1024);
+        if (rc < 0) {
+            perror("read");
+            return NULL;
+        }
+        i++;
+    } while (i < 100 && rc == 0);
+
+    if (rc == 0) {
+        fprintf(stderr, "no data to read");
+        free(json_str);
+        return NULL;
+    }
+
+    fprintf(stderr, "read %s", json_str);
+
+    return json_str;
+}
+
+int main(int argc, char *argv[]) {
+    int rc = -1;
+    int qmpfd, bootfd, hotfd_host, hotfd_guest;
+    int flags = O_RDWR;
+    int mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
+    pid_t child_pid;
+    char *drive_str = NULL;;
+    char *drive_add_str = NULL;
+    char *device_add_str = NULL;
+    char *drive_add_qmp = NULL;
+    char *device_add_qmp = NULL;
+    char *json_str;
+    struct json_object *json_obj;
+
+    if (argc != 3) {
+        fprintf(stderr, "usage: %s <boot-image-file> <attach-image-file>\n",
+                argv[0]);
+        goto error;
+    }
+
+    /* open the image files */
+    bootfd = open(argv[1], flags, mode);
+    if (bootfd == -1) {
+        perror("open");
+        goto error;
+    }
+
+    hotfd_host = open(argv[2], flags, mode);
+    if (hotfd_host == -1) {
+        perror("open");
+        goto error;
+    }
+
+    /* use '-drive file=/dev/fd/X' on QEMU command line to open boot image */
+    asprintf(&drive_str, "file=/dev/fd/%d,if=none,id=drive-virtio-disk0",
+             bootfd);
+
+    char *child_argv[] = {
+        "qemu-system-x86_64",
+        "-enable-kvm",
+        "-m", "1024",
+        "-chardev", "socket,id=qmp,path=./qmp-sock,server",
+        "-mon", "chardev=qmp,mode=control,pretty=on",
+        "-drive", drive_str,
+        "-device",
+        
"virtio-blk-pci,bus=pci.0,addr=0x4,drive=drive-virtio-disk0,id=virtio-disk0",
+        "-vnc", ":0",
+        NULL,
+    };
+
+    rc = posix_spawn(&child_pid, "/usr/local/bin/qemu-system-x86_64",
+                     NULL, NULL, child_argv, environ);
+    if (rc != 0) {
+        perror("posix_spawn\n");
+        goto error;
+    }
+
+    qmpfd = openMonitor("./qmp-sock");
+    if (qmpfd == -1) {
+        rc = -1;
+        goto error;
+    }
+
+    json_str = readQMP(qmpfd);
+    if (json_str == NULL) {
+        rc = -1;
+        goto error;
+    }
+    free(json_str);
+
+    rc = writeQMP(qmpfd, "{ \"execute\": \"qmp_capabilities\" }");
+    if (rc < 0) {
+        goto error;
+    }
+
+    json_str = readQMP(qmpfd);
+    if (json_str == NULL) {
+        rc = -1;
+        goto error;
+    }
+    free(json_str);
+
+    /* issue 'getfd' monitor command and get QEMU guest's fd in return */
+    rc = writeQMPfd(qmpfd, hotfd_host,
+         "{ \"execute\": \"getfd\", \"arguments\": { \"fdname\": \"fd1\" } }");
+    if (rc < 0) {
+        goto error;
+    }
+
+    json_str = readQMP(qmpfd);
+    if (json_str == NULL) {
+        rc = -1;
+        goto error;
+    }
+    json_obj = json_tokener_parse(json_str);
+    json_obj = json_object_object_get(json_obj, "return");
+    hotfd_guest = json_object_get_int(json_obj);
+    json_object_put(json_obj);
+    free(json_str);
+
+    /* issue 'drive_add' monitor command with guest's /dev/fd/X path */
+    asprintf(&drive_add_str, "drive_add data_drive file=/dev/fd/%d,%s",
+             hotfd_guest,
+             "if=none,id=drive-virtio-disk1,cache=writethrough\r\n");
+    asprintf(&drive_add_qmp,
+             "{ \"%s\": \"%s\", \"%s\": { \"%s\": \"%s\" } }",
+             "execute", "human-monitor-command", "arguments",
+             "command-line", drive_add_str);
+    rc = writeQMP(qmpfd, drive_add_qmp);
+    if (rc < 0) {
+        goto error;
+    }
+
+    json_str = readQMP(qmpfd);
+    if (json_str == NULL) {
+        rc = -1;
+        goto error;
+    }
+    free(json_str);
+
+    /* issue 'device_add' monitor command to add the disk drive */
+    asprintf(&device_add_str, "device_add virtio-blk-pci,bus=pci.0,%s",
+             "addr=0x6,drive=drive-virtio-disk1,id=virtio-disk1\r\n");
+    asprintf(&device_add_qmp,
+             "{ \"%s\": \"%s\", \"%s\": { \"%s\": \"%s\" } }",
+             "execute", "human-monitor-command", "arguments",
+             "command-line", device_add_str);
+    rc = writeQMP(qmpfd, device_add_qmp);
+    if (rc < 0) {
+        goto error;
+    }
+
+    json_str = readQMP(qmpfd);
+    if (json_str == NULL) {
+        rc = -1;
+        goto error;
+    }
+    free(json_str);
+
+    rc = 0;
+
+error:
+    if (drive_str) {
+        free(drive_str);
+    }
+    if (drive_add_str) {
+        free(drive_add_str);
+    }
+    if (device_add_str) {
+        free(device_add_str);
+    }
+    if (drive_add_qmp) {
+        free(drive_add_qmp);
+    }
+    if (device_add_qmp) {
+        free(device_add_qmp);
+    }
+    return rc;
+}
-- 
1.7.10.2




reply via email to

[Prev in Thread] Current Thread [Next in Thread]