Files
xen/tools/xl/xl_parse.c
T
Roger Pau Monne 1f762642d2 libxl: add support for running bootloader in restricted mode
Much like the device model depriv mode, add the same kind of support for the
bootloader.  Such feature allows passing a UID as a parameter for the
bootloader to run as, together with the bootloader itself taking the necessary
actions to isolate.

Note that the user to run the bootloader as must have the right permissions to
access the guest disk image (in read mode only), and that the bootloader will
be run in non-interactive mode when restricted.

If enabled bootloader restrict mode will attempt to re-use the user(s) from the
QEMU depriv implementation if no user is provided on the configuration file or
the environment.  See docs/features/qemu-deprivilege.pandoc for more
information about how to setup those users.

Bootloader restrict mode is not enabled by default as it requires certain
setup to be done first (setup of the user(s) to use in restrict mode).

This is part of XSA-443 / CVE-2023-34325

Signed-off-by: Roger Pau Monné <roger.pau@citrix.com>
Reviewed-by: Anthony PERARD <anthony.perard@citrix.com>
2023-10-11 06:36:50 +01:00

3092 lines
109 KiB
C

/*
* Copyright 2009-2017 Citrix Ltd and other contributors
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published
* by the Free Software Foundation; version 2.1 only. with the special
* exception on linking described in file LICENSE.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*/
#include <ctype.h>
#include <inttypes.h>
#include <limits.h>
#include <stdio.h>
#include <stdlib.h>
#include <xen/hvm/e820.h>
#include <xen/hvm/params.h>
#include <xen/io/sndif.h>
#include <xen/io/kbdif.h>
#include <libxl.h>
#include <libxl_utils.h>
#include <libxlutil.h>
#include "xl.h"
#include "xl_utils.h"
#include "xl_parse.h"
extern void set_default_nic_values(libxl_device_nic *nic);
#define ARRAY_EXTEND_INIT__CORE(array,count,initfn,more) \
({ \
typeof((count)) array_extend_old_count = (count); \
(count)++; \
(array) = xrealloc((array), sizeof(*array) * (count)); \
(initfn)(&(array)[array_extend_old_count]); \
more; \
&(array)[array_extend_old_count]; \
})
#define ARRAY_EXTEND_INIT(array,count,initfn) \
ARRAY_EXTEND_INIT__CORE((array),(count),(initfn), ({ \
(array)[array_extend_old_count].devid = array_extend_old_count; \
}))
#define ARRAY_EXTEND_INIT_NODEVID(array,count,initfn) \
ARRAY_EXTEND_INIT__CORE((array),(count),(initfn), /* nothing */ )
static const char *action_on_shutdown_names[] = {
[LIBXL_ACTION_ON_SHUTDOWN_DESTROY] = "destroy",
[LIBXL_ACTION_ON_SHUTDOWN_RESTART] = "restart",
[LIBXL_ACTION_ON_SHUTDOWN_RESTART_RENAME] = "rename-restart",
[LIBXL_ACTION_ON_SHUTDOWN_PRESERVE] = "preserve",
[LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY] = "coredump-destroy",
[LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART] = "coredump-restart",
[LIBXL_ACTION_ON_SHUTDOWN_SOFT_RESET] = "soft-reset",
};
const char *get_action_on_shutdown_name(libxl_action_on_shutdown a)
{
return action_on_shutdown_names[a];
}
static int parse_action_on_shutdown(const char *buf, libxl_action_on_shutdown *a)
{
int i;
const char *n;
for (i = 0; i < sizeof(action_on_shutdown_names) / sizeof(action_on_shutdown_names[0]); i++) {
n = action_on_shutdown_names[i];
if (!n) continue;
if (strcmp(buf, n) == 0) {
*a = i;
return 1;
}
}
return 0;
}
#define DSTATE_INITIAL 0
#define DSTATE_TAP 1
#define DSTATE_PHYSPATH 2
#define DSTATE_VIRTPATH 3
#define DSTATE_VIRTTYPE 4
#define DSTATE_RW 5
#define DSTATE_TERMINAL 6
void parse_disk_config_multistring(XLU_Config **config,
int nspecs, const char *const *specs,
libxl_device_disk *disk)
{
int e;
libxl_device_disk_init(disk);
if (!*config) {
*config = xlu_cfg_init(stderr, "command line");
if (!*config) { perror("xlu_cfg_init"); exit(-1); }
}
e = xlu_disk_parse(*config, nspecs, specs, disk);
if (e == EINVAL) exit(EXIT_FAILURE);
if (e) {
fprintf(stderr,"xlu_disk_parse failed: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
}
void parse_disk_config(XLU_Config **config, const char *spec,
libxl_device_disk *disk)
{
parse_disk_config_multistring(config, 1, &spec, disk);
}
static void parse_vif_rate(XLU_Config **config, const char *rate,
libxl_device_nic *nic)
{
int e;
e = xlu_vif_parse_rate(*config, rate, nic);
if (e == EINVAL || e == EOVERFLOW) exit(EXIT_FAILURE);
if (e) {
fprintf(stderr,"xlu_vif_parse_rate failed: %s\n",strerror(errno));
exit(EXIT_FAILURE);
}
}
int parse_range(const char *str, unsigned long *a, unsigned long *b)
{
const char *nstr;
char *endptr;
*a = *b = strtoul(str, &endptr, 10);
if (endptr == str || *a == ULONG_MAX)
return 1;
if (*endptr == '-') {
nstr = endptr + 1;
*b = strtoul(nstr, &endptr, 10);
if (endptr == nstr || *b == ULONG_MAX || *b < *a)
return 1;
}
/* Valid value or range so far, but we also don't want junk after that */
if (*endptr != '\0')
return 1;
return 0;
}
/*
* Add or removes a specific set of cpus (specified in str, either as
* single cpus or as entire NUMA nodes) to/from cpumap.
*/
static int update_cpumap_range(const char *str, libxl_bitmap *cpumap)
{
unsigned long ida, idb;
libxl_bitmap node_cpumap;
bool is_not = false, is_nodes = false;
int rc = 0;
libxl_bitmap_init(&node_cpumap);
rc = libxl_node_bitmap_alloc(ctx, &node_cpumap, 0);
if (rc) {
fprintf(stderr, "libxl_node_bitmap_alloc failed.\n");
goto out;
}
/* Are we adding or removing cpus/nodes? */
if (STR_SKIP_PREFIX(str, "^")) {
is_not = true;
}
/* Are we dealing with cpus or full nodes? */
if (STR_SKIP_PREFIX(str, "node:") || STR_SKIP_PREFIX(str, "nodes:")) {
is_nodes = true;
}
if (strcmp(str, "all") == 0) {
/* We do not accept "^all" or "^nodes:all" */
if (is_not) {
fprintf(stderr, "Can't combine \"^\" and \"all\".\n");
rc = ERROR_INVAL;
} else
libxl_bitmap_set_any(cpumap);
goto out;
}
rc = parse_range(str, &ida, &idb);
if (rc) {
fprintf(stderr, "Invalid pcpu range: %s.\n", str);
goto out;
}
/* Add or remove the specified cpus in the range */
while (ida <= idb) {
if (is_nodes) {
/* Add/Remove all the cpus of a NUMA node */
int i;
rc = libxl_node_to_cpumap(ctx, ida, &node_cpumap);
if (rc) {
fprintf(stderr, "libxl_node_to_cpumap failed.\n");
goto out;
}
/* Add/Remove all the cpus in the node cpumap */
libxl_for_each_set_bit(i, node_cpumap) {
is_not ? libxl_bitmap_reset(cpumap, i) :
libxl_bitmap_set(cpumap, i);
}
} else {
/* Add/Remove this cpu */
is_not ? libxl_bitmap_reset(cpumap, ida) :
libxl_bitmap_set(cpumap, ida);
}
ida++;
}
out:
libxl_bitmap_dispose(&node_cpumap);
return rc;
}
/*
* Takes a string representing a set of cpus (specified either as
* single cpus or as eintire NUMA nodes) and turns it into the
* corresponding libxl_bitmap (in cpumap).
*/
int parse_cpurange(const char *cpu, libxl_bitmap *cpumap)
{
char *ptr, *saveptr = NULL, *buf = xstrdup(cpu);
int rc = 0;
for (ptr = strtok_r(buf, ",", &saveptr); ptr;
ptr = strtok_r(NULL, ",", &saveptr)) {
rc = update_cpumap_range(ptr, cpumap);
if (rc)
break;
}
free(buf);
return rc;
}
static void parse_top_level_vnc_options(XLU_Config *config,
libxl_vnc_info *vnc)
{
long l;
xlu_cfg_get_defbool(config, "vnc", &vnc->enable, 0);
xlu_cfg_replace_string (config, "vnclisten", &vnc->listen, 0);
xlu_cfg_replace_string (config, "vncpasswd", &vnc->passwd, 0);
if (!xlu_cfg_get_long (config, "vncdisplay", &l, 0))
vnc->display = l;
xlu_cfg_get_defbool(config, "vncunused", &vnc->findunused, 0);
}
static void parse_top_level_sdl_options(XLU_Config *config,
libxl_sdl_info *sdl)
{
xlu_cfg_get_defbool(config, "sdl", &sdl->enable, 0);
xlu_cfg_get_defbool(config, "opengl", &sdl->opengl, 0);
xlu_cfg_replace_string (config, "display", &sdl->display, 0);
xlu_cfg_replace_string (config, "xauthority", &sdl->xauthority, 0);
}
static char *parse_cmdline(XLU_Config *config)
{
char *cmdline = NULL;
const char *root = NULL, *extra = NULL, *buf = NULL;
xlu_cfg_get_string (config, "cmdline", &buf, 0);
xlu_cfg_get_string (config, "root", &root, 0);
xlu_cfg_get_string (config, "extra", &extra, 0);
if (buf) {
cmdline = strdup(buf);
if (root || extra)
fprintf(stderr, "Warning: ignoring root= and extra= "
"in favour of cmdline=\n");
} else {
if (root && extra) {
xasprintf(&cmdline, "root=%s %s", root, extra);
} else if (root) {
xasprintf(&cmdline, "root=%s", root);
} else if (extra) {
cmdline = strdup(extra);
}
}
if ((buf || root || extra) && !cmdline) {
fprintf(stderr, "Failed to allocate memory for cmdline\n");
exit(EXIT_FAILURE);
}
return cmdline;
}
static void parse_vcpu_affinity(libxl_domain_build_info *b_info,
XLU_ConfigList *cpus, const char *buf,
int num_cpus, bool is_hard)
{
libxl_bitmap *vcpu_affinity_array;
/*
* If we are here, and buf is !NULL, we're dealing with a string. What
* we do in this case is parse it, and copy the result in _all_ (up to
* b_info->max_vcpus) the elements of the vcpu affinity array.
*
* If buf is NULL, we have a list, and what we do is putting in the
* i-eth element of the vcpu affinity array the result of the parsing
* of the i-eth entry of the list. If there are more vcpus than
* entries, it is fine to just not touch the last array elements.
*/
/* Silently ignore values corresponding to non existing vcpus */
if (buf || num_cpus > b_info->max_vcpus)
num_cpus = b_info->max_vcpus;
if (is_hard) {
b_info->num_vcpu_hard_affinity = num_cpus;
b_info->vcpu_hard_affinity = xmalloc(num_cpus * sizeof(libxl_bitmap));
vcpu_affinity_array = b_info->vcpu_hard_affinity;
} else {
b_info->num_vcpu_soft_affinity = num_cpus;
b_info->vcpu_soft_affinity = xmalloc(num_cpus * sizeof(libxl_bitmap));
vcpu_affinity_array = b_info->vcpu_soft_affinity;
}
if (!buf) {
int j = 0;
while ((buf = xlu_cfg_get_listitem(cpus, j)) != NULL && j < num_cpus) {
libxl_bitmap_init(&vcpu_affinity_array[j]);
if (libxl_cpu_bitmap_alloc(ctx, &vcpu_affinity_array[j], 0)) {
fprintf(stderr, "Unable to allocate cpumap for vcpu %d\n", j);
exit(EXIT_FAILURE);
}
if (parse_cpurange(buf, &vcpu_affinity_array[j]))
exit(EXIT_FAILURE);
j++;
}
/* When we have a list of cpumaps, always disable automatic placement */
libxl_defbool_set(&b_info->numa_placement, false);
} else {
int i;
libxl_bitmap_init(&vcpu_affinity_array[0]);
if (libxl_cpu_bitmap_alloc(ctx, &vcpu_affinity_array[0], 0)) {
fprintf(stderr, "Unable to allocate cpumap for vcpu 0\n");
exit(EXIT_FAILURE);
}
if (parse_cpurange(buf, &vcpu_affinity_array[0]))
exit(EXIT_FAILURE);
for (i = 1; i < b_info->max_vcpus; i++) {
libxl_bitmap_init(&vcpu_affinity_array[i]);
if (libxl_cpu_bitmap_alloc(ctx, &vcpu_affinity_array[i], 0)) {
fprintf(stderr, "Unable to allocate cpumap for vcpu %d\n", i);
exit(EXIT_FAILURE);
}
libxl_bitmap_copy(ctx, &vcpu_affinity_array[i],
&vcpu_affinity_array[0]);
}
/* We have soft affinity already, disable automatic placement */
if (!is_hard)
libxl_defbool_set(&b_info->numa_placement, false);
}
}
static unsigned long parse_ulong(const char *str)
{
char *endptr;
unsigned long val;
val = strtoul(str, &endptr, 10);
if (endptr == str || val == ULONG_MAX) {
fprintf(stderr, "xl: failed to convert \"%s\" to number\n", str);
exit(EXIT_FAILURE);
}
return val;
}
void replace_string(char **str, const char *val)
{
free(*str);
*str = xstrdup(val);
}
int match_option_size(const char *prefix, size_t len,
char *arg, char **argopt)
{
int rc = strncmp(prefix, arg, len);
if (!rc) *argopt = arg+len;
return !rc;
}
/* Parses network data and adds info into nic
* Returns 1 if the input token does not match one of the keys
* or parsed values are not correct. Successful parse returns 0 */
int parse_nic_config(libxl_device_nic *nic, XLU_Config **config, char *token)
{
char *endptr, *oparg;
int i;
unsigned int val;
if (MATCH_OPTION("type", token, oparg)) {
if (!strcmp("vif", oparg)) {
nic->nictype = LIBXL_NIC_TYPE_VIF;
} else if (!strcmp("ioemu", oparg)) {
nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
} else {
fprintf(stderr, "Invalid parameter `type'.\n");
return 1;
}
} else if (MATCH_OPTION("mac", token, oparg)) {
for (i = 0; i < 6; i++) {
val = strtoul(oparg, &endptr, 16);
if ((oparg == endptr) || (val > 255)) {
fprintf(stderr, "Invalid parameter `mac'.\n");
return 1;
}
nic->mac[i] = val;
oparg = endptr + 1;
}
} else if (MATCH_OPTION("bridge", token, oparg)) {
replace_string(&nic->bridge, oparg);
} else if (MATCH_OPTION("netdev", token, oparg)) {
fprintf(stderr, "the netdev parameter is deprecated, "
"please use gatewaydev instead\n");
replace_string(&nic->gatewaydev, oparg);
} else if (MATCH_OPTION("gatewaydev", token, oparg)) {
replace_string(&nic->gatewaydev, oparg);
} else if (MATCH_OPTION("ip", token, oparg)) {
replace_string(&nic->ip, oparg);
} else if (MATCH_OPTION("script", token, oparg)) {
replace_string(&nic->script, oparg);
} else if (MATCH_OPTION("backend", token, oparg)) {
replace_string(&nic->backend_domname, oparg);
} else if (MATCH_OPTION("vifname", token, oparg)) {
replace_string(&nic->ifname, oparg);
} else if (MATCH_OPTION("model", token, oparg)) {
replace_string(&nic->model, oparg);
} else if (MATCH_OPTION("rate", token, oparg)) {
parse_vif_rate(config, oparg, nic);
} else if (MATCH_OPTION("forwarddev", token, oparg)) {
replace_string(&nic->coloft_forwarddev, oparg);
} else if (MATCH_OPTION("colo_sock_mirror_id", token, oparg)) {
replace_string(&nic->colo_sock_mirror_id, oparg);
} else if (MATCH_OPTION("colo_sock_mirror_ip", token, oparg)) {
replace_string(&nic->colo_sock_mirror_ip, oparg);
} else if (MATCH_OPTION("colo_sock_mirror_port", token, oparg)) {
replace_string(&nic->colo_sock_mirror_port, oparg);
} else if (MATCH_OPTION("colo_sock_compare_sec_in_id", token, oparg)) {
replace_string(&nic->colo_sock_compare_sec_in_id, oparg);
} else if (MATCH_OPTION("colo_sock_compare_sec_in_ip", token, oparg)) {
replace_string(&nic->colo_sock_compare_sec_in_ip, oparg);
} else if (MATCH_OPTION("colo_sock_compare_sec_in_port", token, oparg)) {
replace_string(&nic->colo_sock_compare_sec_in_port, oparg);
} else if (MATCH_OPTION("colo_sock_redirector0_id", token, oparg)) {
replace_string(&nic->colo_sock_redirector0_id, oparg);
} else if (MATCH_OPTION("colo_sock_redirector0_ip", token, oparg)) {
replace_string(&nic->colo_sock_redirector0_ip, oparg);
} else if (MATCH_OPTION("colo_sock_redirector0_port", token, oparg)) {
replace_string(&nic->colo_sock_redirector0_port, oparg);
} else if (MATCH_OPTION("colo_sock_redirector1_id", token, oparg)) {
replace_string(&nic->colo_sock_redirector1_id, oparg);
} else if (MATCH_OPTION("colo_sock_redirector1_ip", token, oparg)) {
replace_string(&nic->colo_sock_redirector1_ip, oparg);
} else if (MATCH_OPTION("colo_sock_redirector1_port", token, oparg)) {
replace_string(&nic->colo_sock_redirector1_port, oparg);
} else if (MATCH_OPTION("colo_sock_redirector2_id", token, oparg)) {
replace_string(&nic->colo_sock_redirector2_id, oparg);
} else if (MATCH_OPTION("colo_sock_redirector2_ip", token, oparg)) {
replace_string(&nic->colo_sock_redirector2_ip, oparg);
} else if (MATCH_OPTION("colo_sock_redirector2_port", token, oparg)) {
replace_string(&nic->colo_sock_redirector2_port, oparg);
} else if (MATCH_OPTION("colo_sock_compare_pri_in_id", token, oparg)) {
replace_string(&nic->colo_sock_compare_pri_in_id, oparg);
} else if (MATCH_OPTION("colo_sock_compare_pri_in_ip", token, oparg)) {
replace_string(&nic->colo_sock_compare_pri_in_ip, oparg);
} else if (MATCH_OPTION("colo_sock_compare_pri_in_port", token, oparg)) {
replace_string(&nic->colo_sock_compare_pri_in_port, oparg);
} else if (MATCH_OPTION("colo_sock_compare_notify_id", token, oparg)) {
replace_string(&nic->colo_sock_compare_notify_id, oparg);
} else if (MATCH_OPTION("colo_sock_compare_notify_ip", token, oparg)) {
replace_string(&nic->colo_sock_compare_notify_ip, oparg);
} else if (MATCH_OPTION("colo_sock_compare_notify_port", token, oparg)) {
replace_string(&nic->colo_sock_compare_notify_port, oparg);
} else if (MATCH_OPTION("colo_filter_mirror_queue", token, oparg)) {
replace_string(&nic->colo_filter_mirror_queue, oparg);
} else if (MATCH_OPTION("colo_filter_mirror_outdev", token, oparg)) {
replace_string(&nic->colo_filter_mirror_outdev, oparg);
} else if (MATCH_OPTION("colo_filter_redirector0_queue", token, oparg)) {
replace_string(&nic->colo_filter_redirector0_queue, oparg);
} else if (MATCH_OPTION("colo_filter_redirector0_indev", token, oparg)) {
replace_string(&nic->colo_filter_redirector0_indev, oparg);
} else if (MATCH_OPTION("colo_filter_redirector0_outdev", token, oparg)) {
replace_string(&nic->colo_filter_redirector0_outdev, oparg);
} else if (MATCH_OPTION("colo_filter_redirector1_queue", token, oparg)) {
replace_string(&nic->colo_filter_redirector1_queue, oparg);
} else if (MATCH_OPTION("colo_filter_redirector1_indev", token, oparg)) {
replace_string(&nic->colo_filter_redirector1_indev, oparg);
} else if (MATCH_OPTION("colo_filter_redirector1_outdev", token, oparg)) {
replace_string(&nic->colo_filter_redirector1_outdev, oparg);
} else if (MATCH_OPTION("colo_compare_pri_in", token, oparg)) {
replace_string(&nic->colo_compare_pri_in, oparg);
} else if (MATCH_OPTION("colo_compare_sec_in", token, oparg)) {
replace_string(&nic->colo_compare_sec_in, oparg);
} else if (MATCH_OPTION("colo_compare_out", token, oparg)) {
replace_string(&nic->colo_compare_out, oparg);
} else if (MATCH_OPTION("colo_compare_notify_dev", token, oparg)) {
replace_string(&nic->colo_compare_notify_dev, oparg);
} else if (MATCH_OPTION("colo_sock_sec_redirector0_id", token, oparg)) {
replace_string(&nic->colo_sock_sec_redirector0_id, oparg);
} else if (MATCH_OPTION("colo_sock_sec_redirector0_ip", token, oparg)) {
replace_string(&nic->colo_sock_sec_redirector0_ip, oparg);
} else if (MATCH_OPTION("colo_sock_sec_redirector0_port", token, oparg)) {
replace_string(&nic->colo_sock_sec_redirector0_port, oparg);
} else if (MATCH_OPTION("colo_sock_sec_redirector1_id", token, oparg)) {
replace_string(&nic->colo_sock_sec_redirector1_id, oparg);
} else if (MATCH_OPTION("colo_sock_sec_redirector1_ip", token, oparg)) {
replace_string(&nic->colo_sock_sec_redirector1_ip, oparg);
} else if (MATCH_OPTION("colo_sock_sec_redirector1_port", token, oparg)) {
replace_string(&nic->colo_sock_sec_redirector1_port, oparg);
} else if (MATCH_OPTION("colo_filter_sec_redirector0_queue", token, oparg)) {
replace_string(&nic->colo_filter_sec_redirector0_queue, oparg);
} else if (MATCH_OPTION("colo_filter_sec_redirector0_indev", token, oparg)) {
replace_string(&nic->colo_filter_sec_redirector0_indev, oparg);
} else if (MATCH_OPTION("colo_filter_sec_redirector0_outdev", token, oparg)) {
replace_string(&nic->colo_filter_sec_redirector0_outdev, oparg);
} else if (MATCH_OPTION("colo_filter_sec_redirector1_queue", token, oparg)) {
replace_string(&nic->colo_filter_sec_redirector1_queue, oparg);
} else if (MATCH_OPTION("colo_filter_sec_redirector1_indev", token, oparg)) {
replace_string(&nic->colo_filter_sec_redirector1_indev, oparg);
} else if (MATCH_OPTION("colo_filter_sec_redirector1_outdev", token, oparg)) {
replace_string(&nic->colo_filter_sec_redirector1_outdev, oparg);
} else if (MATCH_OPTION("colo_filter_sec_rewriter0_queue", token, oparg)) {
replace_string(&nic->colo_filter_sec_rewriter0_queue, oparg);
} else if (MATCH_OPTION("colo_checkpoint_host", token, oparg)) {
replace_string(&nic->colo_checkpoint_host, oparg);
} else if (MATCH_OPTION("colo_checkpoint_port", token, oparg)) {
replace_string(&nic->colo_checkpoint_port, oparg);
} else if (MATCH_OPTION("accel", token, oparg)) {
fprintf(stderr, "the accel parameter for vifs is currently not supported\n");
} else if (MATCH_OPTION("devid", token, oparg)) {
nic->devid = parse_ulong(oparg);
} else if (MATCH_OPTION("mtu", token, oparg)) {
nic->mtu = parse_ulong(oparg);
} else if (!strcmp("trusted", token)) {
libxl_defbool_set(&nic->trusted, true);
} else if (!strcmp("untrusted", token)) {
libxl_defbool_set(&nic->trusted, false);
} else {
fprintf(stderr, "unrecognized argument `%s'\n", token);
return 1;
}
return 0;
}
static void parse_vnuma_config(const XLU_Config *config,
libxl_domain_build_info *b_info)
{
libxl_physinfo physinfo;
uint32_t nr_nodes;
XLU_ConfigList *vnuma;
int i, j, len, num_vnuma;
unsigned long max_vcpus = 0, max_memkb = 0;
/* Temporary storage for parsed vcpus information to avoid
* parsing config twice. This array has num_vnuma elements.
*/
libxl_bitmap *vcpu_parsed;
libxl_physinfo_init(&physinfo);
if (libxl_get_physinfo(ctx, &physinfo) != 0) {
libxl_physinfo_dispose(&physinfo);
fprintf(stderr, "libxl_get_physinfo failed\n");
exit(EXIT_FAILURE);
}
nr_nodes = physinfo.nr_nodes;
libxl_physinfo_dispose(&physinfo);
if (xlu_cfg_get_list(config, "vnuma", &vnuma, &num_vnuma, 1))
return;
if (!num_vnuma)
return;
b_info->num_vnuma_nodes = num_vnuma;
b_info->vnuma_nodes = xcalloc(num_vnuma, sizeof(libxl_vnode_info));
vcpu_parsed = xcalloc(num_vnuma, sizeof(libxl_bitmap));
for (i = 0; i < num_vnuma; i++) {
libxl_bitmap_init(&vcpu_parsed[i]);
if (libxl_cpu_bitmap_alloc(ctx, &vcpu_parsed[i], b_info->max_vcpus)) {
fprintf(stderr, "libxl_node_bitmap_alloc failed.\n");
exit(EXIT_FAILURE);
}
}
for (i = 0; i < b_info->num_vnuma_nodes; i++) {
libxl_vnode_info *p = &b_info->vnuma_nodes[i];
libxl_vnode_info_init(p);
p->distances = xcalloc(b_info->num_vnuma_nodes,
sizeof(*p->distances));
p->num_distances = b_info->num_vnuma_nodes;
}
for (i = 0; i < num_vnuma; i++) {
XLU_ConfigValue *vnode_spec, *conf_option;
XLU_ConfigList *vnode_config_list;
int conf_count;
libxl_vnode_info *p = &b_info->vnuma_nodes[i];
vnode_spec = xlu_cfg_get_listitem2(vnuma, i);
assert(vnode_spec);
xlu_cfg_value_get_list(config, vnode_spec, &vnode_config_list, 0);
if (!vnode_config_list) {
fprintf(stderr, "xl: cannot get vnode config option list\n");
exit(EXIT_FAILURE);
}
for (conf_count = 0;
(conf_option =
xlu_cfg_get_listitem2(vnode_config_list, conf_count));
conf_count++) {
if (xlu_cfg_value_type(conf_option) == XLU_STRING) {
char *buf;
char *option, *value;
unsigned long val;
xlu_cfg_value_get_string(config, conf_option, &buf, 0);
if (!buf) continue;
if (split_string_into_pair(buf, '=', &option, &value,
isspace)) {
fprintf(stderr, "xl: failed to split \"%s\" into pair\n",
buf);
exit(EXIT_FAILURE);
}
if (!strcmp("pnode", option)) {
val = parse_ulong(value);
if (val >= nr_nodes) {
fprintf(stderr,
"xl: invalid pnode number: %lu\n", val);
exit(EXIT_FAILURE);
}
p->pnode = val;
libxl_defbool_set(&b_info->numa_placement, false);
} else if (!strcmp("size", option)) {
val = parse_ulong(value);
p->memkb = val << 10;
max_memkb += p->memkb;
} else if (!strcmp("vcpus", option)) {
libxl_string_list cpu_spec_list;
unsigned long s, e;
split_string_into_string_list(value, ",", &cpu_spec_list);
len = libxl_string_list_length(&cpu_spec_list);
for (j = 0; j < len; j++) {
parse_range(cpu_spec_list[j], &s, &e);
for (; s <= e; s++) {
/*
* Note that if we try to set a bit beyond
* the size of bitmap, libxl_bitmap_set
* has no effect. The resulted bitmap
* doesn't reflect what user wants. The
* fallout is dealt with later after
* parsing.
*/
libxl_bitmap_set(&vcpu_parsed[i], s);
max_vcpus++;
}
}
libxl_string_list_dispose(&cpu_spec_list);
} else if (!strcmp("vdistances", option)) {
libxl_string_list vdist;
split_string_into_string_list(value, ",", &vdist);
len = libxl_string_list_length(&vdist);
for (j = 0; j < len; j++) {
val = parse_ulong(vdist[j]);
p->distances[j] = val;
}
libxl_string_list_dispose(&vdist);
}
free(option);
free(value);
}
}
}
/* User has specified maxvcpus= */
if (b_info->max_vcpus != 0) {
if (b_info->max_vcpus != max_vcpus) {
fprintf(stderr, "xl: vnuma vcpus and maxvcpus= mismatch\n");
exit(EXIT_FAILURE);
}
} else {
int host_cpus = libxl_get_online_cpus(ctx);
if (host_cpus < 0) {
fprintf(stderr, "Failed to get online cpus\n");
exit(EXIT_FAILURE);
}
if (host_cpus < max_vcpus) {
fprintf(stderr, "xl: vnuma specifies more vcpus than pcpus, "\
"use maxvcpus= to override this check.\n");
exit(EXIT_FAILURE);
}
b_info->max_vcpus = max_vcpus;
}
/* User has specified maxmem= */
if (b_info->max_memkb != LIBXL_MEMKB_DEFAULT &&
b_info->max_memkb != max_memkb) {
fprintf(stderr, "xl: maxmem and vnuma memory size mismatch\n");
exit(EXIT_FAILURE);
} else
b_info->max_memkb = max_memkb;
for (i = 0; i < b_info->num_vnuma_nodes; i++) {
libxl_vnode_info *p = &b_info->vnuma_nodes[i];
libxl_bitmap_copy_alloc(ctx, &p->vcpus, &vcpu_parsed[i]);
libxl_bitmap_dispose(&vcpu_parsed[i]);
}
free(vcpu_parsed);
}
/* Parses usbctrl data and adds info into usbctrl
* Returns 1 if the input token does not match one of the keys
* or parsed values are not correct. Successful parse returns 0 */
int parse_usbctrl_config(libxl_device_usbctrl *usbctrl, char *token)
{
char *oparg;
if (MATCH_OPTION("type", token, oparg)) {
if (libxl_usbctrl_type_from_string(oparg, &usbctrl->type)) {
fprintf(stderr, "Invalid usb controller type '%s'\n", oparg);
return 1;
}
} else if (MATCH_OPTION("version", token, oparg)) {
usbctrl->version = atoi(oparg);
} else if (MATCH_OPTION("ports", token, oparg)) {
usbctrl->ports = atoi(oparg);
} else {
fprintf(stderr, "Unknown string `%s' in usbctrl spec\n", token);
return 1;
}
return 0;
}
/* Parses usbdev data and adds info into usbdev
* Returns 1 if the input token does not match one of the keys
* or parsed values are not correct. Successful parse returns 0 */
int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token)
{
char *oparg;
if (MATCH_OPTION("type", token, oparg)) {
if (libxl_usbdev_type_from_string(oparg, &usbdev->type)) {
fprintf(stderr, "Invalid usb device type: %s\n", optarg);
return 1;
}
} else if (MATCH_OPTION("hostbus", token, oparg)) {
usbdev->u.hostdev.hostbus = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION("hostaddr", token, oparg)) {
usbdev->u.hostdev.hostaddr = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION("controller", token, oparg)) {
usbdev->ctrl = atoi(oparg);
} else if (MATCH_OPTION("port", token, oparg)) {
usbdev->port = atoi(oparg);
} else {
fprintf(stderr, "Unknown string `%s' in usbdev spec\n", token);
return 1;
}
return 0;
}
int parse_vdispl_config(libxl_device_vdispl *vdispl, char *token)
{
char *oparg;
libxl_string_list connectors = NULL;
int i;
int rc;
if (MATCH_OPTION("backend", token, oparg)) {
vdispl->backend_domname = strdup(oparg);
} else if (MATCH_OPTION("be-alloc", token, oparg)) {
vdispl->be_alloc = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION("connectors", token, oparg)) {
split_string_into_string_list(oparg, ";", &connectors);
vdispl->num_connectors = libxl_string_list_length(&connectors);
vdispl->connectors = xcalloc(vdispl->num_connectors,
sizeof(*vdispl->connectors));
for(i = 0; i < vdispl->num_connectors; i++)
{
char *resolution;
rc = split_string_into_pair(connectors[i], ':',
&vdispl->connectors[i].unique_id,
&resolution, NULL);
rc= sscanf(resolution, "%ux%u", &vdispl->connectors[i].width,
&vdispl->connectors[i].height);
free(resolution);
if (rc != 2) {
fprintf(stderr, "Can't parse connector resolution\n");
goto out;
}
}
} else {
fprintf(stderr, "Unknown string \"%s\" in vdispl spec\n", token);
rc = 1; goto out;
}
rc = 0;
out:
libxl_string_list_dispose(&connectors);
return rc;
}
static int parse_vsnd_params(libxl_vsnd_params *params, char *token)
{
char *oparg;
int i;
if (MATCH_OPTION(XENSND_FIELD_SAMPLE_RATES, token, oparg)) {
libxl_string_list rates = NULL;
split_string_into_string_list(oparg, ";", &rates);
params->num_sample_rates = libxl_string_list_length(&rates);
params->sample_rates = xcalloc(params->num_sample_rates,
sizeof(*params->sample_rates));
for (i = 0; i < params->num_sample_rates; i++) {
params->sample_rates[i] = strtoul(rates[i], NULL, 0);
}
libxl_string_list_dispose(&rates);
} else if (MATCH_OPTION(XENSND_FIELD_SAMPLE_FORMATS, token, oparg)) {
libxl_string_list formats = NULL;
split_string_into_string_list(oparg, ";", &formats);
params->num_sample_formats = libxl_string_list_length(&formats);
params->sample_formats = xcalloc(params->num_sample_formats,
sizeof(*params->sample_formats));
for (i = 0; i < params->num_sample_formats; i++) {
libxl_vsnd_pcm_format format;
if (libxl_vsnd_pcm_format_from_string(formats[i], &format)) {
fprintf(stderr, "Invalid pcm format: %s\n", formats[i]);
exit(EXIT_FAILURE);
}
params->sample_formats[i] = format;
}
libxl_string_list_dispose(&formats);
} else if (MATCH_OPTION(XENSND_FIELD_CHANNELS_MIN, token, oparg)) {
params->channels_min = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENSND_FIELD_CHANNELS_MAX, token, oparg)) {
params->channels_max = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENSND_FIELD_BUFFER_SIZE, token, oparg)) {
params->buffer_size = strtoul(oparg, NULL, 0);
} else {
return 1;
}
return 0;
}
static int parse_vsnd_pcm_stream(libxl_device_vsnd *vsnd, char *param)
{
if (vsnd->num_vsnd_pcms == 0) {
fprintf(stderr, "No vsnd pcm device\n");
return -1;
}
libxl_vsnd_pcm *pcm = &vsnd->pcms[vsnd->num_vsnd_pcms - 1];
if (pcm->num_vsnd_streams == 0) {
fprintf(stderr, "No vsnd stream\n");
return -1;
}
libxl_vsnd_stream *stream = &pcm->streams[pcm->num_vsnd_streams - 1];
if (parse_vsnd_params(&stream->params, param)) {
char *oparg;
if (MATCH_OPTION(XENSND_FIELD_STREAM_UNIQUE_ID, param, oparg)) {
stream->unique_id = strdup(oparg);
} else if (MATCH_OPTION(XENSND_FIELD_TYPE, param, oparg)) {
if (libxl_vsnd_stream_type_from_string(oparg, &stream->type)) {
fprintf(stderr, "Invalid stream type: %s\n", oparg);
return -1;
}
} else {
fprintf(stderr, "Invalid parameter: %s\n", param);
return -1;
}
}
return 0;
}
static int parse_vsnd_pcm_param(libxl_device_vsnd *vsnd, char *param)
{
if (vsnd->num_vsnd_pcms == 0) {
fprintf(stderr, "No pcm device\n");
return -1;
}
libxl_vsnd_pcm *pcm = &vsnd->pcms[vsnd->num_vsnd_pcms - 1];
if (parse_vsnd_params(&pcm->params, param)) {
char *oparg;
if (MATCH_OPTION(XENSND_FIELD_DEVICE_NAME, param, oparg)) {
pcm->name = strdup(oparg);
} else {
fprintf(stderr, "Invalid parameter: %s\n", param);
return -1;
}
}
return 0;
}
static int parse_vsnd_card_param(libxl_device_vsnd *vsnd, char *param)
{
if (parse_vsnd_params(&vsnd->params, param)) {
char *oparg;
if (MATCH_OPTION("backend", param, oparg)) {
vsnd->backend_domname = strdup(oparg);
} else if (MATCH_OPTION(XENSND_FIELD_VCARD_SHORT_NAME, param, oparg)) {
vsnd->short_name = strdup(oparg);
} else if (MATCH_OPTION(XENSND_FIELD_VCARD_LONG_NAME, param, oparg)) {
vsnd->long_name = strdup(oparg);
} else {
fprintf(stderr, "Invalid parameter: %s\n", param);
return -1;
}
}
return 0;
}
static int parse_vsnd_create_item(libxl_device_vsnd *vsnd, const char *key)
{
if (strcasecmp(key, "card") == 0) {
} else if (strcasecmp(key, "pcm") == 0) {
ARRAY_EXTEND_INIT_NODEVID(vsnd->pcms, vsnd->num_vsnd_pcms,
libxl_vsnd_pcm_init);
} else if (strcasecmp(key, "stream") == 0) {
if (vsnd->num_vsnd_pcms == 0) {
ARRAY_EXTEND_INIT_NODEVID(vsnd->pcms, vsnd->num_vsnd_pcms,
libxl_vsnd_pcm_init);
}
libxl_vsnd_pcm *pcm = &vsnd->pcms[vsnd->num_vsnd_pcms - 1];
ARRAY_EXTEND_INIT_NODEVID(pcm->streams, pcm->num_vsnd_streams,
libxl_vsnd_stream_init);
} else {
fprintf(stderr, "Invalid key: %s\n", key);
return -1;
}
return 0;
}
int parse_vsnd_item(libxl_device_vsnd *vsnd, const char *spec)
{
char *buf = strdup(spec);
char *token = strtok(buf, ",");
char *key = NULL;
int ret;
while (token) {
while (*token == ' ') token++;
if (!key) {
key = token;
ret = parse_vsnd_create_item(vsnd, key);
if (ret) goto out;
} else {
if (strcasecmp(key, "card") == 0) {
ret = parse_vsnd_card_param(vsnd, token);
if (ret) goto out;
} else if (strcasecmp(key, "pcm") == 0) {
ret = parse_vsnd_pcm_param(vsnd, token);
if (ret) goto out;
} else if (strcasecmp(key, "stream") == 0) {
ret = parse_vsnd_pcm_stream(vsnd, token);
if (ret) goto out;
}
}
token = strtok (NULL, ",");
}
ret = 0;
out:
free(buf);
return ret;
}
static void parse_vsnd_card_config(const XLU_Config *config,
XLU_ConfigValue *card_value,
libxl_domain_config *d_config)
{
int ret;
XLU_ConfigList *card_list;
libxl_device_vsnd *vsnd;
const char *card_item;
int item = 0;
ret = xlu_cfg_value_get_list(config, card_value, &card_list, 0);
if (ret) {
fprintf(stderr, "Failed to get vsnd card list: %s\n", strerror(ret));
goto out;
}
vsnd = ARRAY_EXTEND_INIT(d_config->vsnds,
d_config->num_vsnds,
libxl_device_vsnd_init);
while ((card_item = xlu_cfg_get_listitem(card_list, item++)) != NULL) {
ret = parse_vsnd_item(vsnd, card_item);
if (ret) goto out;
}
ret = 0;
out:
if (ret) exit(EXIT_FAILURE);
}
static void parse_vsnd_config(const XLU_Config *config,
libxl_domain_config *d_config)
{
XLU_ConfigList *vsnds;
if (!xlu_cfg_get_list(config, "vsnd", &vsnds, 0, 0)) {
XLU_ConfigValue *card_value;
d_config->num_vsnds = 0;
d_config->vsnds = NULL;
while ((card_value = xlu_cfg_get_listitem2(vsnds, d_config->num_vsnds))
!= NULL) {
parse_vsnd_card_config(config, card_value, d_config);
}
}
}
int parse_vkb_config(libxl_device_vkb *vkb, char *token)
{
char *oparg;
if (MATCH_OPTION("backend", token, oparg)) {
vkb->backend_domname = strdup(oparg);
} else if (MATCH_OPTION("backend-type", token, oparg)) {
libxl_vkb_backend backend_type;
if (libxl_vkb_backend_from_string(oparg, &backend_type)) {
fprintf(stderr, "Unknown backend_type \"%s\" in vkb spec\n",
oparg);
return -1;
}
vkb->backend_type = backend_type;
} else if (MATCH_OPTION(XENKBD_FIELD_UNIQUE_ID, token, oparg)) {
vkb->unique_id = strdup(oparg);
} else if (MATCH_OPTION(XENKBD_FIELD_FEAT_DSBL_KEYBRD, token, oparg)) {
vkb->feature_disable_keyboard = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_FEAT_DSBL_POINTER, token, oparg)) {
vkb->feature_disable_pointer = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_FEAT_ABS_POINTER, token, oparg)) {
vkb->feature_abs_pointer = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_FEAT_RAW_POINTER, token, oparg)) {
vkb->feature_raw_pointer = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_FEAT_MTOUCH, token, oparg)) {
vkb->feature_multi_touch = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_MT_WIDTH, token, oparg)) {
vkb->multi_touch_width = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_MT_HEIGHT, token, oparg)) {
vkb->multi_touch_height = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_MT_NUM_CONTACTS, token, oparg)) {
vkb->multi_touch_num_contacts = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_WIDTH, token, oparg)) {
vkb->width = strtoul(oparg, NULL, 0);
} else if (MATCH_OPTION(XENKBD_FIELD_HEIGHT, token, oparg)) {
vkb->height = strtoul(oparg, NULL, 0);
} else {
fprintf(stderr, "Unknown string \"%s\" in vkb spec\n", token);
return -1;
}
return 0;
}
static void parse_vkb_list(const XLU_Config *config,
libxl_domain_config *d_config)
{
XLU_ConfigList *vkbs;
const char *item;
char *buf = NULL;
int rc;
if (!xlu_cfg_get_list (config, "vkb", &vkbs, 0, 0)) {
int entry = 0;
while ((item = xlu_cfg_get_listitem(vkbs, entry)) != NULL) {
libxl_device_vkb *vkb;
char *p;
vkb = ARRAY_EXTEND_INIT(d_config->vkbs,
d_config->num_vkbs,
libxl_device_vkb_init);
buf = strdup(item);
p = strtok (buf, ",");
while (p != NULL)
{
while (*p == ' ') p++;
rc = parse_vkb_config(vkb, p);
if (rc) goto out;
p = strtok (NULL, ",");
}
if (vkb->backend_type == LIBXL_VKB_BACKEND_UNKNOWN) {
fprintf(stderr, "backend-type should be set in vkb spec\n");
rc = ERROR_FAIL; goto out;
}
if (vkb->multi_touch_height || vkb->multi_touch_width ||
vkb->multi_touch_num_contacts) {
vkb->feature_multi_touch = true;
}
if (vkb->feature_multi_touch && !(vkb->multi_touch_height ||
vkb->multi_touch_width || vkb->multi_touch_num_contacts)) {
fprintf(stderr, XENKBD_FIELD_MT_WIDTH", "XENKBD_FIELD_MT_HEIGHT", "
XENKBD_FIELD_MT_NUM_CONTACTS" should be set for "
"multi touch in vkb spec\n");
rc = ERROR_FAIL; goto out;
}
entry++;
}
}
rc = 0;
out:
free(buf);
if (rc) exit(EXIT_FAILURE);
}
static int parse_virtio_config(libxl_device_virtio *virtio, char *token)
{
char *oparg;
int rc;
if (MATCH_OPTION("backend", token, oparg)) {
virtio->backend_domname = strdup(oparg);
} else if (MATCH_OPTION("type", token, oparg)) {
virtio->type = strdup(oparg);
} else if (MATCH_OPTION("transport", token, oparg)) {
rc = libxl_virtio_transport_from_string(oparg, &virtio->transport);
if (rc) return rc;
} else if (MATCH_OPTION("grant_usage", token, oparg)) {
libxl_defbool_set(&virtio->grant_usage, strtoul(oparg, NULL, 0));
} else {
fprintf(stderr, "Unknown string \"%s\" in virtio spec\n", token);
return -1;
}
return 0;
}
static void parse_virtio_list(const XLU_Config *config,
libxl_domain_config *d_config)
{
XLU_ConfigList *virtios;
const char *item;
char *buf = NULL, *oparg, *str = NULL;
int rc;
if (!xlu_cfg_get_list (config, "virtio", &virtios, 0, 0)) {
int entry = 0;
while ((item = xlu_cfg_get_listitem(virtios, entry)) != NULL) {
libxl_device_virtio *virtio;
char *p;
virtio = ARRAY_EXTEND_INIT(d_config->virtios, d_config->num_virtios,
libxl_device_virtio_init);
buf = strdup(item);
p = strtok(buf, ",");
while (p != NULL)
{
while (*p == ' ') p++;
// Type may contain a comma, do special handling.
if (MATCH_OPTION("type", p, oparg)) {
if (!strncmp(oparg, "virtio", strlen("virtio"))) {
char *p2 = strtok(NULL, ",");
str = malloc(strlen(p) + strlen(p2) + 2);
strcpy(str, p);
strcat(str, ",");
strcat(str, p2);
p = str;
}
}
rc = parse_virtio_config(virtio, p);
if (rc) goto out;
free(str);
str = NULL;
p = strtok(NULL, ",");
}
entry++;
free(buf);
}
}
return;
out:
free(buf);
if (rc) exit(EXIT_FAILURE);
}
void parse_config_data(const char *config_source,
const char *config_data,
int config_len,
libxl_domain_config *d_config)
{
libxl_physinfo physinfo;
const char *buf;
long l, vcpus = 0;
XLU_Config *config;
XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
*usbctrls, *usbdevs, *p9devs, *vdispls, *pvcallsifs_devs;
XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs,
*mca_caps, *smbios;
int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian, num_mca_caps;
int num_smbios;
int pci_power_mgmt = 0;
int pci_msitranslate = 0;
int pci_permissive = 0;
int pci_seize = 0;
int i, e;
char *kernel_basename;
libxl_domain_create_info *c_info = &d_config->c_info;
libxl_domain_build_info *b_info = &d_config->b_info;
libxl_physinfo_init(&physinfo);
if (libxl_get_physinfo(ctx, &physinfo) != 0) {
libxl_physinfo_dispose(&physinfo);
fprintf(stderr, "libxl_get_physinfo failed\n");
exit(EXIT_FAILURE);
}
libxl_physinfo_dispose(&physinfo);
config= xlu_cfg_init(stderr, config_source);
if (!config) {
fprintf(stderr, "Failed to allocate for configuration\n");
exit(1);
}
e= xlu_cfg_readdata(config, config_data, config_len);
if (e) {
fprintf(stderr, "Failed to parse config: %s\n", strerror(e));
exit(1);
}
if (!xlu_cfg_get_string (config, "init_seclabel", &buf, 0))
xlu_cfg_replace_string(config, "init_seclabel",
&c_info->ssid_label, 0);
if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) {
if (c_info->ssid_label)
xlu_cfg_replace_string(config, "seclabel",
&b_info->exec_ssid_label, 0);
else
xlu_cfg_replace_string(config, "seclabel",
&c_info->ssid_label, 0);
}
libxl_defbool_set(&c_info->run_hotplug_scripts, run_hotplug_scripts);
if (!xlu_cfg_get_string(config, "type", &buf, 0)) {
if (!strncmp(buf, "hvm", strlen(buf)))
c_info->type = LIBXL_DOMAIN_TYPE_HVM;
else if (!strncmp(buf, "pv", strlen(buf)))
c_info->type = LIBXL_DOMAIN_TYPE_PV;
else if (!strncmp(buf, "pvh", strlen(buf)))
c_info->type = LIBXL_DOMAIN_TYPE_PVH;
else {
fprintf(stderr, "Invalid domain type %s.\n", buf);
exit(1);
}
}
/* Deprecated since Xen 4.10. */
if (!xlu_cfg_get_string(config, "builder", &buf, 0)) {
libxl_domain_type builder_type;
if (!strncmp(buf, "hvm", strlen(buf)))
builder_type = LIBXL_DOMAIN_TYPE_HVM;
else if (!strncmp(buf, "generic", strlen(buf)))
builder_type = LIBXL_DOMAIN_TYPE_PV;
else {
fprintf(stderr, "Invalid domain type %s.\n", buf);
exit(1);
}
if (c_info->type != LIBXL_DOMAIN_TYPE_INVALID &&
c_info->type != builder_type) {
fprintf(stderr,
"Contradicting \"builder\" and \"type\" options specified.\n");
exit(1);
}
c_info->type = builder_type;
}
if (c_info->type == LIBXL_DOMAIN_TYPE_INVALID)
#if defined(__arm__) || defined(__aarch64__)
c_info->type = LIBXL_DOMAIN_TYPE_PVH;
#else
c_info->type = LIBXL_DOMAIN_TYPE_PV;
#endif
xlu_cfg_get_defbool(config, "hap", &c_info->hap, 0);
if (xlu_cfg_replace_string (config, "name", &c_info->name, 0)) {
fprintf(stderr, "Domain name must be specified.\n");
exit(1);
}
if (!xlu_cfg_get_string (config, "uuid", &buf, 0) ) {
if ( libxl_uuid_from_string(&c_info->uuid, buf) ) {
fprintf(stderr, "Failed to parse UUID: %s\n", buf);
exit(1);
}
}else{
libxl_uuid_generate(&c_info->uuid);
}
xlu_cfg_get_defbool(config, "oos", &c_info->oos, 0);
if (!xlu_cfg_get_string (config, "pool", &buf, 0))
xlu_cfg_replace_string(config, "pool", &c_info->pool_name, 0);
libxl_domain_build_info_init_type(b_info, c_info->type);
if (b_info->type == LIBXL_DOMAIN_TYPE_PVH) {
xlu_cfg_get_defbool(config, "pvshim", &b_info->u.pvh.pvshim, 0);
if (!xlu_cfg_get_string(config, "pvshim_path", &buf, 0))
xlu_cfg_replace_string(config, "pvshim_path",
&b_info->u.pvh.pvshim_path, 0);
if (!xlu_cfg_get_string(config, "pvshim_cmdline", &buf, 0))
xlu_cfg_replace_string(config, "pvshim_cmdline",
&b_info->u.pvh.pvshim_cmdline, 0);
if (!xlu_cfg_get_string(config, "pvshim_extra", &buf, 0))
xlu_cfg_replace_string(config, "pvshim_extra",
&b_info->u.pvh.pvshim_extra, 0);
}
if (blkdev_start)
b_info->blkdev_start = strdup(blkdev_start);
/* the following is the actual config parsing with overriding
* values in the structures */
if (!xlu_cfg_get_long (config, "cpu_weight", &l, 0))
b_info->sched_params.weight = l;
if (!xlu_cfg_get_long (config, "cap", &l, 0))
b_info->sched_params.cap = l;
if (!xlu_cfg_get_long (config, "period", &l, 0))
b_info->sched_params.period = l;
if (!xlu_cfg_get_long (config, "slice", &l, 0))
b_info->sched_params.slice = l;
if (!xlu_cfg_get_long (config, "latency", &l, 0))
b_info->sched_params.latency = l;
if (!xlu_cfg_get_long (config, "extratime", &l, 0))
b_info->sched_params.extratime = l;
if (!xlu_cfg_get_long (config, "memory", &l, 0))
b_info->target_memkb = l * 1024;
if (!xlu_cfg_get_long (config, "maxmem", &l, 0))
b_info->max_memkb = l * 1024;
if (!xlu_cfg_get_long (config, "vcpus", &l, 0)) {
vcpus = l;
if (libxl_cpu_bitmap_alloc(ctx, &b_info->avail_vcpus, l)) {
fprintf(stderr, "Unable to allocate cpumap\n");
exit(1);
}
libxl_bitmap_set_none(&b_info->avail_vcpus);
while (l-- > 0)
libxl_bitmap_set((&b_info->avail_vcpus), l);
}
if (!xlu_cfg_get_long (config, "maxvcpus", &l, 0))
b_info->max_vcpus = l;
if (!xlu_cfg_get_string(config, "vuart", &buf, 0)) {
if (libxl_vuart_type_from_string(buf, &b_info->arch_arm.vuart)) {
fprintf(stderr, "ERROR: invalid value \"%s\" for \"vuart\"\n",
buf);
exit(1);
}
}
parse_vnuma_config(config, b_info);
/* Set max_memkb to target_memkb and max_vcpus to avail_vcpus if
* they are not set by user specified config option or vnuma.
*/
if (b_info->max_memkb == LIBXL_MEMKB_DEFAULT)
b_info->max_memkb = b_info->target_memkb;
if (b_info->max_vcpus == 0)
b_info->max_vcpus = vcpus;
if (b_info->max_vcpus < vcpus) {
fprintf(stderr, "xl: maxvcpus < vcpus\n");
exit(1);
}
buf = NULL;
if (!xlu_cfg_get_list (config, "cpus", &cpus, &num_cpus, 1) ||
!xlu_cfg_get_string (config, "cpus", &buf, 0))
parse_vcpu_affinity(b_info, cpus, buf, num_cpus, /* is_hard */ true);
buf = NULL;
if (!xlu_cfg_get_list (config, "cpus_soft", &cpus, &num_cpus, 1) ||
!xlu_cfg_get_string (config, "cpus_soft", &buf, 0))
parse_vcpu_affinity(b_info, cpus, buf, num_cpus, false);
e = xlu_cfg_get_bounded_long (config, "max_grant_frames", 0, INT_MAX,
&l, 1);
if (e == ESRCH) /* not specified */
b_info->max_grant_frames = max_grant_frames;
else if (!e)
b_info->max_grant_frames = l;
else
exit(1);
e = xlu_cfg_get_bounded_long (config, "max_maptrack_frames", 0,
INT_MAX, &l, 1);
if (e == ESRCH) /* not specified */
b_info->max_maptrack_frames = max_maptrack_frames;
else if (!e)
b_info->max_maptrack_frames = l;
else
exit(1);
e = xlu_cfg_get_bounded_long (config, "max_grant_version", 0,
INT_MAX, &l, 1);
if (e == ESRCH) /* not specified */
b_info->max_grant_version = max_grant_version;
else if (!e)
b_info->max_grant_version = l;
else
exit(1);
libxl_defbool_set(&b_info->claim_mode, claim_mode);
if (xlu_cfg_get_string (config, "on_poweroff", &buf, 0))
buf = "destroy";
if (!parse_action_on_shutdown(buf, &d_config->on_poweroff)) {
fprintf(stderr, "Unknown on_poweroff action \"%s\" specified\n", buf);
exit(1);
}
if (xlu_cfg_get_string (config, "on_reboot", &buf, 0))
buf = "restart";
if (!parse_action_on_shutdown(buf, &d_config->on_reboot)) {
fprintf(stderr, "Unknown on_reboot action \"%s\" specified\n", buf);
exit(1);
}
if (xlu_cfg_get_string (config, "on_watchdog", &buf, 0))
buf = "destroy";
if (!parse_action_on_shutdown(buf, &d_config->on_watchdog)) {
fprintf(stderr, "Unknown on_watchdog action \"%s\" specified\n", buf);
exit(1);
}
if (xlu_cfg_get_string (config, "on_crash", &buf, 0))
buf = "destroy";
if (!parse_action_on_shutdown(buf, &d_config->on_crash)) {
fprintf(stderr, "Unknown on_crash action \"%s\" specified\n", buf);
exit(1);
}
if (xlu_cfg_get_string (config, "on_soft_reset", &buf, 0))
buf = "soft-reset";
if (!parse_action_on_shutdown(buf, &d_config->on_soft_reset)) {
fprintf(stderr, "Unknown on_soft_reset action \"%s\" specified\n", buf);
exit(1);
}
/* To be reworked (automatically enabled) once the auto ballooning
* after guest starts is done (with PCI devices passed in). */
if (c_info->type == LIBXL_DOMAIN_TYPE_PV) {
xlu_cfg_get_defbool(config, "e820_host", &b_info->u.pv.e820_host, 0);
}
if (!xlu_cfg_get_long (config, "pci_msitranslate", &l, 0))
pci_msitranslate = l;
if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l, 0))
pci_power_mgmt = l;
if (!xlu_cfg_get_long (config, "pci_permissive", &l, 0))
pci_permissive = l;
if (!xlu_cfg_get_long (config, "pci_seize", &l, 0))
pci_seize = l;
if (!xlu_cfg_get_string(config, "rdm", &buf, 0)) {
libxl_rdm_reserve rdm;
if (!xlu_rdm_parse(config, &rdm, buf)) {
b_info->u.hvm.rdm.strategy = rdm.strategy;
b_info->u.hvm.rdm.policy = rdm.policy;
}
}
if (!xlu_cfg_get_list (config, "pci", &pcis, 0, 0)) {
d_config->num_pcidevs = 0;
d_config->pcidevs = NULL;
for(i = 0; (buf = xlu_cfg_get_listitem (pcis, i)) != NULL; i++) {
libxl_device_pci *pci;
pci = ARRAY_EXTEND_INIT_NODEVID(d_config->pcidevs,
d_config->num_pcidevs,
libxl_device_pci_init);
pci->msitranslate = pci_msitranslate;
pci->power_mgmt = pci_power_mgmt;
pci->permissive = pci_permissive;
pci->seize = pci_seize;
/*
* Like other pci option, the per-device policy always follows
* the global policy by default.
*/
pci->rdm_policy = b_info->u.hvm.rdm.policy;
e = xlu_pci_parse_spec_string(config, pci, buf);
if (e) {
fprintf(stderr,
"unable to parse PCI_SPEC_STRING `%s' for passthrough\n",
buf);
exit(-e);
}
}
if (d_config->num_pcidevs && c_info->type == LIBXL_DOMAIN_TYPE_PV)
libxl_defbool_set(&b_info->u.pv.e820_host, true);
}
if (!xlu_cfg_get_list (config, "dtdev", &dtdevs, 0, 0)) {
d_config->num_dtdevs = 0;
d_config->dtdevs = NULL;
for (i = 0; (buf = xlu_cfg_get_listitem(dtdevs, i)) != NULL; i++) {
libxl_device_dtdev *dtdev;
dtdev = ARRAY_EXTEND_INIT_NODEVID(d_config->dtdevs,
d_config->num_dtdevs,
libxl_device_dtdev_init);
dtdev->path = strdup(buf);
if (dtdev->path == NULL) {
fprintf(stderr, "unable to duplicate string for dtdevs\n");
exit(-1);
}
}
}
if (!xlu_cfg_get_string(config, "passthrough", &buf, 0)) {
if (libxl_passthrough_from_string(buf, &c_info->passthrough)) {
fprintf(stderr,
"ERROR: unknown passthrough option '%s'\n",
buf);
exit(1);
}
}
if (!xlu_cfg_get_long(config, "shadow_memory", &l, 0))
b_info->shadow_memkb = l * 1024;
xlu_cfg_get_defbool(config, "nomigrate", &b_info->disable_migrate, 0);
if (!xlu_cfg_get_long(config, "tsc_mode", &l, 1)) {
const char *s = libxl_tsc_mode_to_string(l);
fprintf(stderr, "WARNING: specifying \"tsc_mode\" as an integer is deprecated. "
"Please use the named parameter variant. %s%s%s\n",
s ? "e.g. tsc_mode=\"" : "",
s ? s : "",
s ? "\"" : "");
if (l < LIBXL_TSC_MODE_DEFAULT ||
l > LIBXL_TSC_MODE_NATIVE_PARAVIRT) {
fprintf(stderr, "ERROR: invalid value %ld for \"tsc_mode\"\n", l);
exit (1);
}
b_info->tsc_mode = l;
} else if (!xlu_cfg_get_string(config, "tsc_mode", &buf, 0)) {
fprintf(stderr, "got a tsc mode string: \"%s\"\n", buf);
if (libxl_tsc_mode_from_string(buf, &b_info->tsc_mode)) {
fprintf(stderr, "ERROR: invalid value \"%s\" for \"tsc_mode\"\n",
buf);
exit (1);
}
}
if (!xlu_cfg_get_long(config, "rtc_timeoffset", &l, 0))
b_info->rtc_timeoffset = l;
if (!xlu_cfg_get_long(config, "vncviewer", &l, 0))
fprintf(stderr, "WARNING: ignoring \"vncviewer\" option. "
"Use \"-V\" option of \"xl create\" to automatically spawn vncviewer.\n");
xlu_cfg_get_defbool(config, "localtime", &b_info->localtime, 0);
if (!xlu_cfg_get_long (config, "videoram", &l, 0))
b_info->video_memkb = l * 1024;
if (!xlu_cfg_get_long(config, "max_event_channels", &l, 0))
b_info->event_channels = l;
xlu_cfg_replace_string (config, "kernel", &b_info->kernel, 0);
xlu_cfg_replace_string (config, "ramdisk", &b_info->ramdisk, 0);
xlu_cfg_replace_string (config, "device_tree", &b_info->device_tree, 0);
b_info->cmdline = parse_cmdline(config);
xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0);
xlu_cfg_get_defbool(config, "acpi", &b_info->acpi, 0);
xlu_cfg_replace_string (config, "bootloader", &b_info->bootloader, 0);
#ifndef HAVE_PYGRUB
if (b_info->bootloader &&
(!strcmp(b_info->bootloader, "pygrub") ||
!strcmp(b_info->bootloader, "/usr/bin/pygrub"))) {
fprintf(stderr, "ERROR: this instance of Xen has been built without support of \"pygrub\".\n");
exit(-ERROR_FAIL);
}
#endif
xlu_cfg_get_defbool(config, "bootloader_restrict",
&b_info->bootloader_restrict, 0);
if (!libxl_defbool_is_default(bootloader_restrict))
libxl_defbool_setdefault(&b_info->bootloader_restrict,
libxl_defbool_val(bootloader_restrict));
xlu_cfg_replace_string(config, "bootloader_user",
&b_info->bootloader_user, 0);
switch (xlu_cfg_get_list_as_string_list(config, "bootloader_args",
&b_info->bootloader_args, 1)) {
case 0:
break; /* Success */
case ESRCH: break; /* Option not present */
case EINVAL:
if (!xlu_cfg_get_string(config, "bootloader_args", &buf, 0)) {
fprintf(stderr, "WARNING: Specifying \"bootloader_args\""
" as a string is deprecated. "
"Please use a list of arguments.\n");
split_string_into_string_list(buf, " \t\n",
&b_info->bootloader_args);
}
break;
default:
fprintf(stderr,"xl: Unable to parse bootloader_args.\n");
exit(-ERROR_FAIL);
}
if (!xlu_cfg_get_long(config, "timer_mode", &l, 1)) {
const char *s = libxl_timer_mode_to_string(l);
if (b_info->type == LIBXL_DOMAIN_TYPE_PV) {
fprintf(stderr,
"ERROR: \"timer_mode\" option is not supported for PV guests.\n");
exit(-ERROR_FAIL);
}
fprintf(stderr,
"WARNING: specifying \"timer_mode\" as an integer is deprecated. "
"Please use the named parameter variant. %s%s%s\n",
s ? "e.g. timer_mode=\"" : "",
s ? s : "",
s ? "\"" : "");
if (l < LIBXL_TIMER_MODE_DELAY_FOR_MISSED_TICKS ||
l > LIBXL_TIMER_MODE_ONE_MISSED_TICK_PENDING) {
fprintf(stderr, "ERROR: invalid value %ld for \"timer_mode\"\n",
l);
exit (1);
}
b_info->timer_mode = l;
} else if (!xlu_cfg_get_string(config, "timer_mode", &buf, 0)) {
if (b_info->type == LIBXL_DOMAIN_TYPE_PV) {
fprintf(stderr,
"ERROR: \"timer_mode\" option is not supported for PV guests.\n");
exit(-ERROR_FAIL);
}
if (libxl_timer_mode_from_string(buf, &b_info->timer_mode)) {
fprintf(stderr,
"ERROR: invalid value \"%s\" for \"timer_mode\"\n", buf);
exit (1);
}
}
xlu_cfg_get_defbool(config, "nestedhvm", &b_info->nested_hvm, 0);
switch(b_info->type) {
case LIBXL_DOMAIN_TYPE_HVM:
kernel_basename = libxl_basename(b_info->kernel);
if (!strcmp(kernel_basename, "hvmloader")) {
fprintf(stderr, "WARNING: you seem to be using \"kernel\" "
"directive to override HVM guest firmware. Ignore "
"that. Use \"firmware_override\" instead if you "
"really want a non-default firmware\n");
b_info->kernel = NULL;
}
free(kernel_basename);
xlu_cfg_replace_string (config, "firmware_override",
&b_info->u.hvm.firmware, 0);
xlu_cfg_replace_string (config, "bios_path_override",
&b_info->u.hvm.system_firmware, 0);
if (!xlu_cfg_get_string(config, "bios", &buf, 0)) {
if (libxl_bios_type_from_string(buf, &b_info->u.hvm.bios)) {
fprintf(stderr, "ERROR: invalid value \"%s\" for \"bios\"\n",
buf);
exit (1);
}
} else if (b_info->u.hvm.system_firmware)
fprintf(stderr, "WARNING: "
"bios_path_override given without specific bios name\n");
xlu_cfg_get_defbool(config, "pae", &b_info->u.hvm.pae, 0);
xlu_cfg_get_defbool(config, "acpi_s3", &b_info->u.hvm.acpi_s3, 0);
xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0);
xlu_cfg_get_defbool(config, "acpi_laptop_slate", &b_info->u.hvm.acpi_laptop_slate, 0);
xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0);
xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0);
xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0);
xlu_cfg_get_defbool(config, "apic", &b_info->apic, 0);
switch (xlu_cfg_get_list(config, "viridian",
&viridian, &num_viridian, 1))
{
case 0: /* Success */
if (num_viridian) {
libxl_bitmap_alloc(ctx, &b_info->u.hvm.viridian_enable,
LIBXL_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE_WIDTH);
libxl_bitmap_alloc(ctx, &b_info->u.hvm.viridian_disable,
LIBXL_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE_WIDTH);
}
for (i = 0; i < num_viridian; i++) {
libxl_viridian_enlightenment v;
buf = xlu_cfg_get_listitem(viridian, i);
if (strcmp(buf, "all") == 0)
libxl_bitmap_set_any(&b_info->u.hvm.viridian_enable);
else if (strcmp(buf, "defaults") == 0)
libxl_defbool_set(&b_info->u.hvm.viridian, true);
else {
libxl_bitmap *s = &b_info->u.hvm.viridian_enable;
libxl_bitmap *r = &b_info->u.hvm.viridian_disable;
if (*buf == '!') {
s = &b_info->u.hvm.viridian_disable;
r = &b_info->u.hvm.viridian_enable;
buf++;
}
e = libxl_viridian_enlightenment_from_string(buf, &v);
if (e) {
fprintf(stderr,
"xl: unknown viridian enlightenment '%s'\n",
buf);
exit(-ERROR_FAIL);
}
libxl_bitmap_set(s, v);
libxl_bitmap_reset(r, v);
}
}
break;
case ESRCH: break; /* Option not present */
case EINVAL:
xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 1);
break;
default:
fprintf(stderr,"xl: Unable to parse viridian enlightenments.\n");
exit(-ERROR_FAIL);
}
if (!xlu_cfg_get_long(config, "mmio_hole", &l, 0)) {
uint64_t mmio_hole_size;
b_info->u.hvm.mmio_hole_memkb = l * 1024;
mmio_hole_size = b_info->u.hvm.mmio_hole_memkb * 1024;
if (mmio_hole_size < HVM_BELOW_4G_MMIO_LENGTH ||
mmio_hole_size > HVM_BELOW_4G_MMIO_START) {
fprintf(stderr,
"ERROR: invalid value %ld for \"mmio_hole\"\n", l);
exit (1);
}
}
if (!xlu_cfg_get_defbool(config, "altp2mhvm", &b_info->u.hvm.altp2m, 0))
fprintf(stderr, "WARNING: Specifying \"altp2mhvm\" is deprecated. "
"Please use \"altp2m\" instead.\n");
xlu_cfg_replace_string(config, "smbios_firmware",
&b_info->u.hvm.smbios_firmware, 0);
xlu_cfg_replace_string(config, "acpi_firmware",
&b_info->u.hvm.acpi_firmware, 0);
switch (xlu_cfg_get_list(config, "smbios", &smbios, &num_smbios, 0))
{
case 0: /* Success */
{
unsigned int num_oem = 1;
b_info->u.hvm.num_smbios = num_smbios;
b_info->u.hvm.smbios = xcalloc(num_smbios, sizeof(libxl_smbios));
for (i = 0; i < num_smbios; i++) {
libxl_smbios_type type;
char *option;
char *value;
buf = xlu_cfg_get_listitem(smbios, i);
if (!buf) {
fprintf(stderr,
"xl: Unable to get element #%d in smbios list\n",
i);
exit(EXIT_FAILURE);
}
option = xstrdup(buf);
value = strchr(option, '=');
if (value == NULL) {
fprintf(stderr, "xl: failed to split \"%s\" at '='\n",
option);
exit(EXIT_FAILURE);
}
*value = '\0';
value++;
if (*value == '\0') {
fprintf(stderr,
"xl: empty value not allowed for smbios \"%s=\"\n",
option);
exit(EXIT_FAILURE);
}
e = libxl_smbios_type_from_string(option, &type);
if (e) {
fprintf(stderr, "xl: unknown smbios type '%s'\n", option);
exit(EXIT_FAILURE);
}
if (type == LIBXL_SMBIOS_TYPE_OEM) {
if (num_oem > 99) {
fprintf(stderr,
"xl: smbios limited to 99 oem strings\n");
exit(EXIT_FAILURE);
}
num_oem++;
}
b_info->u.hvm.smbios[i].key = type;
b_info->u.hvm.smbios[i].value = xstrdup(value);
free(option);
}
break;
}
case ESRCH: /* Option not present */
break;
default:
fprintf(stderr,"xl: Unable to parse smbios options.\n");
exit(EXIT_FAILURE);
}
if (!xlu_cfg_get_string(config, "ms_vm_genid", &buf, 0)) {
if (!strcmp(buf, "generate")) {
e = libxl_ms_vm_genid_generate(ctx, &b_info->u.hvm.ms_vm_genid);
if (e) {
fprintf(stderr, "ERROR: failed to generate a VM Generation ID\n");
exit(1);
}
} else if (!strcmp(buf, "none")) {
;
} else {
fprintf(stderr, "ERROR: \"ms_vm_genid\" option must be \"generate\" or \"none\"\n");
exit(1);
}
}
if (!xlu_cfg_get_long (config, "rdm_mem_boundary", &l, 0))
b_info->u.hvm.rdm_mem_boundary_memkb = l * 1024;
switch (xlu_cfg_get_list(config, "mca_caps",
&mca_caps, &num_mca_caps, 1))
{
case 0: /* Success */
for (i = 0; i < num_mca_caps; i++) {
buf = xlu_cfg_get_listitem(mca_caps, i);
if (!strcmp(buf, "lmce"))
b_info->u.hvm.mca_caps |= XEN_HVM_MCA_CAP_LMCE;
else {
fprintf(stderr, "ERROR: unrecognized MCA capability '%s'.\n",
buf);
exit(-ERROR_FAIL);
}
}
break;
case ESRCH: /* Option not present */
break;
default:
fprintf(stderr, "ERROR: unable to parse mca_caps.\n");
exit(-ERROR_FAIL);
}
/*
* The firmware config option can be used as a simplification
* instead of setting bios or firmware_override. It has the
* following meanings for HVM guests:
*
* - ovmf | seabios | rombios: maps directly into the "bios"
* option.
* - uefi | bios: maps into one of the above options and is set
* in the bios field.
* - Anything else is treated as a path that is copied into
* firmware.
*/
if (!xlu_cfg_get_string (config, "firmware", &buf, 0) &&
libxl_bios_type_from_string(buf, &b_info->u.hvm.bios)) {
if (!strncmp(buf, "uefi", strlen(buf)))
b_info->u.hvm.bios = LIBXL_BIOS_TYPE_OVMF;
else if (strncmp(buf, "bios", strlen(buf)))
/* Assume it's a path to a custom firmware. */
xlu_cfg_replace_string(config, "firmware",
&b_info->u.hvm.firmware, 0);
/*
* BIOS is the default, and will be chosen by libxl based on
* the device model specified.
*/
}
break;
case LIBXL_DOMAIN_TYPE_PVH:
case LIBXL_DOMAIN_TYPE_PV:
{
/*
* The firmware config option can be used as a simplification
* instead of directly setting kernel. It will be translated to
* XENFIRMWAREDIR/<string>.bin
*/
if (!xlu_cfg_get_string (config, "firmware", &buf, 0)) {
if (b_info->kernel) {
fprintf(stderr,
"ERROR: both kernel and firmware specified\n");
exit(1);
}
if (strncmp(buf, "pvgrub32", strlen(buf)) &&
strncmp(buf, "pvgrub64", strlen(buf))) {
fprintf(stderr,
"ERROR: only pvgrub{32|64} supported as firmware options\n");
exit(1);
}
xasprintf(&b_info->kernel, XENFIRMWAREDIR "/%s.bin", buf);
}
if (!b_info->bootloader && !b_info->kernel) {
fprintf(stderr, "Neither kernel nor bootloader specified\n");
exit(1);
}
break;
}
default:
abort();
}
if (!xlu_cfg_get_long(config, "altp2m", &l, 1)) {
if (l < LIBXL_ALTP2M_MODE_DISABLED ||
l > LIBXL_ALTP2M_MODE_LIMITED) {
fprintf(stderr, "ERROR: invalid value %ld for \"altp2m\"\n", l);
exit (1);
}
b_info->altp2m = l;
} else if (!xlu_cfg_get_string(config, "altp2m", &buf, 0)) {
if (libxl_altp2m_mode_from_string(buf, &b_info->altp2m)) {
fprintf(stderr, "ERROR: invalid value \"%s\" for \"altp2m\"\n",
buf);
exit (1);
}
}
if (!xlu_cfg_get_long(config, "vmtrace_buf_kb", &l, 1) && l) {
b_info->vmtrace_buf_kb = l;
}
if (!xlu_cfg_get_list(config, "ioports", &ioports, &num_ioports, 0)) {
b_info->num_ioports = num_ioports;
b_info->ioports = calloc(num_ioports, sizeof(*b_info->ioports));
if (b_info->ioports == NULL) {
fprintf(stderr, "unable to allocate memory for ioports\n");
exit(-1);
}
for (i = 0; i < num_ioports; i++) {
const char *buf2;
char *ep;
uint32_t start, end;
unsigned long ul;
buf = xlu_cfg_get_listitem (ioports, i);
if (!buf) {
fprintf(stderr,
"xl: Unable to get element #%d in ioport list\n", i);
exit(1);
}
ul = strtoul(buf, &ep, 16);
if (ep == buf) {
fprintf(stderr, "xl: Invalid argument parsing ioport: %s\n",
buf);
exit(1);
}
if (ul >= UINT32_MAX) {
fprintf(stderr, "xl: ioport %lx too big\n", ul);
exit(1);
}
start = end = ul;
if (*ep == '-') {
buf2 = ep + 1;
ul = strtoul(buf2, &ep, 16);
if (ep == buf2 || *ep != '\0' || start > end) {
fprintf(stderr,
"xl: Invalid argument parsing ioport: %s\n", buf);
exit(1);
}
if (ul >= UINT32_MAX) {
fprintf(stderr, "xl: ioport %lx too big\n", ul);
exit(1);
}
end = ul;
} else if ( *ep != '\0' )
fprintf(stderr,
"xl: Invalid argument parsing ioport: %s\n", buf);
b_info->ioports[i].first = start;
b_info->ioports[i].number = end - start + 1;
}
}
if (!xlu_cfg_get_list(config, "irqs", &irqs, &num_irqs, 0)) {
b_info->num_irqs = num_irqs;
b_info->irqs = calloc(num_irqs, sizeof(*b_info->irqs));
if (b_info->irqs == NULL) {
fprintf(stderr, "unable to allocate memory for ioports\n");
exit(-1);
}
for (i = 0; i < num_irqs; i++) {
char *ep;
unsigned long ul;
buf = xlu_cfg_get_listitem (irqs, i);
if (!buf) {
fprintf(stderr,
"xl: Unable to get element %d in irq list\n", i);
exit(1);
}
ul = strtoul(buf, &ep, 10);
if (ep == buf || *ep != '\0') {
fprintf(stderr,
"xl: Invalid argument parsing irq: %s\n", buf);
exit(1);
}
if (ul >= UINT32_MAX) {
fprintf(stderr, "xl: irq %lx too big\n", ul);
exit(1);
}
b_info->irqs[i] = ul;
}
}
if (!xlu_cfg_get_list(config, "iomem", &iomem, &num_iomem, 0)) {
int ret;
b_info->num_iomem = num_iomem;
b_info->iomem = calloc(num_iomem, sizeof(*b_info->iomem));
if (b_info->iomem == NULL) {
fprintf(stderr, "unable to allocate memory for iomem\n");
exit(-1);
}
for (i = 0; i < num_iomem; i++) {
int used;
buf = xlu_cfg_get_listitem (iomem, i);
if (!buf) {
fprintf(stderr,
"xl: Unable to get element %d in iomem list\n", i);
exit(1);
}
libxl_iomem_range_init(&b_info->iomem[i]);
ret = sscanf(buf, "%" SCNx64",%" SCNx64"%n@%" SCNx64"%n",
&b_info->iomem[i].start,
&b_info->iomem[i].number, &used,
&b_info->iomem[i].gfn, &used);
if (ret < 2 || buf[used] != '\0') {
fprintf(stderr,
"xl: Invalid argument parsing iomem: %s\n", buf);
exit(1);
}
}
}
if (!xlu_cfg_get_list (config, "disk", &vbds, 0, 0)) {
d_config->num_disks = 0;
d_config->disks = NULL;
while ((buf = xlu_cfg_get_listitem (vbds, d_config->num_disks)) != NULL) {
libxl_device_disk *disk;
char *buf2 = strdup(buf);
disk = ARRAY_EXTEND_INIT_NODEVID(d_config->disks,
d_config->num_disks,
libxl_device_disk_init);
parse_disk_config(&config, buf2, disk);
free(buf2);
}
}
if (!xlu_cfg_get_list(config, "p9", &p9devs, 0, 0)) {
libxl_device_p9 *p9;
d_config->num_p9s = 0;
d_config->p9s = NULL;
while ((buf = xlu_cfg_get_listitem (p9devs, d_config->num_p9s)) != NULL) {
libxl_string_list pairs;
int len;
p9 = ARRAY_EXTEND_INIT(d_config->p9s,
d_config->num_p9s,
libxl_device_p9_init);
libxl_device_p9_init(p9);
split_string_into_string_list(buf, ",", &pairs);
len = libxl_string_list_length(&pairs);
for (i = 0; i < len; i++) {
char *key, *value;
int rc;
rc = split_string_into_pair(pairs[i], '=', &key, &value,
isspace);
if (rc != 0) {
fprintf(stderr, "failed to parse 9pfs configuration: %s",
pairs[i]);
exit(1);
}
if (!strcmp(key, "security_model")) {
replace_string(&p9->security_model, value);
} else if (!strcmp(key, "path")) {
replace_string(&p9->path, value);
} else if (!strcmp(key, "tag")) {
replace_string(&p9->tag, value);
} else if (!strcmp(key, "backend")) {
replace_string(&p9->backend_domname, value);
} else {
fprintf(stderr, "Unknown 9pfs parameter '%s'\n", key);
exit(1);
}
free(key);
free(value);
}
libxl_string_list_dispose(&pairs);
if (!p9->path || !p9->security_model || !p9->tag) {
fprintf(stderr, "9pfs spec missing required field!\n");
exit(1);
}
}
}
if (!xlu_cfg_get_list(config, "vtpm", &vtpms, 0, 0)) {
d_config->num_vtpms = 0;
d_config->vtpms = NULL;
while ((buf = xlu_cfg_get_listitem (vtpms, d_config->num_vtpms)) != NULL) {
libxl_device_vtpm *vtpm;
char * buf2 = strdup(buf);
char *p, *p2;
bool got_backend = false;
vtpm = ARRAY_EXTEND_INIT(d_config->vtpms,
d_config->num_vtpms,
libxl_device_vtpm_init);
p = strtok(buf2, ",");
if(p) {
do {
while(*p == ' ')
++p;
if ((p2 = strchr(p, '=')) == NULL)
break;
*p2 = '\0';
if (!strcmp(p, "backend")) {
vtpm->backend_domname = strdup(p2 + 1);
got_backend = true;
} else if(!strcmp(p, "uuid")) {
if( libxl_uuid_from_string(&vtpm->uuid, p2 + 1) ) {
fprintf(stderr,
"Failed to parse vtpm UUID: %s\n", p2 + 1);
exit(1);
}
} else {
fprintf(stderr, "Unknown string `%s' in vtpm spec\n", p);
exit(1);
}
} while ((p = strtok(NULL, ",")) != NULL);
}
if(!got_backend) {
fprintf(stderr, "vtpm spec missing required backend field!\n");
exit(1);
}
free(buf2);
}
}
if (!xlu_cfg_get_list(config, "vdispl", &vdispls, 0, 0)) {
d_config->num_vdispls = 0;
d_config->vdispls = NULL;
while ((buf = xlu_cfg_get_listitem(vdispls, d_config->num_vdispls)) != NULL) {
libxl_device_vdispl *vdispl;
char * buf2 = strdup(buf);
char *p;
vdispl = ARRAY_EXTEND_INIT(d_config->vdispls,
d_config->num_vdispls,
libxl_device_vdispl_init);
p = strtok (buf2, ",");
while (p != NULL)
{
while (*p == ' ') p++;
if (parse_vdispl_config(vdispl, p)) {
free(buf2);
exit(1);
}
p = strtok (NULL, ",");
}
free(buf2);
if (vdispl->num_connectors == 0) {
fprintf(stderr, "At least one connector should be specified.\n");
exit(1);
}
}
}
if (!xlu_cfg_get_list(config, "pvcalls", &pvcallsifs_devs, 0, 0)) {
d_config->num_pvcallsifs = 0;
d_config->pvcallsifs = NULL;
while ((buf = xlu_cfg_get_listitem (pvcallsifs_devs, d_config->num_pvcallsifs)) != NULL) {
libxl_device_pvcallsif *pvcallsif;
char *backend = NULL;
char *p, *p2, *buf2;
pvcallsif = ARRAY_EXTEND_INIT(d_config->pvcallsifs,
d_config->num_pvcallsifs,
libxl_device_pvcallsif_init);
buf2 = strdup(buf);
p = strtok(buf2, ",");
if (p) {
do {
while (*p == ' ')
++p;
if ((p2 = strchr(p, '=')) == NULL)
break;
*p2 = '\0';
if(!strcmp(p, "backend")) {
backend = strdup(p2 + 1);
} else {
fprintf(stderr, "Unknown string `%s' in pvcalls spec\n", p);
exit(1);
}
} while ((p = strtok(NULL, ",")) != NULL);
}
free(buf2);
if (backend)
replace_string(&pvcallsif->backend_domname, backend);
}
}
parse_vsnd_config(config, d_config);
if (!xlu_cfg_get_list (config, "channel", &channels, 0, 0)) {
d_config->num_channels = 0;
d_config->channels = NULL;
while ((buf = xlu_cfg_get_listitem (channels,
d_config->num_channels)) != NULL) {
libxl_device_channel *chn;
libxl_string_list pairs;
char *path = NULL;
int len;
chn = ARRAY_EXTEND_INIT(d_config->channels, d_config->num_channels,
libxl_device_channel_init);
split_string_into_string_list(buf, ",", &pairs);
len = libxl_string_list_length(&pairs);
for (i = 0; i < len; i++) {
char *key, *value;
int rc;
rc = split_string_into_pair(pairs[i], '=', &key, &value,
isspace);
if (rc != 0) {
fprintf(stderr, "failed to parse channel configuration: %s",
pairs[i]);
exit(1);
}
if (!strcmp(key, "backend")) {
replace_string(&chn->backend_domname, value);
} else if (!strcmp(key, "name")) {
replace_string(&chn->name, value);
} else if (!strcmp(key, "path")) {
replace_string(&path, value);
} else if (!strcmp(key, "connection")) {
if (!strcmp(value, "pty")) {
chn->connection = LIBXL_CHANNEL_CONNECTION_PTY;
} else if (!strcmp(value, "socket")) {
chn->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
} else {
fprintf(stderr, "unknown channel connection '%s'\n",
value);
exit(1);
}
} else {
fprintf(stderr, "unknown channel parameter '%s',"
" ignoring\n", key);
}
free(key);
free(value);
}
switch (chn->connection) {
case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
fprintf(stderr, "channel has unknown 'connection'\n");
exit(1);
case LIBXL_CHANNEL_CONNECTION_SOCKET:
if (!path) {
fprintf(stderr, "channel connection 'socket' requires path=..\n");
exit(1);
}
chn->u.socket.path = xstrdup(path);
break;
case LIBXL_CHANNEL_CONNECTION_PTY:
/* Nothing to do since PTY has no arguments */
break;
default:
fprintf(stderr, "unknown channel connection: %d",
chn->connection);
exit(1);
}
libxl_string_list_dispose(&pairs);
free(path);
}
}
if (!xlu_cfg_get_list (config, "vif", &nics, 0, 0)) {
d_config->num_nics = 0;
d_config->nics = NULL;
while ((buf = xlu_cfg_get_listitem (nics, d_config->num_nics)) != NULL) {
libxl_device_nic *nic;
char *buf2 = strdup(buf);
char *p;
nic = ARRAY_EXTEND_INIT(d_config->nics,
d_config->num_nics,
libxl_device_nic_init);
set_default_nic_values(nic);
p = strtok(buf2, ",");
if (!p)
goto skip_nic;
do {
while (*p == ' ')
p++;
parse_nic_config(nic, &config, p);
} while ((p = strtok(NULL, ",")) != NULL);
skip_nic:
free(buf2);
}
}
if (!xlu_cfg_get_list(config, "vif2", NULL, 0, 0)) {
fprintf(stderr, "WARNING: vif2: netchannel2 is deprecated and not supported by xl\n");
}
d_config->num_vfbs = 0;
d_config->num_vkbs = 0;
d_config->vfbs = NULL;
d_config->vkbs = NULL;
if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0, 0)) {
while ((buf = xlu_cfg_get_listitem (cvfbs, d_config->num_vfbs)) != NULL) {
libxl_device_vfb *vfb;
libxl_device_vkb *vkb;
char *buf2 = strdup(buf);
char *p, *p2;
vfb = ARRAY_EXTEND_INIT(d_config->vfbs, d_config->num_vfbs,
libxl_device_vfb_init);
vkb = ARRAY_EXTEND_INIT(d_config->vkbs, d_config->num_vkbs,
libxl_device_vkb_init);
p = strtok(buf2, ",");
if (!p)
goto skip_vfb;
do {
while (*p == ' ')
p++;
if ((p2 = strchr(p, '=')) == NULL)
break;
*p2 = '\0';
if (!strcmp(p, "vnc")) {
libxl_defbool_set(&vfb->vnc.enable, atoi(p2 + 1));
} else if (!strcmp(p, "vnclisten")) {
free(vfb->vnc.listen);
vfb->vnc.listen = strdup(p2 + 1);
} else if (!strcmp(p, "vncpasswd")) {
free(vfb->vnc.passwd);
vfb->vnc.passwd = strdup(p2 + 1);
} else if (!strcmp(p, "vncdisplay")) {
vfb->vnc.display = atoi(p2 + 1);
} else if (!strcmp(p, "vncunused")) {
libxl_defbool_set(&vfb->vnc.findunused, atoi(p2 + 1));
} else if (!strcmp(p, "keymap")) {
free(vfb->keymap);
vfb->keymap = strdup(p2 + 1);
} else if (!strcmp(p, "sdl")) {
libxl_defbool_set(&vfb->sdl.enable, atoi(p2 + 1));
} else if (!strcmp(p, "opengl")) {
libxl_defbool_set(&vfb->sdl.opengl, atoi(p2 + 1));
} else if (!strcmp(p, "display")) {
free(vfb->sdl.display);
vfb->sdl.display = strdup(p2 + 1);
} else if (!strcmp(p, "xauthority")) {
free(vfb->sdl.xauthority);
vfb->sdl.xauthority = strdup(p2 + 1);
}
} while ((p = strtok(NULL, ",")) != NULL);
skip_vfb:
free(buf2);
}
}
if (!xlu_cfg_get_list(config, "usbctrl", &usbctrls, 0, 0)) {
d_config->num_usbctrls = 0;
d_config->usbctrls = NULL;
while ((buf = xlu_cfg_get_listitem(usbctrls, d_config->num_usbctrls))
!= NULL) {
libxl_device_usbctrl *usbctrl;
char *buf2 = strdup(buf);
char *p;
usbctrl = ARRAY_EXTEND_INIT(d_config->usbctrls,
d_config->num_usbctrls,
libxl_device_usbctrl_init);
p = strtok(buf2, ",");
if (!p)
goto skip_usbctrl;
do {
while (*p == ' ')
p++;
if (parse_usbctrl_config(usbctrl, p))
exit(1);
} while ((p = strtok(NULL, ",")) != NULL);
skip_usbctrl:
free(buf2);
}
}
if (!xlu_cfg_get_list(config, "usbdev", &usbdevs, 0, 0)) {
d_config->num_usbdevs = 0;
d_config->usbdevs = NULL;
while ((buf = xlu_cfg_get_listitem(usbdevs, d_config->num_usbdevs))
!= NULL) {
libxl_device_usbdev *usbdev;
char *buf2 = strdup(buf);
char *p;
usbdev = ARRAY_EXTEND_INIT_NODEVID(d_config->usbdevs,
d_config->num_usbdevs,
libxl_device_usbdev_init);
p = strtok(buf2, ",");
if (!p)
goto skip_usbdev;
do {
while (*p == ' ')
p++;
if (parse_usbdev_config(usbdev, p))
exit(1);
} while ((p = strtok(NULL, ",")) != NULL);
skip_usbdev:
free(buf2);
}
}
switch (xlu_cfg_get_list(config, "cpuid", &cpuids, 0, 1)) {
case 0:
{
const char *errstr;
for (i = 0; (buf = xlu_cfg_get_listitem(cpuids, i)) != NULL; i++) {
e = libxl_cpuid_parse_config_xend(&b_info->cpuid, buf);
switch (e) {
case 0: continue;
case 1:
errstr = "illegal leaf number";
break;
case 2:
errstr = "illegal subleaf number";
break;
case 3:
errstr = "missing colon";
break;
case 4:
errstr = "invalid register name (must be e[abcd]x)";
break;
case 5:
errstr = "policy string must be exactly 32 characters long";
break;
default:
errstr = "unknown error";
break;
}
fprintf(stderr, "while parsing CPUID line: \"%s\":\n", buf);
fprintf(stderr, " error #%i: %s\n", e, errstr);
}
}
break;
case EINVAL: /* config option is not a list, parse as a string */
if (!xlu_cfg_get_string(config, "cpuid", &buf, 0)) {
char *buf2, *p, *strtok_ptr = NULL;
const char *errstr;
buf2 = strdup(buf);
p = strtok_r(buf2, ",", &strtok_ptr);
if (p == NULL) {
free(buf2);
break;
}
if (strcmp(p, "host")) {
fprintf(stderr, "while parsing CPUID string: \"%s\":\n", buf);
fprintf(stderr, " error: first word must be \"host\"\n");
free(buf2);
break;
}
for (p = strtok_r(NULL, ",", &strtok_ptr); p != NULL;
p = strtok_r(NULL, ",", &strtok_ptr)) {
e = libxl_cpuid_parse_config(&b_info->cpuid, p);
switch (e) {
case 0: continue;
case 1:
errstr = "missing \"=\" in key=value";
break;
case 2:
errstr = "unknown CPUID flag name";
break;
case 3:
errstr = "illegal CPUID value (must be: [0|1|x|k|s])";
break;
case ERROR_NOMEM:
errstr = "out of memory";
break;
default:
errstr = "unknown error";
break;
}
fprintf(stderr, "while parsing CPUID flag: \"%s\":\n", p);
fprintf(stderr, " error #%i: %s\n", e, errstr);
}
free(buf2);
}
break;
default:
break;
}
/* parse device model arguments, this works for pv, hvm and stubdom */
if (!xlu_cfg_get_string (config, "device_model", &buf, 0)) {
fprintf(stderr,
"WARNING: ignoring device_model directive.\n"
"WARNING: Use \"device_model_override\" instead if you"
" really want a non-default device_model\n");
if (strstr(buf, "stubdom-dm")) {
if (c_info->type == LIBXL_DOMAIN_TYPE_HVM)
fprintf(stderr, "WARNING: Or use"
" \"device_model_stubdomain_override\" if you "
" want to enable stubdomains\n");
else
fprintf(stderr, "WARNING: ignoring"
" \"device_model_stubdomain_override\" directive"
" for pv guest\n");
}
}
xlu_cfg_replace_string (config, "device_model_override",
&b_info->device_model, 0);
if (!xlu_cfg_get_string (config, "device_model_version", &buf, 0)) {
if (!strcmp(buf, "qemu-xen-traditional")) {
b_info->device_model_version
= LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
} else if (!strcmp(buf, "qemu-xen")) {
b_info->device_model_version
= LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
} else {
fprintf(stderr,
"Unknown device_model_version \"%s\" specified\n", buf);
exit(1);
}
} else if (b_info->device_model)
fprintf(stderr, "WARNING: device model override given without specific DM version\n");
xlu_cfg_get_defbool (config, "device_model_stubdomain_override",
&b_info->device_model_stubdomain, 0);
if (!xlu_cfg_get_string (config, "device_model_stubdomain_seclabel",
&buf, 0))
xlu_cfg_replace_string(config, "device_model_stubdomain_seclabel",
&b_info->device_model_ssid_label, 0);
xlu_cfg_replace_string(config, "device_model_user",
&b_info->device_model_user, 0);
xlu_cfg_replace_string (config, "stubdomain_kernel",
&b_info->stubdomain_kernel, 0);
xlu_cfg_replace_string (config, "stubdomain_cmdline",
&b_info->stubdomain_cmdline, 0);
xlu_cfg_replace_string (config, "stubdomain_ramdisk",
&b_info->stubdomain_ramdisk, 0);
if (!xlu_cfg_get_long (config, "stubdomain_memory", &l, 0))
b_info->stubdomain_memkb = l * 1024;
#define parse_extra_args(type) \
e = xlu_cfg_get_list_as_string_list(config, "device_model_args"#type, \
&b_info->extra##type, 0); \
if (e && e != ESRCH) { \
fprintf(stderr,"xl: Unable to parse device_model_args"#type".\n");\
exit(-ERROR_FAIL); \
}
/* parse extra args for qemu, common to both pv, hvm */
parse_extra_args();
/* parse extra args dedicated to pv */
parse_extra_args(_pv);
/* parse extra args dedicated to hvm */
parse_extra_args(_hvm);
#undef parse_extra_args
/* If we've already got vfb=[] for PV guest then ignore top level
* VNC config. */
if (c_info->type == LIBXL_DOMAIN_TYPE_PV && !d_config->num_vfbs) {
long vnc_enabled = 0;
if (!xlu_cfg_get_long (config, "vnc", &l, 0))
vnc_enabled = l;
if (vnc_enabled) {
libxl_device_vfb *vfb;
libxl_device_vkb *vkb;
vfb = ARRAY_EXTEND_INIT(d_config->vfbs, d_config->num_vfbs,
libxl_device_vfb_init);
vkb = ARRAY_EXTEND_INIT(d_config->vkbs, d_config->num_vkbs,
libxl_device_vkb_init);
parse_top_level_vnc_options(config, &vfb->vnc);
parse_top_level_sdl_options(config, &vfb->sdl);
xlu_cfg_replace_string (config, "keymap", &vfb->keymap, 0);
}
} else {
parse_top_level_vnc_options(config, &b_info->u.hvm.vnc);
parse_top_level_sdl_options(config, &b_info->u.hvm.sdl);
}
xlu_cfg_get_defbool(config, "dm_restrict", &b_info->dm_restrict, 0);
if (c_info->type == LIBXL_DOMAIN_TYPE_HVM) {
if (!xlu_cfg_get_string (config, "vga", &buf, 0)) {
if (!strcmp(buf, "stdvga")) {
b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_STD;
} else if (!strcmp(buf, "cirrus")) {
b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
} else if (!strcmp(buf, "none")) {
b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_NONE;
} else if (!strcmp(buf, "qxl")) {
b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_QXL;
} else {
fprintf(stderr, "Unknown vga \"%s\" specified\n", buf);
exit(1);
}
} else if (!xlu_cfg_get_long(config, "stdvga", &l, 0))
b_info->u.hvm.vga.kind = l ? LIBXL_VGA_INTERFACE_TYPE_STD :
LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
if (!xlu_cfg_get_string(config, "hdtype", &buf, 0) &&
libxl_hdtype_from_string(buf, &b_info->u.hvm.hdtype)) {
fprintf(stderr, "ERROR: invalid value \"%s\" for \"hdtype\"\n",
buf);
exit (1);
}
xlu_cfg_replace_string (config, "keymap", &b_info->u.hvm.keymap, 0);
xlu_cfg_get_defbool (config, "spice", &b_info->u.hvm.spice.enable, 0);
if (!xlu_cfg_get_long (config, "spiceport", &l, 0))
b_info->u.hvm.spice.port = l;
if (!xlu_cfg_get_long (config, "spicetls_port", &l, 0))
b_info->u.hvm.spice.tls_port = l;
xlu_cfg_replace_string (config, "spicehost",
&b_info->u.hvm.spice.host, 0);
xlu_cfg_get_defbool(config, "spicedisable_ticketing",
&b_info->u.hvm.spice.disable_ticketing, 0);
xlu_cfg_replace_string (config, "spicepasswd",
&b_info->u.hvm.spice.passwd, 0);
xlu_cfg_get_defbool(config, "spiceagent_mouse",
&b_info->u.hvm.spice.agent_mouse, 0);
xlu_cfg_get_defbool(config, "spicevdagent",
&b_info->u.hvm.spice.vdagent, 0);
xlu_cfg_get_defbool(config, "spice_clipboard_sharing",
&b_info->u.hvm.spice.clipboard_sharing, 0);
if (!xlu_cfg_get_long (config, "spiceusbredirection", &l, 0))
b_info->u.hvm.spice.usbredirection = l;
xlu_cfg_replace_string (config, "spice_image_compression",
&b_info->u.hvm.spice.image_compression, 0);
xlu_cfg_replace_string (config, "spice_streaming_video",
&b_info->u.hvm.spice.streaming_video, 0);
xlu_cfg_get_defbool(config, "nographic", &b_info->u.hvm.nographic, 0);
if (!xlu_cfg_get_long(config, "gfx_passthru", &l, 1)) {
libxl_defbool_set(&b_info->u.hvm.gfx_passthru, l);
} else if (!xlu_cfg_get_string(config, "gfx_passthru", &buf, 0)) {
if (libxl_gfx_passthru_kind_from_string(buf,
&b_info->u.hvm.gfx_passthru_kind)) {
fprintf(stderr,
"ERROR: invalid value \"%s\" for \"gfx_passthru\"\n",
buf);
exit (1);
}
libxl_defbool_set(&b_info->u.hvm.gfx_passthru, true);
}
switch (xlu_cfg_get_list_as_string_list(config, "serial",
&b_info->u.hvm.serial_list,
1))
{
case 0: break; /* Success */
case ESRCH: break; /* Option not present */
case EINVAL:
/* If it's not a valid list, try reading it as an atom,
* falling through to an error if it fails */
if (!xlu_cfg_replace_string(config, "serial",
&b_info->u.hvm.serial, 0))
break;
/* FALLTHRU */
default:
fprintf(stderr,"xl: Unable to parse serial.\n");
exit(-ERROR_FAIL);
}
xlu_cfg_replace_string (config, "boot", &b_info->u.hvm.boot, 0);
xlu_cfg_get_defbool(config, "usb", &b_info->u.hvm.usb, 0);
if (!xlu_cfg_get_long (config, "usbversion", &l, 0))
b_info->u.hvm.usbversion = l;
switch (xlu_cfg_get_list_as_string_list(config, "usbdevice",
&b_info->u.hvm.usbdevice_list,
1))
{
case 0: break; /* Success */
case ESRCH: break; /* Option not present */
case EINVAL:
/* If it's not a valid list, try reading it as an atom,
* falling through to an error if it fails */
if (!xlu_cfg_replace_string(config, "usbdevice",
&b_info->u.hvm.usbdevice, 0))
break;
/* FALLTHRU */
default:
fprintf(stderr,"xl: Unable to parse usbdevice.\n");
exit(-ERROR_FAIL);
}
xlu_cfg_get_defbool(config, "vkb_device", &b_info->u.hvm.vkb_device, 0);
xlu_cfg_replace_string (config, "soundhw", &b_info->u.hvm.soundhw, 0);
xlu_cfg_get_defbool(config, "xen_platform_pci",
&b_info->u.hvm.xen_platform_pci, 0);
if(b_info->u.hvm.vnc.listen
&& b_info->u.hvm.vnc.display
&& strchr(b_info->u.hvm.vnc.listen, ':') != NULL) {
fprintf(stderr,
"ERROR: Display specified both in vnclisten"
" and vncdisplay!\n");
exit (1);
}
if (!xlu_cfg_get_string (config, "vendor_device", &buf, 0)) {
libxl_vendor_device d;
e = libxl_vendor_device_from_string(buf, &d);
if (e) {
fprintf(stderr,
"xl: unknown vendor_device '%s'\n",
buf);
exit(-ERROR_FAIL);
}
b_info->u.hvm.vendor_device = d;
}
}
if (!xlu_cfg_get_string (config, "gic_version", &buf, 1)) {
e = libxl_gic_version_from_string(buf, &b_info->arch_arm.gic_version);
if (e) {
fprintf(stderr,
"Unknown gic_version \"%s\" specified\n", buf);
exit(-ERROR_FAIL);
}
}
if (!xlu_cfg_get_string (config, "tee", &buf, 1)) {
e = libxl_tee_type_from_string(buf, &b_info->tee);
if (e) {
fprintf(stderr,
"Unknown tee \"%s\" specified\n", buf);
exit(-ERROR_FAIL);
}
}
if (!xlu_cfg_get_string (config, "sve", &buf, 1)) {
e = libxl_sve_type_from_string(buf, &b_info->arch_arm.sve_vl);
if (e) {
fprintf(stderr, "Unknown sve \"%s\" specified\n", buf);
exit(EXIT_FAILURE);
}
}
parse_vkb_list(config, d_config);
d_config->virtios = NULL;
d_config->num_virtios = 0;
parse_virtio_list(config, d_config);
xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
&c_info->xend_suspend_evtchn_compat, 0);
if (!xlu_cfg_get_defbool(config, "msr_relaxed",
&b_info->arch_x86.msr_relaxed, 0))
fprintf(stderr,
"WARNING: msr_relaxed will be removed in future versions.\n"
"If it fixes an issue you are having please report to "
"xen-devel@lists.xenproject.org.\n");
xlu_cfg_get_defbool(config, "vpmu", &b_info->vpmu, 0);
xlu_cfg_destroy(config);
}
/* Returns -1 on failure; the amount of memory on success. */
int64_t parse_mem_size_kb(const char *mem)
{
char *endptr;
int64_t kbytes;
kbytes = strtoll(mem, &endptr, 10);
if (strlen(endptr) > 1)
return -1;
switch (tolower((uint8_t)*endptr)) {
case 't':
kbytes <<= 10;
/* fallthrough */
case 'g':
kbytes <<= 10;
/* fallthrough */
case '\0':
case 'm':
kbytes <<= 10;
/* fallthrough */
case 'k':
break;
case 'b':
kbytes >>= 10;
break;
default:
return -1;
}
return kbytes;
}
void split_string_into_string_list(const char *str,
const char *delim,
libxl_string_list *psl)
{
char *s, *saveptr;
const char *p;
libxl_string_list sl;
int i = 0, nr = 0;
s = strdup(str);
if (s == NULL) {
fprintf(stderr, "unable to allocate memory to split string\n");
exit(-1);
}
/* Count number of entries */
p = strtok_r(s, delim, &saveptr);
do {
nr++;
} while ((p = strtok_r(NULL, delim, &saveptr)));
free(s);
s = strdup(str);
sl = malloc((nr+1) * sizeof (char *));
if (sl == NULL) {
fprintf(stderr, "unable to allocate memory to split string\n");
exit(-1);
}
p = strtok_r(s, delim, &saveptr);
do {
assert(i < nr);
sl[i] = strdup(p);
i++;
} while ((p = strtok_r(NULL, delim, &saveptr)));
sl[i] = NULL;
*psl = sl;
free(s);
}
void trim(char_predicate_t predicate, const char *input, char **output)
{
const char *first, *after;
for (first = input;
*first && predicate((unsigned char)first[0]);
first++)
;
for (after = first + strlen(first);
after > first && predicate((unsigned char)after[-1]);
after--)
;
size_t len_nonnull = after - first;
char *result = xmalloc(len_nonnull + 1);
memcpy(result, first, len_nonnull);
result[len_nonnull] = 0;
*output = result;
}
int split_string_into_pair(const char *str, char delim, char **a, char **b,
char_predicate_t predicate)
{
char *s, *p, *aa = NULL, *bb = NULL;
int rc = 0;
s = xstrdup(str);
p = strchr(s, delim);
if (p == NULL) {
rc = ERROR_INVAL;
goto out;
}
*p = 0;
if (predicate) {
trim(predicate, s, &aa);
} else {
aa = xstrdup(s);
}
p++;
if (!*p) {
rc = ERROR_INVAL;
goto out;
}
if (predicate) {
trim(predicate, p, &bb);
} else {
bb = xstrdup(p);
}
*a = aa;
aa = NULL;
*b = bb;
bb = NULL;
out:
free(s);
free(aa);
free(bb);
return rc;
}
/*
* Local variables:
* mode: C
* c-basic-offset: 4
* indent-tabs-mode: nil
* End:
*/