debuggers.hg

view tools/libxl/libxl_utils.c @ 21989:88adea5b4546

libxl, Introduce the command line handler for the new qemu.
From: Anthony PERARD <anthony.perard@citrix.com>

This patch adds a function to check the version of the device model.
Depending on the version of the DM, the command line arguments will be
built differently.

Signed-off-by: Anthony PERARD <anthony.perard@citrix.com>
Signed-off-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
---
tools/libxl/libxl.c | 160 ++++++++++++++++++++++++++++++++++++++++++++-
tools/libxl/libxl_utils.c | 78 ++++++++++++++++++++++
tools/libxl/libxl_utils.h | 6 ++
3 files changed, 243 insertions(+), 1 deletions(-)
author Anthony Perard <anthony.perard@citrix.com>
date Mon Aug 09 16:46:01 2010 +0100 (2010-08-09)
parents baaa4b9d385f
children 72ae90e325ea
line source
1 /*
2 * Copyright (C) 2009 Citrix Ltd.
3 * Author Stefano Stabellini <stefano.stabellini@eu.citrix.com>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU Lesser General Public License as published
7 * by the Free Software Foundation; version 2.1 only. with the special
8 * exception on linking described in file LICENSE.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU Lesser General Public License for more details.
14 */
16 #include "libxl_osdeps.h"
18 #include <stdio.h>
19 #include <stdlib.h>
20 #include <stdint.h>
21 #include <string.h>
22 #include <xs.h>
23 #include <xenctrl.h>
24 #include <ctype.h>
25 #include <errno.h>
26 #include <sys/stat.h>
27 #include <sys/types.h>
28 #include <unistd.h>
29 #include <assert.h>
31 #include "libxl_utils.h"
32 #include "libxl_internal.h"
35 unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus)
36 {
37 /* 256 pages (1MB) per vcpu,
38 plus 1 page per MiB of RAM for the P2M map,
39 plus 1 page per MiB of RAM to shadow the resident processes.
40 This is higher than the minimum that Xen would allocate if no value
41 were given (but the Xen minimum is for safety, not performance).
42 */
43 return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024));
44 }
46 char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid)
47 {
48 unsigned int len;
49 char path[strlen("/local/domain") + 12];
50 char *s;
52 snprintf(path, sizeof(path), "/local/domain/%d/name", domid);
53 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
54 libxl_ptr_add(ctx, s);
55 return s;
56 }
58 int libxl_name_to_domid(libxl_ctx *ctx, const char *name,
59 uint32_t *domid)
60 {
61 int i, nb_domains;
62 char *domname;
63 libxl_dominfo *dominfo;
64 int ret = -1;
66 dominfo = libxl_list_domain(ctx, &nb_domains);
67 if (!dominfo)
68 return ERROR_NOMEM;
70 for (i = 0; i < nb_domains; i++) {
71 domname = libxl_domid_to_name(ctx, dominfo[i].domid);
72 if (!domname)
73 continue;
74 if (strcmp(domname, name) == 0) {
75 *domid = dominfo[i].domid;
76 ret = 0;
77 break;
78 }
79 }
80 free(dominfo);
81 return ret;
82 }
84 char *libxl_poolid_to_name(libxl_ctx *ctx, uint32_t poolid)
85 {
86 unsigned int len;
87 char path[strlen("/local/pool") + 12];
88 char *s;
90 if (poolid == 0)
91 return "Pool-0";
92 snprintf(path, sizeof(path), "/local/pool/%d/name", poolid);
93 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
94 libxl_ptr_add(ctx, s);
95 return s;
96 }
98 int libxl_name_to_poolid(libxl_ctx *ctx, const char *name,
99 uint32_t *poolid)
100 {
101 int i, nb_pools;
102 char *poolname;
103 libxl_poolinfo *poolinfo;
104 int ret = -1;
106 poolinfo = libxl_list_pool(ctx, &nb_pools);
107 if (!poolinfo)
108 return ERROR_NOMEM;
110 for (i = 0; i < nb_pools; i++) {
111 poolname = libxl_poolid_to_name(ctx, poolinfo[i].poolid);
112 if (!poolname)
113 continue;
114 if (strcmp(poolname, name) == 0) {
115 *poolid = poolinfo[i].poolid;
116 ret = 0;
117 break;
118 }
119 }
120 free(poolinfo);
121 return ret;
122 }
124 int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid)
125 {
126 char * stubdom_id_s = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/image/device-model-domid", libxl_xs_get_dompath(ctx, guest_domid)));
127 if (stubdom_id_s)
128 return atoi(stubdom_id_s);
129 else
130 return 0;
131 }
133 int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid)
134 {
135 char *target, *endptr;
136 uint32_t value;
138 target = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/target", libxl_xs_get_dompath(ctx, domid)));
139 if (!target)
140 return 0;
141 value = strtol(target, &endptr, 10);
142 if (*endptr != '\0')
143 return 0;
144 if (target_domid)
145 *target_domid = value;
146 return 1;
147 }
149 static int logrename(libxl_ctx *ctx, const char *old, const char *new) {
150 int r;
152 r = rename(old, new);
153 if (r) {
154 if (errno == ENOENT) return 0; /* ok */
156 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to rotate logfile - could not"
157 " rename %s to %s", old, new);
158 return ERROR_FAIL;
159 }
160 return 0;
161 }
163 int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name)
164 {
165 struct stat stat_buf;
166 char *logfile, *logfile_new;
167 int i, rc;
169 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name);
170 if (stat(logfile, &stat_buf) == 0) {
171 /* file exists, rotate */
172 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log.10", name);
173 unlink(logfile);
174 for (i = 9; i > 0; i--) {
175 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i);
176 logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.%d", name, i + 1);
177 rc = logrename(ctx, logfile, logfile_new);
178 if (rc) return rc;
179 }
180 logfile = libxl_sprintf(ctx, "/var/log/xen/%s.log", name);
181 logfile_new = libxl_sprintf(ctx, "/var/log/xen/%s.log.1", name);
183 rc = logrename(ctx, logfile, logfile_new);
184 if (rc) return rc;
185 } else {
186 if (errno != ENOENT)
187 XL_LOG_ERRNO(ctx, XL_LOG_WARNING, "problem checking existence of"
188 " logfile %s, which might have needed to be rotated",
189 name);
190 }
191 *full_name = strdup(logfile);
192 return 0;
193 }
195 int libxl_string_to_phystype(libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype)
196 {
197 char *p;
198 int rc = 0;
200 if (!strcmp(s, "phy")) {
201 *phystype = PHYSTYPE_PHY;
202 } else if (!strcmp(s, "file")) {
203 *phystype = PHYSTYPE_FILE;
204 } else if (!strcmp(s, "tap")) {
205 p = strchr(s, ':');
206 if (!p) {
207 rc = -1;
208 goto out;
209 }
210 p++;
211 if (!strcmp(p, "aio")) {
212 *phystype = PHYSTYPE_AIO;
213 } else if (!strcmp(p, "vhd")) {
214 *phystype = PHYSTYPE_VHD;
215 } else if (!strcmp(p, "qcow")) {
216 *phystype = PHYSTYPE_QCOW;
217 } else if (!strcmp(p, "qcow2")) {
218 *phystype = PHYSTYPE_QCOW2;
219 }
220 }
221 out:
222 return rc;
223 }
225 int libxl_read_file_contents(libxl_ctx *ctx, const char *filename,
226 void **data_r, int *datalen_r) {
227 FILE *f = 0;
228 uint8_t *data = 0;
229 int datalen = 0;
230 int e;
231 struct stat stab;
232 ssize_t rs;
234 f = fopen(filename, "r");
235 if (!f) {
236 if (errno == ENOENT) return ENOENT;
237 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to open %s", filename);
238 goto xe;
239 }
241 if (fstat(fileno(f), &stab)) {
242 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to fstat %s", filename);
243 goto xe;
244 }
246 if (!S_ISREG(stab.st_mode)) {
247 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "%s is not a plain file", filename);
248 errno = ENOTTY;
249 goto xe;
250 }
252 if (stab.st_size > INT_MAX) {
253 XL_LOG(ctx, XL_LOG_ERROR, "file %s is far too large", filename);
254 errno = EFBIG;
255 goto xe;
256 }
258 datalen = stab.st_size;
260 if (stab.st_size && data_r) {
261 data = malloc(datalen);
262 if (!data) goto xe;
264 rs = fread(data, 1, datalen, f);
265 if (rs != datalen) {
266 if (ferror(f))
267 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to read %s", filename);
268 else if (feof(f))
269 XL_LOG(ctx, XL_LOG_ERROR, "%s changed size while we"
270 " were reading it", filename);
271 else
272 abort();
273 goto xe;
274 }
275 }
277 if (fclose(f)) {
278 f = 0;
279 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to close %s", filename);
280 goto xe;
281 }
283 if (data_r) *data_r = data;
284 if (datalen_r) *datalen_r = datalen;
286 return 0;
288 xe:
289 e = errno;
290 assert(e != ENOENT);
291 if (f) fclose(f);
292 if (data) free(data);
293 return e;
294 }
296 #define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata) \
297 \
298 int libxl_##rw##_exactly(libxl_ctx *ctx, int fd, \
299 constdata void *data, ssize_t sz, \
300 const char *filename, const char *what) { \
301 ssize_t got; \
302 \
303 while (sz > 0) { \
304 got = rw(fd, data, sz); \
305 if (got == -1) { \
306 if (errno == EINTR) continue; \
307 if (!ctx) return errno; \
308 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "failed to " #rw " %s%s%s", \
309 what?what:"", what?" from ":"", filename); \
310 return errno; \
311 } \
312 if (got == 0) { \
313 if (!ctx) return EPROTO; \
314 XL_LOG(ctx, XL_LOG_ERROR, \
315 zero_is_eof \
316 ? "file/stream truncated reading %s%s%s" \
317 : "file/stream write returned 0! writing %s%s%s", \
318 what?what:"", what?" from ":"", filename); \
319 return EPROTO; \
320 } \
321 sz -= got; \
322 data = (char*)data + got; \
323 } \
324 return 0; \
325 }
327 READ_WRITE_EXACTLY(read, 1, /* */)
328 READ_WRITE_EXACTLY(write, 0, const)
331 int libxl_ctx_postfork(libxl_ctx *ctx) {
332 if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
333 ctx->xsh = xs_daemon_open();
334 if (!ctx->xsh) return ERROR_FAIL;
335 return 0;
336 }
338 pid_t libxl_fork(libxl_ctx *ctx)
339 {
340 pid_t pid;
342 pid = fork();
343 if (pid == -1) {
344 XL_LOG_ERRNO(ctx, XL_LOG_ERROR, "fork failed");
345 return -1;
346 }
348 if (!pid) {
349 if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
350 ctx->xsh = 0;
351 /* This ensures that anyone who forks but doesn't exec,
352 * and doesn't reinitialise the libxl_ctx, is OK.
353 * It also means they can safely call libxl_ctx_free. */
354 }
356 return pid;
357 }
359 int libxl_pipe(libxl_ctx *ctx, int pipes[2])
360 {
361 if (pipe(pipes) < 0) {
362 XL_LOG(ctx, XL_LOG_ERROR, "Failed to create a pipe");
363 return -1;
364 }
365 return 0;
366 }
368 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
369 const char *mac, libxl_device_nic *nic)
370 {
371 libxl_nicinfo *nics;
372 unsigned int nb, i;
373 uint8_t mac_n[6];
374 uint8_t *a, *b;
375 const char *tok;
376 char *endptr;
378 nics = libxl_list_nics(ctx, domid, &nb);
379 if (!nics) {
380 return ERROR_FAIL;
381 }
383 for (i = 0, tok = mac; *tok && (i < 6); ++i, tok += 3) {
384 mac_n[i] = strtol(tok, &endptr, 16);
385 if (endptr != (tok + 2)) {
386 return ERROR_INVAL;
387 }
388 }
389 memset(nic, 0, sizeof (libxl_device_nic));
390 for (; nb; --nb, ++nics) {
391 for (i = 0, a = nics->mac, b = mac_n;
392 (b < mac_n + 6) && (*a == *b); ++a, ++b)
393 ;
394 if ((b >= mac_n + 6) && (*a == *b)) {
395 nic->backend_domid = nics->backend_id;
396 nic->domid = nics->frontend_id;
397 nic->devid = nics->devid;
398 memcpy(nic->mac, nics->mac, sizeof (nic->mac));
399 nic->script = nics->script;
400 libxl_free(ctx, nics);
401 return 0;
402 }
403 }
405 libxl_free(ctx, nics);
406 return 0;
407 }
409 int libxl_devid_to_device_nic(libxl_ctx *ctx, uint32_t domid,
410 const char *devid, libxl_device_nic *nic)
411 {
412 char *tok, *val;
413 char *dompath, *nic_path_fe, *nic_path_be;
414 unsigned int i;
416 memset(nic, 0, sizeof (libxl_device_nic));
417 dompath = libxl_xs_get_dompath(ctx, domid);
418 if (!dompath) {
419 return ERROR_FAIL;
420 }
421 nic_path_fe = libxl_sprintf(ctx, "%s/device/vif/%s", dompath, devid);
422 nic_path_be = libxl_xs_read(ctx, XBT_NULL,
423 libxl_sprintf(ctx, "%s/backend", nic_path_fe));
424 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", nic_path_fe));
425 nic->backend_domid = strtoul(val, NULL, 10);
426 nic->devid = strtoul(devid, NULL, 10);
427 libxl_free(ctx, val);
429 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", nic_path_fe));
430 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
431 ++i, tok = strtok(NULL, ":")) {
432 nic->mac[i] = strtoul(tok, NULL, 16);
433 }
434 libxl_free(ctx, val);
435 nic->script = libxl_xs_read(ctx, XBT_NULL,
436 libxl_sprintf(ctx, "%s/script", nic_path_be));
437 libxl_free(ctx, nic_path_fe);
438 libxl_free(ctx, nic_path_be);
439 return 0;
440 }
442 int libxl_devid_to_device_disk(libxl_ctx *ctx, uint32_t domid,
443 const char *devid, libxl_device_disk *disk)
444 {
445 char *endptr, *val;
446 char *dompath, *diskpath, *be_path;
447 unsigned int devid_n;
449 devid_n = strtoul(devid, &endptr, 10);
450 if (devid == endptr) {
451 return ERROR_INVAL;
452 }
453 dompath = libxl_xs_get_dompath(ctx, domid);
454 diskpath = libxl_sprintf(ctx, "%s/device/vbd/%s", dompath, devid);
455 if (!diskpath) {
456 return ERROR_FAIL;
457 }
459 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", diskpath));
460 if (!val)
461 return ERROR_FAIL;
462 disk->backend_domid = strtoul(val, NULL, 10);
463 disk->domid = domid;
464 be_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", diskpath));
465 disk->physpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/params", be_path));
466 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/type", be_path));
467 libxl_string_to_phystype(ctx, val, &(disk->phystype));
468 disk->virtpath = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/dev", be_path));
469 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/removable", be_path));
470 disk->unpluggable = !strcmp(val, "1");
471 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mode", be_path));
472 disk->readwrite = !!strcmp(val, "w");
473 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/device-type", diskpath));
474 disk->is_cdrom = !strcmp(val, "cdrom");
476 return 0;
477 }
479 int libxl_devid_to_device_net2(libxl_ctx *ctx, uint32_t domid,
480 const char *devid, libxl_device_net2 *net2)
481 {
482 char *tok, *endptr, *val;
483 char *dompath, *net2path, *be_path;
484 unsigned int devid_n, i;
486 devid_n = strtoul(devid, &endptr, 10);
487 if (devid == endptr) {
488 return ERROR_INVAL;
489 }
490 dompath = libxl_xs_get_dompath(ctx, domid);
491 net2path = libxl_sprintf(ctx, "%s/device/vif2/%s", dompath, devid);
492 if (!net2path) {
493 return ERROR_FAIL;
494 }
495 memset(net2, 0, sizeof (libxl_device_net2));
496 be_path = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend", net2path));
498 net2->devid = devid_n;
499 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/mac", net2path));
500 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
501 ++i, tok = strtok(NULL, ":")) {
502 net2->front_mac[i] = strtoul(tok, NULL, 16);
503 }
504 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/remote-mac", net2path));
505 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
506 ++i, tok = strtok(NULL, ":")) {
507 net2->back_mac[i] = strtoul(tok, NULL, 16);
508 }
509 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/backend-id", net2path));
510 net2->backend_domid = strtoul(val, NULL, 10);
512 net2->domid = domid;
513 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/remote-trusted", be_path));
514 net2->trusted = strtoul(val, NULL, 10);
515 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/local-trusted", be_path));
516 net2->back_trusted = strtoul(val, NULL, 10);
517 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/filter-mac", be_path));
518 net2->filter_mac = strtoul(val, NULL, 10);
519 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/filter-mac", net2path));
520 net2->front_filter_mac = strtoul(val, NULL, 10);
521 val = libxl_xs_read(ctx, XBT_NULL, libxl_sprintf(ctx, "%s/max-bypasses", be_path));
522 net2->max_bypasses = strtoul(val, NULL, 10);
524 return 0;
525 }
527 int libxl_strtomac(const char *mac_s, uint8_t *mac)
528 {
529 const char *end = mac_s + 17;
530 char val, *endptr;
532 for (; mac_s < end; mac_s += 3, ++mac) {
533 val = strtoul(mac_s, &endptr, 16);
534 if (endptr != (mac_s + 2)) {
535 return ERROR_INVAL;
536 }
537 *mac = val;
538 }
539 return 0;
540 }
542 #define QEMU_VERSION_STR "QEMU emulator version "
545 int libxl_check_device_model_version(libxl_ctx *ctx, char *path)
546 {
547 pid_t pid = -1;
548 int pipefd[2];
549 char buf[100];
550 ssize_t i, count = 0;
551 int status;
552 char *abs_path = NULL;
554 abs_path = libxl_abs_path(ctx, path, libxl_private_bindir_path());
556 if (pipe(pipefd))
557 return -1;
559 pid = fork();
560 if (pid == -1) {
561 return -1;
562 }
564 if (!pid) {
565 close(pipefd[0]);
566 if (dup2(pipefd[1], STDOUT_FILENO) == -1)
567 exit(1);
568 execlp(abs_path, abs_path, "-h", NULL);
570 close(pipefd[1]);
571 exit(127);
572 }
574 close(pipefd[1]);
575 if (abs_path != path)
576 libxl_free(ctx, abs_path);
578 /* attempt to get the first line of `qemu -h` */
579 while ((i = read(pipefd[0], buf + count, 99 - count)) > 0) {
580 if (i + count > 90)
581 break;
582 for (int j = 0; j < i; j++) {
583 if (buf[j + count] == '\n')
584 break;
585 }
586 count += i;
587 }
588 count += i;
589 close(pipefd[0]);
590 waitpid(pid, &status, 0);
591 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
592 return -1;
593 }
595 /* Check if we have the forked qemu-xen. */
596 /* QEMU-DM emulator version 0.10.2, ... */
597 if (strncmp("QEMU-DM ", buf, 7) == 0) {
598 return 0;
599 }
601 /* Check if the version is above 12.0 */
602 /* The first line is : QEMU emulator version 0.12.50, ... */
603 if (strncmp(QEMU_VERSION_STR, buf, strlen(QEMU_VERSION_STR)) == 0) {
604 int major, minor;
605 char *endptr = NULL;
606 char *v = buf + strlen(QEMU_VERSION_STR);
608 major = strtol(v, &endptr, 10);
609 if (major == 0 && endptr && *endptr == '.') {
610 v = endptr + 1;
611 minor = strtol(v, &endptr, 10);
612 if (minor >= 12)
613 return 1;
614 }
615 }
617 return -1;
618 }