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 */
15
16 #include "libxl_osdeps.h" /* must come before any other headers */
17
18 #include <ctype.h>
19
20 #include "libxl_internal.h"
21
22 #ifndef LIBXL_HAVE_NONCONST_LIBXL_BASENAME_RETURN_VALUE
23 const
24 #endif
libxl_basename(const char * name)25 char *libxl_basename(const char *name)
26 {
27 const char *filename;
28 if (name == NULL)
29 return strdup(".");
30 if (name[0] == '\0')
31 return strdup(".");
32
33 filename = strrchr(name, '/');
34 if (filename)
35 return strdup(filename+1);
36 return strdup(name);
37 }
38
libxl_get_required_shadow_memory(unsigned long maxmem_kb,unsigned int smp_cpus)39 unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus)
40 {
41 return libxl__get_required_paging_memory(maxmem_kb, smp_cpus,
42 LIBXL_DOMAIN_TYPE_INVALID, false);
43 }
44
libxl_domid_to_name(libxl_ctx * ctx,uint32_t domid)45 char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid)
46 {
47 unsigned int len;
48 char path[strlen("/local/domain") + 12];
49 char *s;
50
51 snprintf(path, sizeof(path), "/local/domain/%d/name", domid);
52 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
53 return s;
54 }
55
libxl__domid_to_name(libxl__gc * gc,uint32_t domid)56 char *libxl__domid_to_name(libxl__gc *gc, uint32_t domid)
57 {
58 char *s = libxl_domid_to_name(CTX, domid);
59 libxl__ptr_add(gc, s);
60 return s;
61 }
62
libxl_name_to_domid(libxl_ctx * ctx,const char * name,uint32_t * domid)63 int libxl_name_to_domid(libxl_ctx *ctx, const char *name,
64 uint32_t *domid)
65 {
66 int i, nb_domains;
67 char *domname;
68 libxl_dominfo *dominfo;
69 int ret = ERROR_INVAL;
70
71 dominfo = libxl_list_domain(ctx, &nb_domains);
72 if (!dominfo)
73 return ERROR_NOMEM;
74
75 for (i = 0; i < nb_domains; i++) {
76 domname = libxl_domid_to_name(ctx, dominfo[i].domid);
77 if (!domname)
78 continue;
79 if (strcmp(domname, name) == 0) {
80 *domid = dominfo[i].domid;
81 ret = 0;
82 free(domname);
83 break;
84 }
85 free(domname);
86 }
87 libxl_dominfo_list_free(dominfo, nb_domains);
88 return ret;
89 }
90
libxl_domain_qualifier_to_domid(libxl_ctx * ctx,const char * name,uint32_t * domid)91 int libxl_domain_qualifier_to_domid(libxl_ctx *ctx, const char *name,
92 uint32_t *domid)
93 {
94 int i, rv;
95 for (i=0; name[i]; i++) {
96 if (!CTYPE(isdigit, name[i])) {
97 goto nondigit_found;
98 }
99 }
100 *domid = strtoul(name, NULL, 10);
101 return 0;
102
103 nondigit_found:
104 /* this could also check for uuids */
105 rv = libxl_name_to_domid(ctx, name, domid);
106 return rv;
107 }
108
qualifier_to_id(const char * p,uint32_t * id_r)109 static int qualifier_to_id(const char *p, uint32_t *id_r)
110 {
111 int i, alldigit;
112
113 alldigit = 1;
114 for (i = 0; p[i]; i++) {
115 if (!isdigit((uint8_t)p[i])) {
116 alldigit = 0;
117 break;
118 }
119 }
120
121 if (i > 0 && alldigit) {
122 *id_r = strtoul(p, NULL, 10);
123 return 0;
124 } else {
125 /* check here if it's a uuid and do proper conversion */
126 }
127 return 1;
128 }
129
libxl_cpupool_qualifier_to_cpupoolid(libxl_ctx * ctx,const char * p,uint32_t * poolid_r,int * was_name_r)130 int libxl_cpupool_qualifier_to_cpupoolid(libxl_ctx *ctx, const char *p,
131 uint32_t *poolid_r,
132 int *was_name_r)
133 {
134 int was_name;
135
136 was_name = qualifier_to_id(p, poolid_r);
137 if (was_name_r) *was_name_r = was_name;
138 return was_name ? libxl_name_to_cpupoolid(ctx, p, poolid_r) : 0;
139 }
140
libxl_cpupoolid_to_name(libxl_ctx * ctx,uint32_t poolid)141 char *libxl_cpupoolid_to_name(libxl_ctx *ctx, uint32_t poolid)
142 {
143 unsigned int len;
144 char path[strlen("/local/pool") + 12];
145 char *s;
146
147 snprintf(path, sizeof(path), "/local/pool/%d/name", poolid);
148 s = xs_read(ctx->xsh, XBT_NULL, path, &len);
149
150 return s;
151 }
152
153 /* This is a bit horrid but without xs_exists it seems like the only way. */
libxl_cpupoolid_is_valid(libxl_ctx * ctx,uint32_t poolid)154 int libxl_cpupoolid_is_valid(libxl_ctx *ctx, uint32_t poolid)
155 {
156 int ret;
157 char *s = libxl_cpupoolid_to_name(ctx, poolid);
158
159 ret = (s != NULL);
160 free(s);
161 return ret;
162 }
163
libxl__cpupoolid_to_name(libxl__gc * gc,uint32_t poolid)164 char *libxl__cpupoolid_to_name(libxl__gc *gc, uint32_t poolid)
165 {
166 char *s = libxl_cpupoolid_to_name(CTX, poolid);
167 libxl__ptr_add(gc, s);
168 return s;
169 }
170
libxl_name_to_cpupoolid(libxl_ctx * ctx,const char * name,uint32_t * poolid)171 int libxl_name_to_cpupoolid(libxl_ctx *ctx, const char *name,
172 uint32_t *poolid)
173 {
174 int i, nb_pools;
175 char *poolname;
176 libxl_cpupoolinfo *poolinfo;
177 int ret = ERROR_INVAL;
178
179 poolinfo = libxl_list_cpupool(ctx, &nb_pools);
180 if (!poolinfo)
181 return ERROR_NOMEM;
182
183 for (i = 0; i < nb_pools; i++) {
184 if (ret && ((poolname = libxl_cpupoolid_to_name(ctx,
185 poolinfo[i].poolid)) != NULL)) {
186 if (strcmp(poolname, name) == 0) {
187 *poolid = poolinfo[i].poolid;
188 ret = 0;
189 }
190 free(poolname);
191 }
192 }
193 libxl_cpupoolinfo_list_free(poolinfo, nb_pools);
194 return ret;
195 }
196
libxl_get_stubdom_id(libxl_ctx * ctx,int guest_domid)197 int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid)
198 {
199 GC_INIT(ctx);
200 char * stubdom_id_s;
201 int ret;
202
203 stubdom_id_s = libxl__xs_read(gc, XBT_NULL,
204 GCSPRINTF("%s/image/device-model-domid",
205 libxl__xs_get_dompath(gc, guest_domid)));
206 if (stubdom_id_s)
207 ret = atoi(stubdom_id_s);
208 else
209 ret = 0;
210 GC_FREE;
211 return ret;
212 }
213
libxl_is_stubdom(libxl_ctx * ctx,uint32_t domid,uint32_t * target_domid)214 int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid)
215 {
216 GC_INIT(ctx);
217 char *target, *endptr;
218 uint32_t value;
219 int ret = 0;
220
221 target = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/target",
222 libxl__xs_get_dompath(gc, domid)));
223 if (!target)
224 goto out;
225 value = strtol(target, &endptr, 10);
226 if (*endptr != '\0')
227 goto out;
228 if (target_domid)
229 *target_domid = value;
230 ret = 1;
231 out:
232 GC_FREE;
233 return ret;
234 }
235
logrename(libxl__gc * gc,const char * old,const char * new)236 static int logrename(libxl__gc *gc, const char *old, const char *new)
237 {
238 int r;
239
240 r = rename(old, new);
241 if (r) {
242 if (errno == ENOENT) return 0; /* ok */
243
244 LOGE(ERROR, "failed to rotate logfile - "
245 "could not rename %s to %s", old, new);
246 return ERROR_FAIL;
247 }
248 return 0;
249 }
250
libxl_create_logfile(libxl_ctx * ctx,const char * name,char ** full_name)251 int libxl_create_logfile(libxl_ctx *ctx, const char *name, char **full_name)
252 {
253 GC_INIT(ctx);
254 struct stat stat_buf;
255 char *logfile, *logfile_new;
256 int i, rc;
257
258 logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log", name);
259 if (stat(logfile, &stat_buf) == 0) {
260 /* file exists, rotate */
261 logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log.10", name);
262 unlink(logfile);
263 for (i = 9; i > 0; i--) {
264 logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log.%d", name, i);
265 logfile_new = GCSPRINTF(XEN_LOG_DIR "/%s.log.%d", name, i + 1);
266 rc = logrename(gc, logfile, logfile_new);
267 if (rc)
268 goto out;
269 }
270 logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log", name);
271 logfile_new = GCSPRINTF(XEN_LOG_DIR "/%s.log.1", name);
272
273 rc = logrename(gc, logfile, logfile_new);
274 if (rc)
275 goto out;
276 } else {
277 if (errno != ENOENT)
278 LOGE(WARN, "problem checking existence of logfile %s, "
279 "which might have needed to be rotated",
280 name);
281 }
282 *full_name = strdup(logfile);
283 rc = 0;
284 out:
285 GC_FREE;
286 return rc;
287 }
288
libxl_string_to_backend(libxl_ctx * ctx,char * s,libxl_disk_backend * backend)289 int libxl_string_to_backend(libxl_ctx *ctx, char *s, libxl_disk_backend *backend)
290 {
291 char *p;
292 int rc = 0;
293
294 if (!strcmp(s, "phy")) {
295 *backend = LIBXL_DISK_BACKEND_PHY;
296 } else if (!strcmp(s, "file")) {
297 *backend = LIBXL_DISK_BACKEND_TAP;
298 } else if (!strcmp(s, "vbd3")) {
299 *backend = LIBXL_DISK_BACKEND_TAP;
300 } else if (!strcmp(s, "qdisk")) {
301 *backend = LIBXL_DISK_BACKEND_QDISK;
302 } else if (!strcmp(s, "standalone")) {
303 *backend = LIBXL_DISK_BACKEND_STANDALONE;
304 } else if (!strcmp(s, "tap")) {
305 p = strchr(s, ':');
306 if (!p) {
307 rc = ERROR_INVAL;
308 goto out;
309 }
310 p++;
311 if (!strcmp(p, "vhd")) {
312 *backend = LIBXL_DISK_BACKEND_TAP;
313 } else if (!strcmp(p, "qcow")) {
314 *backend = LIBXL_DISK_BACKEND_QDISK;
315 } else if (!strcmp(p, "qcow2")) {
316 *backend = LIBXL_DISK_BACKEND_QDISK;
317 } else if (!strcmp(p, "qed")) {
318 *backend = LIBXL_DISK_BACKEND_QDISK;
319 }
320 }
321 out:
322 return rc;
323 }
324
libxl_read_file_contents(libxl_ctx * ctx,const char * filename,void ** data_r,int * datalen_r)325 int libxl_read_file_contents(libxl_ctx *ctx, const char *filename,
326 void **data_r, int *datalen_r) {
327 GC_INIT(ctx);
328 FILE *f = 0;
329 uint8_t *data = 0;
330 int datalen = 0;
331 int e;
332 struct stat stab;
333 ssize_t rs;
334
335 f = fopen(filename, "r");
336 if (!f) {
337 if (errno == ENOENT) return ENOENT;
338 LOGE(ERROR, "failed to open %s", filename);
339 goto xe;
340 }
341
342 if (fstat(fileno(f), &stab)) {
343 LOGE(ERROR, "failed to fstat %s", filename);
344 goto xe;
345 }
346
347 if (!S_ISREG(stab.st_mode)) {
348 LOGE(ERROR, "%s is not a plain file", filename);
349 errno = ENOTTY;
350 goto xe;
351 }
352
353 if (stab.st_size > INT_MAX) {
354 LOG(ERROR, "file %s is far too large", filename);
355 errno = EFBIG;
356 goto xe;
357 }
358
359 datalen = stab.st_size;
360
361 if (stab.st_size && data_r) {
362 data = malloc(datalen);
363 if (!data) goto xe;
364
365 rs = fread(data, 1, datalen, f);
366 if (rs != datalen) {
367 if (ferror(f))
368 LOGE(ERROR, "failed to read %s", filename);
369 else if (feof(f))
370 LOG(ERROR, "%s changed size while we were reading it",
371 filename);
372 else
373 abort();
374 goto xe;
375 }
376 }
377
378 if (fclose(f)) {
379 f = 0;
380 LOGE(ERROR, "failed to close %s", filename);
381 goto xe;
382 }
383
384 if (data_r) *data_r = data;
385 if (datalen_r) *datalen_r = datalen;
386
387 GC_FREE;
388 return 0;
389
390 xe:
391 GC_FREE;
392 e = errno;
393 assert(e != ENOENT);
394 if (f) fclose(f);
395 free(data);
396 return e;
397 }
398
libxl__read_sysfs_file_contents(libxl__gc * gc,const char * filename,void ** data_r,int * datalen_r)399 int libxl__read_sysfs_file_contents(libxl__gc *gc, const char *filename,
400 void **data_r, int *datalen_r)
401 {
402 FILE *f = 0;
403 uint8_t *data = 0;
404 int datalen = 0;
405 int e;
406 struct stat stab;
407 ssize_t rs;
408
409 f = fopen(filename, "r");
410 if (!f) {
411 if (errno == ENOENT) return ENOENT;
412 LOGE(ERROR, "failed to open %s", filename);
413 goto xe;
414 }
415
416 if (fstat(fileno(f), &stab)) {
417 LOGE(ERROR, "failed to fstat %s", filename);
418 goto xe;
419 }
420
421 if (!S_ISREG(stab.st_mode)) {
422 LOGE(ERROR, "%s is not a plain file", filename);
423 errno = ENOTTY;
424 goto xe;
425 }
426
427 if (stab.st_size > INT_MAX) {
428 LOG(ERROR, "file %s is far too large", filename);
429 errno = EFBIG;
430 goto xe;
431 }
432
433 datalen = stab.st_size;
434
435 if (stab.st_size && data_r) {
436 data = libxl__malloc(gc, datalen);
437
438 /* For sysfs file, datalen is always PAGE_SIZE. 'read'
439 * will return the number of bytes of the actual content,
440 * rs <= datalen is expected.
441 */
442 rs = fread(data, 1, datalen, f);
443 if (rs < datalen) {
444 if (ferror(f)) {
445 LOGE(ERROR, "failed to read %s", filename);
446 goto xe;
447 }
448
449 datalen = rs;
450 data = libxl__realloc(gc, data, datalen);
451 }
452 }
453
454 if (fclose(f)) {
455 f = 0;
456 LOGE(ERROR, "failed to close %s", filename);
457 goto xe;
458 }
459
460 if (data_r) *data_r = data;
461 if (datalen_r) *datalen_r = datalen;
462
463 return 0;
464
465 xe:
466 e = errno;
467 assert(e != ENOENT);
468 if (f) fclose(f);
469 return e;
470 }
471
472
473 #define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata) \
474 \
475 int libxl_##rw##_exactly(libxl_ctx *ctx, int fd, \
476 constdata void *data, ssize_t sz, \
477 const char *source, const char *what) { \
478 ssize_t got; \
479 GC_INIT(ctx); \
480 \
481 while (sz > 0) { \
482 got = rw(fd, data, sz); \
483 if (got == -1) { \
484 if (errno == EINTR) continue; \
485 if (!ctx) { GC_FREE; return errno; } \
486 LOGE(ERROR, "failed to "#rw" %s%s%s", \
487 what ? what : "", what ? " from " : "", source); \
488 GC_FREE; \
489 return errno; \
490 } \
491 if (got == 0) { \
492 if (!ctx) { GC_FREE; return EPROTO; } \
493 LOG(ERROR, zero_is_eof \
494 ? "file/stream truncated reading %s%s%s" \
495 : "file/stream write returned 0! writing %s%s%s", \
496 what ? what : "", what ? " from " : "", source); \
497 GC_FREE; \
498 return EPROTO; \
499 } \
500 sz -= got; \
501 data = (char*)data + got; \
502 } \
503 GC_FREE; \
504 return 0; \
505 }
506
507 READ_WRITE_EXACTLY(read, 1, /* */)
508 READ_WRITE_EXACTLY(write, 0, const)
509
libxl__remove_file(libxl__gc * gc,const char * path)510 int libxl__remove_file(libxl__gc *gc, const char *path)
511 {
512 for (;;) {
513 int r = unlink(path);
514 if (!r) return 0;
515 if (errno == ENOENT) return 0;
516 if (errno == EINTR) continue;
517 LOGE(ERROR, "failed to remove file %s", path);
518 return ERROR_FAIL;
519 }
520 }
521
libxl__remove_file_or_directory(libxl__gc * gc,const char * path)522 int libxl__remove_file_or_directory(libxl__gc *gc, const char *path)
523 {
524 for (;;) {
525 int r = rmdir(path);
526 if (!r) return 0;
527 if (errno == ENOENT) return 0;
528 if (errno == ENOTEMPTY) return libxl__remove_directory(gc, path);
529 if (errno == ENOTDIR) return libxl__remove_file(gc, path);
530 if (errno == EINTR) continue;
531 LOGE(ERROR, "failed to remove %s", path);
532 return ERROR_FAIL;
533 }
534 }
535
libxl__remove_directory(libxl__gc * gc,const char * dirpath)536 int libxl__remove_directory(libxl__gc *gc, const char *dirpath)
537 {
538 int rc = 0;
539 DIR *d = 0;
540
541 d = opendir(dirpath);
542 if (!d) {
543 if (errno == ENOENT)
544 goto out;
545
546 LOGE(ERROR, "failed to opendir %s for removal", dirpath);
547 rc = ERROR_FAIL;
548 goto out;
549 }
550
551 struct dirent *de;
552
553 for (;;) {
554 errno = 0;
555 de = readdir(d);
556 if (!de && errno) {
557 LOGE(ERROR, "failed to readdir %s for removal", dirpath);
558 rc = ERROR_FAIL;
559 break;
560 }
561 if (!de)
562 break;
563
564 if (!strcmp(de->d_name, ".") ||
565 !strcmp(de->d_name, ".."))
566 continue;
567
568 const char *subpath = GCSPRINTF("%s/%s", dirpath, de->d_name);
569 if (libxl__remove_file_or_directory(gc, subpath))
570 rc = ERROR_FAIL;
571 }
572
573 for (;;) {
574 int r = rmdir(dirpath);
575 if (!r) break;
576 if (errno == ENOENT) goto out;
577 if (errno == EINTR) continue;
578 LOGE(ERROR, "failed to remove emptied directory %s", dirpath);
579 rc = ERROR_FAIL;
580 }
581
582 out:
583 if (d) closedir(d);
584
585 return rc;
586 }
587
libxl_pipe(libxl_ctx * ctx,int pipes[2])588 int libxl_pipe(libxl_ctx *ctx, int pipes[2])
589 {
590 GC_INIT(ctx);
591 int ret = 0;
592 if (pipe(pipes) < 0) {
593 LOG(ERROR, "Failed to create a pipe");
594 ret = -1;
595 }
596 GC_FREE;
597 return ret;
598 }
599
libxl_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * bitmap,int n_bits)600 int libxl_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *bitmap, int n_bits)
601 {
602 GC_INIT(ctx);
603 int sz;
604
605 sz = (n_bits + 7) / 8;
606 bitmap->map = libxl__calloc(NOGC, sizeof(*bitmap->map), sz);
607 bitmap->size = sz;
608
609 GC_FREE;
610 return 0;
611 }
612
libxl_bitmap_init(libxl_bitmap * map)613 void libxl_bitmap_init(libxl_bitmap *map)
614 {
615 memset(map, '\0', sizeof(*map));
616 }
617
libxl_bitmap_dispose(libxl_bitmap * map)618 void libxl_bitmap_dispose(libxl_bitmap *map)
619 {
620 if (!map)
621 return;
622
623 free(map->map);
624 map->map = NULL;
625 map->size = 0;
626 }
627
libxl_bitmap_copy(libxl_ctx * ctx,libxl_bitmap * dptr,const libxl_bitmap * sptr)628 void libxl_bitmap_copy(libxl_ctx *ctx, libxl_bitmap *dptr,
629 const libxl_bitmap *sptr)
630 {
631 int sz;
632
633 assert(dptr->size == sptr->size);
634 sz = dptr->size = sptr->size;
635 memcpy(dptr->map, sptr->map, sz * sizeof(*dptr->map));
636 }
637
638 /* This function copies X bytes from source to destination bitmap,
639 * where X is the smaller of the two sizes.
640 *
641 * If destination's size is larger than source, the extra bytes are
642 * untouched.
643 */
libxl__bitmap_copy_best_effort(libxl__gc * gc,libxl_bitmap * dptr,const libxl_bitmap * sptr)644 void libxl__bitmap_copy_best_effort(libxl__gc *gc, libxl_bitmap *dptr,
645 const libxl_bitmap *sptr)
646 {
647 int sz;
648
649 sz = dptr->size < sptr->size ? dptr->size : sptr->size;
650 memcpy(dptr->map, sptr->map, sz * sizeof(*dptr->map));
651 }
652
libxl_bitmap_copy_alloc(libxl_ctx * ctx,libxl_bitmap * dptr,const libxl_bitmap * sptr)653 void libxl_bitmap_copy_alloc(libxl_ctx *ctx,
654 libxl_bitmap *dptr,
655 const libxl_bitmap *sptr)
656 {
657 GC_INIT(ctx);
658
659 dptr->map = libxl__calloc(NOGC, sptr->size, sizeof(*sptr->map));
660 dptr->size = sptr->size;
661 memcpy(dptr->map, sptr->map, sptr->size * sizeof(*sptr->map));
662
663 GC_FREE;
664 }
665
libxl_bitmap_is_full(const libxl_bitmap * bitmap)666 int libxl_bitmap_is_full(const libxl_bitmap *bitmap)
667 {
668 int i;
669
670 for (i = 0; i < bitmap->size; i++)
671 if (bitmap->map[i] != (uint8_t)-1)
672 return 0;
673 return 1;
674 }
675
libxl_bitmap_is_empty(const libxl_bitmap * bitmap)676 int libxl_bitmap_is_empty(const libxl_bitmap *bitmap)
677 {
678 int i;
679
680 for (i = 0; i < bitmap->size; i++)
681 if (bitmap->map[i])
682 return 0;
683 return 1;
684 }
685
libxl_bitmap_test(const libxl_bitmap * bitmap,int bit)686 int libxl_bitmap_test(const libxl_bitmap *bitmap, int bit)
687 {
688 if (bit >= bitmap->size * 8 || bit < 0)
689 return 0;
690 return (bitmap->map[bit / 8] & (1 << (bit & 7))) ? 1 : 0;
691 }
692
libxl_bitmap_set(libxl_bitmap * bitmap,int bit)693 void libxl_bitmap_set(libxl_bitmap *bitmap, int bit)
694 {
695 if (bit >= bitmap->size * 8 || bit < 0)
696 return;
697 bitmap->map[bit / 8] |= 1 << (bit & 7);
698 }
699
libxl_bitmap_reset(libxl_bitmap * bitmap,int bit)700 void libxl_bitmap_reset(libxl_bitmap *bitmap, int bit)
701 {
702 if (bit >= bitmap->size * 8 || bit < 0)
703 return;
704 bitmap->map[bit / 8] &= ~(1 << (bit & 7));
705 }
706
libxl_bitmap_or(libxl_ctx * ctx,libxl_bitmap * or_map,const libxl_bitmap * map1,const libxl_bitmap * map2)707 int libxl_bitmap_or(libxl_ctx *ctx, libxl_bitmap *or_map,
708 const libxl_bitmap *map1, const libxl_bitmap *map2)
709 {
710 GC_INIT(ctx);
711 int rc;
712 uint32_t i;
713 const libxl_bitmap *large_map;
714 const libxl_bitmap *small_map;
715
716 if (map1->size > map2->size) {
717 large_map = map1;
718 small_map = map2;
719 } else {
720 large_map = map2;
721 small_map = map1;
722 }
723
724 rc = libxl_bitmap_alloc(ctx, or_map, large_map->size * 8);
725 if (rc)
726 goto out;
727
728 /*
729 * If bitmaps aren't the same size, their union (logical or) will
730 * be size of larger bit map. Any bit past the end of the
731 * smaller bit map, will match the larger one.
732 */
733 for (i = 0; i < small_map->size; i++)
734 or_map->map[i] = (small_map->map[i] | large_map->map[i]);
735
736 for (i = small_map->size; i < large_map->size; i++)
737 or_map->map[i] = large_map->map[i];
738
739 out:
740 GC_FREE;
741 return rc;
742 }
743
libxl_bitmap_and(libxl_ctx * ctx,libxl_bitmap * and_map,const libxl_bitmap * map1,const libxl_bitmap * map2)744 int libxl_bitmap_and(libxl_ctx *ctx, libxl_bitmap *and_map,
745 const libxl_bitmap *map1, const libxl_bitmap *map2)
746 {
747 GC_INIT(ctx);
748 int rc;
749 uint32_t i;
750 const libxl_bitmap *large_map;
751 const libxl_bitmap *small_map;
752
753 if (map1->size > map2->size) {
754 large_map = map1;
755 small_map = map2;
756 } else {
757 large_map = map2;
758 small_map = map1;
759 }
760
761 rc = libxl_bitmap_alloc(ctx, and_map, small_map->size * 8);
762 if (rc)
763 goto out;
764
765 /*
766 * If bitmaps aren't same size, their 'and' will be size of
767 * smaller bit map
768 */
769 for (i = 0; i < and_map->size; i++)
770 and_map->map[i] = (large_map->map[i] & small_map->map[i]);
771
772 out:
773 GC_FREE;
774 return rc;
775 }
776
libxl_bitmap_count_set(const libxl_bitmap * bitmap)777 int libxl_bitmap_count_set(const libxl_bitmap *bitmap)
778 {
779 int i, nr_set_bits = 0;
780 libxl_for_each_set_bit(i, *bitmap)
781 nr_set_bits++;
782
783 return nr_set_bits;
784 }
785
786 /* NB. caller is responsible for freeing the memory */
libxl_bitmap_to_hex_string(libxl_ctx * ctx,const libxl_bitmap * bitmap)787 char *libxl_bitmap_to_hex_string(libxl_ctx *ctx, const libxl_bitmap *bitmap)
788 {
789 GC_INIT(ctx);
790 int i = bitmap->size;
791 char *p = libxl__zalloc(NOGC, bitmap->size * 2 + 3);
792 char *q = p;
793 strncpy(p, "0x", 3);
794 p += 2;
795 while(--i >= 0) {
796 sprintf(p, "%02x", bitmap->map[i]);
797 p += 2;
798 }
799 *p = '\0';
800 GC_FREE;
801 return q;
802 }
803
libxl_cpu_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * cpumap,int max_cpus)804 int libxl_cpu_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *cpumap, int max_cpus)
805 {
806 GC_INIT(ctx);
807 int rc = 0;
808
809 if (max_cpus < 0) {
810 rc = ERROR_INVAL;
811 LOG(ERROR, "invalid number of cpus provided");
812 goto out;
813 }
814 if (max_cpus == 0)
815 max_cpus = libxl_get_max_cpus(ctx);
816 if (max_cpus < 0) {
817 LOG(ERROR, "failed to retrieve the maximum number of cpus");
818 rc = max_cpus;
819 goto out;
820 }
821 /* This can't fail: no need to check and log */
822 libxl_bitmap_alloc(ctx, cpumap, max_cpus);
823
824 out:
825 GC_FREE;
826 return rc;
827 }
828
libxl_node_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * nodemap,int max_nodes)829 int libxl_node_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *nodemap,
830 int max_nodes)
831 {
832 GC_INIT(ctx);
833 int rc = 0;
834
835 if (max_nodes < 0) {
836 rc = ERROR_INVAL;
837 LOG(ERROR, "invalid number of nodes provided");
838 goto out;
839 }
840
841 if (max_nodes == 0)
842 max_nodes = libxl_get_max_nodes(ctx);
843 if (max_nodes < 0) {
844 LOG(ERROR, "failed to retrieve the maximum number of nodes");
845 rc = max_nodes;
846 goto out;
847 }
848 /* This can't fail: no need to check and log */
849 libxl_bitmap_alloc(ctx, nodemap, max_nodes);
850
851 out:
852 GC_FREE;
853 return rc;
854 }
855
libxl__count_physical_sockets(libxl__gc * gc,int * sockets)856 int libxl__count_physical_sockets(libxl__gc *gc, int *sockets)
857 {
858 int rc;
859 libxl_physinfo info;
860
861 libxl_physinfo_init(&info);
862
863 rc = libxl_get_physinfo(CTX, &info);
864 if (rc)
865 return rc;
866
867 *sockets = info.nr_cpus / info.threads_per_core
868 / info.cores_per_socket;
869
870 libxl_physinfo_dispose(&info);
871 return 0;
872 }
873
libxl_socket_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * socketmap,int max_sockets)874 int libxl_socket_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *socketmap,
875 int max_sockets)
876 {
877 GC_INIT(ctx);
878 int rc = 0;
879
880 if (max_sockets < 0) {
881 rc = ERROR_INVAL;
882 LOG(ERROR, "invalid number of sockets provided");
883 goto out;
884 }
885
886 if (max_sockets == 0) {
887 rc = libxl__count_physical_sockets(gc, &max_sockets);
888 if (rc) {
889 LOGE(ERROR, "failed to get system socket count");
890 goto out;
891 }
892 }
893 /* This can't fail: no need to check and log */
894 libxl_bitmap_alloc(ctx, socketmap, max_sockets);
895
896 out:
897 GC_FREE;
898 return rc;
899
900 }
901
libxl_get_online_socketmap(libxl_ctx * ctx,libxl_bitmap * socketmap)902 int libxl_get_online_socketmap(libxl_ctx *ctx, libxl_bitmap *socketmap)
903 {
904 libxl_cputopology *tinfo = NULL;
905 int nr_cpus = 0, i, rc = 0;
906
907 tinfo = libxl_get_cpu_topology(ctx, &nr_cpus);
908 if (tinfo == NULL) {
909 rc = ERROR_FAIL;
910 goto out;
911 }
912
913 libxl_bitmap_set_none(socketmap);
914 for (i = 0; i < nr_cpus; i++)
915 if (tinfo[i].socket != XEN_INVALID_SOCKET_ID
916 && !libxl_bitmap_test(socketmap, tinfo[i].socket))
917 libxl_bitmap_set(socketmap, tinfo[i].socket);
918
919 out:
920 libxl_cputopology_list_free(tinfo, nr_cpus);
921 return rc;
922 }
923
libxl_nodemap_to_cpumap(libxl_ctx * ctx,const libxl_bitmap * nodemap,libxl_bitmap * cpumap)924 int libxl_nodemap_to_cpumap(libxl_ctx *ctx,
925 const libxl_bitmap *nodemap,
926 libxl_bitmap *cpumap)
927 {
928 libxl_cputopology *tinfo = NULL;
929 int nr_cpus = 0, i, rc = 0;
930
931 tinfo = libxl_get_cpu_topology(ctx, &nr_cpus);
932 if (tinfo == NULL) {
933 rc = ERROR_FAIL;
934 goto out;
935 }
936
937 libxl_bitmap_set_none(cpumap);
938 for (i = 0; i < nr_cpus; i++) {
939 if (libxl_bitmap_test(nodemap, tinfo[i].node))
940 libxl_bitmap_set(cpumap, i);
941 }
942 out:
943 libxl_cputopology_list_free(tinfo, nr_cpus);
944 return rc;
945 }
946
libxl_node_to_cpumap(libxl_ctx * ctx,int node,libxl_bitmap * cpumap)947 int libxl_node_to_cpumap(libxl_ctx *ctx, int node,
948 libxl_bitmap *cpumap)
949 {
950 libxl_bitmap nodemap;
951 int rc = 0;
952
953 libxl_bitmap_init(&nodemap);
954
955 rc = libxl_node_bitmap_alloc(ctx, &nodemap, 0);
956 if (rc)
957 goto out;
958
959 libxl_bitmap_set_none(&nodemap);
960 libxl_bitmap_set(&nodemap, node);
961
962 rc = libxl_nodemap_to_cpumap(ctx, &nodemap, cpumap);
963
964 out:
965 libxl_bitmap_dispose(&nodemap);
966 return rc;
967 }
968
libxl_cpumap_to_nodemap(libxl_ctx * ctx,const libxl_bitmap * cpumap,libxl_bitmap * nodemap)969 int libxl_cpumap_to_nodemap(libxl_ctx *ctx,
970 const libxl_bitmap *cpumap,
971 libxl_bitmap *nodemap)
972 {
973 libxl_cputopology *tinfo = NULL;
974 int nr_cpus = 0, i, rc = 0;
975
976 tinfo = libxl_get_cpu_topology(ctx, &nr_cpus);
977 if (tinfo == NULL) {
978 rc = ERROR_FAIL;
979 goto out;
980 }
981
982 libxl_bitmap_set_none(nodemap);
983 libxl_for_each_set_bit(i, *cpumap) {
984 if (i >= nr_cpus)
985 break;
986 libxl_bitmap_set(nodemap, tinfo[i].node);
987 }
988 out:
989 libxl_cputopology_list_free(tinfo, nr_cpus);
990 return rc;
991 }
992
libxl_get_max_cpus(libxl_ctx * ctx)993 int libxl_get_max_cpus(libxl_ctx *ctx)
994 {
995 int max_cpus = xc_get_max_cpus(ctx->xch);
996
997 return max_cpus < 0 ? ERROR_FAIL : max_cpus;
998 }
999
libxl_get_online_cpus(libxl_ctx * ctx)1000 int libxl_get_online_cpus(libxl_ctx *ctx)
1001 {
1002 int online_cpus = xc_get_online_cpus(ctx->xch);
1003
1004 return online_cpus < 0 ? ERROR_FAIL : online_cpus;
1005 }
1006
libxl_get_max_nodes(libxl_ctx * ctx)1007 int libxl_get_max_nodes(libxl_ctx *ctx)
1008 {
1009 int max_nodes = xc_get_max_nodes(ctx->xch);
1010
1011 return max_nodes < 0 ? ERROR_FAIL : max_nodes;
1012 }
1013
libxl__enum_from_string(const libxl_enum_string_table * t,const char * s,int * e)1014 int libxl__enum_from_string(const libxl_enum_string_table *t,
1015 const char *s, int *e)
1016 {
1017 if (!t) return ERROR_INVAL;
1018
1019 for( ; t->s; t++) {
1020 if (!strcasecmp(t->s, s)) {
1021 *e = t->v;
1022 return 0;
1023 }
1024 }
1025 return ERROR_FAIL;
1026 }
1027
libxl_cputopology_list_free(libxl_cputopology * list,int nr)1028 void libxl_cputopology_list_free(libxl_cputopology *list, int nr)
1029 {
1030 int i;
1031 for (i = 0; i < nr; i++)
1032 libxl_cputopology_dispose(&list[i]);
1033 free(list);
1034 }
1035
libxl_pcitopology_list_free(libxl_pcitopology * list,int nr)1036 void libxl_pcitopology_list_free(libxl_pcitopology *list, int nr)
1037 {
1038 int i;
1039 for (i = 0; i < nr; i++)
1040 libxl_pcitopology_dispose(&list[i]);
1041 free(list);
1042 }
1043
libxl_numainfo_list_free(libxl_numainfo * list,int nr)1044 void libxl_numainfo_list_free(libxl_numainfo *list, int nr)
1045 {
1046 int i;
1047 for (i = 0; i < nr; i++)
1048 libxl_numainfo_dispose(&list[i]);
1049 free(list);
1050 }
1051
libxl_vcpuinfo_list_free(libxl_vcpuinfo * list,int nr)1052 void libxl_vcpuinfo_list_free(libxl_vcpuinfo *list, int nr)
1053 {
1054 int i;
1055 for (i = 0; i < nr; i++)
1056 libxl_vcpuinfo_dispose(&list[i]);
1057 free(list);
1058 }
1059
libxl__sendmsg_fds(libxl__gc * gc,int carrier,const char data,int nfds,const int fds[],const char * what)1060 int libxl__sendmsg_fds(libxl__gc *gc, int carrier,
1061 const char data,
1062 int nfds, const int fds[], const char *what) {
1063 struct msghdr msg = { 0 };
1064 struct cmsghdr *cmsg;
1065 size_t spaceneeded = nfds * sizeof(fds[0]);
1066 char control[CMSG_SPACE(spaceneeded)];
1067 const size_t datalen = 1;
1068 struct iovec iov;
1069 int r;
1070
1071 iov.iov_base = (void*)&data;
1072 iov.iov_len = datalen;
1073
1074 /* compose the message */
1075 msg.msg_iov = &iov;
1076 msg.msg_iovlen = 1;
1077 msg.msg_control = control;
1078 msg.msg_controllen = sizeof(control);
1079
1080 /* attach open fd */
1081 cmsg = CMSG_FIRSTHDR(&msg);
1082 cmsg->cmsg_level = SOL_SOCKET;
1083 cmsg->cmsg_type = SCM_RIGHTS;
1084 cmsg->cmsg_len = CMSG_LEN(spaceneeded);
1085 memcpy(CMSG_DATA(cmsg), fds, spaceneeded);
1086
1087 msg.msg_controllen = cmsg->cmsg_len;
1088
1089 while (1) {
1090 r = sendmsg(carrier, &msg, 0);
1091 if (r < 0) {
1092 if (errno == EINTR)
1093 continue;
1094 if (errno == EWOULDBLOCK) {
1095 return ERROR_NOT_READY;
1096 }
1097 LOGE(ERROR, "failed to send fd-carrying message (%s)", what);
1098 return ERROR_FAIL;
1099 }
1100 if (r != datalen) {
1101 LOG(ERROR, "sendmsg have written %d instead of %zu",
1102 r, datalen);
1103 return ERROR_FAIL;
1104 }
1105 break;
1106 };
1107
1108 return 0;
1109 }
1110
libxl__recvmsg_fds(libxl__gc * gc,int carrier,void * databuf,size_t datalen,int nfds,int fds[],const char * what)1111 int libxl__recvmsg_fds(libxl__gc *gc, int carrier,
1112 void *databuf, size_t datalen,
1113 int nfds, int fds[], const char *what)
1114 {
1115 struct msghdr msg = { 0 };
1116 struct cmsghdr *cmsg;
1117 size_t spaceneeded = nfds * sizeof(fds[0]);
1118 char control[CMSG_SPACE(spaceneeded)];
1119 struct iovec iov;
1120 int r;
1121
1122 iov.iov_base = databuf;
1123 iov.iov_len = datalen;
1124
1125 msg.msg_iov = &iov;
1126 msg.msg_iovlen = 1;
1127 msg.msg_control = control;
1128 msg.msg_controllen = sizeof(control);
1129
1130 for (;;) {
1131 r = recvmsg(carrier, &msg, 0);
1132 if (r < 0) {
1133 if (errno == EINTR) continue;
1134 if (errno == EWOULDBLOCK) return -1;
1135 LOGE(ERROR,"recvmsg failed (%s)", what);
1136 return ERROR_FAIL;
1137 }
1138 if (r == 0) {
1139 LOG(ERROR,"recvmsg got EOF (%s)", what);
1140 return ERROR_FAIL;
1141 }
1142 cmsg = CMSG_FIRSTHDR(&msg);
1143 if (cmsg->cmsg_len <= CMSG_LEN(0)) {
1144 LOG(ERROR,"recvmsg got no control msg"
1145 " when expecting fds (%s)", what);
1146 return ERROR_FAIL;
1147 }
1148 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
1149 LOG(ERROR, "recvmsg got unexpected"
1150 " cmsg_level %d (!=%d) or _type %d (!=%d) (%s)",
1151 cmsg->cmsg_level, SOL_SOCKET,
1152 cmsg->cmsg_type, SCM_RIGHTS,
1153 what);
1154 return ERROR_FAIL;
1155 }
1156 if (cmsg->cmsg_len != CMSG_LEN(spaceneeded) ||
1157 msg.msg_controllen != cmsg->cmsg_len) {
1158 LOG(ERROR, "recvmsg got unexpected"
1159 " number of fds or extra control data"
1160 " (%ld bytes' worth, expected %ld) (%s)",
1161 (long)CMSG_LEN(spaceneeded), (long)cmsg->cmsg_len,
1162 what);
1163 int i, fd;
1164 unsigned char *p;
1165 for (i=0, p=CMSG_DATA(cmsg);
1166 CMSG_SPACE(i * sizeof(fds[0]));
1167 i++, i+=sizeof(fd)) {
1168 memcpy(&fd, p, sizeof(fd));
1169 close(fd);
1170 }
1171 return ERROR_FAIL;
1172 }
1173 memcpy(fds, CMSG_DATA(cmsg), spaceneeded);
1174 return 0;
1175 }
1176 }
1177
libxl_dominfo_list_free(libxl_dominfo * list,int nr)1178 void libxl_dominfo_list_free(libxl_dominfo *list, int nr)
1179 {
1180 int i;
1181 for (i = 0; i < nr; i++)
1182 libxl_dominfo_dispose(&list[i]);
1183 free(list);
1184 }
1185
libxl_vminfo_list_free(libxl_vminfo * list,int nr)1186 void libxl_vminfo_list_free(libxl_vminfo *list, int nr)
1187 {
1188 int i;
1189 for (i = 0; i < nr; i++)
1190 libxl_vminfo_dispose(&list[i]);
1191 free(list);
1192 }
1193
libxl_cpupoolinfo_list_free(libxl_cpupoolinfo * list,int nr)1194 void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nr)
1195 {
1196 int i;
1197 for (i = 0; i < nr; i++)
1198 libxl_cpupoolinfo_dispose(&list[i]);
1199 free(list);
1200 }
1201
libxl_domid_valid_guest(uint32_t domid)1202 int libxl_domid_valid_guest(uint32_t domid)
1203 {
1204 /* returns 1 if the value _could_ be a valid guest domid, 0 otherwise
1205 * does not check whether the domain actually exists */
1206 return domid > 0 && domid < DOMID_FIRST_RESERVED;
1207 }
1208
libxl_string_copy(libxl_ctx * ctx,char ** dst,char * const * src)1209 void libxl_string_copy(libxl_ctx *ctx, char **dst, char * const*src)
1210 {
1211 GC_INIT(ctx);
1212
1213 if (*src)
1214 *dst = libxl__strdup(NOGC, *src);
1215 else
1216 *dst = NULL;
1217
1218 GC_FREE;
1219 }
1220
1221 /*
1222 * Fill @buf with @len random bytes.
1223 */
libxl__random_bytes(libxl__gc * gc,uint8_t * buf,size_t len)1224 int libxl__random_bytes(libxl__gc *gc, uint8_t *buf, size_t len)
1225 {
1226 static const char *dev = "/dev/urandom";
1227 int fd;
1228 int ret;
1229
1230 fd = open(dev, O_RDONLY);
1231 if (fd < 0) {
1232 LOGE(ERROR, "failed to open \"%s\"", dev);
1233 return ERROR_FAIL;
1234 }
1235 ret = libxl_fd_set_cloexec(CTX, fd, 1);
1236 if (ret) {
1237 close(fd);
1238 return ERROR_FAIL;
1239 }
1240
1241 ret = libxl_read_exactly(CTX, fd, buf, len, dev, NULL);
1242
1243 close(fd);
1244
1245 return ret;
1246 }
1247
libxl__prepare_sockaddr_un(libxl__gc * gc,struct sockaddr_un * un,const char * path,const char * what)1248 int libxl__prepare_sockaddr_un(libxl__gc *gc,
1249 struct sockaddr_un *un, const char *path,
1250 const char *what)
1251 {
1252 if (sizeof(un->sun_path) - 1 <= strlen(path)) {
1253 LOG(ERROR, "UNIX socket path '%s' is too long for %s", path, what);
1254 LOG(DEBUG, "Path must be less than %zu bytes", sizeof(un->sun_path) - 1);
1255 return ERROR_INVAL;
1256 }
1257 memset(un, 0, sizeof(struct sockaddr_un));
1258 un->sun_family = AF_UNIX;
1259 strncpy(un->sun_path, path, sizeof(un->sun_path) - 1);
1260 return 0;
1261 }
1262
1263 /*
1264 * Local variables:
1265 * mode: C
1266 * c-basic-offset: 4
1267 * indent-tabs-mode: nil
1268 * End:
1269 */
1270