@@ -16,7 +16,7 @@ CFLAGS_XL += $(CFLAGS_libxenlight)
CFLAGS_XL += -Wshadow
XL_OBJS = xl.o xl_cmdimpl.o xl_cmdtable.o xl_sxp.o xl_utils.o
-XL_OBJS += xl_tmem.o
+XL_OBJS += xl_tmem.o xl_parse.o
$(XL_OBJS): CFLAGS += $(CFLAGS_libxentoollog)
$(XL_OBJS): CFLAGS += $(CFLAGS_XL)
@@ -39,6 +39,7 @@
#include <libxlutil.h>
#include "xl.h"
#include "xl_utils.h"
+#include "xl_parse.h"
int logfile = 2;
@@ -86,26 +87,6 @@ struct save_file_header {
uint32_t optional_data_len; /* skip, or skip tail, if not understood */
};
-
-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",
-};
-
-static const char *get_action_on_shutdown_name(libxl_action_on_shutdown a)
-{
- return action_on_shutdown_names[a];
-}
-
/* Optional data, in order:
* 4 bytes uint32_t config file size
* n bytes config file in Unix text file format
@@ -196,2181 +177,216 @@ static int acquire_lock(void)
return ERROR_FAIL;
}
if (fcntl(fd_lock, F_SETFD, FD_CLOEXEC) < 0) {
- close(fd_lock);
- fprintf(stderr, "cannot set cloexec to lockfile %s errno=%d\n", lockfile, errno);
- return ERROR_FAIL;
- }
-get_lock:
- rc = fcntl(fd_lock, F_SETLKW, &fl);
- if (rc < 0 && errno == EINTR)
- goto get_lock;
- if (rc < 0) {
- fprintf(stderr, "cannot acquire lock %s errno=%d\n", lockfile, errno);
- rc = ERROR_FAIL;
- } else
- rc = 0;
- return rc;
-}
-
-static int release_lock(void)
-{
- int rc;
- struct flock fl;
-
- /* lock not acquired */
- if (fd_lock < 0)
- return ERROR_INVAL;
-
-release_lock:
- fl.l_type = F_UNLCK;
- fl.l_whence = SEEK_SET;
- fl.l_start = 0;
- fl.l_len = 0;
-
- rc = fcntl(fd_lock, F_SETLKW, &fl);
- if (rc < 0 && errno == EINTR)
- goto release_lock;
- if (rc < 0) {
- fprintf(stderr, "cannot release lock %s, errno=%d\n", lockfile, errno);
- rc = ERROR_FAIL;
- } else
- rc = 0;
- close(fd_lock);
- fd_lock = -1;
-
- return rc;
-}
-
-
-#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 yajl_gen_status printf_info_one_json(yajl_gen hand, int domid,
- libxl_domain_config *d_config)
-{
- yajl_gen_status s;
-
- s = yajl_gen_map_open(hand);
- if (s != yajl_gen_status_ok)
- goto out;
-
- s = yajl_gen_string(hand, (const unsigned char *)"domid",
- sizeof("domid")-1);
- if (s != yajl_gen_status_ok)
- goto out;
- if (domid != -1)
- s = yajl_gen_integer(hand, domid);
- else
- s = yajl_gen_null(hand);
- if (s != yajl_gen_status_ok)
- goto out;
-
- s = yajl_gen_string(hand, (const unsigned char *)"config",
- sizeof("config")-1);
- if (s != yajl_gen_status_ok)
- goto out;
- s = libxl_domain_config_gen_json(hand, d_config);
- if (s != yajl_gen_status_ok)
- goto out;
-
- s = yajl_gen_map_close(hand);
- if (s != yajl_gen_status_ok)
- goto out;
-
-out:
- return s;
-}
-
-static void printf_info(enum output_format output_format,
- int domid,
- libxl_domain_config *d_config, FILE *fh)
-{
- if (output_format == OUTPUT_FORMAT_SXP)
- return printf_info_sexp(domid, d_config, fh);
-
- const char *buf;
- libxl_yajl_length len = 0;
- yajl_gen_status s;
- yajl_gen hand;
-
- hand = libxl_yajl_gen_alloc(NULL);
- if (!hand) {
- fprintf(stderr, "unable to allocate JSON generator\n");
- return;
- }
-
- s = printf_info_one_json(hand, domid, d_config);
- if (s != yajl_gen_status_ok)
- goto out;
-
- s = yajl_gen_get_buf(hand, (const unsigned char **)&buf, &len);
- if (s != yajl_gen_status_ok)
- goto out;
-
- fputs(buf, fh);
-
-out:
- yajl_gen_free(hand);
-
- if (s != yajl_gen_status_ok)
- fprintf(stderr,
- "unable to format domain config as JSON (YAJL:%d)\n", s);
-
- flush_stream(fh);
-}
-
-static int do_daemonize(char *name, const char *pidfile)
-{
- char *fullname;
- pid_t child1;
- int nullfd, ret = 0;
-
- child1 = xl_fork(child_waitdaemon, "domain monitoring daemonizing child");
- if (child1) {
- ret = child_report(child_waitdaemon);
- if (ret) goto out;
- ret = 1;
- goto out;
- }
-
- postfork();
-
- ret = libxl_create_logfile(ctx, name, &fullname);
- if (ret) {
- LOG("failed to open logfile %s: %s",fullname,strerror(errno));
- exit(-1);
- }
-
- CHK_SYSCALL(logfile = open(fullname, O_WRONLY|O_CREAT|O_APPEND, 0644));
- free(fullname);
- assert(logfile >= 3);
-
- CHK_SYSCALL(nullfd = open("/dev/null", O_RDONLY));
- assert(nullfd >= 3);
-
- dup2(nullfd, 0);
- dup2(logfile, 1);
- dup2(logfile, 2);
-
- close(nullfd);
-
- CHK_SYSCALL(daemon(0, 1));
-
- if (pidfile) {
- int fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR);
- char *pid = NULL;
-
- if (fd == -1) {
- perror("Unable to open pidfile");
- exit(1);
- }
-
- if (asprintf(&pid, "%ld\n", (long)getpid()) == -1) {
- perror("Formatting pid");
- exit(1);
- }
-
- if (write(fd, pid, strlen(pid)) < 0) {
- perror("Writing pid");
- exit(1);
- }
-
- if (close(fd) < 0) {
- perror("Closing pidfile");
- exit(1);
- }
-
- free(pid);
- }
-
-out:
- return ret;
-}
-
-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
-
-static 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);
- }
-}
-
-static 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);
- }
-}
-
-static void set_default_nic_values(libxl_device_nic *nic)
-{
-
- if (default_vifscript) {
- free(nic->script);
- nic->script = strdup(default_vifscript);
- }
-
- if (default_bridge) {
- free(nic->bridge);
- nic->bridge = strdup(default_bridge);
- }
-
- if (default_gatewaydev) {
- free(nic->gatewaydev);
- nic->gatewaydev = strdup(default_gatewaydev);
- }
-
- if (default_vifbackend) {
- free(nic->backend_domname);
- nic->backend_domname = strdup(default_vifbackend);
- }
-}
-
-static 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);
-}
-
-/* NB: this follows the interface used by <ctype.h>. See 'man 3 ctype'
- and look for CTYPE in libxl_internal.h */
-typedef int (*char_predicate_t)(const int c);
-
-static 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;
-}
-
-static int split_string_into_pair(const char *str,
- const char *delim,
- char **a,
- char **b)
-{
- char *s, *p, *saveptr, *aa = NULL, *bb = NULL;
- int rc = 0;
-
- s = xstrdup(str);
-
- p = strtok_r(s, delim, &saveptr);
- if (p == NULL) {
- rc = ERROR_INVAL;
- goto out;
- }
- aa = xstrdup(p);
- p = strtok_r(NULL, delim, &saveptr);
- if (p == NULL) {
- rc = ERROR_INVAL;
- goto out;
- }
- bb = xstrdup(p);
-
- *a = aa;
- aa = NULL;
- *b = bb;
- bb = NULL;
-out:
- free(s);
- free(aa);
- free(bb);
- return rc;
-}
-
-static 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).
- */
-static 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++;
- }
-
- /* We have a list of cpumaps, 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]);
- }
-
- 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;
-}
-
-static void replace_string(char **str, const char *val)
-{
- free(*str);
- *str = xstrdup(val);
-}
-
-static 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;
-}
-#define MATCH_OPTION(prefix, arg, oparg) \
- match_option_size((prefix "="), sizeof((prefix)), (arg), &(oparg))
-
-/* 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 */
-static 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("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 {
- 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, *option_untrimmed, *value_untrimmed;
- 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_untrimmed,
- &value_untrimmed)) {
- fprintf(stderr, "xl: failed to split \"%s\" into pair\n",
- buf);
- exit(EXIT_FAILURE);
- }
- trim(isspace, option_untrimmed, &option);
- trim(isspace, value_untrimmed, &value);
-
- 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);
- free(option_untrimmed);
- free(value_untrimmed);
- }
- }
- }
-
- /* 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 */
-static 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 */
-static 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;
-}
-
-static void parse_config_data(const char *config_source,
- const char *config_data,
- int config_len,
- libxl_domain_config *d_config)
-{
- const char *buf;
- long l, vcpus = 0;
- XLU_Config *config;
- XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
- *usbctrls, *usbdevs;
- XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs;
- int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
- 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;
-
- 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);
- c_info->type = LIBXL_DOMAIN_TYPE_PV;
- if (!xlu_cfg_get_string (config, "builder", &buf, 0) &&
- !strncmp(buf, "hvm", strlen(buf)))
- c_info->type = LIBXL_DOMAIN_TYPE_HVM;
-
- xlu_cfg_get_defbool(config, "pvh", &c_info->pvh, 0);
- 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 (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;
-
- 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);
-
- 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);
- }
-
- /* libxl_get_required_shadow_memory() must be called after final values
- * (default or specified) for vcpus and memory are set, because the
- * calculation depends on those values. */
- b_info->shadow_memkb = !xlu_cfg_get_long(config, "shadow_memory", &l, 0)
- ? l * 1024
- : libxl_get_required_shadow_memory(b_info->max_memkb,
- b_info->max_vcpus);
-
- 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);
-
- 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, "apic", &b_info->u.hvm.apic, 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, "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);
-
- 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_long(config, "timer_mode", &l, 1)) {
- const char *s = libxl_timer_mode_to_string(l);
- 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->u.hvm.timer_mode = l;
- } else if (!xlu_cfg_get_string(config, "timer_mode", &buf, 0)) {
- if (libxl_timer_mode_from_string(buf, &b_info->u.hvm.timer_mode)) {
- fprintf(stderr, "ERROR: invalid value \"%s\" for \"timer_mode\"\n",
- buf);
- exit (1);
- }
- }
-
- xlu_cfg_get_defbool(config, "nestedhvm", &b_info->u.hvm.nested_hvm, 0);
-
- xlu_cfg_get_defbool(config, "altp2mhvm", &b_info->u.hvm.altp2m, 0);
-
- 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);
-
- 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;
- break;
- case LIBXL_DOMAIN_TYPE_PV:
- {
- xlu_cfg_replace_string (config, "bootloader", &b_info->u.pv.bootloader, 0);
- switch (xlu_cfg_get_list_as_string_list(config, "bootloader_args",
- &b_info->u.pv.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->u.pv.bootloader_args);
- }
- break;
- default:
- fprintf(stderr,"xl: Unable to parse bootloader_args.\n");
- exit(-ERROR_FAIL);
- }
-
- if (!b_info->u.pv.bootloader && !b_info->kernel) {
- fprintf(stderr, "Neither kernel nor bootloader specified\n");
- exit(1);
- }
-
- break;
- }
- default:
- abort();
- }
-
- 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;
- }
+ close(fd_lock);
+ fprintf(stderr, "cannot set cloexec to lockfile %s errno=%d\n", lockfile, errno);
+ return ERROR_FAIL;
}
+get_lock:
+ rc = fcntl(fd_lock, F_SETLKW, &fl);
+ if (rc < 0 && errno == EINTR)
+ goto get_lock;
+ if (rc < 0) {
+ fprintf(stderr, "cannot acquire lock %s errno=%d\n", lockfile, errno);
+ rc = ERROR_FAIL;
+ } else
+ rc = 0;
+ return rc;
+}
- 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;
+static int release_lock(void)
+{
+ int rc;
+ struct flock fl;
- 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);
- }
- }
- }
+ /* lock not acquired */
+ if (fd_lock < 0)
+ return ERROR_INVAL;
+release_lock:
+ fl.l_type = F_UNLCK;
+ fl.l_whence = SEEK_SET;
+ fl.l_start = 0;
+ fl.l_len = 0;
+ rc = fcntl(fd_lock, F_SETLKW, &fl);
+ if (rc < 0 && errno == EINTR)
+ goto release_lock;
+ if (rc < 0) {
+ fprintf(stderr, "cannot release lock %s, errno=%d\n", lockfile, errno);
+ rc = ERROR_FAIL;
+ } else
+ rc = 0;
+ close(fd_lock);
+ fd_lock = -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, "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, "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, *key_untrimmed, *value, *value_untrimmed;
- int rc;
- rc = split_string_into_pair(pairs[i], "=",
- &key_untrimmed,
- &value_untrimmed);
- if (rc != 0) {
- fprintf(stderr, "failed to parse channel configuration: %s",
- pairs[i]);
- exit(1);
- }
- trim(isspace, key_untrimmed, &key);
- trim(isspace, value_untrimmed, &value);
-
- 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(key_untrimmed);
- free(value);
- free(value_untrimmed);
- }
- 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);
+ return rc;
+}
-skip_vfb:
- free(buf2);
- }
- }
+static yajl_gen_status printf_info_one_json(yajl_gen hand, int domid,
+ libxl_domain_config *d_config)
+{
+ yajl_gen_status s;
- if (!xlu_cfg_get_long (config, "pci_msitranslate", &l, 0))
- pci_msitranslate = l;
+ s = yajl_gen_map_open(hand);
+ if (s != yajl_gen_status_ok)
+ goto out;
- if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l, 0))
- pci_power_mgmt = l;
+ s = yajl_gen_string(hand, (const unsigned char *)"domid",
+ sizeof("domid")-1);
+ if (s != yajl_gen_status_ok)
+ goto out;
+ if (domid != -1)
+ s = yajl_gen_integer(hand, domid);
+ else
+ s = yajl_gen_null(hand);
+ if (s != yajl_gen_status_ok)
+ goto out;
- if (!xlu_cfg_get_long (config, "pci_permissive", &l, 0))
- pci_permissive = l;
+ s = yajl_gen_string(hand, (const unsigned char *)"config",
+ sizeof("config")-1);
+ if (s != yajl_gen_status_ok)
+ goto out;
+ s = libxl_domain_config_gen_json(hand, d_config);
+ if (s != yajl_gen_status_ok)
+ goto out;
- if (!xlu_cfg_get_long (config, "pci_seize", &l, 0))
- pci_seize = l;
+ s = yajl_gen_map_close(hand);
+ if (s != yajl_gen_status_ok)
+ goto out;
- /* 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);
- }
+out:
+ return s;
+}
- 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;
- }
- }
+static void printf_info(enum output_format output_format,
+ int domid,
+ libxl_domain_config *d_config, FILE *fh)
+{
+ if (output_format == OUTPUT_FORMAT_SXP)
+ return printf_info_sexp(domid, d_config, fh);
- 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 *pcidev;
+ const char *buf;
+ libxl_yajl_length len = 0;
+ yajl_gen_status s;
+ yajl_gen hand;
- pcidev = ARRAY_EXTEND_INIT_NODEVID(d_config->pcidevs,
- d_config->num_pcidevs,
- libxl_device_pci_init);
- pcidev->msitranslate = pci_msitranslate;
- pcidev->power_mgmt = pci_power_mgmt;
- pcidev->permissive = pci_permissive;
- pcidev->seize = pci_seize;
- /*
- * Like other pci option, the per-device policy always follows
- * the global policy by default.
- */
- pcidev->rdm_policy = b_info->u.hvm.rdm.policy;
- e = xlu_pci_parse_bdf(config, pcidev, buf);
- if (e) {
- fprintf(stderr,
- "unable to parse PCI BDF `%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);
+ hand = libxl_yajl_gen_alloc(NULL);
+ if (!hand) {
+ fprintf(stderr, "unable to allocate JSON generator\n");
+ return;
}
- 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;
+ s = printf_info_one_json(hand, domid, d_config);
+ if (s != yajl_gen_status_ok)
+ goto out;
- dtdev = ARRAY_EXTEND_INIT_NODEVID(d_config->dtdevs,
- d_config->num_dtdevs,
- libxl_device_dtdev_init);
+ s = yajl_gen_get_buf(hand, (const unsigned char **)&buf, &len);
+ if (s != yajl_gen_status_ok)
+ goto out;
- dtdev->path = strdup(buf);
- if (dtdev->path == NULL) {
- fprintf(stderr, "unable to duplicate string for dtdevs\n");
- exit(-1);
- }
- }
- }
+ fputs(buf, fh);
- 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;
- 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;
- }
+out:
+ yajl_gen_free(hand);
- /* parse device model arguments, this works for pv, hvm and stubdom */
- if (!xlu_cfg_get_string (config, "device_model", &buf, 0)) {
+ if (s != yajl_gen_status_ok)
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");
- }
- }
+ "unable to format domain config as JSON (YAJL:%d)\n", s);
+ flush_stream(fh);
+}
- 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 if (!strcmp(buf, "none")) {
- b_info->device_model_version = LIBXL_DEVICE_MODEL_VERSION_NONE;
- } 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);
+static int do_daemonize(char *name, const char *pidfile)
+{
+ char *fullname;
+ pid_t child1;
+ int nullfd, ret = 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);
+ child1 = xl_fork(child_waitdaemon, "domain monitoring daemonizing child");
+ if (child1) {
+ ret = child_report(child_waitdaemon);
+ if (ret) goto out;
+ ret = 1;
+ goto out;
+ }
- xlu_cfg_replace_string(config, "device_model_user",
- &b_info->device_model_user, 0);
+ postfork();
-#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); \
+ ret = libxl_create_logfile(ctx, name, &fullname);
+ if (ret) {
+ LOG("failed to open logfile %s: %s",fullname,strerror(errno));
+ exit(-1);
}
- /* parse extra args for qemu, common to both pv, hvm */
- parse_extra_args();
-
- /* parse extra args dedicated to pv */
- parse_extra_args(_pv);
+ CHK_SYSCALL(logfile = open(fullname, O_WRONLY|O_CREAT|O_APPEND, 0644));
+ free(fullname);
+ assert(logfile >= 3);
- /* parse extra args dedicated to hvm */
- parse_extra_args(_hvm);
+ CHK_SYSCALL(nullfd = open("/dev/null", O_RDONLY));
+ assert(nullfd >= 3);
-#undef parse_extra_args
+ dup2(nullfd, 0);
+ dup2(logfile, 1);
+ dup2(logfile, 2);
- /* 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;
+ close(nullfd);
- if (!xlu_cfg_get_long (config, "vnc", &l, 0))
- vnc_enabled = l;
+ CHK_SYSCALL(daemon(0, 1));
- if (vnc_enabled) {
- libxl_device_vfb *vfb;
- libxl_device_vkb *vkb;
+ if (pidfile) {
+ int fd = open(pidfile, O_RDWR | O_CREAT, S_IRUSR|S_IWUSR);
+ char *pid = NULL;
- vfb = ARRAY_EXTEND_INIT(d_config->vfbs, d_config->num_vfbs,
- libxl_device_vfb_init);
+ if (fd == -1) {
+ perror("Unable to open pidfile");
+ exit(1);
+ }
- vkb = ARRAY_EXTEND_INIT(d_config->vkbs, d_config->num_vkbs,
- libxl_device_vkb_init);
+ if (asprintf(&pid, "%ld\n", (long)getpid()) == -1) {
+ perror("Formatting pid");
+ exit(1);
+ }
- 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);
+ if (write(fd, pid, strlen(pid)) < 0) {
+ perror("Writing pid");
+ exit(1);
}
- } else {
- parse_top_level_vnc_options(config, &b_info->u.hvm.vnc);
- parse_top_level_sdl_options(config, &b_info->u.hvm.sdl);
- }
-
- 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);
+
+ if (close(fd) < 0) {
+ perror("Closing pidfile");
+ exit(1);
}
- 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);
+ free(pid);
+ }
- }
+out:
+ return ret;
+}
- if (!xlu_cfg_get_string (config, "vendor_device", &buf, 0)) {
- libxl_vendor_device d;
+void set_default_nic_values(libxl_device_nic *nic);
+void set_default_nic_values(libxl_device_nic *nic)
+{
- e = libxl_vendor_device_from_string(buf, &d);
- if (e) {
- fprintf(stderr,
- "xl: unknown vendor_device '%s'\n",
- buf);
- exit(-ERROR_FAIL);
- }
+ if (default_vifscript) {
+ free(nic->script);
+ nic->script = strdup(default_vifscript);
+ }
- b_info->u.hvm.vendor_device = d;
- }
+ if (default_bridge) {
+ free(nic->bridge);
+ nic->bridge = strdup(default_bridge);
}
- 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 (default_gatewaydev) {
+ free(nic->gatewaydev);
+ nic->gatewaydev = strdup(default_gatewaydev);
+ }
- xlu_cfg_destroy(config);
+ if (default_vifbackend) {
+ free(nic->backend_domname);
+ nic->backend_domname = strdup(default_vifbackend);
+ }
}
static void reload_domain_config(uint32_t domid,
@@ -3154,40 +1170,6 @@ void help(const char *command)
}
}
-/* Returns -1 on failure; the amount of memory on success. */
-static 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;
-}
-
static int set_memory_max(uint32_t domid, const char *mem)
{
int64_t memorykb;
new file mode 100644
@@ -0,0 +1,2052 @@
+/*
+ * 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 <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++;
+ }
+
+ /* We have a list of cpumaps, 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]);
+ }
+
+ 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("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 {
+ 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, *option_untrimmed, *value_untrimmed;
+ 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_untrimmed,
+ &value_untrimmed)) {
+ fprintf(stderr, "xl: failed to split \"%s\" into pair\n",
+ buf);
+ exit(EXIT_FAILURE);
+ }
+ trim(isspace, option_untrimmed, &option);
+ trim(isspace, value_untrimmed, &value);
+
+ 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);
+ free(option_untrimmed);
+ free(value_untrimmed);
+ }
+ }
+ }
+
+ /* 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;
+}
+
+void parse_config_data(const char *config_source,
+ const char *config_data,
+ int config_len,
+ libxl_domain_config *d_config)
+{
+ const char *buf;
+ long l, vcpus = 0;
+ XLU_Config *config;
+ XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
+ *usbctrls, *usbdevs;
+ XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs;
+ int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian;
+ 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;
+
+ 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);
+ c_info->type = LIBXL_DOMAIN_TYPE_PV;
+ if (!xlu_cfg_get_string (config, "builder", &buf, 0) &&
+ !strncmp(buf, "hvm", strlen(buf)))
+ c_info->type = LIBXL_DOMAIN_TYPE_HVM;
+
+ xlu_cfg_get_defbool(config, "pvh", &c_info->pvh, 0);
+ 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 (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;
+
+ 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);
+
+ 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);
+ }
+
+ /* libxl_get_required_shadow_memory() must be called after final values
+ * (default or specified) for vcpus and memory are set, because the
+ * calculation depends on those values. */
+ b_info->shadow_memkb = !xlu_cfg_get_long(config, "shadow_memory", &l, 0)
+ ? l * 1024
+ : libxl_get_required_shadow_memory(b_info->max_memkb,
+ b_info->max_vcpus);
+
+ 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);
+
+ 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, "apic", &b_info->u.hvm.apic, 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, "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);
+
+ 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_long(config, "timer_mode", &l, 1)) {
+ const char *s = libxl_timer_mode_to_string(l);
+ 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->u.hvm.timer_mode = l;
+ } else if (!xlu_cfg_get_string(config, "timer_mode", &buf, 0)) {
+ if (libxl_timer_mode_from_string(buf, &b_info->u.hvm.timer_mode)) {
+ fprintf(stderr, "ERROR: invalid value \"%s\" for \"timer_mode\"\n",
+ buf);
+ exit (1);
+ }
+ }
+
+ xlu_cfg_get_defbool(config, "nestedhvm", &b_info->u.hvm.nested_hvm, 0);
+
+ xlu_cfg_get_defbool(config, "altp2mhvm", &b_info->u.hvm.altp2m, 0);
+
+ 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);
+
+ 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;
+ break;
+ case LIBXL_DOMAIN_TYPE_PV:
+ {
+ xlu_cfg_replace_string (config, "bootloader", &b_info->u.pv.bootloader, 0);
+ switch (xlu_cfg_get_list_as_string_list(config, "bootloader_args",
+ &b_info->u.pv.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->u.pv.bootloader_args);
+ }
+ break;
+ default:
+ fprintf(stderr,"xl: Unable to parse bootloader_args.\n");
+ exit(-ERROR_FAIL);
+ }
+
+ if (!b_info->u.pv.bootloader && !b_info->kernel) {
+ fprintf(stderr, "Neither kernel nor bootloader specified\n");
+ exit(1);
+ }
+
+ break;
+ }
+ default:
+ abort();
+ }
+
+ 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, "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, "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, *key_untrimmed, *value, *value_untrimmed;
+ int rc;
+ rc = split_string_into_pair(pairs[i], "=",
+ &key_untrimmed,
+ &value_untrimmed);
+ if (rc != 0) {
+ fprintf(stderr, "failed to parse channel configuration: %s",
+ pairs[i]);
+ exit(1);
+ }
+ trim(isspace, key_untrimmed, &key);
+ trim(isspace, value_untrimmed, &value);
+
+ 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(key_untrimmed);
+ free(value);
+ free(value_untrimmed);
+ }
+ 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_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;
+
+ /* 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_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 *pcidev;
+
+ pcidev = ARRAY_EXTEND_INIT_NODEVID(d_config->pcidevs,
+ d_config->num_pcidevs,
+ libxl_device_pci_init);
+ pcidev->msitranslate = pci_msitranslate;
+ pcidev->power_mgmt = pci_power_mgmt;
+ pcidev->permissive = pci_permissive;
+ pcidev->seize = pci_seize;
+ /*
+ * Like other pci option, the per-device policy always follows
+ * the global policy by default.
+ */
+ pcidev->rdm_policy = b_info->u.hvm.rdm.policy;
+ e = xlu_pci_parse_bdf(config, pcidev, buf);
+ if (e) {
+ fprintf(stderr,
+ "unable to parse PCI BDF `%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_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;
+ 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 if (!strcmp(buf, "none")) {
+ b_info->device_model_version = LIBXL_DEVICE_MODEL_VERSION_NONE;
+ } 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);
+
+#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);
+ }
+
+ 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_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);
+ }
+ }
+
+ 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,
+ const char *delim,
+ char **a,
+ char **b)
+{
+ char *s, *p, *saveptr, *aa = NULL, *bb = NULL;
+ int rc = 0;
+
+ s = xstrdup(str);
+
+ p = strtok_r(s, delim, &saveptr);
+ if (p == NULL) {
+ rc = ERROR_INVAL;
+ goto out;
+ }
+ aa = xstrdup(p);
+ p = strtok_r(NULL, delim, &saveptr);
+ if (p == NULL) {
+ rc = ERROR_INVAL;
+ goto out;
+ }
+ 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:
+ */
new file mode 100644
@@ -0,0 +1,65 @@
+/*
+ * 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.
+ */
+
+#ifndef XL_PARSE_H
+#define XL_PARSE_H
+
+#include <libxl.h>
+
+void parse_config_data(const char *config_source,
+ const char *config_data,
+ int config_len,
+ libxl_domain_config *d_config);
+int parse_range(const char *str, unsigned long *a, unsigned long *b);
+int64_t parse_mem_size_kb(const char *mem);
+void parse_disk_config(XLU_Config **config, const char *spec,
+ libxl_device_disk *disk);
+
+void parse_disk_config_multistring(XLU_Config **config,
+ int nspecs, const char *const *specs,
+ libxl_device_disk *disk);
+int parse_usbctrl_config(libxl_device_usbctrl *usbctrl, char *token);
+int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token);
+int parse_cpurange(const char *cpu, libxl_bitmap *cpumap);
+int parse_nic_config(libxl_device_nic *nic, XLU_Config **config, char *token);
+
+
+int match_option_size(const char *prefix, size_t len,
+ char *arg, char **argopt);
+#define MATCH_OPTION(prefix, arg, oparg) \
+ match_option_size((prefix "="), sizeof((prefix)), (arg), &(oparg))
+
+
+void split_string_into_string_list(const char *str, const char *delim,
+ libxl_string_list *psl);
+int split_string_into_pair(const char *str, const char *delim,
+ char **a, char **b);
+void replace_string(char **str, const char *val);
+
+/* NB: this follows the interface used by <ctype.h>. See 'man 3 ctype'
+ and look for CTYPE in libxl_internal.h */
+typedef int (*char_predicate_t)(const int c);
+void trim(char_predicate_t predicate, const char *input, char **output);
+
+const char *get_action_on_shutdown_name(libxl_action_on_shutdown a);
+
+#endif /* XL_PARSE_H */
+
+/*
+ * Local variables:
+ * mode: C
+ * c-basic-offset: 4
+ * indent-tabs-mode: nil
+ * End:
+ */
Move all parsing code into xl_parse.c. Export the ones needed in xl_parse.h. Signed-off-by: Wei Liu <wei.liu2@citrix.com> --- tools/xl/Makefile | 2 +- tools/xl/xl_cmdimpl.c | 2346 ++++--------------------------------------------- tools/xl/xl_parse.c | 2052 ++++++++++++++++++++++++++++++++++++++++++ tools/xl/xl_parse.h | 65 ++ 4 files changed, 2282 insertions(+), 2183 deletions(-) create mode 100644 tools/xl/xl_parse.c create mode 100644 tools/xl/xl_parse.h