From patchwork Mon Feb 27 17:47:21 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Wei Liu X-Patchwork-Id: 9593659 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 756B360471 for ; Mon, 27 Feb 2017 17:50:54 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 5C3232840E for ; Mon, 27 Feb 2017 17:50:54 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 4FF2A28488; Mon, 27 Feb 2017 17:50:54 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-4.2 required=2.0 tests=BAYES_00, RCVD_IN_DNSWL_MED autolearn=ham version=3.3.1 Received: from lists.xenproject.org (lists.xenproject.org [192.237.175.120]) (using TLSv1.2 with cipher AES128-GCM-SHA256 (128/128 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id 83F262840E for ; Mon, 27 Feb 2017 17:50:48 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=lists.xenproject.org) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ciPOb-00026U-ST; Mon, 27 Feb 2017 17:47:37 +0000 Received: from mail6.bemta3.messagelabs.com ([195.245.230.39]) by lists.xenproject.org with esmtp (Exim 4.84_2) (envelope-from ) id 1ciPOZ-00025v-Ui for xen-devel@lists.xenproject.org; Mon, 27 Feb 2017 17:47:36 +0000 Received: from [85.158.137.68] by server-4.bemta-3.messagelabs.com id F6/33-03705-73664B85; Mon, 27 Feb 2017 17:47:35 +0000 X-Brightmail-Tracker: H4sIAAAAAAAAA+NgFmphkeJIrShJLcpLzFFi42JxWrohUtcsbUu EwZnHMhbft0xmcmD0OPzhCksAYxRrZl5SfkUCa8a8n2oFd9u5Kn4ce8XcwPj1PFsXIyeHhIC/ xIMDu5lBbDYBZYmfnb1gcREBPYmmA88ZQWxmAS+JHyt62EFsYQEDiU+9J8FqWARUJd5PvsfUx cjBwStgIXFxTgzESHmJXW0XWUFsTgFLiak/frOBlAgJ5Ekc3BYLEhYSUJDomH6MCcTmFRCUOD nzCQvEJgmJgy9eME9g5J2FJDULSWoBI9MqRo3i1KKy1CJdI0O9pKLM9IyS3MTMHF1DA2O93NT i4sT01JzEpGK95PzcTYzA0KlnYGDcwdiz1+8QoyQHk5Io79TkLRFCfEn5KZUZicUZ8UWlOanF hxhlODiUJHiNUoFygkWp6akVaZk5wCCGSUtw8CiJ8NaCpHmLCxJzizPTIVKnGBWlxHl7QBICI ImM0jy4NljkXGKUlRLmZWRgYBDiKUgtys0sQZV/xSjOwagkzKsOMoUnM68EbvoroMVMQItnG2 8EWVySiJCSamAMsf07y1mNWTPK1DhET+H7MpHrxYuZz51wcp3NwHc87rDqr21PHs+s71swoXL +1579xuULL2+5ftinO/HRp7XFOmEz09f85pPTETnm2/1Nc9bm98bMQlXK24Ud2ws3m///dEQq 7shHg0+zOHoebwnbVuDF9mr9grJzzglXbKeX7nlx+tjT6P28SizFGYmGWsxFxYkAwBewZ5cCA AA= X-Env-Sender: prvs=2241cd559=wei.liu2@citrix.com X-Msg-Ref: server-3.tower-31.messagelabs.com!1488217650!87669006!2 X-Originating-IP: [66.165.176.89] X-SpamReason: No, hits=0.0 required=7.0 tests=sa_preprocessor: VHJ1c3RlZCBJUDogNjYuMTY1LjE3Ni44OSA9PiAyMDMwMDc=\n, received_headers: No Received headers X-StarScan-Received: X-StarScan-Version: 9.2.3; banners=-,-,- X-VirusChecked: Checked Received: (qmail 32531 invoked from network); 27 Feb 2017 17:47:32 -0000 Received: from smtp.citrix.com (HELO SMTP.CITRIX.COM) (66.165.176.89) by server-3.tower-31.messagelabs.com with RC4-SHA encrypted SMTP; 27 Feb 2017 17:47:32 -0000 X-IronPort-AV: E=Sophos;i="5.35,215,1484006400"; d="scan'208";a="410056383" From: Wei Liu To: Xen-devel Date: Mon, 27 Feb 2017 17:47:21 +0000 Message-ID: <20170227174721.15957-3-wei.liu2@citrix.com> X-Mailer: git-send-email 2.11.0 In-Reply-To: <20170227174721.15957-1-wei.liu2@citrix.com> References: <22708.19545.469240.122558@mariner.uk.xensource.com> <20170227174721.15957-1-wei.liu2@citrix.com> MIME-Version: 1.0 Cc: Wei Liu , Ian Jackson Subject: [Xen-devel] [PATCH 3/3] xl: split out xl_parse.[ch] X-BeenThere: xen-devel@lists.xen.org X-Mailman-Version: 2.1.18 Precedence: list List-Id: Xen developer discussion List-Unsubscribe: , List-Post: List-Help: List-Subscribe: , Errors-To: xen-devel-bounces@lists.xen.org Sender: "Xen-devel" X-Virus-Scanned: ClamAV using ClamSMTP Move all parsing code into xl_parse.c. Export the ones needed in xl_parse.h. Signed-off-by: Wei Liu Acked-by: Ian Jackson --- 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 diff --git a/tools/xl/Makefile b/tools/xl/Makefile index f5df366e0a..d7f7f01549 100644 --- a/tools/xl/Makefile +++ b/tools/xl/Makefile @@ -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) diff --git a/tools/xl/xl_cmdimpl.c b/tools/xl/xl_cmdimpl.c index d027d53a3f..51976f94b3 100644 --- a/tools/xl/xl_cmdimpl.c +++ b/tools/xl/xl_cmdimpl.c @@ -39,6 +39,7 @@ #include #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 . 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; diff --git a/tools/xl/xl_parse.c b/tools/xl/xl_parse.c new file mode 100644 index 0000000000..1ef0c272a8 --- /dev/null +++ b/tools/xl/xl_parse.c @@ -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 +#include +#include +#include +#include +#include + +#include +#include +#include + +#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: + */ diff --git a/tools/xl/xl_parse.h b/tools/xl/xl_parse.h new file mode 100644 index 0000000000..db8bc3f051 --- /dev/null +++ b/tools/xl/xl_parse.h @@ -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 + +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 . 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: + */