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[sizeof("/local/domain") + 11];
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[sizeof("/local/pool") + 11];
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 break;
581 }
582
583 out:
584 if (d) closedir(d);
585
586 return rc;
587 }
588
libxl_pipe(libxl_ctx * ctx,int pipes[2])589 int libxl_pipe(libxl_ctx *ctx, int pipes[2])
590 {
591 GC_INIT(ctx);
592 int ret = 0;
593 if (pipe(pipes) < 0) {
594 LOG(ERROR, "Failed to create a pipe");
595 ret = -1;
596 }
597 GC_FREE;
598 return ret;
599 }
600
libxl_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * bitmap,int n_bits)601 int libxl_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *bitmap, int n_bits)
602 {
603 GC_INIT(ctx);
604 int sz;
605
606 sz = (n_bits + 7) / 8;
607 bitmap->map = libxl__calloc(NOGC, sizeof(*bitmap->map), sz);
608 bitmap->size = sz;
609
610 GC_FREE;
611 return 0;
612 }
613
libxl_bitmap_init(libxl_bitmap * map)614 void libxl_bitmap_init(libxl_bitmap *map)
615 {
616 memset(map, '\0', sizeof(*map));
617 }
618
libxl_bitmap_dispose(libxl_bitmap * map)619 void libxl_bitmap_dispose(libxl_bitmap *map)
620 {
621 if (!map)
622 return;
623
624 free(map->map);
625 map->map = NULL;
626 map->size = 0;
627 }
628
libxl_bitmap_copy(libxl_ctx * ctx,libxl_bitmap * dptr,const libxl_bitmap * sptr)629 void libxl_bitmap_copy(libxl_ctx *ctx, libxl_bitmap *dptr,
630 const libxl_bitmap *sptr)
631 {
632 int sz;
633
634 assert(dptr->size == sptr->size);
635 sz = dptr->size = sptr->size;
636 memcpy(dptr->map, sptr->map, sz * sizeof(*dptr->map));
637 }
638
639 /* This function copies X bytes from source to destination bitmap,
640 * where X is the smaller of the two sizes.
641 *
642 * If destination's size is larger than source, the extra bytes are
643 * untouched.
644 */
libxl__bitmap_copy_best_effort(libxl__gc * gc,libxl_bitmap * dptr,const libxl_bitmap * sptr)645 void libxl__bitmap_copy_best_effort(libxl__gc *gc, libxl_bitmap *dptr,
646 const libxl_bitmap *sptr)
647 {
648 int sz;
649
650 sz = dptr->size < sptr->size ? dptr->size : sptr->size;
651 memcpy(dptr->map, sptr->map, sz * sizeof(*dptr->map));
652 }
653
libxl_bitmap_copy_alloc(libxl_ctx * ctx,libxl_bitmap * dptr,const libxl_bitmap * sptr)654 void libxl_bitmap_copy_alloc(libxl_ctx *ctx,
655 libxl_bitmap *dptr,
656 const libxl_bitmap *sptr)
657 {
658 GC_INIT(ctx);
659
660 dptr->map = libxl__calloc(NOGC, sptr->size, sizeof(*sptr->map));
661 dptr->size = sptr->size;
662 memcpy(dptr->map, sptr->map, sptr->size * sizeof(*sptr->map));
663
664 GC_FREE;
665 }
666
libxl_bitmap_is_full(const libxl_bitmap * bitmap)667 int libxl_bitmap_is_full(const libxl_bitmap *bitmap)
668 {
669 int i;
670
671 for (i = 0; i < bitmap->size; i++)
672 if (bitmap->map[i] != (uint8_t)-1)
673 return 0;
674 return 1;
675 }
676
libxl_bitmap_is_empty(const libxl_bitmap * bitmap)677 int libxl_bitmap_is_empty(const libxl_bitmap *bitmap)
678 {
679 int i;
680
681 for (i = 0; i < bitmap->size; i++)
682 if (bitmap->map[i])
683 return 0;
684 return 1;
685 }
686
libxl_bitmap_test(const libxl_bitmap * bitmap,int bit)687 int libxl_bitmap_test(const libxl_bitmap *bitmap, int bit)
688 {
689 if (bit >= bitmap->size * 8 || bit < 0)
690 return 0;
691 return (bitmap->map[bit / 8] & (1 << (bit & 7))) ? 1 : 0;
692 }
693
libxl_bitmap_set(libxl_bitmap * bitmap,int bit)694 void libxl_bitmap_set(libxl_bitmap *bitmap, int bit)
695 {
696 if (bit >= bitmap->size * 8 || bit < 0)
697 return;
698 bitmap->map[bit / 8] |= 1 << (bit & 7);
699 }
700
libxl_bitmap_reset(libxl_bitmap * bitmap,int bit)701 void libxl_bitmap_reset(libxl_bitmap *bitmap, int bit)
702 {
703 if (bit >= bitmap->size * 8 || bit < 0)
704 return;
705 bitmap->map[bit / 8] &= ~(1 << (bit & 7));
706 }
707
libxl_bitmap_or(libxl_ctx * ctx,libxl_bitmap * or_map,const libxl_bitmap * map1,const libxl_bitmap * map2)708 int libxl_bitmap_or(libxl_ctx *ctx, libxl_bitmap *or_map,
709 const libxl_bitmap *map1, const libxl_bitmap *map2)
710 {
711 GC_INIT(ctx);
712 int rc;
713 uint32_t i;
714 const libxl_bitmap *large_map;
715 const libxl_bitmap *small_map;
716
717 if (map1->size > map2->size) {
718 large_map = map1;
719 small_map = map2;
720 } else {
721 large_map = map2;
722 small_map = map1;
723 }
724
725 rc = libxl_bitmap_alloc(ctx, or_map, large_map->size * 8);
726 if (rc)
727 goto out;
728
729 /*
730 * If bitmaps aren't the same size, their union (logical or) will
731 * be size of larger bit map. Any bit past the end of the
732 * smaller bit map, will match the larger one.
733 */
734 for (i = 0; i < small_map->size; i++)
735 or_map->map[i] = (small_map->map[i] | large_map->map[i]);
736
737 for (i = small_map->size; i < large_map->size; i++)
738 or_map->map[i] = large_map->map[i];
739
740 out:
741 GC_FREE;
742 return rc;
743 }
744
libxl_bitmap_and(libxl_ctx * ctx,libxl_bitmap * and_map,const libxl_bitmap * map1,const libxl_bitmap * map2)745 int libxl_bitmap_and(libxl_ctx *ctx, libxl_bitmap *and_map,
746 const libxl_bitmap *map1, const libxl_bitmap *map2)
747 {
748 GC_INIT(ctx);
749 int rc;
750 uint32_t i;
751 const libxl_bitmap *large_map;
752 const libxl_bitmap *small_map;
753
754 if (map1->size > map2->size) {
755 large_map = map1;
756 small_map = map2;
757 } else {
758 large_map = map2;
759 small_map = map1;
760 }
761
762 rc = libxl_bitmap_alloc(ctx, and_map, small_map->size * 8);
763 if (rc)
764 goto out;
765
766 /*
767 * If bitmaps aren't same size, their 'and' will be size of
768 * smaller bit map
769 */
770 for (i = 0; i < and_map->size; i++)
771 and_map->map[i] = (large_map->map[i] & small_map->map[i]);
772
773 out:
774 GC_FREE;
775 return rc;
776 }
777
libxl_bitmap_count_set(const libxl_bitmap * bitmap)778 int libxl_bitmap_count_set(const libxl_bitmap *bitmap)
779 {
780 int i, nr_set_bits = 0;
781 libxl_for_each_set_bit(i, *bitmap)
782 nr_set_bits++;
783
784 return nr_set_bits;
785 }
786
787 /* NB. caller is responsible for freeing the memory */
libxl_bitmap_to_hex_string(libxl_ctx * ctx,const libxl_bitmap * bitmap)788 char *libxl_bitmap_to_hex_string(libxl_ctx *ctx, const libxl_bitmap *bitmap)
789 {
790 GC_INIT(ctx);
791 int i = bitmap->size;
792 char *p = libxl__zalloc(NOGC, bitmap->size * 2 + 3);
793 char *q = p;
794 strncpy(p, "0x", 3);
795 p += 2;
796 while(--i >= 0) {
797 sprintf(p, "%02x", bitmap->map[i]);
798 p += 2;
799 }
800 *p = '\0';
801 GC_FREE;
802 return q;
803 }
804
libxl_cpu_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * cpumap,int max_cpus)805 int libxl_cpu_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *cpumap, int max_cpus)
806 {
807 GC_INIT(ctx);
808 int rc = 0;
809
810 if (max_cpus < 0) {
811 rc = ERROR_INVAL;
812 LOG(ERROR, "invalid number of cpus provided");
813 goto out;
814 }
815 if (max_cpus == 0)
816 max_cpus = libxl_get_max_cpus(ctx);
817 if (max_cpus < 0) {
818 LOG(ERROR, "failed to retrieve the maximum number of cpus");
819 rc = max_cpus;
820 goto out;
821 }
822 /* This can't fail: no need to check and log */
823 libxl_bitmap_alloc(ctx, cpumap, max_cpus);
824
825 out:
826 GC_FREE;
827 return rc;
828 }
829
libxl_node_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * nodemap,int max_nodes)830 int libxl_node_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *nodemap,
831 int max_nodes)
832 {
833 GC_INIT(ctx);
834 int rc = 0;
835
836 if (max_nodes < 0) {
837 rc = ERROR_INVAL;
838 LOG(ERROR, "invalid number of nodes provided");
839 goto out;
840 }
841
842 if (max_nodes == 0)
843 max_nodes = libxl_get_max_nodes(ctx);
844 if (max_nodes < 0) {
845 LOG(ERROR, "failed to retrieve the maximum number of nodes");
846 rc = max_nodes;
847 goto out;
848 }
849 /* This can't fail: no need to check and log */
850 libxl_bitmap_alloc(ctx, nodemap, max_nodes);
851
852 out:
853 GC_FREE;
854 return rc;
855 }
856
libxl__count_physical_sockets(libxl__gc * gc,int * sockets)857 int libxl__count_physical_sockets(libxl__gc *gc, int *sockets)
858 {
859 int rc;
860 libxl_physinfo info;
861
862 libxl_physinfo_init(&info);
863
864 rc = libxl_get_physinfo(CTX, &info);
865 if (rc)
866 return rc;
867
868 *sockets = info.nr_cpus / info.threads_per_core
869 / info.cores_per_socket;
870
871 libxl_physinfo_dispose(&info);
872 return 0;
873 }
874
libxl_socket_bitmap_alloc(libxl_ctx * ctx,libxl_bitmap * socketmap,int max_sockets)875 int libxl_socket_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *socketmap,
876 int max_sockets)
877 {
878 GC_INIT(ctx);
879 int rc = 0;
880
881 if (max_sockets < 0) {
882 rc = ERROR_INVAL;
883 LOG(ERROR, "invalid number of sockets provided");
884 goto out;
885 }
886
887 if (max_sockets == 0) {
888 rc = libxl__count_physical_sockets(gc, &max_sockets);
889 if (rc) {
890 LOGE(ERROR, "failed to get system socket count");
891 goto out;
892 }
893 }
894 /* This can't fail: no need to check and log */
895 libxl_bitmap_alloc(ctx, socketmap, max_sockets);
896
897 out:
898 GC_FREE;
899 return rc;
900
901 }
902
libxl_get_online_socketmap(libxl_ctx * ctx,libxl_bitmap * socketmap)903 int libxl_get_online_socketmap(libxl_ctx *ctx, libxl_bitmap *socketmap)
904 {
905 libxl_cputopology *tinfo = NULL;
906 int nr_cpus = 0, i, rc = 0;
907
908 tinfo = libxl_get_cpu_topology(ctx, &nr_cpus);
909 if (tinfo == NULL) {
910 rc = ERROR_FAIL;
911 goto out;
912 }
913
914 libxl_bitmap_set_none(socketmap);
915 for (i = 0; i < nr_cpus; i++)
916 if (tinfo[i].socket != XEN_INVALID_SOCKET_ID
917 && !libxl_bitmap_test(socketmap, tinfo[i].socket))
918 libxl_bitmap_set(socketmap, tinfo[i].socket);
919
920 out:
921 libxl_cputopology_list_free(tinfo, nr_cpus);
922 return rc;
923 }
924
libxl_nodemap_to_cpumap(libxl_ctx * ctx,const libxl_bitmap * nodemap,libxl_bitmap * cpumap)925 int libxl_nodemap_to_cpumap(libxl_ctx *ctx,
926 const libxl_bitmap *nodemap,
927 libxl_bitmap *cpumap)
928 {
929 libxl_cputopology *tinfo = NULL;
930 int nr_cpus = 0, i, rc = 0;
931
932 tinfo = libxl_get_cpu_topology(ctx, &nr_cpus);
933 if (tinfo == NULL) {
934 rc = ERROR_FAIL;
935 goto out;
936 }
937
938 libxl_bitmap_set_none(cpumap);
939 for (i = 0; i < nr_cpus; i++) {
940 if (libxl_bitmap_test(nodemap, tinfo[i].node))
941 libxl_bitmap_set(cpumap, i);
942 }
943 out:
944 libxl_cputopology_list_free(tinfo, nr_cpus);
945 return rc;
946 }
947
libxl_node_to_cpumap(libxl_ctx * ctx,int node,libxl_bitmap * cpumap)948 int libxl_node_to_cpumap(libxl_ctx *ctx, int node,
949 libxl_bitmap *cpumap)
950 {
951 libxl_bitmap nodemap;
952 int rc = 0;
953
954 libxl_bitmap_init(&nodemap);
955
956 rc = libxl_node_bitmap_alloc(ctx, &nodemap, 0);
957 if (rc)
958 goto out;
959
960 libxl_bitmap_set_none(&nodemap);
961 libxl_bitmap_set(&nodemap, node);
962
963 rc = libxl_nodemap_to_cpumap(ctx, &nodemap, cpumap);
964
965 out:
966 libxl_bitmap_dispose(&nodemap);
967 return rc;
968 }
969
libxl_cpumap_to_nodemap(libxl_ctx * ctx,const libxl_bitmap * cpumap,libxl_bitmap * nodemap)970 int libxl_cpumap_to_nodemap(libxl_ctx *ctx,
971 const libxl_bitmap *cpumap,
972 libxl_bitmap *nodemap)
973 {
974 libxl_cputopology *tinfo = NULL;
975 int nr_cpus = 0, i, rc = 0;
976
977 tinfo = libxl_get_cpu_topology(ctx, &nr_cpus);
978 if (tinfo == NULL) {
979 rc = ERROR_FAIL;
980 goto out;
981 }
982
983 libxl_bitmap_set_none(nodemap);
984 libxl_for_each_set_bit(i, *cpumap) {
985 if (i >= nr_cpus)
986 break;
987 libxl_bitmap_set(nodemap, tinfo[i].node);
988 }
989 out:
990 libxl_cputopology_list_free(tinfo, nr_cpus);
991 return rc;
992 }
993
libxl_get_max_cpus(libxl_ctx * ctx)994 int libxl_get_max_cpus(libxl_ctx *ctx)
995 {
996 int max_cpus = xc_get_max_cpus(ctx->xch);
997
998 return max_cpus < 0 ? ERROR_FAIL : max_cpus;
999 }
1000
libxl_get_online_cpus(libxl_ctx * ctx)1001 int libxl_get_online_cpus(libxl_ctx *ctx)
1002 {
1003 int online_cpus = xc_get_online_cpus(ctx->xch);
1004
1005 return online_cpus < 0 ? ERROR_FAIL : online_cpus;
1006 }
1007
libxl_get_max_nodes(libxl_ctx * ctx)1008 int libxl_get_max_nodes(libxl_ctx *ctx)
1009 {
1010 int max_nodes = xc_get_max_nodes(ctx->xch);
1011
1012 return max_nodes < 0 ? ERROR_FAIL : max_nodes;
1013 }
1014
libxl__enum_from_string(const libxl_enum_string_table * t,const char * s,int * e)1015 int libxl__enum_from_string(const libxl_enum_string_table *t,
1016 const char *s, int *e)
1017 {
1018 if (!t) return ERROR_INVAL;
1019
1020 for( ; t->s; t++) {
1021 if (!strcasecmp(t->s, s)) {
1022 *e = t->v;
1023 return 0;
1024 }
1025 }
1026 return ERROR_FAIL;
1027 }
1028
libxl_cputopology_list_free(libxl_cputopology * list,int nr)1029 void libxl_cputopology_list_free(libxl_cputopology *list, int nr)
1030 {
1031 int i;
1032 for (i = 0; i < nr; i++)
1033 libxl_cputopology_dispose(&list[i]);
1034 free(list);
1035 }
1036
libxl_pcitopology_list_free(libxl_pcitopology * list,int nr)1037 void libxl_pcitopology_list_free(libxl_pcitopology *list, int nr)
1038 {
1039 int i;
1040 for (i = 0; i < nr; i++)
1041 libxl_pcitopology_dispose(&list[i]);
1042 free(list);
1043 }
1044
libxl_numainfo_list_free(libxl_numainfo * list,int nr)1045 void libxl_numainfo_list_free(libxl_numainfo *list, int nr)
1046 {
1047 int i;
1048 for (i = 0; i < nr; i++)
1049 libxl_numainfo_dispose(&list[i]);
1050 free(list);
1051 }
1052
libxl_vcpuinfo_list_free(libxl_vcpuinfo * list,int nr)1053 void libxl_vcpuinfo_list_free(libxl_vcpuinfo *list, int nr)
1054 {
1055 int i;
1056 for (i = 0; i < nr; i++)
1057 libxl_vcpuinfo_dispose(&list[i]);
1058 free(list);
1059 }
1060
libxl__sendmsg_fds(libxl__gc * gc,int carrier,const char data,int nfds,const int fds[],const char * what)1061 int libxl__sendmsg_fds(libxl__gc *gc, int carrier,
1062 const char data,
1063 int nfds, const int fds[], const char *what) {
1064 struct msghdr msg = { 0 };
1065 struct cmsghdr *cmsg;
1066 size_t spaceneeded = nfds * sizeof(fds[0]);
1067 char control[CMSG_SPACE(spaceneeded)];
1068 const size_t datalen = 1;
1069 struct iovec iov;
1070 int r;
1071
1072 iov.iov_base = (void*)&data;
1073 iov.iov_len = datalen;
1074
1075 /* compose the message */
1076 msg.msg_iov = &iov;
1077 msg.msg_iovlen = 1;
1078 msg.msg_control = control;
1079 msg.msg_controllen = sizeof(control);
1080
1081 /* attach open fd */
1082 cmsg = CMSG_FIRSTHDR(&msg);
1083 cmsg->cmsg_level = SOL_SOCKET;
1084 cmsg->cmsg_type = SCM_RIGHTS;
1085 cmsg->cmsg_len = CMSG_LEN(spaceneeded);
1086 memcpy(CMSG_DATA(cmsg), fds, spaceneeded);
1087
1088 msg.msg_controllen = cmsg->cmsg_len;
1089
1090 while (1) {
1091 r = sendmsg(carrier, &msg, 0);
1092 if (r < 0) {
1093 if (errno == EINTR)
1094 continue;
1095 if (errno == EWOULDBLOCK) {
1096 return ERROR_NOT_READY;
1097 }
1098 LOGE(ERROR, "failed to send fd-carrying message (%s)", what);
1099 return ERROR_FAIL;
1100 }
1101 if (r != datalen) {
1102 LOG(ERROR, "sendmsg have written %d instead of %zu",
1103 r, datalen);
1104 return ERROR_FAIL;
1105 }
1106 break;
1107 };
1108
1109 return 0;
1110 }
1111
libxl__recvmsg_fds(libxl__gc * gc,int carrier,void * databuf,size_t datalen,int nfds,int fds[],const char * what)1112 int libxl__recvmsg_fds(libxl__gc *gc, int carrier,
1113 void *databuf, size_t datalen,
1114 int nfds, int fds[], const char *what)
1115 {
1116 struct msghdr msg = { 0 };
1117 struct cmsghdr *cmsg;
1118 size_t spaceneeded = nfds * sizeof(fds[0]);
1119 char control[CMSG_SPACE(spaceneeded)];
1120 struct iovec iov;
1121 int r;
1122
1123 iov.iov_base = databuf;
1124 iov.iov_len = datalen;
1125
1126 msg.msg_iov = &iov;
1127 msg.msg_iovlen = 1;
1128 msg.msg_control = control;
1129 msg.msg_controllen = sizeof(control);
1130
1131 for (;;) {
1132 r = recvmsg(carrier, &msg, 0);
1133 if (r < 0) {
1134 if (errno == EINTR) continue;
1135 if (errno == EWOULDBLOCK) return -1;
1136 LOGE(ERROR,"recvmsg failed (%s)", what);
1137 return ERROR_FAIL;
1138 }
1139 if (r == 0) {
1140 LOG(ERROR,"recvmsg got EOF (%s)", what);
1141 return ERROR_FAIL;
1142 }
1143 cmsg = CMSG_FIRSTHDR(&msg);
1144 if (cmsg->cmsg_len <= CMSG_LEN(0)) {
1145 LOG(ERROR,"recvmsg got no control msg"
1146 " when expecting fds (%s)", what);
1147 return ERROR_FAIL;
1148 }
1149 if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
1150 LOG(ERROR, "recvmsg got unexpected"
1151 " cmsg_level %d (!=%d) or _type %d (!=%d) (%s)",
1152 cmsg->cmsg_level, SOL_SOCKET,
1153 cmsg->cmsg_type, SCM_RIGHTS,
1154 what);
1155 return ERROR_FAIL;
1156 }
1157 if (cmsg->cmsg_len != CMSG_LEN(spaceneeded) ||
1158 msg.msg_controllen != cmsg->cmsg_len) {
1159 LOG(ERROR, "recvmsg got unexpected"
1160 " number of fds or extra control data"
1161 " (%ld bytes' worth, expected %ld) (%s)",
1162 (long)CMSG_LEN(spaceneeded), (long)cmsg->cmsg_len,
1163 what);
1164 int i, fd;
1165 unsigned char *p;
1166 for (i=0, p=CMSG_DATA(cmsg);
1167 CMSG_SPACE(i * sizeof(fds[0]));
1168 i++, i+=sizeof(fd)) {
1169 memcpy(&fd, p, sizeof(fd));
1170 close(fd);
1171 }
1172 return ERROR_FAIL;
1173 }
1174 memcpy(fds, CMSG_DATA(cmsg), spaceneeded);
1175 return 0;
1176 }
1177 }
1178
libxl_dominfo_list_free(libxl_dominfo * list,int nr)1179 void libxl_dominfo_list_free(libxl_dominfo *list, int nr)
1180 {
1181 int i;
1182 for (i = 0; i < nr; i++)
1183 libxl_dominfo_dispose(&list[i]);
1184 free(list);
1185 }
1186
libxl_vminfo_list_free(libxl_vminfo * list,int nr)1187 void libxl_vminfo_list_free(libxl_vminfo *list, int nr)
1188 {
1189 int i;
1190 for (i = 0; i < nr; i++)
1191 libxl_vminfo_dispose(&list[i]);
1192 free(list);
1193 }
1194
libxl_cpupoolinfo_list_free(libxl_cpupoolinfo * list,int nr)1195 void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nr)
1196 {
1197 int i;
1198 for (i = 0; i < nr; i++)
1199 libxl_cpupoolinfo_dispose(&list[i]);
1200 free(list);
1201 }
1202
libxl_domid_valid_guest(uint32_t domid)1203 int libxl_domid_valid_guest(uint32_t domid)
1204 {
1205 /* returns 1 if the value _could_ be a valid guest domid, 0 otherwise
1206 * does not check whether the domain actually exists */
1207 return domid > 0 && domid < DOMID_FIRST_RESERVED;
1208 }
1209
libxl_string_copy(libxl_ctx * ctx,char ** dst,char * const * src)1210 void libxl_string_copy(libxl_ctx *ctx, char **dst, char * const*src)
1211 {
1212 GC_INIT(ctx);
1213
1214 if (*src)
1215 *dst = libxl__strdup(NOGC, *src);
1216 else
1217 *dst = NULL;
1218
1219 GC_FREE;
1220 }
1221
1222 /*
1223 * Fill @buf with @len random bytes.
1224 */
libxl__random_bytes(libxl__gc * gc,uint8_t * buf,size_t len)1225 int libxl__random_bytes(libxl__gc *gc, uint8_t *buf, size_t len)
1226 {
1227 static const char *dev = "/dev/urandom";
1228 int fd;
1229 int ret;
1230
1231 fd = open(dev, O_RDONLY);
1232 if (fd < 0) {
1233 LOGE(ERROR, "failed to open \"%s\"", dev);
1234 return ERROR_FAIL;
1235 }
1236 ret = libxl_fd_set_cloexec(CTX, fd, 1);
1237 if (ret) {
1238 close(fd);
1239 return ERROR_FAIL;
1240 }
1241
1242 ret = libxl_read_exactly(CTX, fd, buf, len, dev, NULL);
1243
1244 close(fd);
1245
1246 return ret;
1247 }
1248
libxl__prepare_sockaddr_un(libxl__gc * gc,struct sockaddr_un * un,const char * path,const char * what)1249 int libxl__prepare_sockaddr_un(libxl__gc *gc,
1250 struct sockaddr_un *un, const char *path,
1251 const char *what)
1252 {
1253 if (sizeof(un->sun_path) - 1 <= strlen(path)) {
1254 LOG(ERROR, "UNIX socket path '%s' is too long for %s", path, what);
1255 LOG(DEBUG, "Path must be less than %zu bytes", sizeof(un->sun_path) - 1);
1256 return ERROR_INVAL;
1257 }
1258 memset(un, 0, sizeof(struct sockaddr_un));
1259 un->sun_family = AF_UNIX;
1260 strncpy(un->sun_path, path, sizeof(un->sun_path) - 1);
1261 return 0;
1262 }
1263
1264 /*
1265 * Local variables:
1266 * mode: C
1267 * c-basic-offset: 4
1268 * indent-tabs-mode: nil
1269 * End:
1270 */
1271