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