[libvirt] [PATCH v2 5/5] bhyve: implement argument parser for loader

Fabian Freyer fabian.freyer at physik.tu-berlin.de
Thu Jun 9 01:51:35 UTC 2016


A simple getopt-based argument parser is added for the /usr/sbin/bhyveload
command, loosely based on its argument parser.

The boot disk is guessed by iterating over all
disks and matching their sources. If any non-default arguments are found,
def->os.bootloaderArgs is set accordingly, and the bootloader is treated as a
custom bootloader.

Custom bootloader are supported by setting the def->os.bootloader and
def->os.bootloaderArgs accordingly

grub-bhyve is also treated as a custom bootloader. Since we don't get the
device map in the native format anyways, we can't reconstruct the complete
boot order. While it is possible to check what type the grub boot disk is by
checking if the --root argument is "cd" or "hd0,msdos1", and then just use the
first disk found, implementing the grub-bhyve argument parser as-is in the
grub-bhyve source would mean adding a dependency to argp or duplicating lots
of the code of argp. Therefore it's not really worth implementing that now.

Signed-off-by: Fabian Freyer <fabian.freyer at physik.tu-berlin.de>
---
 src/bhyve/bhyve_parse_command.c | 122 ++++++++++++++++++++++++++++++++++++++++
 1 file changed, 122 insertions(+)

diff --git a/src/bhyve/bhyve_parse_command.c b/src/bhyve/bhyve_parse_command.c
index be4ff2a..6600111 100644
--- a/src/bhyve/bhyve_parse_command.c
+++ b/src/bhyve/bhyve_parse_command.c
@@ -712,6 +712,121 @@ error:
     return -1;
 }
 
+/*
+ * Parse the /usr/sbin/bhyveload command line.
+ */
+static int
+bhyveParseBhyveLoadCommandLine(virDomainDefPtr def,
+                               int argc, char **argv)
+{
+    int c;
+    /* bhyveload called with default arguments when only -m and -d are given.
+     * Store this in a bit field and check if only those two options are given
+     * later */
+    unsigned arguments = 0;
+    size_t memory = 0;
+    struct _getopt_data *parser;
+    int i = 0;
+
+    const char optstr[] = "CSc:d:e:h:l:m:";
+
+    if (!argv)
+        goto error;
+
+    if (VIR_ALLOC(parser) < 0)
+        goto error;
+
+    while ((c = _getopt_internal_r(argc, argv, optstr,
+            NULL, NULL, 0, parser, 0)) != -1) {
+        switch (c) {
+        case 'd':
+            arguments |= 1;
+            /* Iterate over the disks of the domain trying to match up the
+             * source */
+            for (i = 0; i < def->ndisks; i++) {
+                if (STREQ(virDomainDiskGetSource(def->disks[i]),
+                          parser->optarg)) {
+                    def->disks[i]->info.bootIndex = i;
+                    break;
+                }
+            }
+            break;
+        case 'm':
+            arguments |= 2;
+            if (virStrToLong_ul(parser->optarg, NULL, 10, &memory) < 0) {
+                virReportError(VIR_ERR_OPERATION_FAILED,
+                               _("Failed to parse Memory."));
+                goto error;
+            }
+            if (memory < 1024)
+                memory *= 1024;
+            else
+                memory /= 1024UL;
+            if (def->mem.cur_balloon != 0 && def->mem.cur_balloon != memory) {
+                virReportError(VIR_ERR_OPERATION_FAILED,
+                           _("Failed to parse Memory: Memory size mismatch."));
+                goto error;
+            }
+            def->mem.cur_balloon = memory;
+            virDomainDefSetMemoryTotal(def, memory);
+            break;
+        default:
+            arguments |= 4;
+        }
+    }
+
+    if (arguments != 3) {
+        /* Set os.bootloader since virDomainDefFormatInternal will only format
+         * the bootloader arguments if os->bootloader is set. */
+        if (VIR_STRDUP(def->os.bootloader, argv[0]) < 0)
+           goto error;
+
+        def->os.bootloaderArgs = virStringJoin((const char**) &argv[1], " ");
+    }
+
+    if (argc != parser->optind) {
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("Failed to parse arguments for bhyveload command."));
+        goto error;
+    }
+
+    if (def->name == NULL) {
+        if (VIR_STRDUP(def->name, argv[argc]) < 0)
+            goto error;
+    }
+    else if (STRNEQ(def->name, argv[argc])) {
+        /* the vm name of the loader and the bhyverun command differ, throw an
+         * error here */
+        virReportError(VIR_ERR_OPERATION_FAILED,
+                       _("Failed to parse arguments: VM name mismatch."));
+        goto error;
+    }
+
+    VIR_FREE(parser);
+    return 0;
+error:
+    VIR_FREE(parser);
+    return -1;
+}
+
+static int
+bhyveParseCustomLoaderCommandLine(virDomainDefPtr def,
+                                  int argc ATTRIBUTE_UNUSED,
+                                  char **argv)
+{
+    if (!argv)
+        goto error;
+
+    if (VIR_STRDUP(def->os.bootloader, argv[0]) < 0)
+       goto error;
+
+    def->os.bootloaderArgs = virStringJoin((const char**) &argv[1], " ");
+
+    return 0;
+error:
+    return -1;
+}
+
 virDomainDefPtr
 bhyveParseCommandLineString(const char* nativeConfig,
                             unsigned caps,
@@ -745,6 +860,13 @@ bhyveParseCommandLineString(const char* nativeConfig,
 
     if (bhyveParseBhyveCommandLine(def, xmlopt, caps, bhyve_argc, bhyve_argv))
         goto cleanup;
+    if (STREQ(loader_argv[0], "/usr/sbin/bhyveload")) {
+        if (bhyveParseBhyveLoadCommandLine(def, loader_argc, loader_argv))
+            goto cleanup;
+    }
+    else if (loader_argv)
+        if (bhyveParseCustomLoaderCommandLine(def, loader_argc, loader_argv))
+            goto cleanup;
 
 cleanup:
     virStringFreeList(loader_argv);
-- 
2.7.0




More information about the libvir-list mailing list