bhyve: implement argument parser for loader

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@physik.tu-berlin.de>
This commit is contained in:
Fabian Freyer 2016-06-01 10:03:05 +02:00 committed by Roman Bogorodskiy
parent 8151b300fb
commit 9f22b347b4

View File

@ -738,6 +738,116 @@ bhyveParseBhyveCommandLine(virDomainDefPtr def,
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;
size_t i = 0;
int ret = -1;
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 (bhyveParseMemsize(parser->optarg, &memory)) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Failed to parse memory"));
goto error;
}
if (def->mem.cur_balloon != 0 && def->mem.cur_balloon != memory) {
virReportError(VIR_ERR_OPERATION_FAILED, "%s",
_("Failed to parse 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, "%s",
_("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, "%s",
_("Failed to parse arguments: VM name mismatch"));
goto error;
}
ret = 0;
error:
VIR_FREE(parser);
return ret;
}
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,
@ -774,6 +884,13 @@ bhyveParseCommandLineString(const char* nativeConfig,
if (bhyveParseBhyveCommandLine(def, xmlopt, caps, bhyve_argc, bhyve_argv))
goto error;
if (loader_argv && STREQ(loader_argv[0], "/usr/sbin/bhyveload")) {
if (bhyveParseBhyveLoadCommandLine(def, loader_argc, loader_argv))
goto error;
} else if (loader_argv) {
if (bhyveParseCustomLoaderCommandLine(def, loader_argc, loader_argv))
goto error;
}
cleanup:
virStringFreeList(loader_argv);