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