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