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      free(dominfo);
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 void * data,size_t datalen,int nfds,const int fds[],const char * what)1063  int libxl__sendmsg_fds(libxl__gc *gc, int carrier,
1064                         const void *data, size_t datalen,
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      struct iovec iov;
1071      int r;
1072  
1073      iov.iov_base = (void*)data;
1074      iov.iov_len  = datalen;
1075  
1076      /* compose the message */
1077      msg.msg_iov = &iov;
1078      msg.msg_iovlen = 1;
1079      msg.msg_control = control;
1080      msg.msg_controllen = sizeof(control);
1081  
1082      /* attach open fd */
1083      cmsg = CMSG_FIRSTHDR(&msg);
1084      cmsg->cmsg_level = SOL_SOCKET;
1085      cmsg->cmsg_type = SCM_RIGHTS;
1086      cmsg->cmsg_len = CMSG_LEN(spaceneeded);
1087      memcpy(CMSG_DATA(cmsg), fds, spaceneeded);
1088  
1089      msg.msg_controllen = cmsg->cmsg_len;
1090  
1091      r = sendmsg(carrier, &msg, 0);
1092      if (r < 0) {
1093          LOGE(ERROR, "failed to send fd-carrying message (%s)", what);
1094          return ERROR_FAIL;
1095      }
1096  
1097      return 0;
1098  }
1099  
libxl__recvmsg_fds(libxl__gc * gc,int carrier,void * databuf,size_t datalen,int nfds,int fds[],const char * what)1100  int libxl__recvmsg_fds(libxl__gc *gc, int carrier,
1101                         void *databuf, size_t datalen,
1102                         int nfds, int fds[], const char *what)
1103  {
1104      struct msghdr msg = { 0 };
1105      struct cmsghdr *cmsg;
1106      size_t spaceneeded = nfds * sizeof(fds[0]);
1107      char control[CMSG_SPACE(spaceneeded)];
1108      struct iovec iov;
1109      int r;
1110  
1111      iov.iov_base = databuf;
1112      iov.iov_len  = datalen;
1113  
1114      msg.msg_iov = &iov;
1115      msg.msg_iovlen = 1;
1116      msg.msg_control = control;
1117      msg.msg_controllen = sizeof(control);
1118  
1119      for (;;) {
1120          r = recvmsg(carrier, &msg, 0);
1121          if (r < 0) {
1122              if (errno == EINTR) continue;
1123              if (errno == EWOULDBLOCK) return -1;
1124              LOGE(ERROR,"recvmsg failed (%s)", what);
1125              return ERROR_FAIL;
1126          }
1127          if (r == 0) {
1128              LOG(ERROR,"recvmsg got EOF (%s)", what);
1129              return ERROR_FAIL;
1130          }
1131          cmsg = CMSG_FIRSTHDR(&msg);
1132          if (cmsg->cmsg_len <= CMSG_LEN(0)) {
1133              LOG(ERROR,"recvmsg got no control msg"
1134                  " when expecting fds (%s)", what);
1135              return ERROR_FAIL;
1136          }
1137          if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) {
1138              LOG(ERROR, "recvmsg got unexpected"
1139                  " cmsg_level %d (!=%d) or _type %d (!=%d) (%s)",
1140                  cmsg->cmsg_level, SOL_SOCKET,
1141                  cmsg->cmsg_type, SCM_RIGHTS,
1142                  what);
1143              return ERROR_FAIL;
1144          }
1145          if (cmsg->cmsg_len != CMSG_LEN(spaceneeded) ||
1146              msg.msg_controllen != cmsg->cmsg_len) {
1147              LOG(ERROR, "recvmsg got unexpected"
1148                  " number of fds or extra control data"
1149                  " (%ld bytes' worth, expected %ld) (%s)",
1150                  (long)CMSG_LEN(spaceneeded), (long)cmsg->cmsg_len,
1151                  what);
1152              int i, fd;
1153              unsigned char *p;
1154              for (i=0, p=CMSG_DATA(cmsg);
1155                   CMSG_SPACE(i * sizeof(fds[0]));
1156                   i++, i+=sizeof(fd)) {
1157                  memcpy(&fd, p, sizeof(fd));
1158                  close(fd);
1159              }
1160              return ERROR_FAIL;
1161          }
1162          memcpy(fds, CMSG_DATA(cmsg), spaceneeded);
1163          return 0;
1164      }
1165  }
1166  
libxl_dominfo_list_free(libxl_dominfo * list,int nr)1167  void libxl_dominfo_list_free(libxl_dominfo *list, int nr)
1168  {
1169      int i;
1170      for (i = 0; i < nr; i++)
1171          libxl_dominfo_dispose(&list[i]);
1172      free(list);
1173  }
1174  
libxl_vminfo_list_free(libxl_vminfo * list,int nr)1175  void libxl_vminfo_list_free(libxl_vminfo *list, int nr)
1176  {
1177      int i;
1178      for (i = 0; i < nr; i++)
1179          libxl_vminfo_dispose(&list[i]);
1180      free(list);
1181  }
1182  
libxl_cpupoolinfo_list_free(libxl_cpupoolinfo * list,int nr)1183  void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nr)
1184  {
1185      int i;
1186      for (i = 0; i < nr; i++)
1187          libxl_cpupoolinfo_dispose(&list[i]);
1188      free(list);
1189  }
1190  
libxl_domid_valid_guest(uint32_t domid)1191  int libxl_domid_valid_guest(uint32_t domid)
1192  {
1193      /* returns 1 if the value _could_ be a valid guest domid, 0 otherwise
1194       * does not check whether the domain actually exists */
1195      return domid > 0 && domid < DOMID_FIRST_RESERVED;
1196  }
1197  
libxl_string_copy(libxl_ctx * ctx,char ** dst,char * const * src)1198  void libxl_string_copy(libxl_ctx *ctx, char **dst, char * const*src)
1199  {
1200      GC_INIT(ctx);
1201  
1202      if (*src)
1203          *dst = libxl__strdup(NOGC, *src);
1204      else
1205          *dst = NULL;
1206  
1207      GC_FREE;
1208  }
1209  
1210  /*
1211   * Fill @buf with @len random bytes.
1212   */
libxl__random_bytes(libxl__gc * gc,uint8_t * buf,size_t len)1213  int libxl__random_bytes(libxl__gc *gc, uint8_t *buf, size_t len)
1214  {
1215      static const char *dev = "/dev/urandom";
1216      int fd;
1217      int ret;
1218  
1219      fd = open(dev, O_RDONLY);
1220      if (fd < 0) {
1221          LOGE(ERROR, "failed to open \"%s\"", dev);
1222          return ERROR_FAIL;
1223      }
1224      ret = libxl_fd_set_cloexec(CTX, fd, 1);
1225      if (ret) {
1226          close(fd);
1227          return ERROR_FAIL;
1228      }
1229  
1230      ret = libxl_read_exactly(CTX, fd, buf, len, dev, NULL);
1231  
1232      close(fd);
1233  
1234      return ret;
1235  }
1236  
1237  /*
1238   * Local variables:
1239   * mode: C
1240   * c-basic-offset: 4
1241   * indent-tabs-mode: nil
1242   * End:
1243   */
1244