debuggers.hg

view tools/libxl/libxl_utils.c @ 22865:67d5b8004947

libxl: band-aid for functions which return literal "-1"

Many libxl functions erroneously return "-1" on error, rather than
some ERROR_* value.

To deal with this, invent a new ERROR_NONSPECIFIC "-1" which indicates
that "the function which generated this error code is broken".

Fix up the one we care about for forthcoming duplicate domain
detection (libxl_name_to_domid) and the others following the same
pattern nearby; leave the rest for post-4.1.

Signed-off-by: Ian Jackson <ian.jackson@eu.citrix.com>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
author Ian Jackson <ian.jackson@eu.citrix.com>
date Wed Jan 26 11:58:45 2011 +0000 (2011-01-26)
parents 63fd6f886f49
children
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"
34 struct schedid_name {
35 char *name;
36 int id;
37 };
39 static struct schedid_name schedid_name[] = {
40 { "credit", XEN_SCHEDULER_CREDIT },
41 { "sedf", XEN_SCHEDULER_SEDF },
42 { "credit2", XEN_SCHEDULER_CREDIT2 },
43 { NULL, -1 }
44 };
46 const char *libxl_basename(const char *name)
47 {
48 const char *filename;
49 if (name == NULL)
50 return strdup(".");
51 if (name[0] == '\0')
52 return strdup(".");
54 filename = strrchr(name, '/');
55 if (filename)
56 return strdup(filename+1);
57 return strdup(name);
58 }
60 unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus)
61 {
62 /* 256 pages (1MB) per vcpu,
63 plus 1 page per MiB of RAM for the P2M map,
64 plus 1 page per MiB of RAM to shadow the resident processes.
65 This is higher than the minimum that Xen would allocate if no value
66 were given (but the Xen minimum is for safety, not performance).
67 */
68 return 4 * (256 * smp_cpus + 2 * (maxmem_kb / 1024));
69 }
71 char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid)
72 {
73 unsigned int len;
74 char path[strlen("/local/domain") + 12];
75 char *s;
77 snprintf(path, sizeof(path), "/local/domain/%d/name", domid);
78 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
79 return s;
80 }
82 char *libxl__domid_to_name(libxl__gc *gc, uint32_t domid)
83 {
84 char *s = libxl_domid_to_name(libxl__gc_owner(gc), domid);
85 if ( s )
86 libxl__ptr_add(gc, s);
87 return s;
88 }
90 int libxl_name_to_domid(libxl_ctx *ctx, const char *name,
91 uint32_t *domid)
92 {
93 int i, nb_domains;
94 char *domname;
95 libxl_dominfo *dominfo;
96 int ret = ERROR_INVAL;
98 dominfo = libxl_list_domain(ctx, &nb_domains);
99 if (!dominfo)
100 return ERROR_NOMEM;
102 for (i = 0; i < nb_domains; i++) {
103 domname = libxl_domid_to_name(ctx, dominfo[i].domid);
104 if (!domname)
105 continue;
106 if (strcmp(domname, name) == 0) {
107 *domid = dominfo[i].domid;
108 ret = 0;
109 free(domname);
110 break;
111 }
112 free(domname);
113 }
114 free(dominfo);
115 return ret;
116 }
118 char *libxl_cpupoolid_to_name(libxl_ctx *ctx, uint32_t poolid)
119 {
120 unsigned int len;
121 char path[strlen("/local/pool") + 12];
122 char *s;
124 snprintf(path, sizeof(path), "/local/pool/%d/name", poolid);
125 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
126 if (!s && (poolid == 0))
127 return strdup("Pool-0");
128 return s;
129 }
131 char *libxl__cpupoolid_to_name(libxl__gc *gc, uint32_t poolid)
132 {
133 char *s = libxl_cpupoolid_to_name(libxl__gc_owner(gc), poolid);
134 if ( s )
135 libxl__ptr_add(gc, s);
136 return s;
137 }
139 int libxl_name_to_cpupoolid(libxl_ctx *ctx, const char *name,
140 uint32_t *poolid)
141 {
142 int i, nb_pools;
143 char *poolname;
144 libxl_cpupoolinfo *poolinfo;
145 int ret = ERROR_INVAL;
147 poolinfo = libxl_list_cpupool(ctx, &nb_pools);
148 if (!poolinfo)
149 return ERROR_NOMEM;
151 for (i = 0; i < nb_pools; i++) {
152 if (ret && ((poolname = libxl_cpupoolid_to_name(ctx,
153 poolinfo[i].poolid)) != NULL)) {
154 if (strcmp(poolname, name) == 0) {
155 *poolid = poolinfo[i].poolid;
156 ret = 0;
157 }
158 free(poolname);
159 }
160 libxl_cpupoolinfo_destroy(poolinfo + i);
161 }
162 free(poolinfo);
163 return ret;
164 }
166 int libxl_name_to_schedid(libxl_ctx *ctx, const char *name)
167 {
168 int i;
170 for (i = 0; schedid_name[i].name != NULL; i++)
171 if (strcmp(name, schedid_name[i].name) == 0)
172 return schedid_name[i].id;
174 return ERROR_INVAL;
175 }
177 char *libxl_schedid_to_name(libxl_ctx *ctx, int schedid)
178 {
179 int i;
181 for (i = 0; schedid_name[i].name != NULL; i++)
182 if (schedid_name[i].id == schedid)
183 return schedid_name[i].name;
185 return "unknown";
186 }
188 int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid)
189 {
190 libxl__gc gc = LIBXL_INIT_GC(ctx);
191 char * stubdom_id_s;
192 int ret;
194 stubdom_id_s = libxl__xs_read(&gc, XBT_NULL,
195 libxl__sprintf(&gc, "%s/image/device-model-domid",
196 libxl__xs_get_dompath(&gc, guest_domid)));
197 if (stubdom_id_s)
198 ret = atoi(stubdom_id_s);
199 else
200 ret = 0;
201 libxl__free_all(&gc);
202 return ret;
203 }
205 int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid)
206 {
207 libxl__gc gc = LIBXL_INIT_GC(ctx);
208 char *target, *endptr;
209 uint32_t value;
210 int ret = 0;
212 target = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/target", libxl__xs_get_dompath(&gc, domid)));
213 if (!target)
214 goto out;
215 value = strtol(target, &endptr, 10);
216 if (*endptr != '\0')
217 goto out;
218 if (target_domid)
219 *target_domid = value;
220 ret = 1;
221 out:
222 libxl__free_all(&gc);
223 return ret;
224 }
226 static int logrename(libxl_ctx *ctx, const char *old, const char *new) {
227 int r;
229 r = rename(old, new);
230 if (r) {
231 if (errno == ENOENT) return 0; /* ok */
233 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to rotate logfile - could not"
234 " rename %s to %s", old, new);
235 return ERROR_FAIL;
236 }
237 return 0;
238 }
240 int libxl_create_logfile(libxl_ctx *ctx, char *name, char **full_name)
241 {
242 libxl__gc gc = LIBXL_INIT_GC(ctx);
243 struct stat stat_buf;
244 char *logfile, *logfile_new;
245 int i, rc;
247 logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log", name);
248 if (stat(logfile, &stat_buf) == 0) {
249 /* file exists, rotate */
250 logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log.10", name);
251 unlink(logfile);
252 for (i = 9; i > 0; i--) {
253 logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log.%d", name, i);
254 logfile_new = libxl__sprintf(&gc, "/var/log/xen/%s.log.%d", name, i + 1);
255 rc = logrename(ctx, logfile, logfile_new);
256 if (rc)
257 goto out;
258 }
259 logfile = libxl__sprintf(&gc, "/var/log/xen/%s.log", name);
260 logfile_new = libxl__sprintf(&gc, "/var/log/xen/%s.log.1", name);
262 rc = logrename(ctx, logfile, logfile_new);
263 if (rc)
264 goto out;
265 } else {
266 if (errno != ENOENT)
267 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_WARNING, "problem checking existence of"
268 " logfile %s, which might have needed to be rotated",
269 name);
270 }
271 *full_name = strdup(logfile);
272 rc = 0;
273 out:
274 libxl__free_all(&gc);
275 return rc;
276 }
278 int libxl_string_to_phystype(libxl_ctx *ctx, char *s, libxl_disk_phystype *phystype)
279 {
280 char *p;
281 int rc = 0;
283 if (!strcmp(s, "phy")) {
284 *phystype = PHYSTYPE_PHY;
285 } else if (!strcmp(s, "file")) {
286 *phystype = PHYSTYPE_FILE;
287 } else if (!strcmp(s, "tap")) {
288 p = strchr(s, ':');
289 if (!p) {
290 rc = ERROR_INVAL;
291 goto out;
292 }
293 p++;
294 if (!strcmp(p, "aio")) {
295 *phystype = PHYSTYPE_AIO;
296 } else if (!strcmp(p, "vhd")) {
297 *phystype = PHYSTYPE_VHD;
298 } else if (!strcmp(p, "qcow")) {
299 *phystype = PHYSTYPE_QCOW;
300 } else if (!strcmp(p, "qcow2")) {
301 *phystype = PHYSTYPE_QCOW2;
302 }
303 }
304 out:
305 return rc;
306 }
308 int libxl_read_file_contents(libxl_ctx *ctx, const char *filename,
309 void **data_r, int *datalen_r) {
310 FILE *f = 0;
311 uint8_t *data = 0;
312 int datalen = 0;
313 int e;
314 struct stat stab;
315 ssize_t rs;
317 f = fopen(filename, "r");
318 if (!f) {
319 if (errno == ENOENT) return ENOENT;
320 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to open %s", filename);
321 goto xe;
322 }
324 if (fstat(fileno(f), &stab)) {
325 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to fstat %s", filename);
326 goto xe;
327 }
329 if (!S_ISREG(stab.st_mode)) {
330 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "%s is not a plain file", filename);
331 errno = ENOTTY;
332 goto xe;
333 }
335 if (stab.st_size > INT_MAX) {
336 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "file %s is far too large", filename);
337 errno = EFBIG;
338 goto xe;
339 }
341 datalen = stab.st_size;
343 if (stab.st_size && data_r) {
344 data = malloc(datalen);
345 if (!data) goto xe;
347 rs = fread(data, 1, datalen, f);
348 if (rs != datalen) {
349 if (ferror(f))
350 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to read %s", filename);
351 else if (feof(f))
352 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "%s changed size while we"
353 " were reading it", filename);
354 else
355 abort();
356 goto xe;
357 }
358 }
360 if (fclose(f)) {
361 f = 0;
362 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to close %s", filename);
363 goto xe;
364 }
366 if (data_r) *data_r = data;
367 if (datalen_r) *datalen_r = datalen;
369 return 0;
371 xe:
372 e = errno;
373 assert(e != ENOENT);
374 if (f) fclose(f);
375 if (data) free(data);
376 return e;
377 }
379 #define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata) \
380 \
381 int libxl_##rw##_exactly(libxl_ctx *ctx, int fd, \
382 constdata void *data, ssize_t sz, \
383 const char *filename, const char *what) { \
384 ssize_t got; \
385 \
386 while (sz > 0) { \
387 got = rw(fd, data, sz); \
388 if (got == -1) { \
389 if (errno == EINTR) continue; \
390 if (!ctx) return errno; \
391 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "failed to " #rw " %s%s%s", \
392 what?what:"", what?" from ":"", filename); \
393 return errno; \
394 } \
395 if (got == 0) { \
396 if (!ctx) return EPROTO; \
397 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, \
398 zero_is_eof \
399 ? "file/stream truncated reading %s%s%s" \
400 : "file/stream write returned 0! writing %s%s%s", \
401 what?what:"", what?" from ":"", filename); \
402 return EPROTO; \
403 } \
404 sz -= got; \
405 data = (char*)data + got; \
406 } \
407 return 0; \
408 }
410 READ_WRITE_EXACTLY(read, 1, /* */)
411 READ_WRITE_EXACTLY(write, 0, const)
414 int libxl_ctx_postfork(libxl_ctx *ctx) {
415 if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
416 ctx->xsh = xs_daemon_open();
417 if (!ctx->xsh) return ERROR_FAIL;
418 return 0;
419 }
421 pid_t libxl_fork(libxl_ctx *ctx)
422 {
423 pid_t pid;
425 pid = fork();
426 if (pid == -1) {
427 LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "fork failed");
428 return -1;
429 }
431 if (!pid) {
432 if (ctx->xsh) xs_daemon_destroy_postfork(ctx->xsh);
433 ctx->xsh = 0;
434 /* This ensures that anyone who forks but doesn't exec,
435 * and doesn't reinitialise the libxl_ctx, is OK.
436 * It also means they can safely call libxl_ctx_free. */
437 }
439 return pid;
440 }
442 int libxl_pipe(libxl_ctx *ctx, int pipes[2])
443 {
444 if (pipe(pipes) < 0) {
445 LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "Failed to create a pipe");
446 return -1;
447 }
448 return 0;
449 }
451 int libxl_mac_to_device_nic(libxl_ctx *ctx, uint32_t domid,
452 const char *mac, libxl_device_nic *nic)
453 {
454 libxl_nicinfo *nics;
455 unsigned int nb, i;
456 int found;
457 uint8_t mac_n[6];
458 uint8_t *a, *b;
459 const char *tok;
460 char *endptr;
462 nics = libxl_list_nics(ctx, domid, &nb);
463 if (!nics)
464 return ERROR_FAIL;
466 for (i = 0, tok = mac; *tok && (i < 6); ++i, tok += 3) {
467 mac_n[i] = strtol(tok, &endptr, 16);
468 if (endptr != (tok + 2))
469 return ERROR_INVAL;
470 }
471 memset(nic, 0, sizeof (libxl_device_nic));
472 found = 0;
473 for (i = 0; i < nb; ++i) {
474 for (i = 0, a = nics[i].mac, b = mac_n;
475 (b < mac_n + 6) && (*a == *b); ++a, ++b)
476 ;
477 if ((b >= mac_n + 6) && (*a == *b)) {
478 nic->backend_domid = nics[i].backend_id;
479 nic->domid = nics[i].frontend_id;
480 nic->devid = nics[i].devid;
481 memcpy(nic->mac, nics[i].mac, sizeof (nic->mac));
482 nic->script = strdup(nics[i].script);
483 found = 1;
484 break;
485 }
486 }
488 for (i=0; i<nb; i++)
489 libxl_nicinfo_destroy(&nics[i]);
490 free(nics);
491 return found;
492 }
494 int libxl_devid_to_device_nic(libxl_ctx *ctx, uint32_t domid,
495 const char *devid, libxl_device_nic *nic)
496 {
497 libxl__gc gc = LIBXL_INIT_GC(ctx);
498 char *tok, *val;
499 char *dompath, *nic_path_fe, *nic_path_be;
500 unsigned int i;
501 int rc = ERROR_FAIL;
503 memset(nic, 0, sizeof (libxl_device_nic));
504 dompath = libxl__xs_get_dompath(&gc, domid);
505 if (!dompath) {
506 goto out;
507 }
508 nic_path_fe = libxl__sprintf(&gc, "%s/device/vif/%s", dompath, devid);
509 nic_path_be = libxl__xs_read(&gc, XBT_NULL,
510 libxl__sprintf(&gc, "%s/backend", nic_path_fe));
511 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", nic_path_fe));
512 if ( NULL == val ) {
513 goto out;
514 }
515 nic->backend_domid = strtoul(val, NULL, 10);
516 nic->devid = strtoul(devid, NULL, 10);
518 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mac", nic_path_fe));
519 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
520 ++i, tok = strtok(NULL, ":")) {
521 nic->mac[i] = strtoul(tok, NULL, 16);
522 }
523 nic->script = xs_read(ctx->xsh, XBT_NULL, libxl__sprintf(&gc, "%s/script", nic_path_be), NULL);
524 rc = 0;
525 out:
526 libxl__free_all(&gc);
527 return rc;
528 }
530 int libxl_devid_to_device_disk(libxl_ctx *ctx, uint32_t domid,
531 const char *devid, libxl_device_disk *disk)
532 {
533 libxl__gc gc = LIBXL_INIT_GC(ctx);
534 char *endptr, *val;
535 char *dompath, *diskpath, *be_path;
536 unsigned int devid_n;
537 int rc = ERROR_INVAL;
539 devid_n = strtoul(devid, &endptr, 10);
540 if (devid == endptr) {
541 goto out;
542 }
543 rc = ERROR_FAIL;
544 dompath = libxl__xs_get_dompath(&gc, domid);
545 diskpath = libxl__sprintf(&gc, "%s/device/vbd/%s", dompath, devid);
546 if (!diskpath) {
547 goto out;
548 }
550 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", diskpath));
551 if (!val)
552 goto out;
553 disk->backend_domid = strtoul(val, NULL, 10);
554 disk->domid = domid;
555 be_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend", diskpath));
556 disk->physpath = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/params", be_path));
557 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/type", be_path));
558 libxl_string_to_phystype(ctx, val, &(disk->phystype));
559 disk->virtpath = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/dev", be_path));
560 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/removable", be_path));
561 disk->unpluggable = !strcmp(val, "1");
562 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mode", be_path));
563 disk->readwrite = !!strcmp(val, "w");
564 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/device-type", diskpath));
565 disk->is_cdrom = !strcmp(val, "cdrom");
566 rc = 0;
568 out:
569 libxl__free_all(&gc);
570 return rc;
571 }
573 int libxl_devid_to_device_net2(libxl_ctx *ctx, uint32_t domid,
574 const char *devid, libxl_device_net2 *net2)
575 {
576 libxl__gc gc = LIBXL_INIT_GC(ctx);
577 char *tok, *endptr, *val;
578 char *dompath, *net2path, *be_path;
579 unsigned int devid_n, i;
580 int rc = ERROR_INVAL;
582 devid_n = strtoul(devid, &endptr, 10);
583 if (devid == endptr) {
584 goto out;
585 }
586 rc = ERROR_FAIL;
587 dompath = libxl__xs_get_dompath(&gc, domid);
588 net2path = libxl__sprintf(&gc, "%s/device/vif2/%s", dompath, devid);
589 if (!net2path) {
590 goto out;
591 }
592 memset(net2, 0, sizeof (libxl_device_net2));
593 be_path = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend", net2path));
595 net2->devid = devid_n;
596 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/mac", net2path));
597 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
598 ++i, tok = strtok(NULL, ":")) {
599 net2->front_mac[i] = strtoul(tok, NULL, 16);
600 }
601 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/remote-mac", net2path));
602 for (i = 0, tok = strtok(val, ":"); tok && (i < 6);
603 ++i, tok = strtok(NULL, ":")) {
604 net2->back_mac[i] = strtoul(tok, NULL, 16);
605 }
606 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/backend-id", net2path));
607 net2->backend_domid = strtoul(val, NULL, 10);
609 net2->domid = domid;
610 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/remote-trusted", be_path));
611 net2->trusted = strtoul(val, NULL, 10);
612 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/local-trusted", be_path));
613 net2->back_trusted = strtoul(val, NULL, 10);
614 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/filter-mac", be_path));
615 net2->filter_mac = strtoul(val, NULL, 10);
616 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/filter-mac", net2path));
617 net2->front_filter_mac = strtoul(val, NULL, 10);
618 val = libxl__xs_read(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/max-bypasses", be_path));
619 net2->max_bypasses = strtoul(val, NULL, 10);
620 rc = 0;
622 out:
623 libxl__free_all(&gc);
624 return rc;
625 }
627 int libxl_strtomac(const char *mac_s, uint8_t *mac)
628 {
629 const char *end = mac_s + 17;
630 char val, *endptr;
632 for (; mac_s < end; mac_s += 3, ++mac) {
633 val = strtoul(mac_s, &endptr, 16);
634 if (endptr != (mac_s + 2)) {
635 return ERROR_INVAL;
636 }
637 *mac = val;
638 }
639 return 0;
640 }
642 #define QEMU_VERSION_STR "QEMU emulator version "
645 int libxl_check_device_model_version(libxl_ctx *ctx, char *path)
646 {
647 libxl__gc gc = LIBXL_INIT_GC(ctx);
648 pid_t pid = -1;
649 int pipefd[2];
650 char buf[100];
651 ssize_t i, count = 0;
652 int status;
653 char *abs_path = NULL;
654 int rc = -1;
656 abs_path = libxl__abs_path(&gc, path, libxl_private_bindir_path());
658 if (pipe(pipefd))
659 goto out;
661 pid = fork();
662 if (pid == -1) {
663 goto out;
664 }
666 if (!pid) {
667 close(pipefd[0]);
668 if (dup2(pipefd[1], STDOUT_FILENO) == -1)
669 exit(1);
670 execlp(abs_path, abs_path, "-h", NULL);
672 close(pipefd[1]);
673 exit(127);
674 }
676 close(pipefd[1]);
678 /* attempt to get the first line of `qemu -h` */
679 while ((i = read(pipefd[0], buf + count, 99 - count)) > 0) {
680 if (i + count > 90)
681 break;
682 for (int j = 0; j < i; j++) {
683 if (buf[j + count] == '\n')
684 break;
685 }
686 count += i;
687 }
688 count += i;
689 close(pipefd[0]);
690 waitpid(pid, &status, 0);
691 if (!WIFEXITED(status) || WEXITSTATUS(status) != 0) {
692 goto out;
693 }
695 /* Check if we have the forked qemu-xen. */
696 /* QEMU-DM emulator version 0.10.2, ... */
697 if (strncmp("QEMU-DM ", buf, 7) == 0) {
698 rc = 0;
699 goto out;
700 }
702 /* Check if the version is above 12.0 */
703 /* The first line is : QEMU emulator version 0.12.50, ... */
704 if (strncmp(QEMU_VERSION_STR, buf, strlen(QEMU_VERSION_STR)) == 0) {
705 int major, minor;
706 char *endptr = NULL;
707 char *v = buf + strlen(QEMU_VERSION_STR);
709 major = strtol(v, &endptr, 10);
710 if (major == 0 && endptr && *endptr == '.') {
711 v = endptr + 1;
712 minor = strtol(v, &endptr, 10);
713 if (minor >= 12) {
714 rc = 1;
715 goto out;
716 }
717 }
718 }
719 rc = 0;
720 out:
721 libxl__free_all(&gc);
722 return rc;
723 }
725 int libxl_cpumap_alloc(libxl_ctx *ctx, libxl_cpumap *cpumap)
726 {
727 int max_cpus;
728 int sz;
730 max_cpus = libxl_get_max_cpus(ctx);
731 if (max_cpus == 0)
732 return ERROR_FAIL;
734 sz = (max_cpus + 7) / 8;
735 cpumap->map = calloc(sz, sizeof(*cpumap->map));
736 if (!cpumap->map)
737 return ERROR_NOMEM;
738 cpumap->size = sz;
739 return 0;
740 }
742 void libxl_cpumap_destroy(libxl_cpumap *map)
743 {
744 free(map->map);
745 }
747 int libxl_cpumap_test(libxl_cpumap *cpumap, int cpu)
748 {
749 if (cpu >= cpumap->size * 8)
750 return 0;
751 return (cpumap->map[cpu / 8] & (1 << (cpu & 7))) ? 1 : 0;
752 }
754 void libxl_cpumap_set(libxl_cpumap *cpumap, int cpu)
755 {
756 if (cpu >= cpumap->size * 8)
757 return;
758 cpumap->map[cpu / 8] |= 1 << (cpu & 7);
759 }
761 void libxl_cpumap_reset(libxl_cpumap *cpumap, int cpu)
762 {
763 if (cpu >= cpumap->size * 8)
764 return;
765 cpumap->map[cpu / 8] &= ~(1 << (cpu & 7));
766 }
768 int libxl_cpuarray_alloc(libxl_ctx *ctx, libxl_cpuarray *cpuarray)
769 {
770 int max_cpus;
771 int i;
773 max_cpus = libxl_get_max_cpus(ctx);
774 if (max_cpus == 0)
775 return ERROR_FAIL;
777 cpuarray->array = calloc(max_cpus, sizeof(*cpuarray->array));
778 if (!cpuarray->array)
779 return ERROR_NOMEM;
780 cpuarray->entries = max_cpus;
781 for (i = 0; i < max_cpus; i++)
782 cpuarray->array[i] = LIBXL_CPUARRAY_INVALID_ENTRY;
784 return 0;
785 }
787 void libxl_cpuarray_destroy(libxl_cpuarray *array)
788 {
789 free(array->array);
790 }
792 int libxl_get_max_cpus(libxl_ctx *ctx)
793 {
794 return xc_get_max_cpus(ctx->xch);
795 }