Patchwork [RFC,v6,21/23] virtagent: add virtagent guest daemon

login
register
mail settings
Submitter Michael Roth
Date Jan. 17, 2011, 1:15 p.m.
Message ID <1295270117-24760-22-git-send-email-mdroth@linux.vnet.ibm.com>
Download mbox | patch
Permalink /patch/79177/
State New
Headers show

Comments

Michael Roth - Jan. 17, 2011, 1:15 p.m.
Signed-off-by: Michael Roth <mdroth@linux.vnet.ibm.com>
---
 Makefile           |    4 +-
 qemu-va.c          |  238 ++++++++++++++++++++++++++++++++++++++++++++++++++++
 virtagent-common.h |    1 +
 3 files changed, 242 insertions(+), 1 deletions(-)
 create mode 100644 qemu-va.c

Patch

diff --git a/Makefile b/Makefile
index 6d601ee..f1f4d18 100644
--- a/Makefile
+++ b/Makefile
@@ -151,7 +151,7 @@  version-obj-$(CONFIG_WIN32) += version.o
 ######################################################################
 
 qemu-img.o: qemu-img-cmds.h
-qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o: $(GENERATED_HEADERS)
+qemu-img.o qemu-tool.o qemu-nbd.o qemu-io.o cmd.o qemu-va.o: $(GENERATED_HEADERS)
 
 qemu-img$(EXESUF): qemu-img.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
@@ -159,6 +159,8 @@  qemu-nbd$(EXESUF): qemu-nbd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-ob
 
 qemu-io$(EXESUF): qemu-io.o cmd.o qemu-tool.o qemu-error.o $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o
 
+qemu-va$(EXESUF): qemu-va.o virtagent.o virtagent-server.o virtagent-common.o qemu-tool.o qemu-error.o qemu-sockets.c $(oslib-obj-y) $(trace-obj-y) $(block-obj-y) $(qobject-obj-y) $(version-obj-y) qemu-timer-common.o qemu-timer.o
+
 qemu-img-cmds.h: $(SRC_PATH)/qemu-img-cmds.hx
 	$(call quiet-command,sh $(SRC_PATH)/hxtool -h < $< > $@,"  GEN   $@")
 
