1 /*
2 * Copyright 2009-2017 Citrix Ltd and other contributors
3 *
4 * This program is free software; you can redistribute it and/or modify
5 * it under the terms of the GNU Lesser General Public License as published
6 * by the Free Software Foundation; version 2.1 only. with the special
7 * exception on linking described in file LICENSE.
8 *
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU Lesser General Public License for more details.
13 */
14
15 #include <ctype.h>
16 #include <inttypes.h>
17 #include <limits.h>
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <xen/hvm/e820.h>
21 #include <xen/hvm/params.h>
22 #include <xen/io/sndif.h>
23 #include <xen/io/kbdif.h>
24
25 #include <libxl.h>
26 #include <libxl_utils.h>
27 #include <libxlutil.h>
28
29 #include "xl.h"
30 #include "xl_utils.h"
31 #include "xl_parse.h"
32
33 extern void set_default_nic_values(libxl_device_nic *nic);
34
35 #define ARRAY_EXTEND_INIT__CORE(array,count,initfn,more) \
36 ({ \
37 typeof((count)) array_extend_old_count = (count); \
38 (count)++; \
39 (array) = xrealloc((array), sizeof(*array) * (count)); \
40 (initfn)(&(array)[array_extend_old_count]); \
41 more; \
42 &(array)[array_extend_old_count]; \
43 })
44
45 #define ARRAY_EXTEND_INIT(array,count,initfn) \
46 ARRAY_EXTEND_INIT__CORE((array),(count),(initfn), ({ \
47 (array)[array_extend_old_count].devid = array_extend_old_count; \
48 }))
49
50 #define ARRAY_EXTEND_INIT_NODEVID(array,count,initfn) \
51 ARRAY_EXTEND_INIT__CORE((array),(count),(initfn), /* nothing */ )
52
53 static const char *action_on_shutdown_names[] = {
54 [LIBXL_ACTION_ON_SHUTDOWN_DESTROY] = "destroy",
55
56 [LIBXL_ACTION_ON_SHUTDOWN_RESTART] = "restart",
57 [LIBXL_ACTION_ON_SHUTDOWN_RESTART_RENAME] = "rename-restart",
58
59 [LIBXL_ACTION_ON_SHUTDOWN_PRESERVE] = "preserve",
60
61 [LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_DESTROY] = "coredump-destroy",
62 [LIBXL_ACTION_ON_SHUTDOWN_COREDUMP_RESTART] = "coredump-restart",
63
64 [LIBXL_ACTION_ON_SHUTDOWN_SOFT_RESET] = "soft-reset",
65 };
66
get_action_on_shutdown_name(libxl_action_on_shutdown a)67 const char *get_action_on_shutdown_name(libxl_action_on_shutdown a)
68 {
69 return action_on_shutdown_names[a];
70 }
71
parse_action_on_shutdown(const char * buf,libxl_action_on_shutdown * a)72 static int parse_action_on_shutdown(const char *buf, libxl_action_on_shutdown *a)
73 {
74 int i;
75 const char *n;
76
77 for (i = 0; i < sizeof(action_on_shutdown_names) / sizeof(action_on_shutdown_names[0]); i++) {
78 n = action_on_shutdown_names[i];
79
80 if (!n) continue;
81
82 if (strcmp(buf, n) == 0) {
83 *a = i;
84 return 1;
85 }
86 }
87 return 0;
88 }
89
90 #define DSTATE_INITIAL 0
91 #define DSTATE_TAP 1
92 #define DSTATE_PHYSPATH 2
93 #define DSTATE_VIRTPATH 3
94 #define DSTATE_VIRTTYPE 4
95 #define DSTATE_RW 5
96 #define DSTATE_TERMINAL 6
97
parse_disk_config_multistring(XLU_Config ** config,int nspecs,const char * const * specs,libxl_device_disk * disk)98 void parse_disk_config_multistring(XLU_Config **config,
99 int nspecs, const char *const *specs,
100 libxl_device_disk *disk)
101 {
102 int e;
103
104 libxl_device_disk_init(disk);
105
106 if (!*config) {
107 *config = xlu_cfg_init(stderr, "command line");
108 if (!*config) { perror("xlu_cfg_init"); exit(-1); }
109 }
110
111 e = xlu_disk_parse(*config, nspecs, specs, disk);
112 if (e == EINVAL) exit(EXIT_FAILURE);
113 if (e) {
114 fprintf(stderr,"xlu_disk_parse failed: %s\n",strerror(errno));
115 exit(EXIT_FAILURE);
116 }
117 }
118
parse_disk_config(XLU_Config ** config,const char * spec,libxl_device_disk * disk)119 void parse_disk_config(XLU_Config **config, const char *spec,
120 libxl_device_disk *disk)
121 {
122 parse_disk_config_multistring(config, 1, &spec, disk);
123 }
124
parse_vif_rate(XLU_Config ** config,const char * rate,libxl_device_nic * nic)125 static void parse_vif_rate(XLU_Config **config, const char *rate,
126 libxl_device_nic *nic)
127 {
128 int e;
129
130 e = xlu_vif_parse_rate(*config, rate, nic);
131 if (e == EINVAL || e == EOVERFLOW) exit(EXIT_FAILURE);
132 if (e) {
133 fprintf(stderr,"xlu_vif_parse_rate failed: %s\n",strerror(errno));
134 exit(EXIT_FAILURE);
135 }
136 }
137
parse_range(const char * str,unsigned long * a,unsigned long * b)138 int parse_range(const char *str, unsigned long *a, unsigned long *b)
139 {
140 const char *nstr;
141 char *endptr;
142
143 *a = *b = strtoul(str, &endptr, 10);
144 if (endptr == str || *a == ULONG_MAX)
145 return 1;
146
147 if (*endptr == '-') {
148 nstr = endptr + 1;
149
150 *b = strtoul(nstr, &endptr, 10);
151 if (endptr == nstr || *b == ULONG_MAX || *b < *a)
152 return 1;
153 }
154
155 /* Valid value or range so far, but we also don't want junk after that */
156 if (*endptr != '\0')
157 return 1;
158
159 return 0;
160 }
161
162 /*
163 * Add or removes a specific set of cpus (specified in str, either as
164 * single cpus or as entire NUMA nodes) to/from cpumap.
165 */
update_cpumap_range(const char * str,libxl_bitmap * cpumap)166 static int update_cpumap_range(const char *str, libxl_bitmap *cpumap)
167 {
168 unsigned long ida, idb;
169 libxl_bitmap node_cpumap;
170 bool is_not = false, is_nodes = false;
171 int rc = 0;
172
173 libxl_bitmap_init(&node_cpumap);
174
175 rc = libxl_node_bitmap_alloc(ctx, &node_cpumap, 0);
176 if (rc) {
177 fprintf(stderr, "libxl_node_bitmap_alloc failed.\n");
178 goto out;
179 }
180
181 /* Are we adding or removing cpus/nodes? */
182 if (STR_SKIP_PREFIX(str, "^")) {
183 is_not = true;
184 }
185
186 /* Are we dealing with cpus or full nodes? */
187 if (STR_SKIP_PREFIX(str, "node:") || STR_SKIP_PREFIX(str, "nodes:")) {
188 is_nodes = true;
189 }
190
191 if (strcmp(str, "all") == 0) {
192 /* We do not accept "^all" or "^nodes:all" */
193 if (is_not) {
194 fprintf(stderr, "Can't combine \"^\" and \"all\".\n");
195 rc = ERROR_INVAL;
196 } else
197 libxl_bitmap_set_any(cpumap);
198 goto out;
199 }
200
201 rc = parse_range(str, &ida, &idb);
202 if (rc) {
203 fprintf(stderr, "Invalid pcpu range: %s.\n", str);
204 goto out;
205 }
206
207 /* Add or remove the specified cpus in the range */
208 while (ida <= idb) {
209 if (is_nodes) {
210 /* Add/Remove all the cpus of a NUMA node */
211 int i;
212
213 rc = libxl_node_to_cpumap(ctx, ida, &node_cpumap);
214 if (rc) {
215 fprintf(stderr, "libxl_node_to_cpumap failed.\n");
216 goto out;
217 }
218
219 /* Add/Remove all the cpus in the node cpumap */
220 libxl_for_each_set_bit(i, node_cpumap) {
221 is_not ? libxl_bitmap_reset(cpumap, i) :
222 libxl_bitmap_set(cpumap, i);
223 }
224 } else {
225 /* Add/Remove this cpu */
226 is_not ? libxl_bitmap_reset(cpumap, ida) :
227 libxl_bitmap_set(cpumap, ida);
228 }
229 ida++;
230 }
231
232 out:
233 libxl_bitmap_dispose(&node_cpumap);
234 return rc;
235 }
236
237 /*
238 * Takes a string representing a set of cpus (specified either as
239 * single cpus or as eintire NUMA nodes) and turns it into the
240 * corresponding libxl_bitmap (in cpumap).
241 */
parse_cpurange(const char * cpu,libxl_bitmap * cpumap)242 int parse_cpurange(const char *cpu, libxl_bitmap *cpumap)
243 {
244 char *ptr, *saveptr = NULL, *buf = xstrdup(cpu);
245 int rc = 0;
246
247 for (ptr = strtok_r(buf, ",", &saveptr); ptr;
248 ptr = strtok_r(NULL, ",", &saveptr)) {
249 rc = update_cpumap_range(ptr, cpumap);
250 if (rc)
251 break;
252 }
253 free(buf);
254
255 return rc;
256 }
257
parse_top_level_vnc_options(XLU_Config * config,libxl_vnc_info * vnc)258 static void parse_top_level_vnc_options(XLU_Config *config,
259 libxl_vnc_info *vnc)
260 {
261 long l;
262
263 xlu_cfg_get_defbool(config, "vnc", &vnc->enable, 0);
264 xlu_cfg_replace_string (config, "vnclisten", &vnc->listen, 0);
265 xlu_cfg_replace_string (config, "vncpasswd", &vnc->passwd, 0);
266 if (!xlu_cfg_get_long (config, "vncdisplay", &l, 0))
267 vnc->display = l;
268 xlu_cfg_get_defbool(config, "vncunused", &vnc->findunused, 0);
269 }
270
parse_top_level_sdl_options(XLU_Config * config,libxl_sdl_info * sdl)271 static void parse_top_level_sdl_options(XLU_Config *config,
272 libxl_sdl_info *sdl)
273 {
274 xlu_cfg_get_defbool(config, "sdl", &sdl->enable, 0);
275 xlu_cfg_get_defbool(config, "opengl", &sdl->opengl, 0);
276 xlu_cfg_replace_string (config, "display", &sdl->display, 0);
277 xlu_cfg_replace_string (config, "xauthority", &sdl->xauthority, 0);
278 }
279
parse_cmdline(XLU_Config * config)280 static char *parse_cmdline(XLU_Config *config)
281 {
282 char *cmdline = NULL;
283 const char *root = NULL, *extra = NULL, *buf = NULL;
284
285 xlu_cfg_get_string (config, "cmdline", &buf, 0);
286 xlu_cfg_get_string (config, "root", &root, 0);
287 xlu_cfg_get_string (config, "extra", &extra, 0);
288
289 if (buf) {
290 cmdline = strdup(buf);
291 if (root || extra)
292 fprintf(stderr, "Warning: ignoring root= and extra= "
293 "in favour of cmdline=\n");
294 } else {
295 if (root && extra) {
296 xasprintf(&cmdline, "root=%s %s", root, extra);
297 } else if (root) {
298 xasprintf(&cmdline, "root=%s", root);
299 } else if (extra) {
300 cmdline = strdup(extra);
301 }
302 }
303
304 if ((buf || root || extra) && !cmdline) {
305 fprintf(stderr, "Failed to allocate memory for cmdline\n");
306 exit(EXIT_FAILURE);
307 }
308
309 return cmdline;
310 }
311
parse_vcpu_affinity(libxl_domain_build_info * b_info,XLU_ConfigList * cpus,const char * buf,int num_cpus,bool is_hard)312 static void parse_vcpu_affinity(libxl_domain_build_info *b_info,
313 XLU_ConfigList *cpus, const char *buf,
314 int num_cpus, bool is_hard)
315 {
316 libxl_bitmap *vcpu_affinity_array;
317
318 /*
319 * If we are here, and buf is !NULL, we're dealing with a string. What
320 * we do in this case is parse it, and copy the result in _all_ (up to
321 * b_info->max_vcpus) the elements of the vcpu affinity array.
322 *
323 * If buf is NULL, we have a list, and what we do is putting in the
324 * i-eth element of the vcpu affinity array the result of the parsing
325 * of the i-eth entry of the list. If there are more vcpus than
326 * entries, it is fine to just not touch the last array elements.
327 */
328
329 /* Silently ignore values corresponding to non existing vcpus */
330 if (buf || num_cpus > b_info->max_vcpus)
331 num_cpus = b_info->max_vcpus;
332
333 if (is_hard) {
334 b_info->num_vcpu_hard_affinity = num_cpus;
335 b_info->vcpu_hard_affinity = xmalloc(num_cpus * sizeof(libxl_bitmap));
336 vcpu_affinity_array = b_info->vcpu_hard_affinity;
337 } else {
338 b_info->num_vcpu_soft_affinity = num_cpus;
339 b_info->vcpu_soft_affinity = xmalloc(num_cpus * sizeof(libxl_bitmap));
340 vcpu_affinity_array = b_info->vcpu_soft_affinity;
341 }
342
343 if (!buf) {
344 int j = 0;
345
346 while ((buf = xlu_cfg_get_listitem(cpus, j)) != NULL && j < num_cpus) {
347 libxl_bitmap_init(&vcpu_affinity_array[j]);
348 if (libxl_cpu_bitmap_alloc(ctx, &vcpu_affinity_array[j], 0)) {
349 fprintf(stderr, "Unable to allocate cpumap for vcpu %d\n", j);
350 exit(EXIT_FAILURE);
351 }
352
353 if (parse_cpurange(buf, &vcpu_affinity_array[j]))
354 exit(EXIT_FAILURE);
355
356 j++;
357 }
358
359 /* When we have a list of cpumaps, always disable automatic placement */
360 libxl_defbool_set(&b_info->numa_placement, false);
361 } else {
362 int i;
363
364 libxl_bitmap_init(&vcpu_affinity_array[0]);
365 if (libxl_cpu_bitmap_alloc(ctx, &vcpu_affinity_array[0], 0)) {
366 fprintf(stderr, "Unable to allocate cpumap for vcpu 0\n");
367 exit(EXIT_FAILURE);
368 }
369
370 if (parse_cpurange(buf, &vcpu_affinity_array[0]))
371 exit(EXIT_FAILURE);
372
373 for (i = 1; i < b_info->max_vcpus; i++) {
374 libxl_bitmap_init(&vcpu_affinity_array[i]);
375 if (libxl_cpu_bitmap_alloc(ctx, &vcpu_affinity_array[i], 0)) {
376 fprintf(stderr, "Unable to allocate cpumap for vcpu %d\n", i);
377 exit(EXIT_FAILURE);
378 }
379 libxl_bitmap_copy(ctx, &vcpu_affinity_array[i],
380 &vcpu_affinity_array[0]);
381 }
382
383 /* We have soft affinity already, disable automatic placement */
384 if (!is_hard)
385 libxl_defbool_set(&b_info->numa_placement, false);
386 }
387 }
388
parse_ulong(const char * str)389 static unsigned long parse_ulong(const char *str)
390 {
391 char *endptr;
392 unsigned long val;
393
394 val = strtoul(str, &endptr, 10);
395 if (endptr == str || val == ULONG_MAX) {
396 fprintf(stderr, "xl: failed to convert \"%s\" to number\n", str);
397 exit(EXIT_FAILURE);
398 }
399 return val;
400 }
401
replace_string(char ** str,const char * val)402 void replace_string(char **str, const char *val)
403 {
404 free(*str);
405 *str = xstrdup(val);
406 }
407
match_option_size(const char * prefix,size_t len,char * arg,char ** argopt)408 int match_option_size(const char *prefix, size_t len,
409 char *arg, char **argopt)
410 {
411 int rc = strncmp(prefix, arg, len);
412 if (!rc) *argopt = arg+len;
413 return !rc;
414 }
415
416 /* Parses network data and adds info into nic
417 * Returns 1 if the input token does not match one of the keys
418 * or parsed values are not correct. Successful parse returns 0 */
parse_nic_config(libxl_device_nic * nic,XLU_Config ** config,char * token)419 int parse_nic_config(libxl_device_nic *nic, XLU_Config **config, char *token)
420 {
421 char *endptr, *oparg;
422 int i;
423 unsigned int val;
424
425 if (MATCH_OPTION("type", token, oparg)) {
426 if (!strcmp("vif", oparg)) {
427 nic->nictype = LIBXL_NIC_TYPE_VIF;
428 } else if (!strcmp("ioemu", oparg)) {
429 nic->nictype = LIBXL_NIC_TYPE_VIF_IOEMU;
430 } else {
431 fprintf(stderr, "Invalid parameter `type'.\n");
432 return 1;
433 }
434 } else if (MATCH_OPTION("mac", token, oparg)) {
435 for (i = 0; i < 6; i++) {
436 val = strtoul(oparg, &endptr, 16);
437 if ((oparg == endptr) || (val > 255)) {
438 fprintf(stderr, "Invalid parameter `mac'.\n");
439 return 1;
440 }
441 nic->mac[i] = val;
442 oparg = endptr + 1;
443 }
444 } else if (MATCH_OPTION("bridge", token, oparg)) {
445 replace_string(&nic->bridge, oparg);
446 } else if (MATCH_OPTION("netdev", token, oparg)) {
447 fprintf(stderr, "the netdev parameter is deprecated, "
448 "please use gatewaydev instead\n");
449 replace_string(&nic->gatewaydev, oparg);
450 } else if (MATCH_OPTION("gatewaydev", token, oparg)) {
451 replace_string(&nic->gatewaydev, oparg);
452 } else if (MATCH_OPTION("ip", token, oparg)) {
453 replace_string(&nic->ip, oparg);
454 } else if (MATCH_OPTION("script", token, oparg)) {
455 replace_string(&nic->script, oparg);
456 } else if (MATCH_OPTION("backend", token, oparg)) {
457 replace_string(&nic->backend_domname, oparg);
458 } else if (MATCH_OPTION("vifname", token, oparg)) {
459 replace_string(&nic->ifname, oparg);
460 } else if (MATCH_OPTION("model", token, oparg)) {
461 replace_string(&nic->model, oparg);
462 } else if (MATCH_OPTION("rate", token, oparg)) {
463 parse_vif_rate(config, oparg, nic);
464 } else if (MATCH_OPTION("forwarddev", token, oparg)) {
465 replace_string(&nic->coloft_forwarddev, oparg);
466 } else if (MATCH_OPTION("colo_sock_mirror_id", token, oparg)) {
467 replace_string(&nic->colo_sock_mirror_id, oparg);
468 } else if (MATCH_OPTION("colo_sock_mirror_ip", token, oparg)) {
469 replace_string(&nic->colo_sock_mirror_ip, oparg);
470 } else if (MATCH_OPTION("colo_sock_mirror_port", token, oparg)) {
471 replace_string(&nic->colo_sock_mirror_port, oparg);
472 } else if (MATCH_OPTION("colo_sock_compare_sec_in_id", token, oparg)) {
473 replace_string(&nic->colo_sock_compare_sec_in_id, oparg);
474 } else if (MATCH_OPTION("colo_sock_compare_sec_in_ip", token, oparg)) {
475 replace_string(&nic->colo_sock_compare_sec_in_ip, oparg);
476 } else if (MATCH_OPTION("colo_sock_compare_sec_in_port", token, oparg)) {
477 replace_string(&nic->colo_sock_compare_sec_in_port, oparg);
478 } else if (MATCH_OPTION("colo_sock_redirector0_id", token, oparg)) {
479 replace_string(&nic->colo_sock_redirector0_id, oparg);
480 } else if (MATCH_OPTION("colo_sock_redirector0_ip", token, oparg)) {
481 replace_string(&nic->colo_sock_redirector0_ip, oparg);
482 } else if (MATCH_OPTION("colo_sock_redirector0_port", token, oparg)) {
483 replace_string(&nic->colo_sock_redirector0_port, oparg);
484 } else if (MATCH_OPTION("colo_sock_redirector1_id", token, oparg)) {
485 replace_string(&nic->colo_sock_redirector1_id, oparg);
486 } else if (MATCH_OPTION("colo_sock_redirector1_ip", token, oparg)) {
487 replace_string(&nic->colo_sock_redirector1_ip, oparg);
488 } else if (MATCH_OPTION("colo_sock_redirector1_port", token, oparg)) {
489 replace_string(&nic->colo_sock_redirector1_port, oparg);
490 } else if (MATCH_OPTION("colo_sock_redirector2_id", token, oparg)) {
491 replace_string(&nic->colo_sock_redirector2_id, oparg);
492 } else if (MATCH_OPTION("colo_sock_redirector2_ip", token, oparg)) {
493 replace_string(&nic->colo_sock_redirector2_ip, oparg);
494 } else if (MATCH_OPTION("colo_sock_redirector2_port", token, oparg)) {
495 replace_string(&nic->colo_sock_redirector2_port, oparg);
496 } else if (MATCH_OPTION("colo_sock_compare_pri_in_id", token, oparg)) {
497 replace_string(&nic->colo_sock_compare_pri_in_id, oparg);
498 } else if (MATCH_OPTION("colo_sock_compare_pri_in_ip", token, oparg)) {
499 replace_string(&nic->colo_sock_compare_pri_in_ip, oparg);
500 } else if (MATCH_OPTION("colo_sock_compare_pri_in_port", token, oparg)) {
501 replace_string(&nic->colo_sock_compare_pri_in_port, oparg);
502 } else if (MATCH_OPTION("colo_sock_compare_notify_id", token, oparg)) {
503 replace_string(&nic->colo_sock_compare_notify_id, oparg);
504 } else if (MATCH_OPTION("colo_sock_compare_notify_ip", token, oparg)) {
505 replace_string(&nic->colo_sock_compare_notify_ip, oparg);
506 } else if (MATCH_OPTION("colo_sock_compare_notify_port", token, oparg)) {
507 replace_string(&nic->colo_sock_compare_notify_port, oparg);
508 } else if (MATCH_OPTION("colo_filter_mirror_queue", token, oparg)) {
509 replace_string(&nic->colo_filter_mirror_queue, oparg);
510 } else if (MATCH_OPTION("colo_filter_mirror_outdev", token, oparg)) {
511 replace_string(&nic->colo_filter_mirror_outdev, oparg);
512 } else if (MATCH_OPTION("colo_filter_redirector0_queue", token, oparg)) {
513 replace_string(&nic->colo_filter_redirector0_queue, oparg);
514 } else if (MATCH_OPTION("colo_filter_redirector0_indev", token, oparg)) {
515 replace_string(&nic->colo_filter_redirector0_indev, oparg);
516 } else if (MATCH_OPTION("colo_filter_redirector0_outdev", token, oparg)) {
517 replace_string(&nic->colo_filter_redirector0_outdev, oparg);
518 } else if (MATCH_OPTION("colo_filter_redirector1_queue", token, oparg)) {
519 replace_string(&nic->colo_filter_redirector1_queue, oparg);
520 } else if (MATCH_OPTION("colo_filter_redirector1_indev", token, oparg)) {
521 replace_string(&nic->colo_filter_redirector1_indev, oparg);
522 } else if (MATCH_OPTION("colo_filter_redirector1_outdev", token, oparg)) {
523 replace_string(&nic->colo_filter_redirector1_outdev, oparg);
524 } else if (MATCH_OPTION("colo_compare_pri_in", token, oparg)) {
525 replace_string(&nic->colo_compare_pri_in, oparg);
526 } else if (MATCH_OPTION("colo_compare_sec_in", token, oparg)) {
527 replace_string(&nic->colo_compare_sec_in, oparg);
528 } else if (MATCH_OPTION("colo_compare_out", token, oparg)) {
529 replace_string(&nic->colo_compare_out, oparg);
530 } else if (MATCH_OPTION("colo_compare_notify_dev", token, oparg)) {
531 replace_string(&nic->colo_compare_notify_dev, oparg);
532 } else if (MATCH_OPTION("colo_sock_sec_redirector0_id", token, oparg)) {
533 replace_string(&nic->colo_sock_sec_redirector0_id, oparg);
534 } else if (MATCH_OPTION("colo_sock_sec_redirector0_ip", token, oparg)) {
535 replace_string(&nic->colo_sock_sec_redirector0_ip, oparg);
536 } else if (MATCH_OPTION("colo_sock_sec_redirector0_port", token, oparg)) {
537 replace_string(&nic->colo_sock_sec_redirector0_port, oparg);
538 } else if (MATCH_OPTION("colo_sock_sec_redirector1_id", token, oparg)) {
539 replace_string(&nic->colo_sock_sec_redirector1_id, oparg);
540 } else if (MATCH_OPTION("colo_sock_sec_redirector1_ip", token, oparg)) {
541 replace_string(&nic->colo_sock_sec_redirector1_ip, oparg);
542 } else if (MATCH_OPTION("colo_sock_sec_redirector1_port", token, oparg)) {
543 replace_string(&nic->colo_sock_sec_redirector1_port, oparg);
544 } else if (MATCH_OPTION("colo_filter_sec_redirector0_queue", token, oparg)) {
545 replace_string(&nic->colo_filter_sec_redirector0_queue, oparg);
546 } else if (MATCH_OPTION("colo_filter_sec_redirector0_indev", token, oparg)) {
547 replace_string(&nic->colo_filter_sec_redirector0_indev, oparg);
548 } else if (MATCH_OPTION("colo_filter_sec_redirector0_outdev", token, oparg)) {
549 replace_string(&nic->colo_filter_sec_redirector0_outdev, oparg);
550 } else if (MATCH_OPTION("colo_filter_sec_redirector1_queue", token, oparg)) {
551 replace_string(&nic->colo_filter_sec_redirector1_queue, oparg);
552 } else if (MATCH_OPTION("colo_filter_sec_redirector1_indev", token, oparg)) {
553 replace_string(&nic->colo_filter_sec_redirector1_indev, oparg);
554 } else if (MATCH_OPTION("colo_filter_sec_redirector1_outdev", token, oparg)) {
555 replace_string(&nic->colo_filter_sec_redirector1_outdev, oparg);
556 } else if (MATCH_OPTION("colo_filter_sec_rewriter0_queue", token, oparg)) {
557 replace_string(&nic->colo_filter_sec_rewriter0_queue, oparg);
558 } else if (MATCH_OPTION("colo_checkpoint_host", token, oparg)) {
559 replace_string(&nic->colo_checkpoint_host, oparg);
560 } else if (MATCH_OPTION("colo_checkpoint_port", token, oparg)) {
561 replace_string(&nic->colo_checkpoint_port, oparg);
562 } else if (MATCH_OPTION("accel", token, oparg)) {
563 fprintf(stderr, "the accel parameter for vifs is currently not supported\n");
564 } else if (MATCH_OPTION("devid", token, oparg)) {
565 nic->devid = parse_ulong(oparg);
566 } else {
567 fprintf(stderr, "unrecognized argument `%s'\n", token);
568 return 1;
569 }
570 return 0;
571 }
572
parse_vnuma_config(const XLU_Config * config,libxl_domain_build_info * b_info)573 static void parse_vnuma_config(const XLU_Config *config,
574 libxl_domain_build_info *b_info)
575 {
576 libxl_physinfo physinfo;
577 uint32_t nr_nodes;
578 XLU_ConfigList *vnuma;
579 int i, j, len, num_vnuma;
580 unsigned long max_vcpus = 0, max_memkb = 0;
581 /* Temporary storage for parsed vcpus information to avoid
582 * parsing config twice. This array has num_vnuma elements.
583 */
584 libxl_bitmap *vcpu_parsed;
585
586 libxl_physinfo_init(&physinfo);
587 if (libxl_get_physinfo(ctx, &physinfo) != 0) {
588 libxl_physinfo_dispose(&physinfo);
589 fprintf(stderr, "libxl_get_physinfo failed\n");
590 exit(EXIT_FAILURE);
591 }
592
593 nr_nodes = physinfo.nr_nodes;
594 libxl_physinfo_dispose(&physinfo);
595
596 if (xlu_cfg_get_list(config, "vnuma", &vnuma, &num_vnuma, 1))
597 return;
598
599 if (!num_vnuma)
600 return;
601
602 b_info->num_vnuma_nodes = num_vnuma;
603 b_info->vnuma_nodes = xcalloc(num_vnuma, sizeof(libxl_vnode_info));
604 vcpu_parsed = xcalloc(num_vnuma, sizeof(libxl_bitmap));
605 for (i = 0; i < num_vnuma; i++) {
606 libxl_bitmap_init(&vcpu_parsed[i]);
607 if (libxl_cpu_bitmap_alloc(ctx, &vcpu_parsed[i], b_info->max_vcpus)) {
608 fprintf(stderr, "libxl_node_bitmap_alloc failed.\n");
609 exit(EXIT_FAILURE);
610 }
611 }
612
613 for (i = 0; i < b_info->num_vnuma_nodes; i++) {
614 libxl_vnode_info *p = &b_info->vnuma_nodes[i];
615
616 libxl_vnode_info_init(p);
617 p->distances = xcalloc(b_info->num_vnuma_nodes,
618 sizeof(*p->distances));
619 p->num_distances = b_info->num_vnuma_nodes;
620 }
621
622 for (i = 0; i < num_vnuma; i++) {
623 XLU_ConfigValue *vnode_spec, *conf_option;
624 XLU_ConfigList *vnode_config_list;
625 int conf_count;
626 libxl_vnode_info *p = &b_info->vnuma_nodes[i];
627
628 vnode_spec = xlu_cfg_get_listitem2(vnuma, i);
629 assert(vnode_spec);
630
631 xlu_cfg_value_get_list(config, vnode_spec, &vnode_config_list, 0);
632 if (!vnode_config_list) {
633 fprintf(stderr, "xl: cannot get vnode config option list\n");
634 exit(EXIT_FAILURE);
635 }
636
637 for (conf_count = 0;
638 (conf_option =
639 xlu_cfg_get_listitem2(vnode_config_list, conf_count));
640 conf_count++) {
641
642 if (xlu_cfg_value_type(conf_option) == XLU_STRING) {
643 char *buf, *option_untrimmed, *value_untrimmed;
644 char *option, *value;
645 unsigned long val;
646
647 xlu_cfg_value_get_string(config, conf_option, &buf, 0);
648
649 if (!buf) continue;
650
651 if (split_string_into_pair(buf, "=",
652 &option_untrimmed,
653 &value_untrimmed)) {
654 fprintf(stderr, "xl: failed to split \"%s\" into pair\n",
655 buf);
656 exit(EXIT_FAILURE);
657 }
658 trim(isspace, option_untrimmed, &option);
659 trim(isspace, value_untrimmed, &value);
660
661 if (!strcmp("pnode", option)) {
662 val = parse_ulong(value);
663 if (val >= nr_nodes) {
664 fprintf(stderr,
665 "xl: invalid pnode number: %lu\n", val);
666 exit(EXIT_FAILURE);
667 }
668 p->pnode = val;
669 libxl_defbool_set(&b_info->numa_placement, false);
670 } else if (!strcmp("size", option)) {
671 val = parse_ulong(value);
672 p->memkb = val << 10;
673 max_memkb += p->memkb;
674 } else if (!strcmp("vcpus", option)) {
675 libxl_string_list cpu_spec_list;
676 unsigned long s, e;
677
678 split_string_into_string_list(value, ",", &cpu_spec_list);
679 len = libxl_string_list_length(&cpu_spec_list);
680
681 for (j = 0; j < len; j++) {
682 parse_range(cpu_spec_list[j], &s, &e);
683 for (; s <= e; s++) {
684 /*
685 * Note that if we try to set a bit beyond
686 * the size of bitmap, libxl_bitmap_set
687 * has no effect. The resulted bitmap
688 * doesn't reflect what user wants. The
689 * fallout is dealt with later after
690 * parsing.
691 */
692 libxl_bitmap_set(&vcpu_parsed[i], s);
693 max_vcpus++;
694 }
695 }
696
697 libxl_string_list_dispose(&cpu_spec_list);
698 } else if (!strcmp("vdistances", option)) {
699 libxl_string_list vdist;
700
701 split_string_into_string_list(value, ",", &vdist);
702 len = libxl_string_list_length(&vdist);
703
704 for (j = 0; j < len; j++) {
705 val = parse_ulong(vdist[j]);
706 p->distances[j] = val;
707 }
708 libxl_string_list_dispose(&vdist);
709 }
710 free(option);
711 free(value);
712 free(option_untrimmed);
713 free(value_untrimmed);
714 }
715 }
716 }
717
718 /* User has specified maxvcpus= */
719 if (b_info->max_vcpus != 0) {
720 if (b_info->max_vcpus != max_vcpus) {
721 fprintf(stderr, "xl: vnuma vcpus and maxvcpus= mismatch\n");
722 exit(EXIT_FAILURE);
723 }
724 } else {
725 int host_cpus = libxl_get_online_cpus(ctx);
726
727 if (host_cpus < 0) {
728 fprintf(stderr, "Failed to get online cpus\n");
729 exit(EXIT_FAILURE);
730 }
731
732 if (host_cpus < max_vcpus) {
733 fprintf(stderr, "xl: vnuma specifies more vcpus than pcpus, "\
734 "use maxvcpus= to override this check.\n");
735 exit(EXIT_FAILURE);
736 }
737
738 b_info->max_vcpus = max_vcpus;
739 }
740
741 /* User has specified maxmem= */
742 if (b_info->max_memkb != LIBXL_MEMKB_DEFAULT &&
743 b_info->max_memkb != max_memkb) {
744 fprintf(stderr, "xl: maxmem and vnuma memory size mismatch\n");
745 exit(EXIT_FAILURE);
746 } else
747 b_info->max_memkb = max_memkb;
748
749 for (i = 0; i < b_info->num_vnuma_nodes; i++) {
750 libxl_vnode_info *p = &b_info->vnuma_nodes[i];
751
752 libxl_bitmap_copy_alloc(ctx, &p->vcpus, &vcpu_parsed[i]);
753 libxl_bitmap_dispose(&vcpu_parsed[i]);
754 }
755
756 free(vcpu_parsed);
757 }
758
759 /* Parses usbctrl data and adds info into usbctrl
760 * Returns 1 if the input token does not match one of the keys
761 * or parsed values are not correct. Successful parse returns 0 */
parse_usbctrl_config(libxl_device_usbctrl * usbctrl,char * token)762 int parse_usbctrl_config(libxl_device_usbctrl *usbctrl, char *token)
763 {
764 char *oparg;
765
766 if (MATCH_OPTION("type", token, oparg)) {
767 if (libxl_usbctrl_type_from_string(oparg, &usbctrl->type)) {
768 fprintf(stderr, "Invalid usb controller type '%s'\n", oparg);
769 return 1;
770 }
771 } else if (MATCH_OPTION("version", token, oparg)) {
772 usbctrl->version = atoi(oparg);
773 } else if (MATCH_OPTION("ports", token, oparg)) {
774 usbctrl->ports = atoi(oparg);
775 } else {
776 fprintf(stderr, "Unknown string `%s' in usbctrl spec\n", token);
777 return 1;
778 }
779
780 return 0;
781 }
782
783 /* Parses usbdev data and adds info into usbdev
784 * Returns 1 if the input token does not match one of the keys
785 * or parsed values are not correct. Successful parse returns 0 */
parse_usbdev_config(libxl_device_usbdev * usbdev,char * token)786 int parse_usbdev_config(libxl_device_usbdev *usbdev, char *token)
787 {
788 char *oparg;
789
790 if (MATCH_OPTION("type", token, oparg)) {
791 if (libxl_usbdev_type_from_string(oparg, &usbdev->type)) {
792 fprintf(stderr, "Invalid usb device type: %s\n", optarg);
793 return 1;
794 }
795 } else if (MATCH_OPTION("hostbus", token, oparg)) {
796 usbdev->u.hostdev.hostbus = strtoul(oparg, NULL, 0);
797 } else if (MATCH_OPTION("hostaddr", token, oparg)) {
798 usbdev->u.hostdev.hostaddr = strtoul(oparg, NULL, 0);
799 } else if (MATCH_OPTION("controller", token, oparg)) {
800 usbdev->ctrl = atoi(oparg);
801 } else if (MATCH_OPTION("port", token, oparg)) {
802 usbdev->port = atoi(oparg);
803 } else {
804 fprintf(stderr, "Unknown string `%s' in usbdev spec\n", token);
805 return 1;
806 }
807
808 return 0;
809 }
810
parse_vdispl_config(libxl_device_vdispl * vdispl,char * token)811 int parse_vdispl_config(libxl_device_vdispl *vdispl, char *token)
812 {
813 char *oparg;
814 libxl_string_list connectors = NULL;
815 int i;
816 int rc;
817
818 if (MATCH_OPTION("backend", token, oparg)) {
819 vdispl->backend_domname = strdup(oparg);
820 } else if (MATCH_OPTION("be-alloc", token, oparg)) {
821 vdispl->be_alloc = strtoul(oparg, NULL, 0);
822 } else if (MATCH_OPTION("connectors", token, oparg)) {
823 split_string_into_string_list(oparg, ";", &connectors);
824
825 vdispl->num_connectors = libxl_string_list_length(&connectors);
826 vdispl->connectors = xcalloc(vdispl->num_connectors,
827 sizeof(*vdispl->connectors));
828
829 for(i = 0; i < vdispl->num_connectors; i++)
830 {
831 char *resolution;
832
833 rc = split_string_into_pair(connectors[i], ":",
834 &vdispl->connectors[i].unique_id,
835 &resolution);
836
837 rc= sscanf(resolution, "%ux%u", &vdispl->connectors[i].width,
838 &vdispl->connectors[i].height);
839 free(resolution);
840
841 if (rc != 2) {
842 fprintf(stderr, "Can't parse connector resolution\n");
843 goto out;
844 }
845 }
846 } else {
847 fprintf(stderr, "Unknown string \"%s\" in vdispl spec\n", token);
848 rc = 1; goto out;
849 }
850
851 rc = 0;
852
853 out:
854 libxl_string_list_dispose(&connectors);
855 return rc;
856 }
857
parse_vsnd_params(libxl_vsnd_params * params,char * token)858 static int parse_vsnd_params(libxl_vsnd_params *params, char *token)
859 {
860 char *oparg;
861 int i;
862
863 if (MATCH_OPTION(XENSND_FIELD_SAMPLE_RATES, token, oparg)) {
864 libxl_string_list rates = NULL;
865
866 split_string_into_string_list(oparg, ";", &rates);
867
868 params->num_sample_rates = libxl_string_list_length(&rates);
869 params->sample_rates = xcalloc(params->num_sample_rates,
870 sizeof(*params->sample_rates));
871
872 for (i = 0; i < params->num_sample_rates; i++) {
873 params->sample_rates[i] = strtoul(rates[i], NULL, 0);
874 }
875
876 libxl_string_list_dispose(&rates);
877 } else if (MATCH_OPTION(XENSND_FIELD_SAMPLE_FORMATS, token, oparg)) {
878 libxl_string_list formats = NULL;
879
880 split_string_into_string_list(oparg, ";", &formats);
881
882 params->num_sample_formats = libxl_string_list_length(&formats);
883 params->sample_formats = xcalloc(params->num_sample_formats,
884 sizeof(*params->sample_formats));
885
886 for (i = 0; i < params->num_sample_formats; i++) {
887 libxl_vsnd_pcm_format format;
888
889 if (libxl_vsnd_pcm_format_from_string(formats[i], &format)) {
890 fprintf(stderr, "Invalid pcm format: %s\n", formats[i]);
891 exit(EXIT_FAILURE);
892 }
893
894 params->sample_formats[i] = format;
895 }
896
897 libxl_string_list_dispose(&formats);
898 } else if (MATCH_OPTION(XENSND_FIELD_CHANNELS_MIN, token, oparg)) {
899 params->channels_min = strtoul(oparg, NULL, 0);
900 } else if (MATCH_OPTION(XENSND_FIELD_CHANNELS_MAX, token, oparg)) {
901 params->channels_max = strtoul(oparg, NULL, 0);
902 } else if (MATCH_OPTION(XENSND_FIELD_BUFFER_SIZE, token, oparg)) {
903 params->buffer_size = strtoul(oparg, NULL, 0);
904 } else {
905 return 1;
906 }
907
908 return 0;
909 }
910
parse_vsnd_pcm_stream(libxl_device_vsnd * vsnd,char * param)911 static int parse_vsnd_pcm_stream(libxl_device_vsnd *vsnd, char *param)
912 {
913 if (vsnd->num_vsnd_pcms == 0) {
914 fprintf(stderr, "No vsnd pcm device\n");
915 return -1;
916 }
917
918 libxl_vsnd_pcm *pcm = &vsnd->pcms[vsnd->num_vsnd_pcms - 1];
919
920 if (pcm->num_vsnd_streams == 0) {
921 fprintf(stderr, "No vsnd stream\n");
922 return -1;
923 }
924
925 libxl_vsnd_stream *stream = &pcm->streams[pcm->num_vsnd_streams - 1];
926
927 if (parse_vsnd_params(&stream->params, param)) {
928 char *oparg;
929
930 if (MATCH_OPTION(XENSND_FIELD_STREAM_UNIQUE_ID, param, oparg)) {
931 stream->unique_id = strdup(oparg);
932 } else if (MATCH_OPTION(XENSND_FIELD_TYPE, param, oparg)) {
933 if (libxl_vsnd_stream_type_from_string(oparg, &stream->type)) {
934 fprintf(stderr, "Invalid stream type: %s\n", oparg);
935 return -1;
936 }
937 } else {
938 fprintf(stderr, "Invalid parameter: %s\n", param);
939 return -1;
940 }
941 }
942
943 return 0;
944 }
945
parse_vsnd_pcm_param(libxl_device_vsnd * vsnd,char * param)946 static int parse_vsnd_pcm_param(libxl_device_vsnd *vsnd, char *param)
947 {
948 if (vsnd->num_vsnd_pcms == 0) {
949 fprintf(stderr, "No pcm device\n");
950 return -1;
951 }
952
953 libxl_vsnd_pcm *pcm = &vsnd->pcms[vsnd->num_vsnd_pcms - 1];
954
955 if (parse_vsnd_params(&pcm->params, param)) {
956 char *oparg;
957
958 if (MATCH_OPTION(XENSND_FIELD_DEVICE_NAME, param, oparg)) {
959 pcm->name = strdup(oparg);
960 } else {
961 fprintf(stderr, "Invalid parameter: %s\n", param);
962 return -1;
963 }
964 }
965
966 return 0;
967 }
968
parse_vsnd_card_param(libxl_device_vsnd * vsnd,char * param)969 static int parse_vsnd_card_param(libxl_device_vsnd *vsnd, char *param)
970 {
971 if (parse_vsnd_params(&vsnd->params, param)) {
972 char *oparg;
973
974 if (MATCH_OPTION("backend", param, oparg)) {
975 vsnd->backend_domname = strdup(oparg);
976 } else if (MATCH_OPTION(XENSND_FIELD_VCARD_SHORT_NAME, param, oparg)) {
977 vsnd->short_name = strdup(oparg);
978 } else if (MATCH_OPTION(XENSND_FIELD_VCARD_LONG_NAME, param, oparg)) {
979 vsnd->long_name = strdup(oparg);
980 } else {
981 fprintf(stderr, "Invalid parameter: %s\n", param);
982 return -1;
983 }
984 }
985
986 return 0;
987 }
988
parse_vsnd_create_item(libxl_device_vsnd * vsnd,const char * key)989 static int parse_vsnd_create_item(libxl_device_vsnd *vsnd, const char *key)
990 {
991 if (strcasecmp(key, "card") == 0) {
992
993 } else if (strcasecmp(key, "pcm") == 0) {
994 ARRAY_EXTEND_INIT_NODEVID(vsnd->pcms, vsnd->num_vsnd_pcms,
995 libxl_vsnd_pcm_init);
996 } else if (strcasecmp(key, "stream") == 0) {
997 if (vsnd->num_vsnd_pcms == 0) {
998 ARRAY_EXTEND_INIT_NODEVID(vsnd->pcms, vsnd->num_vsnd_pcms,
999 libxl_vsnd_pcm_init);
1000 }
1001
1002 libxl_vsnd_pcm *pcm = &vsnd->pcms[vsnd->num_vsnd_pcms - 1];
1003
1004 ARRAY_EXTEND_INIT_NODEVID(pcm->streams, pcm->num_vsnd_streams,
1005 libxl_vsnd_stream_init);
1006 } else {
1007 fprintf(stderr, "Invalid key: %s\n", key);
1008 return -1;
1009 }
1010
1011 return 0;
1012 }
1013
parse_vsnd_item(libxl_device_vsnd * vsnd,const char * spec)1014 int parse_vsnd_item(libxl_device_vsnd *vsnd, const char *spec)
1015 {
1016 char *buf = strdup(spec);
1017 char *token = strtok(buf, ",");
1018 char *key = NULL;
1019 int ret;
1020
1021 while (token) {
1022 while (*token == ' ') token++;
1023
1024 if (!key) {
1025 key = token;
1026 ret = parse_vsnd_create_item(vsnd, key);
1027 if (ret) goto out;
1028 } else {
1029 if (strcasecmp(key, "card") == 0) {
1030 ret = parse_vsnd_card_param(vsnd, token);
1031 if (ret) goto out;
1032 } else if (strcasecmp(key, "pcm") == 0) {
1033 ret = parse_vsnd_pcm_param(vsnd, token);
1034 if (ret) goto out;
1035 } else if (strcasecmp(key, "stream") == 0) {
1036 ret = parse_vsnd_pcm_stream(vsnd, token);
1037 if (ret) goto out;
1038 }
1039 }
1040 token = strtok (NULL, ",");
1041 }
1042
1043 ret = 0;
1044
1045 out:
1046 free(buf);
1047 return ret;
1048 }
1049
parse_vsnd_card_config(const XLU_Config * config,XLU_ConfigValue * card_value,libxl_domain_config * d_config)1050 static void parse_vsnd_card_config(const XLU_Config *config,
1051 XLU_ConfigValue *card_value,
1052 libxl_domain_config *d_config)
1053 {
1054 int ret;
1055 XLU_ConfigList *card_list;
1056 libxl_device_vsnd *vsnd;
1057 const char *card_item;
1058 int item = 0;
1059
1060 ret = xlu_cfg_value_get_list(config, card_value, &card_list, 0);
1061
1062 if (ret) {
1063 fprintf(stderr, "Failed to get vsnd card list: %s\n", strerror(ret));
1064 goto out;
1065 }
1066
1067 vsnd = ARRAY_EXTEND_INIT(d_config->vsnds,
1068 d_config->num_vsnds,
1069 libxl_device_vsnd_init);
1070
1071 while ((card_item = xlu_cfg_get_listitem(card_list, item++)) != NULL) {
1072 ret = parse_vsnd_item(vsnd, card_item);
1073 if (ret) goto out;
1074 }
1075
1076 ret = 0;
1077
1078 out:
1079
1080 if (ret) exit(EXIT_FAILURE);
1081 }
1082
parse_vsnd_config(const XLU_Config * config,libxl_domain_config * d_config)1083 static void parse_vsnd_config(const XLU_Config *config,
1084 libxl_domain_config *d_config)
1085 {
1086 XLU_ConfigList *vsnds;
1087
1088 if (!xlu_cfg_get_list(config, "vsnd", &vsnds, 0, 0)) {
1089 XLU_ConfigValue *card_value;
1090
1091 d_config->num_vsnds = 0;
1092 d_config->vsnds = NULL;
1093
1094 while ((card_value = xlu_cfg_get_listitem2(vsnds, d_config->num_vsnds))
1095 != NULL) {
1096 parse_vsnd_card_config(config, card_value, d_config);
1097 }
1098 }
1099 }
1100
parse_vkb_config(libxl_device_vkb * vkb,char * token)1101 int parse_vkb_config(libxl_device_vkb *vkb, char *token)
1102 {
1103 char *oparg;
1104
1105 if (MATCH_OPTION("backend", token, oparg)) {
1106 vkb->backend_domname = strdup(oparg);
1107 } else if (MATCH_OPTION("backend-type", token, oparg)) {
1108 libxl_vkb_backend backend_type;
1109 if (libxl_vkb_backend_from_string(oparg, &backend_type)) {
1110 fprintf(stderr, "Unknown backend_type \"%s\" in vkb spec\n",
1111 oparg);
1112 return -1;
1113 }
1114 vkb->backend_type = backend_type;
1115 } else if (MATCH_OPTION(XENKBD_FIELD_UNIQUE_ID, token, oparg)) {
1116 vkb->unique_id = strdup(oparg);
1117 } else if (MATCH_OPTION(XENKBD_FIELD_FEAT_DSBL_KEYBRD, token, oparg)) {
1118 vkb->feature_disable_keyboard = strtoul(oparg, NULL, 0);
1119 } else if (MATCH_OPTION(XENKBD_FIELD_FEAT_DSBL_POINTER, token, oparg)) {
1120 vkb->feature_disable_pointer = strtoul(oparg, NULL, 0);
1121 } else if (MATCH_OPTION(XENKBD_FIELD_FEAT_ABS_POINTER, token, oparg)) {
1122 vkb->feature_abs_pointer = strtoul(oparg, NULL, 0);
1123 } else if (MATCH_OPTION(XENKBD_FIELD_FEAT_RAW_POINTER, token, oparg)) {
1124 vkb->feature_raw_pointer = strtoul(oparg, NULL, 0);
1125 } else if (MATCH_OPTION(XENKBD_FIELD_FEAT_MTOUCH, token, oparg)) {
1126 vkb->feature_multi_touch = strtoul(oparg, NULL, 0);
1127 } else if (MATCH_OPTION(XENKBD_FIELD_MT_WIDTH, token, oparg)) {
1128 vkb->multi_touch_width = strtoul(oparg, NULL, 0);
1129 } else if (MATCH_OPTION(XENKBD_FIELD_MT_HEIGHT, token, oparg)) {
1130 vkb->multi_touch_height = strtoul(oparg, NULL, 0);
1131 } else if (MATCH_OPTION(XENKBD_FIELD_MT_NUM_CONTACTS, token, oparg)) {
1132 vkb->multi_touch_num_contacts = strtoul(oparg, NULL, 0);
1133 } else if (MATCH_OPTION(XENKBD_FIELD_WIDTH, token, oparg)) {
1134 vkb->width = strtoul(oparg, NULL, 0);
1135 } else if (MATCH_OPTION(XENKBD_FIELD_HEIGHT, token, oparg)) {
1136 vkb->height = strtoul(oparg, NULL, 0);
1137 } else {
1138 fprintf(stderr, "Unknown string \"%s\" in vkb spec\n", token);
1139 return -1;
1140 }
1141
1142 return 0;
1143 }
1144
parse_vkb_list(const XLU_Config * config,libxl_domain_config * d_config)1145 static void parse_vkb_list(const XLU_Config *config,
1146 libxl_domain_config *d_config)
1147 {
1148 XLU_ConfigList *vkbs;
1149 const char *item;
1150 char *buf = NULL;
1151 int rc;
1152
1153 if (!xlu_cfg_get_list (config, "vkb", &vkbs, 0, 0)) {
1154 int entry = 0;
1155 while ((item = xlu_cfg_get_listitem(vkbs, entry)) != NULL) {
1156 libxl_device_vkb *vkb;
1157 char *p;
1158
1159 vkb = ARRAY_EXTEND_INIT(d_config->vkbs,
1160 d_config->num_vkbs,
1161 libxl_device_vkb_init);
1162
1163 buf = strdup(item);
1164
1165 p = strtok (buf, ",");
1166 while (p != NULL)
1167 {
1168 while (*p == ' ') p++;
1169
1170 rc = parse_vkb_config(vkb, p);
1171 if (rc) goto out;
1172
1173 p = strtok (NULL, ",");
1174 }
1175
1176 if (vkb->backend_type == LIBXL_VKB_BACKEND_UNKNOWN) {
1177 fprintf(stderr, "backend-type should be set in vkb spec\n");
1178 rc = ERROR_FAIL; goto out;
1179 }
1180
1181 if (vkb->multi_touch_height || vkb->multi_touch_width ||
1182 vkb->multi_touch_num_contacts) {
1183 vkb->feature_multi_touch = true;
1184 }
1185
1186 if (vkb->feature_multi_touch && !(vkb->multi_touch_height ||
1187 vkb->multi_touch_width || vkb->multi_touch_num_contacts)) {
1188 fprintf(stderr, XENKBD_FIELD_MT_WIDTH", "XENKBD_FIELD_MT_HEIGHT", "
1189 XENKBD_FIELD_MT_NUM_CONTACTS" should be set for "
1190 "multi touch in vkb spec\n");
1191 rc = ERROR_FAIL; goto out;
1192 }
1193
1194 entry++;
1195 }
1196 }
1197
1198 rc = 0;
1199
1200 out:
1201 free(buf);
1202 if (rc) exit(EXIT_FAILURE);
1203 }
1204
parse_config_data(const char * config_source,const char * config_data,int config_len,libxl_domain_config * d_config)1205 void parse_config_data(const char *config_source,
1206 const char *config_data,
1207 int config_len,
1208 libxl_domain_config *d_config)
1209 {
1210 libxl_physinfo physinfo;
1211 const char *buf;
1212 long l, vcpus = 0;
1213 XLU_Config *config;
1214 XLU_ConfigList *cpus, *vbds, *nics, *pcis, *cvfbs, *cpuids, *vtpms,
1215 *usbctrls, *usbdevs, *p9devs, *vdispls, *pvcallsifs_devs;
1216 XLU_ConfigList *channels, *ioports, *irqs, *iomem, *viridian, *dtdevs,
1217 *mca_caps;
1218 int num_ioports, num_irqs, num_iomem, num_cpus, num_viridian, num_mca_caps;
1219 int pci_power_mgmt = 0;
1220 int pci_msitranslate = 0;
1221 int pci_permissive = 0;
1222 int pci_seize = 0;
1223 int i, e;
1224 char *kernel_basename;
1225
1226 libxl_domain_create_info *c_info = &d_config->c_info;
1227 libxl_domain_build_info *b_info = &d_config->b_info;
1228
1229 libxl_physinfo_init(&physinfo);
1230 if (libxl_get_physinfo(ctx, &physinfo) != 0) {
1231 libxl_physinfo_dispose(&physinfo);
1232 fprintf(stderr, "libxl_get_physinfo failed\n");
1233 exit(EXIT_FAILURE);
1234 }
1235
1236 libxl_physinfo_dispose(&physinfo);
1237
1238 config= xlu_cfg_init(stderr, config_source);
1239 if (!config) {
1240 fprintf(stderr, "Failed to allocate for configuration\n");
1241 exit(1);
1242 }
1243
1244 e= xlu_cfg_readdata(config, config_data, config_len);
1245 if (e) {
1246 fprintf(stderr, "Failed to parse config: %s\n", strerror(e));
1247 exit(1);
1248 }
1249
1250 if (!xlu_cfg_get_string (config, "init_seclabel", &buf, 0))
1251 xlu_cfg_replace_string(config, "init_seclabel",
1252 &c_info->ssid_label, 0);
1253
1254 if (!xlu_cfg_get_string (config, "seclabel", &buf, 0)) {
1255 if (c_info->ssid_label)
1256 xlu_cfg_replace_string(config, "seclabel",
1257 &b_info->exec_ssid_label, 0);
1258 else
1259 xlu_cfg_replace_string(config, "seclabel",
1260 &c_info->ssid_label, 0);
1261 }
1262
1263 libxl_defbool_set(&c_info->run_hotplug_scripts, run_hotplug_scripts);
1264
1265 if (!xlu_cfg_get_string(config, "type", &buf, 0)) {
1266 if (!strncmp(buf, "hvm", strlen(buf)))
1267 c_info->type = LIBXL_DOMAIN_TYPE_HVM;
1268 else if (!strncmp(buf, "pv", strlen(buf)))
1269 c_info->type = LIBXL_DOMAIN_TYPE_PV;
1270 else if (!strncmp(buf, "pvh", strlen(buf)))
1271 c_info->type = LIBXL_DOMAIN_TYPE_PVH;
1272 else {
1273 fprintf(stderr, "Invalid domain type %s.\n", buf);
1274 exit(1);
1275 }
1276 }
1277
1278 /* Deprecated since Xen 4.10. */
1279 if (!xlu_cfg_get_string(config, "builder", &buf, 0)) {
1280 libxl_domain_type builder_type;
1281
1282 if (!strncmp(buf, "hvm", strlen(buf)))
1283 builder_type = LIBXL_DOMAIN_TYPE_HVM;
1284 else if (!strncmp(buf, "generic", strlen(buf)))
1285 builder_type = LIBXL_DOMAIN_TYPE_PV;
1286 else {
1287 fprintf(stderr, "Invalid domain type %s.\n", buf);
1288 exit(1);
1289 }
1290
1291 if (c_info->type != LIBXL_DOMAIN_TYPE_INVALID &&
1292 c_info->type != builder_type) {
1293 fprintf(stderr,
1294 "Contradicting \"builder\" and \"type\" options specified.\n");
1295 exit(1);
1296 }
1297 c_info->type = builder_type;
1298 }
1299
1300 if (c_info->type == LIBXL_DOMAIN_TYPE_INVALID)
1301 #if defined(__arm__) || defined(__aarch64__)
1302 c_info->type = LIBXL_DOMAIN_TYPE_PVH;
1303 #else
1304 c_info->type = LIBXL_DOMAIN_TYPE_PV;
1305 #endif
1306
1307 xlu_cfg_get_defbool(config, "hap", &c_info->hap, 0);
1308
1309 if (xlu_cfg_replace_string (config, "name", &c_info->name, 0)) {
1310 fprintf(stderr, "Domain name must be specified.\n");
1311 exit(1);
1312 }
1313
1314 if (!xlu_cfg_get_string (config, "uuid", &buf, 0) ) {
1315 if ( libxl_uuid_from_string(&c_info->uuid, buf) ) {
1316 fprintf(stderr, "Failed to parse UUID: %s\n", buf);
1317 exit(1);
1318 }
1319 }else{
1320 libxl_uuid_generate(&c_info->uuid);
1321 }
1322
1323 xlu_cfg_get_defbool(config, "oos", &c_info->oos, 0);
1324
1325 if (!xlu_cfg_get_string (config, "pool", &buf, 0))
1326 xlu_cfg_replace_string(config, "pool", &c_info->pool_name, 0);
1327
1328 libxl_domain_build_info_init_type(b_info, c_info->type);
1329
1330 if (b_info->type == LIBXL_DOMAIN_TYPE_PVH) {
1331 xlu_cfg_get_defbool(config, "pvshim", &b_info->u.pvh.pvshim, 0);
1332 if (!xlu_cfg_get_string(config, "pvshim_path", &buf, 0))
1333 xlu_cfg_replace_string(config, "pvshim_path",
1334 &b_info->u.pvh.pvshim_path, 0);
1335 if (!xlu_cfg_get_string(config, "pvshim_cmdline", &buf, 0))
1336 xlu_cfg_replace_string(config, "pvshim_cmdline",
1337 &b_info->u.pvh.pvshim_cmdline, 0);
1338 if (!xlu_cfg_get_string(config, "pvshim_extra", &buf, 0))
1339 xlu_cfg_replace_string(config, "pvshim_extra",
1340 &b_info->u.pvh.pvshim_extra, 0);
1341 }
1342
1343 if (blkdev_start)
1344 b_info->blkdev_start = strdup(blkdev_start);
1345
1346 /* the following is the actual config parsing with overriding
1347 * values in the structures */
1348 if (!xlu_cfg_get_long (config, "cpu_weight", &l, 0))
1349 b_info->sched_params.weight = l;
1350 if (!xlu_cfg_get_long (config, "cap", &l, 0))
1351 b_info->sched_params.cap = l;
1352 if (!xlu_cfg_get_long (config, "period", &l, 0))
1353 b_info->sched_params.period = l;
1354 if (!xlu_cfg_get_long (config, "slice", &l, 0))
1355 b_info->sched_params.slice = l;
1356 if (!xlu_cfg_get_long (config, "latency", &l, 0))
1357 b_info->sched_params.latency = l;
1358 if (!xlu_cfg_get_long (config, "extratime", &l, 0))
1359 b_info->sched_params.extratime = l;
1360
1361 if (!xlu_cfg_get_long (config, "memory", &l, 0))
1362 b_info->target_memkb = l * 1024;
1363
1364 if (!xlu_cfg_get_long (config, "maxmem", &l, 0))
1365 b_info->max_memkb = l * 1024;
1366
1367 if (!xlu_cfg_get_long (config, "vcpus", &l, 0)) {
1368 vcpus = l;
1369 if (libxl_cpu_bitmap_alloc(ctx, &b_info->avail_vcpus, l)) {
1370 fprintf(stderr, "Unable to allocate cpumap\n");
1371 exit(1);
1372 }
1373 libxl_bitmap_set_none(&b_info->avail_vcpus);
1374 while (l-- > 0)
1375 libxl_bitmap_set((&b_info->avail_vcpus), l);
1376 }
1377
1378 if (!xlu_cfg_get_long (config, "maxvcpus", &l, 0))
1379 b_info->max_vcpus = l;
1380
1381 if (!xlu_cfg_get_string(config, "vuart", &buf, 0)) {
1382 if (libxl_vuart_type_from_string(buf, &b_info->arch_arm.vuart)) {
1383 fprintf(stderr, "ERROR: invalid value \"%s\" for \"vuart\"\n",
1384 buf);
1385 exit(1);
1386 }
1387 }
1388
1389 parse_vnuma_config(config, b_info);
1390
1391 /* Set max_memkb to target_memkb and max_vcpus to avail_vcpus if
1392 * they are not set by user specified config option or vnuma.
1393 */
1394 if (b_info->max_memkb == LIBXL_MEMKB_DEFAULT)
1395 b_info->max_memkb = b_info->target_memkb;
1396 if (b_info->max_vcpus == 0)
1397 b_info->max_vcpus = vcpus;
1398
1399 if (b_info->max_vcpus < vcpus) {
1400 fprintf(stderr, "xl: maxvcpus < vcpus\n");
1401 exit(1);
1402 }
1403
1404 buf = NULL;
1405 if (!xlu_cfg_get_list (config, "cpus", &cpus, &num_cpus, 1) ||
1406 !xlu_cfg_get_string (config, "cpus", &buf, 0))
1407 parse_vcpu_affinity(b_info, cpus, buf, num_cpus, /* is_hard */ true);
1408
1409 buf = NULL;
1410 if (!xlu_cfg_get_list (config, "cpus_soft", &cpus, &num_cpus, 1) ||
1411 !xlu_cfg_get_string (config, "cpus_soft", &buf, 0))
1412 parse_vcpu_affinity(b_info, cpus, buf, num_cpus, false);
1413
1414 e = xlu_cfg_get_bounded_long (config, "max_grant_frames", 0, INT_MAX,
1415 &l, 1);
1416 if (e == ESRCH) /* not specified */
1417 b_info->max_grant_frames = max_grant_frames;
1418 else if (!e)
1419 b_info->max_grant_frames = l;
1420 else
1421 exit(1);
1422
1423 e = xlu_cfg_get_bounded_long (config, "max_maptrack_frames", 0,
1424 INT_MAX, &l, 1);
1425 if (e == ESRCH) /* not specified */
1426 b_info->max_maptrack_frames = max_maptrack_frames;
1427 else if (!e)
1428 b_info->max_maptrack_frames = l;
1429 else
1430 exit(1);
1431
1432 libxl_defbool_set(&b_info->claim_mode, claim_mode);
1433
1434 if (xlu_cfg_get_string (config, "on_poweroff", &buf, 0))
1435 buf = "destroy";
1436 if (!parse_action_on_shutdown(buf, &d_config->on_poweroff)) {
1437 fprintf(stderr, "Unknown on_poweroff action \"%s\" specified\n", buf);
1438 exit(1);
1439 }
1440
1441 if (xlu_cfg_get_string (config, "on_reboot", &buf, 0))
1442 buf = "restart";
1443 if (!parse_action_on_shutdown(buf, &d_config->on_reboot)) {
1444 fprintf(stderr, "Unknown on_reboot action \"%s\" specified\n", buf);
1445 exit(1);
1446 }
1447
1448 if (xlu_cfg_get_string (config, "on_watchdog", &buf, 0))
1449 buf = "destroy";
1450 if (!parse_action_on_shutdown(buf, &d_config->on_watchdog)) {
1451 fprintf(stderr, "Unknown on_watchdog action \"%s\" specified\n", buf);
1452 exit(1);
1453 }
1454
1455
1456 if (xlu_cfg_get_string (config, "on_crash", &buf, 0))
1457 buf = "destroy";
1458 if (!parse_action_on_shutdown(buf, &d_config->on_crash)) {
1459 fprintf(stderr, "Unknown on_crash action \"%s\" specified\n", buf);
1460 exit(1);
1461 }
1462
1463 if (xlu_cfg_get_string (config, "on_soft_reset", &buf, 0))
1464 buf = "soft-reset";
1465 if (!parse_action_on_shutdown(buf, &d_config->on_soft_reset)) {
1466 fprintf(stderr, "Unknown on_soft_reset action \"%s\" specified\n", buf);
1467 exit(1);
1468 }
1469
1470 if (!xlu_cfg_get_list (config, "pci", &pcis, 0, 0)) {
1471 d_config->num_pcidevs = 0;
1472 d_config->pcidevs = NULL;
1473 for(i = 0; (buf = xlu_cfg_get_listitem (pcis, i)) != NULL; i++) {
1474 libxl_device_pci *pcidev;
1475
1476 pcidev = ARRAY_EXTEND_INIT_NODEVID(d_config->pcidevs,
1477 d_config->num_pcidevs,
1478 libxl_device_pci_init);
1479 pcidev->msitranslate = pci_msitranslate;
1480 pcidev->power_mgmt = pci_power_mgmt;
1481 pcidev->permissive = pci_permissive;
1482 pcidev->seize = pci_seize;
1483 /*
1484 * Like other pci option, the per-device policy always follows
1485 * the global policy by default.
1486 */
1487 pcidev->rdm_policy = b_info->u.hvm.rdm.policy;
1488 e = xlu_pci_parse_bdf(config, pcidev, buf);
1489 if (e) {
1490 fprintf(stderr,
1491 "unable to parse PCI BDF `%s' for passthrough\n",
1492 buf);
1493 exit(-e);
1494 }
1495 }
1496 if (d_config->num_pcidevs && c_info->type == LIBXL_DOMAIN_TYPE_PV)
1497 libxl_defbool_set(&b_info->u.pv.e820_host, true);
1498 }
1499
1500 if (!xlu_cfg_get_list (config, "dtdev", &dtdevs, 0, 0)) {
1501 d_config->num_dtdevs = 0;
1502 d_config->dtdevs = NULL;
1503 for (i = 0; (buf = xlu_cfg_get_listitem(dtdevs, i)) != NULL; i++) {
1504 libxl_device_dtdev *dtdev;
1505
1506 dtdev = ARRAY_EXTEND_INIT_NODEVID(d_config->dtdevs,
1507 d_config->num_dtdevs,
1508 libxl_device_dtdev_init);
1509
1510 dtdev->path = strdup(buf);
1511 if (dtdev->path == NULL) {
1512 fprintf(stderr, "unable to duplicate string for dtdevs\n");
1513 exit(-1);
1514 }
1515 }
1516 }
1517
1518 if (!xlu_cfg_get_string(config, "passthrough", &buf, 0)) {
1519 if (libxl_passthrough_from_string(buf, &c_info->passthrough)) {
1520 fprintf(stderr,
1521 "ERROR: unknown passthrough option '%s'\n",
1522 buf);
1523 exit(1);
1524 }
1525 }
1526
1527 if (!xlu_cfg_get_long(config, "shadow_memory", &l, 0))
1528 b_info->shadow_memkb = l * 1024;
1529
1530 xlu_cfg_get_defbool(config, "nomigrate", &b_info->disable_migrate, 0);
1531
1532 if (!xlu_cfg_get_long(config, "tsc_mode", &l, 1)) {
1533 const char *s = libxl_tsc_mode_to_string(l);
1534 fprintf(stderr, "WARNING: specifying \"tsc_mode\" as an integer is deprecated. "
1535 "Please use the named parameter variant. %s%s%s\n",
1536 s ? "e.g. tsc_mode=\"" : "",
1537 s ? s : "",
1538 s ? "\"" : "");
1539
1540 if (l < LIBXL_TSC_MODE_DEFAULT ||
1541 l > LIBXL_TSC_MODE_NATIVE_PARAVIRT) {
1542 fprintf(stderr, "ERROR: invalid value %ld for \"tsc_mode\"\n", l);
1543 exit (1);
1544 }
1545 b_info->tsc_mode = l;
1546 } else if (!xlu_cfg_get_string(config, "tsc_mode", &buf, 0)) {
1547 fprintf(stderr, "got a tsc mode string: \"%s\"\n", buf);
1548 if (libxl_tsc_mode_from_string(buf, &b_info->tsc_mode)) {
1549 fprintf(stderr, "ERROR: invalid value \"%s\" for \"tsc_mode\"\n",
1550 buf);
1551 exit (1);
1552 }
1553 }
1554
1555 if (!xlu_cfg_get_long(config, "rtc_timeoffset", &l, 0))
1556 b_info->rtc_timeoffset = l;
1557
1558 if (!xlu_cfg_get_long(config, "vncviewer", &l, 0))
1559 fprintf(stderr, "WARNING: ignoring \"vncviewer\" option. "
1560 "Use \"-V\" option of \"xl create\" to automatically spawn vncviewer.\n");
1561
1562 xlu_cfg_get_defbool(config, "localtime", &b_info->localtime, 0);
1563
1564 if (!xlu_cfg_get_long (config, "videoram", &l, 0))
1565 b_info->video_memkb = l * 1024;
1566
1567 if (!xlu_cfg_get_long(config, "max_event_channels", &l, 0))
1568 b_info->event_channels = l;
1569
1570 xlu_cfg_replace_string (config, "kernel", &b_info->kernel, 0);
1571 xlu_cfg_replace_string (config, "ramdisk", &b_info->ramdisk, 0);
1572 xlu_cfg_replace_string (config, "device_tree", &b_info->device_tree, 0);
1573 b_info->cmdline = parse_cmdline(config);
1574
1575 xlu_cfg_get_defbool(config, "driver_domain", &c_info->driver_domain, 0);
1576 xlu_cfg_get_defbool(config, "acpi", &b_info->acpi, 0);
1577
1578 xlu_cfg_replace_string (config, "bootloader", &b_info->bootloader, 0);
1579 switch (xlu_cfg_get_list_as_string_list(config, "bootloader_args",
1580 &b_info->bootloader_args, 1)) {
1581 case 0:
1582 break; /* Success */
1583 case ESRCH: break; /* Option not present */
1584 case EINVAL:
1585 if (!xlu_cfg_get_string(config, "bootloader_args", &buf, 0)) {
1586
1587 fprintf(stderr, "WARNING: Specifying \"bootloader_args\""
1588 " as a string is deprecated. "
1589 "Please use a list of arguments.\n");
1590 split_string_into_string_list(buf, " \t\n",
1591 &b_info->bootloader_args);
1592 }
1593 break;
1594 default:
1595 fprintf(stderr,"xl: Unable to parse bootloader_args.\n");
1596 exit(-ERROR_FAIL);
1597 }
1598
1599 if (!xlu_cfg_get_long(config, "timer_mode", &l, 1)) {
1600 const char *s = libxl_timer_mode_to_string(l);
1601
1602 if (b_info->type == LIBXL_DOMAIN_TYPE_PV) {
1603 fprintf(stderr,
1604 "ERROR: \"timer_mode\" option is not supported for PV guests.\n");
1605 exit(-ERROR_FAIL);
1606 }
1607
1608 fprintf(stderr,
1609 "WARNING: specifying \"timer_mode\" as an integer is deprecated. "
1610 "Please use the named parameter variant. %s%s%s\n",
1611 s ? "e.g. timer_mode=\"" : "",
1612 s ? s : "",
1613 s ? "\"" : "");
1614
1615 if (l < LIBXL_TIMER_MODE_DELAY_FOR_MISSED_TICKS ||
1616 l > LIBXL_TIMER_MODE_ONE_MISSED_TICK_PENDING) {
1617 fprintf(stderr, "ERROR: invalid value %ld for \"timer_mode\"\n",
1618 l);
1619 exit (1);
1620 }
1621 b_info->timer_mode = l;
1622 } else if (!xlu_cfg_get_string(config, "timer_mode", &buf, 0)) {
1623 if (b_info->type == LIBXL_DOMAIN_TYPE_PV) {
1624 fprintf(stderr,
1625 "ERROR: \"timer_mode\" option is not supported for PV guests.\n");
1626 exit(-ERROR_FAIL);
1627 }
1628
1629 if (libxl_timer_mode_from_string(buf, &b_info->timer_mode)) {
1630 fprintf(stderr,
1631 "ERROR: invalid value \"%s\" for \"timer_mode\"\n", buf);
1632 exit (1);
1633 }
1634 }
1635
1636 xlu_cfg_get_defbool(config, "nestedhvm", &b_info->nested_hvm, 0);
1637
1638 switch(b_info->type) {
1639 case LIBXL_DOMAIN_TYPE_HVM:
1640 kernel_basename = libxl_basename(b_info->kernel);
1641 if (!strcmp(kernel_basename, "hvmloader")) {
1642 fprintf(stderr, "WARNING: you seem to be using \"kernel\" "
1643 "directive to override HVM guest firmware. Ignore "
1644 "that. Use \"firmware_override\" instead if you "
1645 "really want a non-default firmware\n");
1646 b_info->kernel = NULL;
1647 }
1648 free(kernel_basename);
1649
1650 xlu_cfg_replace_string (config, "firmware_override",
1651 &b_info->u.hvm.firmware, 0);
1652 xlu_cfg_replace_string (config, "bios_path_override",
1653 &b_info->u.hvm.system_firmware, 0);
1654 if (!xlu_cfg_get_string(config, "bios", &buf, 0)) {
1655 if (libxl_bios_type_from_string(buf, &b_info->u.hvm.bios)) {
1656 fprintf(stderr, "ERROR: invalid value \"%s\" for \"bios\"\n",
1657 buf);
1658 exit (1);
1659 }
1660 } else if (b_info->u.hvm.system_firmware)
1661 fprintf(stderr, "WARNING: "
1662 "bios_path_override given without specific bios name\n");
1663
1664 xlu_cfg_get_defbool(config, "pae", &b_info->u.hvm.pae, 0);
1665 xlu_cfg_get_defbool(config, "acpi_s3", &b_info->u.hvm.acpi_s3, 0);
1666 xlu_cfg_get_defbool(config, "acpi_s4", &b_info->u.hvm.acpi_s4, 0);
1667 xlu_cfg_get_defbool(config, "acpi_laptop_slate", &b_info->u.hvm.acpi_laptop_slate, 0);
1668 xlu_cfg_get_defbool(config, "nx", &b_info->u.hvm.nx, 0);
1669 xlu_cfg_get_defbool(config, "hpet", &b_info->u.hvm.hpet, 0);
1670 xlu_cfg_get_defbool(config, "vpt_align", &b_info->u.hvm.vpt_align, 0);
1671 xlu_cfg_get_defbool(config, "apic", &b_info->apic, 0);
1672
1673 switch (xlu_cfg_get_list(config, "viridian",
1674 &viridian, &num_viridian, 1))
1675 {
1676 case 0: /* Success */
1677 if (num_viridian) {
1678 libxl_bitmap_alloc(ctx, &b_info->u.hvm.viridian_enable,
1679 LIBXL_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE_WIDTH);
1680 libxl_bitmap_alloc(ctx, &b_info->u.hvm.viridian_disable,
1681 LIBXL_BUILDINFO_HVM_VIRIDIAN_ENABLE_DISABLE_WIDTH);
1682 }
1683 for (i = 0; i < num_viridian; i++) {
1684 libxl_viridian_enlightenment v;
1685
1686 buf = xlu_cfg_get_listitem(viridian, i);
1687 if (strcmp(buf, "all") == 0)
1688 libxl_bitmap_set_any(&b_info->u.hvm.viridian_enable);
1689 else if (strcmp(buf, "defaults") == 0)
1690 libxl_defbool_set(&b_info->u.hvm.viridian, true);
1691 else {
1692 libxl_bitmap *s = &b_info->u.hvm.viridian_enable;
1693 libxl_bitmap *r = &b_info->u.hvm.viridian_disable;
1694
1695 if (*buf == '!') {
1696 s = &b_info->u.hvm.viridian_disable;
1697 r = &b_info->u.hvm.viridian_enable;
1698 buf++;
1699 }
1700
1701 e = libxl_viridian_enlightenment_from_string(buf, &v);
1702 if (e) {
1703 fprintf(stderr,
1704 "xl: unknown viridian enlightenment '%s'\n",
1705 buf);
1706 exit(-ERROR_FAIL);
1707 }
1708
1709 libxl_bitmap_set(s, v);
1710 libxl_bitmap_reset(r, v);
1711 }
1712 }
1713 break;
1714 case ESRCH: break; /* Option not present */
1715 case EINVAL:
1716 xlu_cfg_get_defbool(config, "viridian", &b_info->u.hvm.viridian, 1);
1717 break;
1718 default:
1719 fprintf(stderr,"xl: Unable to parse viridian enlightenments.\n");
1720 exit(-ERROR_FAIL);
1721 }
1722
1723 if (!xlu_cfg_get_long(config, "mmio_hole", &l, 0)) {
1724 uint64_t mmio_hole_size;
1725
1726 b_info->u.hvm.mmio_hole_memkb = l * 1024;
1727 mmio_hole_size = b_info->u.hvm.mmio_hole_memkb * 1024;
1728 if (mmio_hole_size < HVM_BELOW_4G_MMIO_LENGTH ||
1729 mmio_hole_size > HVM_BELOW_4G_MMIO_START) {
1730 fprintf(stderr,
1731 "ERROR: invalid value %ld for \"mmio_hole\"\n", l);
1732 exit (1);
1733 }
1734 }
1735
1736 if (!xlu_cfg_get_defbool(config, "altp2mhvm", &b_info->u.hvm.altp2m, 0))
1737 fprintf(stderr, "WARNING: Specifying \"altp2mhvm\" is deprecated. "
1738 "Please use \"altp2m\" instead.\n");
1739
1740 xlu_cfg_replace_string(config, "smbios_firmware",
1741 &b_info->u.hvm.smbios_firmware, 0);
1742 xlu_cfg_replace_string(config, "acpi_firmware",
1743 &b_info->u.hvm.acpi_firmware, 0);
1744
1745 if (!xlu_cfg_get_string(config, "ms_vm_genid", &buf, 0)) {
1746 if (!strcmp(buf, "generate")) {
1747 e = libxl_ms_vm_genid_generate(ctx, &b_info->u.hvm.ms_vm_genid);
1748 if (e) {
1749 fprintf(stderr, "ERROR: failed to generate a VM Generation ID\n");
1750 exit(1);
1751 }
1752 } else if (!strcmp(buf, "none")) {
1753 ;
1754 } else {
1755 fprintf(stderr, "ERROR: \"ms_vm_genid\" option must be \"generate\" or \"none\"\n");
1756 exit(1);
1757 }
1758 }
1759
1760 if (!xlu_cfg_get_long (config, "rdm_mem_boundary", &l, 0))
1761 b_info->u.hvm.rdm_mem_boundary_memkb = l * 1024;
1762
1763 switch (xlu_cfg_get_list(config, "mca_caps",
1764 &mca_caps, &num_mca_caps, 1))
1765 {
1766 case 0: /* Success */
1767 for (i = 0; i < num_mca_caps; i++) {
1768 buf = xlu_cfg_get_listitem(mca_caps, i);
1769 if (!strcmp(buf, "lmce"))
1770 b_info->u.hvm.mca_caps |= XEN_HVM_MCA_CAP_LMCE;
1771 else {
1772 fprintf(stderr, "ERROR: unrecognized MCA capability '%s'.\n",
1773 buf);
1774 exit(-ERROR_FAIL);
1775 }
1776 }
1777 break;
1778
1779 case ESRCH: /* Option not present */
1780 break;
1781
1782 default:
1783 fprintf(stderr, "ERROR: unable to parse mca_caps.\n");
1784 exit(-ERROR_FAIL);
1785 }
1786
1787 /*
1788 * The firmware config option can be used as a simplification
1789 * instead of setting bios or firmware_override. It has the
1790 * following meanings for HVM guests:
1791 *
1792 * - ovmf | seabios | rombios: maps directly into the "bios"
1793 * option.
1794 * - uefi | bios: maps into one of the above options and is set
1795 * in the bios field.
1796 * - Anything else is treated as a path that is copied into
1797 * firmware.
1798 */
1799 if (!xlu_cfg_get_string (config, "firmware", &buf, 0) &&
1800 libxl_bios_type_from_string(buf, &b_info->u.hvm.bios)) {
1801 if (!strncmp(buf, "uefi", strlen(buf)))
1802 b_info->u.hvm.bios = LIBXL_BIOS_TYPE_OVMF;
1803 else if (strncmp(buf, "bios", strlen(buf)))
1804 /* Assume it's a path to a custom firmware. */
1805 xlu_cfg_replace_string(config, "firmware",
1806 &b_info->u.hvm.firmware, 0);
1807 /*
1808 * BIOS is the default, and will be chosen by libxl based on
1809 * the device model specified.
1810 */
1811 }
1812
1813 break;
1814 case LIBXL_DOMAIN_TYPE_PVH:
1815 case LIBXL_DOMAIN_TYPE_PV:
1816 {
1817 /*
1818 * The firmware config option can be used as a simplification
1819 * instead of directly setting kernel. It will be translated to
1820 * XENFIRMWAREDIR/<string>.bin
1821 */
1822 if (!xlu_cfg_get_string (config, "firmware", &buf, 0)) {
1823 if (b_info->kernel) {
1824 fprintf(stderr,
1825 "ERROR: both kernel and firmware specified\n");
1826 exit(1);
1827 }
1828 if (strncmp(buf, "pvgrub32", strlen(buf)) &&
1829 strncmp(buf, "pvgrub64", strlen(buf))) {
1830 fprintf(stderr,
1831 "ERROR: only pvgrub{32|64} supported as firmware options\n");
1832 exit(1);
1833 }
1834
1835 xasprintf(&b_info->kernel, XENFIRMWAREDIR "/%s.bin", buf);
1836 }
1837 if (!b_info->bootloader && !b_info->kernel) {
1838 fprintf(stderr, "Neither kernel nor bootloader specified\n");
1839 exit(1);
1840 }
1841
1842 break;
1843 }
1844 default:
1845 abort();
1846 }
1847
1848 if (!xlu_cfg_get_long(config, "altp2m", &l, 1)) {
1849 if (l < LIBXL_ALTP2M_MODE_DISABLED ||
1850 l > LIBXL_ALTP2M_MODE_LIMITED) {
1851 fprintf(stderr, "ERROR: invalid value %ld for \"altp2m\"\n", l);
1852 exit (1);
1853 }
1854
1855 b_info->altp2m = l;
1856 } else if (!xlu_cfg_get_string(config, "altp2m", &buf, 0)) {
1857 if (libxl_altp2m_mode_from_string(buf, &b_info->altp2m)) {
1858 fprintf(stderr, "ERROR: invalid value \"%s\" for \"altp2m\"\n",
1859 buf);
1860 exit (1);
1861 }
1862 }
1863
1864 if (!xlu_cfg_get_list(config, "ioports", &ioports, &num_ioports, 0)) {
1865 b_info->num_ioports = num_ioports;
1866 b_info->ioports = calloc(num_ioports, sizeof(*b_info->ioports));
1867 if (b_info->ioports == NULL) {
1868 fprintf(stderr, "unable to allocate memory for ioports\n");
1869 exit(-1);
1870 }
1871
1872 for (i = 0; i < num_ioports; i++) {
1873 const char *buf2;
1874 char *ep;
1875 uint32_t start, end;
1876 unsigned long ul;
1877
1878 buf = xlu_cfg_get_listitem (ioports, i);
1879 if (!buf) {
1880 fprintf(stderr,
1881 "xl: Unable to get element #%d in ioport list\n", i);
1882 exit(1);
1883 }
1884 ul = strtoul(buf, &ep, 16);
1885 if (ep == buf) {
1886 fprintf(stderr, "xl: Invalid argument parsing ioport: %s\n",
1887 buf);
1888 exit(1);
1889 }
1890 if (ul >= UINT32_MAX) {
1891 fprintf(stderr, "xl: ioport %lx too big\n", ul);
1892 exit(1);
1893 }
1894 start = end = ul;
1895
1896 if (*ep == '-') {
1897 buf2 = ep + 1;
1898 ul = strtoul(buf2, &ep, 16);
1899 if (ep == buf2 || *ep != '\0' || start > end) {
1900 fprintf(stderr,
1901 "xl: Invalid argument parsing ioport: %s\n", buf);
1902 exit(1);
1903 }
1904 if (ul >= UINT32_MAX) {
1905 fprintf(stderr, "xl: ioport %lx too big\n", ul);
1906 exit(1);
1907 }
1908 end = ul;
1909 } else if ( *ep != '\0' )
1910 fprintf(stderr,
1911 "xl: Invalid argument parsing ioport: %s\n", buf);
1912 b_info->ioports[i].first = start;
1913 b_info->ioports[i].number = end - start + 1;
1914 }
1915 }
1916
1917 if (!xlu_cfg_get_list(config, "irqs", &irqs, &num_irqs, 0)) {
1918 b_info->num_irqs = num_irqs;
1919 b_info->irqs = calloc(num_irqs, sizeof(*b_info->irqs));
1920 if (b_info->irqs == NULL) {
1921 fprintf(stderr, "unable to allocate memory for ioports\n");
1922 exit(-1);
1923 }
1924 for (i = 0; i < num_irqs; i++) {
1925 char *ep;
1926 unsigned long ul;
1927 buf = xlu_cfg_get_listitem (irqs, i);
1928 if (!buf) {
1929 fprintf(stderr,
1930 "xl: Unable to get element %d in irq list\n", i);
1931 exit(1);
1932 }
1933 ul = strtoul(buf, &ep, 10);
1934 if (ep == buf || *ep != '\0') {
1935 fprintf(stderr,
1936 "xl: Invalid argument parsing irq: %s\n", buf);
1937 exit(1);
1938 }
1939 if (ul >= UINT32_MAX) {
1940 fprintf(stderr, "xl: irq %lx too big\n", ul);
1941 exit(1);
1942 }
1943 b_info->irqs[i] = ul;
1944 }
1945 }
1946
1947 if (!xlu_cfg_get_list(config, "iomem", &iomem, &num_iomem, 0)) {
1948 int ret;
1949 b_info->num_iomem = num_iomem;
1950 b_info->iomem = calloc(num_iomem, sizeof(*b_info->iomem));
1951 if (b_info->iomem == NULL) {
1952 fprintf(stderr, "unable to allocate memory for iomem\n");
1953 exit(-1);
1954 }
1955 for (i = 0; i < num_iomem; i++) {
1956 int used;
1957
1958 buf = xlu_cfg_get_listitem (iomem, i);
1959 if (!buf) {
1960 fprintf(stderr,
1961 "xl: Unable to get element %d in iomem list\n", i);
1962 exit(1);
1963 }
1964 libxl_iomem_range_init(&b_info->iomem[i]);
1965 ret = sscanf(buf, "%" SCNx64",%" SCNx64"%n@%" SCNx64"%n",
1966 &b_info->iomem[i].start,
1967 &b_info->iomem[i].number, &used,
1968 &b_info->iomem[i].gfn, &used);
1969 if (ret < 2 || buf[used] != '\0') {
1970 fprintf(stderr,
1971 "xl: Invalid argument parsing iomem: %s\n", buf);
1972 exit(1);
1973 }
1974 }
1975 }
1976
1977
1978
1979 if (!xlu_cfg_get_list (config, "disk", &vbds, 0, 0)) {
1980 d_config->num_disks = 0;
1981 d_config->disks = NULL;
1982 while ((buf = xlu_cfg_get_listitem (vbds, d_config->num_disks)) != NULL) {
1983 libxl_device_disk *disk;
1984 char *buf2 = strdup(buf);
1985
1986 disk = ARRAY_EXTEND_INIT_NODEVID(d_config->disks,
1987 d_config->num_disks,
1988 libxl_device_disk_init);
1989 parse_disk_config(&config, buf2, disk);
1990
1991 free(buf2);
1992 }
1993 }
1994
1995 if (!xlu_cfg_get_list(config, "p9", &p9devs, 0, 0)) {
1996 libxl_device_p9 *p9;
1997 char *security_model = NULL;
1998 char *path = NULL;
1999 char *tag = NULL;
2000 char *backend = NULL;
2001 char *p, *p2, *buf2;
2002
2003 d_config->num_p9s = 0;
2004 d_config->p9s = NULL;
2005 while ((buf = xlu_cfg_get_listitem (p9devs, d_config->num_p9s)) != NULL) {
2006 p9 = ARRAY_EXTEND_INIT(d_config->p9s,
2007 d_config->num_p9s,
2008 libxl_device_p9_init);
2009 libxl_device_p9_init(p9);
2010
2011 buf2 = strdup(buf);
2012 p = strtok(buf2, ",");
2013 if(p) {
2014 do {
2015 while(*p == ' ')
2016 ++p;
2017 if ((p2 = strchr(p, '=')) == NULL)
2018 break;
2019 *p2 = '\0';
2020 if (!strcmp(p, "security_model")) {
2021 security_model = strdup(p2 + 1);
2022 } else if(!strcmp(p, "path")) {
2023 path = strdup(p2 + 1);
2024 } else if(!strcmp(p, "tag")) {
2025 tag = strdup(p2 + 1);
2026 } else if(!strcmp(p, "backend")) {
2027 backend = strdup(p2 + 1);
2028 } else {
2029 fprintf(stderr, "Unknown string `%s' in 9pfs spec\n", p);
2030 exit(1);
2031 }
2032 } while ((p = strtok(NULL, ",")) != NULL);
2033 }
2034 if (!path || !security_model || !tag) {
2035 fprintf(stderr, "9pfs spec missing required field!\n");
2036 exit(1);
2037 }
2038 free(buf2);
2039
2040 replace_string(&p9->tag, tag);
2041 replace_string(&p9->security_model, security_model);
2042 replace_string(&p9->path, path);
2043 if (backend)
2044 replace_string(&p9->backend_domname, backend);
2045 }
2046 }
2047
2048 if (!xlu_cfg_get_list(config, "vtpm", &vtpms, 0, 0)) {
2049 d_config->num_vtpms = 0;
2050 d_config->vtpms = NULL;
2051 while ((buf = xlu_cfg_get_listitem (vtpms, d_config->num_vtpms)) != NULL) {
2052 libxl_device_vtpm *vtpm;
2053 char * buf2 = strdup(buf);
2054 char *p, *p2;
2055 bool got_backend = false;
2056
2057 vtpm = ARRAY_EXTEND_INIT(d_config->vtpms,
2058 d_config->num_vtpms,
2059 libxl_device_vtpm_init);
2060
2061 p = strtok(buf2, ",");
2062 if(p) {
2063 do {
2064 while(*p == ' ')
2065 ++p;
2066 if ((p2 = strchr(p, '=')) == NULL)
2067 break;
2068 *p2 = '\0';
2069 if (!strcmp(p, "backend")) {
2070 vtpm->backend_domname = strdup(p2 + 1);
2071 got_backend = true;
2072 } else if(!strcmp(p, "uuid")) {
2073 if( libxl_uuid_from_string(&vtpm->uuid, p2 + 1) ) {
2074 fprintf(stderr,
2075 "Failed to parse vtpm UUID: %s\n", p2 + 1);
2076 exit(1);
2077 }
2078 } else {
2079 fprintf(stderr, "Unknown string `%s' in vtpm spec\n", p);
2080 exit(1);
2081 }
2082 } while ((p = strtok(NULL, ",")) != NULL);
2083 }
2084 if(!got_backend) {
2085 fprintf(stderr, "vtpm spec missing required backend field!\n");
2086 exit(1);
2087 }
2088 free(buf2);
2089 }
2090 }
2091
2092 if (!xlu_cfg_get_list(config, "vdispl", &vdispls, 0, 0)) {
2093 d_config->num_vdispls = 0;
2094 d_config->vdispls = NULL;
2095 while ((buf = xlu_cfg_get_listitem(vdispls, d_config->num_vdispls)) != NULL) {
2096 libxl_device_vdispl *vdispl;
2097 char * buf2 = strdup(buf);
2098 char *p;
2099 vdispl = ARRAY_EXTEND_INIT(d_config->vdispls,
2100 d_config->num_vdispls,
2101 libxl_device_vdispl_init);
2102 p = strtok (buf2, ",");
2103 while (p != NULL)
2104 {
2105 while (*p == ' ') p++;
2106 if (parse_vdispl_config(vdispl, p)) {
2107 free(buf2);
2108 exit(1);
2109 }
2110 p = strtok (NULL, ",");
2111 }
2112 free(buf2);
2113 if (vdispl->num_connectors == 0) {
2114 fprintf(stderr, "At least one connector should be specified.\n");
2115 exit(1);
2116 }
2117 }
2118 }
2119
2120 if (!xlu_cfg_get_list(config, "pvcalls", &pvcallsifs_devs, 0, 0)) {
2121 d_config->num_pvcallsifs = 0;
2122 d_config->pvcallsifs = NULL;
2123 while ((buf = xlu_cfg_get_listitem (pvcallsifs_devs, d_config->num_pvcallsifs)) != NULL) {
2124 libxl_device_pvcallsif *pvcallsif;
2125 char *backend = NULL;
2126 char *p, *p2, *buf2;
2127 pvcallsif = ARRAY_EXTEND_INIT(d_config->pvcallsifs,
2128 d_config->num_pvcallsifs,
2129 libxl_device_pvcallsif_init);
2130
2131 buf2 = strdup(buf);
2132 p = strtok(buf2, ",");
2133 if (p) {
2134 do {
2135 while (*p == ' ')
2136 ++p;
2137 if ((p2 = strchr(p, '=')) == NULL)
2138 break;
2139 *p2 = '\0';
2140 if(!strcmp(p, "backend")) {
2141 backend = strdup(p2 + 1);
2142 } else {
2143 fprintf(stderr, "Unknown string `%s' in pvcalls spec\n", p);
2144 exit(1);
2145 }
2146 } while ((p = strtok(NULL, ",")) != NULL);
2147 }
2148 free(buf2);
2149
2150 if (backend)
2151 replace_string(&pvcallsif->backend_domname, backend);
2152 }
2153 }
2154
2155 parse_vsnd_config(config, d_config);
2156
2157 if (!xlu_cfg_get_list (config, "channel", &channels, 0, 0)) {
2158 d_config->num_channels = 0;
2159 d_config->channels = NULL;
2160 while ((buf = xlu_cfg_get_listitem (channels,
2161 d_config->num_channels)) != NULL) {
2162 libxl_device_channel *chn;
2163 libxl_string_list pairs;
2164 char *path = NULL;
2165 int len;
2166
2167 chn = ARRAY_EXTEND_INIT(d_config->channels, d_config->num_channels,
2168 libxl_device_channel_init);
2169
2170 split_string_into_string_list(buf, ",", &pairs);
2171 len = libxl_string_list_length(&pairs);
2172 for (i = 0; i < len; i++) {
2173 char *key, *key_untrimmed, *value, *value_untrimmed;
2174 int rc;
2175 rc = split_string_into_pair(pairs[i], "=",
2176 &key_untrimmed,
2177 &value_untrimmed);
2178 if (rc != 0) {
2179 fprintf(stderr, "failed to parse channel configuration: %s",
2180 pairs[i]);
2181 exit(1);
2182 }
2183 trim(isspace, key_untrimmed, &key);
2184 trim(isspace, value_untrimmed, &value);
2185
2186 if (!strcmp(key, "backend")) {
2187 replace_string(&chn->backend_domname, value);
2188 } else if (!strcmp(key, "name")) {
2189 replace_string(&chn->name, value);
2190 } else if (!strcmp(key, "path")) {
2191 replace_string(&path, value);
2192 } else if (!strcmp(key, "connection")) {
2193 if (!strcmp(value, "pty")) {
2194 chn->connection = LIBXL_CHANNEL_CONNECTION_PTY;
2195 } else if (!strcmp(value, "socket")) {
2196 chn->connection = LIBXL_CHANNEL_CONNECTION_SOCKET;
2197 } else {
2198 fprintf(stderr, "unknown channel connection '%s'\n",
2199 value);
2200 exit(1);
2201 }
2202 } else {
2203 fprintf(stderr, "unknown channel parameter '%s',"
2204 " ignoring\n", key);
2205 }
2206 free(key);
2207 free(key_untrimmed);
2208 free(value);
2209 free(value_untrimmed);
2210 }
2211 switch (chn->connection) {
2212 case LIBXL_CHANNEL_CONNECTION_UNKNOWN:
2213 fprintf(stderr, "channel has unknown 'connection'\n");
2214 exit(1);
2215 case LIBXL_CHANNEL_CONNECTION_SOCKET:
2216 if (!path) {
2217 fprintf(stderr, "channel connection 'socket' requires path=..\n");
2218 exit(1);
2219 }
2220 chn->u.socket.path = xstrdup(path);
2221 break;
2222 case LIBXL_CHANNEL_CONNECTION_PTY:
2223 /* Nothing to do since PTY has no arguments */
2224 break;
2225 default:
2226 fprintf(stderr, "unknown channel connection: %d",
2227 chn->connection);
2228 exit(1);
2229 }
2230 libxl_string_list_dispose(&pairs);
2231 free(path);
2232 }
2233 }
2234
2235 if (!xlu_cfg_get_list (config, "vif", &nics, 0, 0)) {
2236 d_config->num_nics = 0;
2237 d_config->nics = NULL;
2238 while ((buf = xlu_cfg_get_listitem (nics, d_config->num_nics)) != NULL) {
2239 libxl_device_nic *nic;
2240 char *buf2 = strdup(buf);
2241 char *p;
2242
2243 nic = ARRAY_EXTEND_INIT(d_config->nics,
2244 d_config->num_nics,
2245 libxl_device_nic_init);
2246 set_default_nic_values(nic);
2247
2248 p = strtok(buf2, ",");
2249 if (!p)
2250 goto skip_nic;
2251 do {
2252 while (*p == ' ')
2253 p++;
2254 parse_nic_config(nic, &config, p);
2255 } while ((p = strtok(NULL, ",")) != NULL);
2256 skip_nic:
2257 free(buf2);
2258 }
2259 }
2260
2261 if (!xlu_cfg_get_list(config, "vif2", NULL, 0, 0)) {
2262 fprintf(stderr, "WARNING: vif2: netchannel2 is deprecated and not supported by xl\n");
2263 }
2264
2265 d_config->num_vfbs = 0;
2266 d_config->num_vkbs = 0;
2267 d_config->vfbs = NULL;
2268 d_config->vkbs = NULL;
2269
2270 if (!xlu_cfg_get_list (config, "vfb", &cvfbs, 0, 0)) {
2271 while ((buf = xlu_cfg_get_listitem (cvfbs, d_config->num_vfbs)) != NULL) {
2272 libxl_device_vfb *vfb;
2273 libxl_device_vkb *vkb;
2274
2275 char *buf2 = strdup(buf);
2276 char *p, *p2;
2277
2278 vfb = ARRAY_EXTEND_INIT(d_config->vfbs, d_config->num_vfbs,
2279 libxl_device_vfb_init);
2280
2281 vkb = ARRAY_EXTEND_INIT(d_config->vkbs, d_config->num_vkbs,
2282 libxl_device_vkb_init);
2283
2284 p = strtok(buf2, ",");
2285 if (!p)
2286 goto skip_vfb;
2287 do {
2288 while (*p == ' ')
2289 p++;
2290 if ((p2 = strchr(p, '=')) == NULL)
2291 break;
2292 *p2 = '\0';
2293 if (!strcmp(p, "vnc")) {
2294 libxl_defbool_set(&vfb->vnc.enable, atoi(p2 + 1));
2295 } else if (!strcmp(p, "vnclisten")) {
2296 free(vfb->vnc.listen);
2297 vfb->vnc.listen = strdup(p2 + 1);
2298 } else if (!strcmp(p, "vncpasswd")) {
2299 free(vfb->vnc.passwd);
2300 vfb->vnc.passwd = strdup(p2 + 1);
2301 } else if (!strcmp(p, "vncdisplay")) {
2302 vfb->vnc.display = atoi(p2 + 1);
2303 } else if (!strcmp(p, "vncunused")) {
2304 libxl_defbool_set(&vfb->vnc.findunused, atoi(p2 + 1));
2305 } else if (!strcmp(p, "keymap")) {
2306 free(vfb->keymap);
2307 vfb->keymap = strdup(p2 + 1);
2308 } else if (!strcmp(p, "sdl")) {
2309 libxl_defbool_set(&vfb->sdl.enable, atoi(p2 + 1));
2310 } else if (!strcmp(p, "opengl")) {
2311 libxl_defbool_set(&vfb->sdl.opengl, atoi(p2 + 1));
2312 } else if (!strcmp(p, "display")) {
2313 free(vfb->sdl.display);
2314 vfb->sdl.display = strdup(p2 + 1);
2315 } else if (!strcmp(p, "xauthority")) {
2316 free(vfb->sdl.xauthority);
2317 vfb->sdl.xauthority = strdup(p2 + 1);
2318 }
2319 } while ((p = strtok(NULL, ",")) != NULL);
2320
2321 skip_vfb:
2322 free(buf2);
2323 }
2324 }
2325
2326 if (!xlu_cfg_get_long (config, "pci_msitranslate", &l, 0))
2327 pci_msitranslate = l;
2328
2329 if (!xlu_cfg_get_long (config, "pci_power_mgmt", &l, 0))
2330 pci_power_mgmt = l;
2331
2332 if (!xlu_cfg_get_long (config, "pci_permissive", &l, 0))
2333 pci_permissive = l;
2334
2335 if (!xlu_cfg_get_long (config, "pci_seize", &l, 0))
2336 pci_seize = l;
2337
2338 /* To be reworked (automatically enabled) once the auto ballooning
2339 * after guest starts is done (with PCI devices passed in). */
2340 if (c_info->type == LIBXL_DOMAIN_TYPE_PV) {
2341 xlu_cfg_get_defbool(config, "e820_host", &b_info->u.pv.e820_host, 0);
2342 }
2343
2344 if (!xlu_cfg_get_string(config, "rdm", &buf, 0)) {
2345 libxl_rdm_reserve rdm;
2346 if (!xlu_rdm_parse(config, &rdm, buf)) {
2347 b_info->u.hvm.rdm.strategy = rdm.strategy;
2348 b_info->u.hvm.rdm.policy = rdm.policy;
2349 }
2350 }
2351
2352 if (!xlu_cfg_get_list(config, "usbctrl", &usbctrls, 0, 0)) {
2353 d_config->num_usbctrls = 0;
2354 d_config->usbctrls = NULL;
2355 while ((buf = xlu_cfg_get_listitem(usbctrls, d_config->num_usbctrls))
2356 != NULL) {
2357 libxl_device_usbctrl *usbctrl;
2358 char *buf2 = strdup(buf);
2359 char *p;
2360
2361 usbctrl = ARRAY_EXTEND_INIT(d_config->usbctrls,
2362 d_config->num_usbctrls,
2363 libxl_device_usbctrl_init);
2364 p = strtok(buf2, ",");
2365 if (!p)
2366 goto skip_usbctrl;
2367 do {
2368 while (*p == ' ')
2369 p++;
2370 if (parse_usbctrl_config(usbctrl, p))
2371 exit(1);
2372 } while ((p = strtok(NULL, ",")) != NULL);
2373 skip_usbctrl:
2374 free(buf2);
2375 }
2376 }
2377
2378 if (!xlu_cfg_get_list(config, "usbdev", &usbdevs, 0, 0)) {
2379 d_config->num_usbdevs = 0;
2380 d_config->usbdevs = NULL;
2381 while ((buf = xlu_cfg_get_listitem(usbdevs, d_config->num_usbdevs))
2382 != NULL) {
2383 libxl_device_usbdev *usbdev;
2384 char *buf2 = strdup(buf);
2385 char *p;
2386
2387 usbdev = ARRAY_EXTEND_INIT_NODEVID(d_config->usbdevs,
2388 d_config->num_usbdevs,
2389 libxl_device_usbdev_init);
2390 p = strtok(buf2, ",");
2391 if (!p)
2392 goto skip_usbdev;
2393 do {
2394 while (*p == ' ')
2395 p++;
2396 if (parse_usbdev_config(usbdev, p))
2397 exit(1);
2398 } while ((p = strtok(NULL, ",")) != NULL);
2399 skip_usbdev:
2400 free(buf2);
2401 }
2402 }
2403
2404 switch (xlu_cfg_get_list(config, "cpuid", &cpuids, 0, 1)) {
2405 case 0:
2406 {
2407 const char *errstr;
2408
2409 for (i = 0; (buf = xlu_cfg_get_listitem(cpuids, i)) != NULL; i++) {
2410 e = libxl_cpuid_parse_config_xend(&b_info->cpuid, buf);
2411 switch (e) {
2412 case 0: continue;
2413 case 1:
2414 errstr = "illegal leaf number";
2415 break;
2416 case 2:
2417 errstr = "illegal subleaf number";
2418 break;
2419 case 3:
2420 errstr = "missing colon";
2421 break;
2422 case 4:
2423 errstr = "invalid register name (must be e[abcd]x)";
2424 break;
2425 case 5:
2426 errstr = "policy string must be exactly 32 characters long";
2427 break;
2428 default:
2429 errstr = "unknown error";
2430 break;
2431 }
2432 fprintf(stderr, "while parsing CPUID line: \"%s\":\n", buf);
2433 fprintf(stderr, " error #%i: %s\n", e, errstr);
2434 }
2435 }
2436 break;
2437 case EINVAL: /* config option is not a list, parse as a string */
2438 if (!xlu_cfg_get_string(config, "cpuid", &buf, 0)) {
2439 char *buf2, *p, *strtok_ptr = NULL;
2440 const char *errstr;
2441
2442 buf2 = strdup(buf);
2443 p = strtok_r(buf2, ",", &strtok_ptr);
2444 if (p == NULL) {
2445 free(buf2);
2446 break;
2447 }
2448 if (strcmp(p, "host")) {
2449 fprintf(stderr, "while parsing CPUID string: \"%s\":\n", buf);
2450 fprintf(stderr, " error: first word must be \"host\"\n");
2451 free(buf2);
2452 break;
2453 }
2454 for (p = strtok_r(NULL, ",", &strtok_ptr); p != NULL;
2455 p = strtok_r(NULL, ",", &strtok_ptr)) {
2456 e = libxl_cpuid_parse_config(&b_info->cpuid, p);
2457 switch (e) {
2458 case 0: continue;
2459 case 1:
2460 errstr = "missing \"=\" in key=value";
2461 break;
2462 case 2:
2463 errstr = "unknown CPUID flag name";
2464 break;
2465 case 3:
2466 errstr = "illegal CPUID value (must be: [0|1|x|k|s])";
2467 break;
2468 default:
2469 errstr = "unknown error";
2470 break;
2471 }
2472 fprintf(stderr, "while parsing CPUID flag: \"%s\":\n", p);
2473 fprintf(stderr, " error #%i: %s\n", e, errstr);
2474 }
2475 free(buf2);
2476 }
2477 break;
2478 default:
2479 break;
2480 }
2481
2482 /* parse device model arguments, this works for pv, hvm and stubdom */
2483 if (!xlu_cfg_get_string (config, "device_model", &buf, 0)) {
2484 fprintf(stderr,
2485 "WARNING: ignoring device_model directive.\n"
2486 "WARNING: Use \"device_model_override\" instead if you"
2487 " really want a non-default device_model\n");
2488 if (strstr(buf, "stubdom-dm")) {
2489 if (c_info->type == LIBXL_DOMAIN_TYPE_HVM)
2490 fprintf(stderr, "WARNING: Or use"
2491 " \"device_model_stubdomain_override\" if you "
2492 " want to enable stubdomains\n");
2493 else
2494 fprintf(stderr, "WARNING: ignoring"
2495 " \"device_model_stubdomain_override\" directive"
2496 " for pv guest\n");
2497 }
2498 }
2499
2500
2501 xlu_cfg_replace_string (config, "device_model_override",
2502 &b_info->device_model, 0);
2503 if (!xlu_cfg_get_string (config, "device_model_version", &buf, 0)) {
2504 if (!strcmp(buf, "qemu-xen-traditional")) {
2505 b_info->device_model_version
2506 = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL;
2507 } else if (!strcmp(buf, "qemu-xen")) {
2508 b_info->device_model_version
2509 = LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN;
2510 } else {
2511 fprintf(stderr,
2512 "Unknown device_model_version \"%s\" specified\n", buf);
2513 exit(1);
2514 }
2515 } else if (b_info->device_model)
2516 fprintf(stderr, "WARNING: device model override given without specific DM version\n");
2517 xlu_cfg_get_defbool (config, "device_model_stubdomain_override",
2518 &b_info->device_model_stubdomain, 0);
2519
2520 if (!xlu_cfg_get_string (config, "device_model_stubdomain_seclabel",
2521 &buf, 0))
2522 xlu_cfg_replace_string(config, "device_model_stubdomain_seclabel",
2523 &b_info->device_model_ssid_label, 0);
2524
2525 xlu_cfg_replace_string(config, "device_model_user",
2526 &b_info->device_model_user, 0);
2527
2528 xlu_cfg_replace_string (config, "stubdomain_kernel",
2529 &b_info->stubdomain_kernel, 0);
2530 xlu_cfg_replace_string (config, "stubdomain_ramdisk",
2531 &b_info->stubdomain_ramdisk, 0);
2532 if (!xlu_cfg_get_long (config, "stubdomain_memory", &l, 0))
2533 b_info->stubdomain_memkb = l * 1024;
2534
2535 #define parse_extra_args(type) \
2536 e = xlu_cfg_get_list_as_string_list(config, "device_model_args"#type, \
2537 &b_info->extra##type, 0); \
2538 if (e && e != ESRCH) { \
2539 fprintf(stderr,"xl: Unable to parse device_model_args"#type".\n");\
2540 exit(-ERROR_FAIL); \
2541 }
2542
2543 /* parse extra args for qemu, common to both pv, hvm */
2544 parse_extra_args();
2545
2546 /* parse extra args dedicated to pv */
2547 parse_extra_args(_pv);
2548
2549 /* parse extra args dedicated to hvm */
2550 parse_extra_args(_hvm);
2551
2552 #undef parse_extra_args
2553
2554 /* If we've already got vfb=[] for PV guest then ignore top level
2555 * VNC config. */
2556 if (c_info->type == LIBXL_DOMAIN_TYPE_PV && !d_config->num_vfbs) {
2557 long vnc_enabled = 0;
2558
2559 if (!xlu_cfg_get_long (config, "vnc", &l, 0))
2560 vnc_enabled = l;
2561
2562 if (vnc_enabled) {
2563 libxl_device_vfb *vfb;
2564 libxl_device_vkb *vkb;
2565
2566 vfb = ARRAY_EXTEND_INIT(d_config->vfbs, d_config->num_vfbs,
2567 libxl_device_vfb_init);
2568
2569 vkb = ARRAY_EXTEND_INIT(d_config->vkbs, d_config->num_vkbs,
2570 libxl_device_vkb_init);
2571
2572 parse_top_level_vnc_options(config, &vfb->vnc);
2573 parse_top_level_sdl_options(config, &vfb->sdl);
2574 xlu_cfg_replace_string (config, "keymap", &vfb->keymap, 0);
2575 }
2576 } else {
2577 parse_top_level_vnc_options(config, &b_info->u.hvm.vnc);
2578 parse_top_level_sdl_options(config, &b_info->u.hvm.sdl);
2579 }
2580
2581 xlu_cfg_get_defbool(config, "dm_restrict", &b_info->dm_restrict, 0);
2582
2583 if (c_info->type == LIBXL_DOMAIN_TYPE_HVM) {
2584 if (!xlu_cfg_get_string (config, "vga", &buf, 0)) {
2585 if (!strcmp(buf, "stdvga")) {
2586 b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_STD;
2587 } else if (!strcmp(buf, "cirrus")) {
2588 b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
2589 } else if (!strcmp(buf, "none")) {
2590 b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_NONE;
2591 } else if (!strcmp(buf, "qxl")) {
2592 b_info->u.hvm.vga.kind = LIBXL_VGA_INTERFACE_TYPE_QXL;
2593 } else {
2594 fprintf(stderr, "Unknown vga \"%s\" specified\n", buf);
2595 exit(1);
2596 }
2597 } else if (!xlu_cfg_get_long(config, "stdvga", &l, 0))
2598 b_info->u.hvm.vga.kind = l ? LIBXL_VGA_INTERFACE_TYPE_STD :
2599 LIBXL_VGA_INTERFACE_TYPE_CIRRUS;
2600
2601 if (!xlu_cfg_get_string(config, "hdtype", &buf, 0) &&
2602 libxl_hdtype_from_string(buf, &b_info->u.hvm.hdtype)) {
2603 fprintf(stderr, "ERROR: invalid value \"%s\" for \"hdtype\"\n",
2604 buf);
2605 exit (1);
2606 }
2607
2608 xlu_cfg_replace_string (config, "keymap", &b_info->u.hvm.keymap, 0);
2609 xlu_cfg_get_defbool (config, "spice", &b_info->u.hvm.spice.enable, 0);
2610 if (!xlu_cfg_get_long (config, "spiceport", &l, 0))
2611 b_info->u.hvm.spice.port = l;
2612 if (!xlu_cfg_get_long (config, "spicetls_port", &l, 0))
2613 b_info->u.hvm.spice.tls_port = l;
2614 xlu_cfg_replace_string (config, "spicehost",
2615 &b_info->u.hvm.spice.host, 0);
2616 xlu_cfg_get_defbool(config, "spicedisable_ticketing",
2617 &b_info->u.hvm.spice.disable_ticketing, 0);
2618 xlu_cfg_replace_string (config, "spicepasswd",
2619 &b_info->u.hvm.spice.passwd, 0);
2620 xlu_cfg_get_defbool(config, "spiceagent_mouse",
2621 &b_info->u.hvm.spice.agent_mouse, 0);
2622 xlu_cfg_get_defbool(config, "spicevdagent",
2623 &b_info->u.hvm.spice.vdagent, 0);
2624 xlu_cfg_get_defbool(config, "spice_clipboard_sharing",
2625 &b_info->u.hvm.spice.clipboard_sharing, 0);
2626 if (!xlu_cfg_get_long (config, "spiceusbredirection", &l, 0))
2627 b_info->u.hvm.spice.usbredirection = l;
2628 xlu_cfg_replace_string (config, "spice_image_compression",
2629 &b_info->u.hvm.spice.image_compression, 0);
2630 xlu_cfg_replace_string (config, "spice_streaming_video",
2631 &b_info->u.hvm.spice.streaming_video, 0);
2632 xlu_cfg_get_defbool(config, "nographic", &b_info->u.hvm.nographic, 0);
2633 if (!xlu_cfg_get_long(config, "gfx_passthru", &l, 1)) {
2634 libxl_defbool_set(&b_info->u.hvm.gfx_passthru, l);
2635 } else if (!xlu_cfg_get_string(config, "gfx_passthru", &buf, 0)) {
2636 if (libxl_gfx_passthru_kind_from_string(buf,
2637 &b_info->u.hvm.gfx_passthru_kind)) {
2638 fprintf(stderr,
2639 "ERROR: invalid value \"%s\" for \"gfx_passthru\"\n",
2640 buf);
2641 exit (1);
2642 }
2643 libxl_defbool_set(&b_info->u.hvm.gfx_passthru, true);
2644 }
2645 switch (xlu_cfg_get_list_as_string_list(config, "serial",
2646 &b_info->u.hvm.serial_list,
2647 1))
2648 {
2649
2650 case 0: break; /* Success */
2651 case ESRCH: break; /* Option not present */
2652 case EINVAL:
2653 /* If it's not a valid list, try reading it as an atom,
2654 * falling through to an error if it fails */
2655 if (!xlu_cfg_replace_string(config, "serial",
2656 &b_info->u.hvm.serial, 0))
2657 break;
2658 /* FALLTHRU */
2659 default:
2660 fprintf(stderr,"xl: Unable to parse serial.\n");
2661 exit(-ERROR_FAIL);
2662 }
2663 xlu_cfg_replace_string (config, "boot", &b_info->u.hvm.boot, 0);
2664 xlu_cfg_get_defbool(config, "usb", &b_info->u.hvm.usb, 0);
2665 if (!xlu_cfg_get_long (config, "usbversion", &l, 0))
2666 b_info->u.hvm.usbversion = l;
2667 switch (xlu_cfg_get_list_as_string_list(config, "usbdevice",
2668 &b_info->u.hvm.usbdevice_list,
2669 1))
2670 {
2671
2672 case 0: break; /* Success */
2673 case ESRCH: break; /* Option not present */
2674 case EINVAL:
2675 /* If it's not a valid list, try reading it as an atom,
2676 * falling through to an error if it fails */
2677 if (!xlu_cfg_replace_string(config, "usbdevice",
2678 &b_info->u.hvm.usbdevice, 0))
2679 break;
2680 /* FALLTHRU */
2681 default:
2682 fprintf(stderr,"xl: Unable to parse usbdevice.\n");
2683 exit(-ERROR_FAIL);
2684 }
2685 xlu_cfg_get_defbool(config, "vkb_device", &b_info->u.hvm.vkb_device, 0);
2686 xlu_cfg_replace_string (config, "soundhw", &b_info->u.hvm.soundhw, 0);
2687 xlu_cfg_get_defbool(config, "xen_platform_pci",
2688 &b_info->u.hvm.xen_platform_pci, 0);
2689
2690 if(b_info->u.hvm.vnc.listen
2691 && b_info->u.hvm.vnc.display
2692 && strchr(b_info->u.hvm.vnc.listen, ':') != NULL) {
2693 fprintf(stderr,
2694 "ERROR: Display specified both in vnclisten"
2695 " and vncdisplay!\n");
2696 exit (1);
2697
2698 }
2699
2700 if (!xlu_cfg_get_string (config, "vendor_device", &buf, 0)) {
2701 libxl_vendor_device d;
2702
2703 e = libxl_vendor_device_from_string(buf, &d);
2704 if (e) {
2705 fprintf(stderr,
2706 "xl: unknown vendor_device '%s'\n",
2707 buf);
2708 exit(-ERROR_FAIL);
2709 }
2710
2711 b_info->u.hvm.vendor_device = d;
2712 }
2713 }
2714
2715 if (!xlu_cfg_get_string (config, "gic_version", &buf, 1)) {
2716 e = libxl_gic_version_from_string(buf, &b_info->arch_arm.gic_version);
2717 if (e) {
2718 fprintf(stderr,
2719 "Unknown gic_version \"%s\" specified\n", buf);
2720 exit(-ERROR_FAIL);
2721 }
2722 }
2723
2724 if (!xlu_cfg_get_string (config, "tee", &buf, 1)) {
2725 e = libxl_tee_type_from_string(buf, &b_info->tee);
2726 if (e) {
2727 fprintf(stderr,
2728 "Unknown tee \"%s\" specified\n", buf);
2729 exit(-ERROR_FAIL);
2730 }
2731 }
2732
2733 parse_vkb_list(config, d_config);
2734
2735 xlu_cfg_get_defbool(config, "xend_suspend_evtchn_compat",
2736 &c_info->xend_suspend_evtchn_compat, 0);
2737
2738 xlu_cfg_destroy(config);
2739 }
2740
2741 /* Returns -1 on failure; the amount of memory on success. */
parse_mem_size_kb(const char * mem)2742 int64_t parse_mem_size_kb(const char *mem)
2743 {
2744 char *endptr;
2745 int64_t kbytes;
2746
2747 kbytes = strtoll(mem, &endptr, 10);
2748
2749 if (strlen(endptr) > 1)
2750 return -1;
2751
2752 switch (tolower((uint8_t)*endptr)) {
2753 case 't':
2754 kbytes <<= 10;
2755 /* fallthrough */
2756 case 'g':
2757 kbytes <<= 10;
2758 /* fallthrough */
2759 case '\0':
2760 case 'm':
2761 kbytes <<= 10;
2762 /* fallthrough */
2763 case 'k':
2764 break;
2765 case 'b':
2766 kbytes >>= 10;
2767 break;
2768 default:
2769 return -1;
2770 }
2771
2772 return kbytes;
2773 }
2774
2775
split_string_into_string_list(const char * str,const char * delim,libxl_string_list * psl)2776 void split_string_into_string_list(const char *str,
2777 const char *delim,
2778 libxl_string_list *psl)
2779 {
2780 char *s, *saveptr;
2781 const char *p;
2782 libxl_string_list sl;
2783
2784 int i = 0, nr = 0;
2785
2786 s = strdup(str);
2787 if (s == NULL) {
2788 fprintf(stderr, "unable to allocate memory to split string\n");
2789 exit(-1);
2790 }
2791
2792 /* Count number of entries */
2793 p = strtok_r(s, delim, &saveptr);
2794 do {
2795 nr++;
2796 } while ((p = strtok_r(NULL, delim, &saveptr)));
2797
2798 free(s);
2799
2800 s = strdup(str);
2801
2802 sl = malloc((nr+1) * sizeof (char *));
2803 if (sl == NULL) {
2804 fprintf(stderr, "unable to allocate memory to split string\n");
2805 exit(-1);
2806 }
2807
2808 p = strtok_r(s, delim, &saveptr);
2809 do {
2810 assert(i < nr);
2811 sl[i] = strdup(p);
2812 i++;
2813 } while ((p = strtok_r(NULL, delim, &saveptr)));
2814 sl[i] = NULL;
2815
2816 *psl = sl;
2817
2818 free(s);
2819 }
2820
trim(char_predicate_t predicate,const char * input,char ** output)2821 void trim(char_predicate_t predicate, const char *input, char **output)
2822 {
2823 const char *first, *after;
2824
2825 for (first = input;
2826 *first && predicate((unsigned char)first[0]);
2827 first++)
2828 ;
2829
2830 for (after = first + strlen(first);
2831 after > first && predicate((unsigned char)after[-1]);
2832 after--)
2833 ;
2834
2835 size_t len_nonnull = after - first;
2836 char *result = xmalloc(len_nonnull + 1);
2837
2838 memcpy(result, first, len_nonnull);
2839 result[len_nonnull] = 0;
2840
2841 *output = result;
2842 }
2843
split_string_into_pair(const char * str,const char * delim,char ** a,char ** b)2844 int split_string_into_pair(const char *str,
2845 const char *delim,
2846 char **a,
2847 char **b)
2848 {
2849 char *s, *p, *saveptr, *aa = NULL, *bb = NULL;
2850 int rc = 0;
2851
2852 s = xstrdup(str);
2853
2854 p = strtok_r(s, delim, &saveptr);
2855 if (p == NULL) {
2856 rc = ERROR_INVAL;
2857 goto out;
2858 }
2859 aa = xstrdup(p);
2860 p = strtok_r(NULL, delim, &saveptr);
2861 if (p == NULL) {
2862 rc = ERROR_INVAL;
2863 goto out;
2864 }
2865 bb = xstrdup(p);
2866
2867 *a = aa;
2868 aa = NULL;
2869 *b = bb;
2870 bb = NULL;
2871 out:
2872 free(s);
2873 free(aa);
2874 free(bb);
2875 return rc;
2876 }
2877
2878
2879 /*
2880 * Local variables:
2881 * mode: C
2882 * c-basic-offset: 4
2883 * indent-tabs-mode: nil
2884 * End:
2885 */
2886