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