diff --git a/qemu-va.c b/qemu-va.c
new file mode 100644
index 0000000..5f1e2ab
--- /dev/null
+++ b/qemu-va.c
@@ -0,0 +1,238 @@ 
+/*
+ * virtagent - QEMU guest agent
+ *
+ * Copyright IBM Corp. 2010
+ *
+ * Authors:
+ *  Michael Roth      <mdroth@linux.vnet.ibm.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ * QEMU System Emulator
+ *
+ * Copyright (c) 2003-2008 Fabrice Bellard
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
+ * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#include <getopt.h>
+#include <err.h>
+#include "qemu-ioh.h"
+#include "qemu-tool.h"
+#include "virtagent-common.h"
+
+static bool verbose_enabled;
+#define DEBUG_ENABLED
+
+#ifdef DEBUG_ENABLED
+#define DEBUG(msg, ...) do { \
+    fprintf(stderr, "%s:%s():L%d: " msg "\n", \
+            __FILE__, __FUNCTION__, __LINE__, ## __VA_ARGS__); \
+} while(0)
+#else
+#define DEBUG(msg, ...) do {} while (0)
+#endif
+
+#define INFO(msg, ...) do { \
+    if (!verbose_enabled) { \
+        break; \
+    } \
+    warnx(msg, ## __VA_ARGS__); \
+} while(0)
+
+/* mirror qemu I/O loop for standalone daemon */
+static void main_loop_wait(int nonblocking)
+{
+    fd_set rfds, wfds, xfds;
+    int ret, nfds;
+    struct timeval tv;
+    int timeout = 100000;
+
+    if (nonblocking) {
+        timeout = 0;
+    }
+
+    /* poll any events */
+    nfds = -1;
+    FD_ZERO(&rfds);
+    FD_ZERO(&wfds);
+    FD_ZERO(&xfds);
+    qemu_get_fdset(&nfds, &rfds, &wfds, &xfds);
+
+    tv.tv_sec = timeout / 1000;
+    tv.tv_usec = (timeout % 1000) * 1000;
+
+    ret = select(nfds + 1, &rfds, &wfds, &xfds, &tv);
+
+    if (ret > 0) {
+        qemu_process_fd_handlers(&rfds, &wfds, &xfds);
+    }
+
+    DEBUG("running timers...");
+    qemu_run_all_timers();
+}
+
+static void usage(const char *cmd)
+{
+    printf(
+"Usage: %s -c <channel_opts>\n"
+"QEMU virtagent guest agent %s\n"
+"\n"
+"  -c, --channel     channel method: one of unix-connect, virtio-serial, or\n"
+"                    isa-serial\n"
+"  -p, --path        channel path\n"
+"  -v, --verbose     display extra debugging information\n"
+"  -d, --daemonize   become a daemon\n"
+"  -h, --help        display this help and exit\n"
+"\n"
+"Report bugs to <mdroth@linux.vnet.ibm.com>\n"
+    , cmd, VA_VERSION);
+}
+
+static int init_virtagent(const char *method, const char *path) {
+    VAContext ctx;
+    int ret;
+
+    INFO("initializing agent...");
+
+    if (method == NULL) {
+        /* try virtio-serial as our default */
+        method = "virtio-serial";
+    }
+
+    if (path == NULL) {
+        if (strcmp(method, "virtio-serial")) {
+            errx(EXIT_FAILURE, "must specify a path for this channel");
+        }
+        /* try the default name for the virtio-serial port */
+        path = VA_GUEST_PATH_VIRTIO_DEFAULT;
+    }
+
+    /* initialize virtagent */
+    ctx.is_host = false;
+    ctx.channel_method = method;
+    ctx.channel_path = path;
+    ret = va_init(ctx);
+    if (ret) {
+        errx(EXIT_FAILURE, "unable to initialize virtagent");
+    }
+
+    return 0;
+}
+
+static void become_daemon(void)
+{
+    pid_t pid, sid;
+
+    pid = fork();
+    if (pid < 0)
+        exit(EXIT_FAILURE);
+    if (pid > 0) {
+        FILE *pidfile = fopen(VA_PIDFILE, "wx");
+        if (!pidfile)
+            errx(EXIT_FAILURE, "Error creating pid file");
+        fprintf(pidfile, "%i", pid);
+        fclose(pidfile);
+        exit(EXIT_SUCCESS);
+    }
+
+    umask(0);
+    sid = setsid();
+    if (sid < 0)
+        goto fail;
+    if ((chdir("/")) < 0)
+        goto fail;
+
+    close(STDIN_FILENO);
+    close(STDOUT_FILENO);
+    close(STDERR_FILENO);
+    return;
+
+fail:
+    unlink(VA_PIDFILE);
+    exit(EXIT_FAILURE);
+}
+
+int main(int argc, char **argv)
+{
+    const char *sopt = "hVvdc:p:", *channel_method = NULL, *channel_path = NULL;
+    struct option lopt[] = {
+        { "help", 0, NULL, 'h' },
+        { "version", 0, NULL, 'V' },
+        { "verbose", 0, NULL, 'v' },
+        { "channel", 0, NULL, 'c' },
+        { "path", 0, NULL, 'p' },
+        { "daemonize", 0, NULL, 'd' },
+        { NULL, 0, NULL, 0 }
+    };
+    int opt_ind = 0, ch, ret, daemonize = 0;
+
+    while ((ch = getopt_long(argc, argv, sopt, lopt, &opt_ind)) != -1) {
+        switch (ch) {
+        case 'c':
+            channel_method = optarg;
+            break;
+        case 'p':
+            channel_path = optarg;
+            break;
+        case 'v':
+            verbose_enabled = 1;
+            break;
+        case 'V':
+            printf("QEMU Virtagent %s\n", VA_VERSION);
+            return 0;
+        case 'd':
+            daemonize = 1;
+            break;
+        case 'h':
+            usage(argv[0]);
+            return 0;
+        case '?':
+            errx(EXIT_FAILURE, "Try '%s --help' for more information.",
+                 argv[0]);
+        }
+    }
+
+    init_clocks();
+    configure_alarms("dynticks");
+    if (init_timer_alarm() < 0) {
+        errx(EXIT_FAILURE, "could not initialize alarm timer");
+    }
+
+    /* initialize virtagent */
+    ret = init_virtagent(channel_method, channel_path);
+    if (ret) {
+        errx(EXIT_FAILURE, "error initializing communication channel");
+    }
+
+    if (daemonize) {
+        become_daemon();
+    }
+
+    /* main i/o loop */
+    for (;;) {
+        DEBUG("entering main_loop_wait()");
+        main_loop_wait(0);
+        DEBUG("left main_loop_wait()");
+    }
+
+    unlink(VA_PIDFILE);
+    return 0;
+}
diff --git a/virtagent-common.h b/virtagent-common.h
index 6ad8036..cb2363c 100644
--- a/virtagent-common.h
+++ b/virtagent-common.h
@@ -44,6 +44,7 @@ 
 #define VA_VERSION "1.0"
 #define EOL "\r\n"
 
+#define VA_PIDFILE "/var/run/qemu-va.pid"
 #define VA_HDR_LEN_MAX 4096 /* http header limit */
 #define VA_CONTENT_LEN_MAX 2*1024*1024 /* rpc/http send limit */
 #define VA_CLIENT_JOBS_MAX 5 /* max client rpcs we can queue */