/* * Copyright (C) 2009 Citrix Ltd. * Author Stefano Stabellini * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Lesser General Public License as published * by the Free Software Foundation; version 2.1 only. with the special * exception on linking described in file LICENSE. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU Lesser General Public License for more details. */ #include "libxl_osdeps.h" /* must come before any other headers */ #include #include "libxl_internal.h" #ifndef LIBXL_HAVE_NONCONST_LIBXL_BASENAME_RETURN_VALUE const #endif char *libxl_basename(const char *name) { const char *filename; if (name == NULL) return strdup("."); if (name[0] == '\0') return strdup("."); filename = strrchr(name, '/'); if (filename) return strdup(filename+1); return strdup(name); } unsigned long libxl_get_required_shadow_memory(unsigned long maxmem_kb, unsigned int smp_cpus) { return libxl__get_required_paging_memory(maxmem_kb, smp_cpus, LIBXL_DOMAIN_TYPE_INVALID, false); } char *libxl_domid_to_name(libxl_ctx *ctx, uint32_t domid) { unsigned int len; char path[strlen("/local/domain") + 12]; char *s; snprintf(path, sizeof(path), "/local/domain/%d/name", domid); s = xs_read(ctx->xsh, XBT_NULL, path, &len); return s; } char *libxl__domid_to_name(libxl__gc *gc, uint32_t domid) { char *s = libxl_domid_to_name(CTX, domid); libxl__ptr_add(gc, s); return s; } int libxl_name_to_domid(libxl_ctx *ctx, const char *name, uint32_t *domid) { int i, nb_domains; char *domname; libxl_dominfo *dominfo; int ret = ERROR_INVAL; dominfo = libxl_list_domain(ctx, &nb_domains); if (!dominfo) return ERROR_NOMEM; for (i = 0; i < nb_domains; i++) { domname = libxl_domid_to_name(ctx, dominfo[i].domid); if (!domname) continue; if (strcmp(domname, name) == 0) { *domid = dominfo[i].domid; ret = 0; free(domname); break; } free(domname); } libxl_dominfo_list_free(dominfo, nb_domains); return ret; } int libxl_domain_qualifier_to_domid(libxl_ctx *ctx, const char *name, uint32_t *domid) { int i, rv; for (i=0; name[i]; i++) { if (!CTYPE(isdigit, name[i])) { goto nondigit_found; } } *domid = strtoul(name, NULL, 10); return 0; nondigit_found: /* this could also check for uuids */ rv = libxl_name_to_domid(ctx, name, domid); return rv; } static int qualifier_to_id(const char *p, uint32_t *id_r) { int i, alldigit; alldigit = 1; for (i = 0; p[i]; i++) { if (!isdigit((uint8_t)p[i])) { alldigit = 0; break; } } if (i > 0 && alldigit) { *id_r = strtoul(p, NULL, 10); return 0; } else { /* check here if it's a uuid and do proper conversion */ } return 1; } int libxl_cpupool_qualifier_to_cpupoolid(libxl_ctx *ctx, const char *p, uint32_t *poolid_r, int *was_name_r) { int was_name; was_name = qualifier_to_id(p, poolid_r); if (was_name_r) *was_name_r = was_name; return was_name ? libxl_name_to_cpupoolid(ctx, p, poolid_r) : 0; } char *libxl_cpupoolid_to_name(libxl_ctx *ctx, uint32_t poolid) { unsigned int len; char path[strlen("/local/pool") + 12]; char *s; snprintf(path, sizeof(path), "/local/pool/%d/name", poolid); s = xs_read(ctx->xsh, XBT_NULL, path, &len); return s; } /* This is a bit horrid but without xs_exists it seems like the only way. */ int libxl_cpupoolid_is_valid(libxl_ctx *ctx, uint32_t poolid) { int ret; char *s = libxl_cpupoolid_to_name(ctx, poolid); ret = (s != NULL); free(s); return ret; } char *libxl__cpupoolid_to_name(libxl__gc *gc, uint32_t poolid) { char *s = libxl_cpupoolid_to_name(CTX, poolid); libxl__ptr_add(gc, s); return s; } int libxl_name_to_cpupoolid(libxl_ctx *ctx, const char *name, uint32_t *poolid) { int i, nb_pools; char *poolname; libxl_cpupoolinfo *poolinfo; int ret = ERROR_INVAL; poolinfo = libxl_list_cpupool(ctx, &nb_pools); if (!poolinfo) return ERROR_NOMEM; for (i = 0; i < nb_pools; i++) { if (ret && ((poolname = libxl_cpupoolid_to_name(ctx, poolinfo[i].poolid)) != NULL)) { if (strcmp(poolname, name) == 0) { *poolid = poolinfo[i].poolid; ret = 0; } free(poolname); } } libxl_cpupoolinfo_list_free(poolinfo, nb_pools); return ret; } int libxl_get_stubdom_id(libxl_ctx *ctx, int guest_domid) { GC_INIT(ctx); char * stubdom_id_s; int ret; stubdom_id_s = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/image/device-model-domid", libxl__xs_get_dompath(gc, guest_domid))); if (stubdom_id_s) ret = atoi(stubdom_id_s); else ret = 0; GC_FREE; return ret; } int libxl_is_stubdom(libxl_ctx *ctx, uint32_t domid, uint32_t *target_domid) { GC_INIT(ctx); char *target, *endptr; uint32_t value; int ret = 0; target = libxl__xs_read(gc, XBT_NULL, GCSPRINTF("%s/target", libxl__xs_get_dompath(gc, domid))); if (!target) goto out; value = strtol(target, &endptr, 10); if (*endptr != '\0') goto out; if (target_domid) *target_domid = value; ret = 1; out: GC_FREE; return ret; } static int logrename(libxl__gc *gc, const char *old, const char *new) { int r; r = rename(old, new); if (r) { if (errno == ENOENT) return 0; /* ok */ LOGE(ERROR, "failed to rotate logfile - " "could not rename %s to %s", old, new); return ERROR_FAIL; } return 0; } int libxl_create_logfile(libxl_ctx *ctx, const char *name, char **full_name) { GC_INIT(ctx); struct stat stat_buf; char *logfile, *logfile_new; int i, rc; logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log", name); if (stat(logfile, &stat_buf) == 0) { /* file exists, rotate */ logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log.10", name); unlink(logfile); for (i = 9; i > 0; i--) { logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log.%d", name, i); logfile_new = GCSPRINTF(XEN_LOG_DIR "/%s.log.%d", name, i + 1); rc = logrename(gc, logfile, logfile_new); if (rc) goto out; } logfile = GCSPRINTF(XEN_LOG_DIR "/%s.log", name); logfile_new = GCSPRINTF(XEN_LOG_DIR "/%s.log.1", name); rc = logrename(gc, logfile, logfile_new); if (rc) goto out; } else { if (errno != ENOENT) LOGE(WARN, "problem checking existence of logfile %s, " "which might have needed to be rotated", name); } *full_name = strdup(logfile); rc = 0; out: GC_FREE; return rc; } int libxl_string_to_backend(libxl_ctx *ctx, char *s, libxl_disk_backend *backend) { char *p; int rc = 0; if (!strcmp(s, "phy")) { *backend = LIBXL_DISK_BACKEND_PHY; } else if (!strcmp(s, "file")) { *backend = LIBXL_DISK_BACKEND_TAP; } else if (!strcmp(s, "qdisk")) { *backend = LIBXL_DISK_BACKEND_QDISK; } else if (!strcmp(s, "standalone")) { *backend = LIBXL_DISK_BACKEND_STANDALONE; } else if (!strcmp(s, "tap")) { p = strchr(s, ':'); if (!p) { rc = ERROR_INVAL; goto out; } p++; if (!strcmp(p, "vhd")) { *backend = LIBXL_DISK_BACKEND_TAP; } else if (!strcmp(p, "qcow")) { *backend = LIBXL_DISK_BACKEND_QDISK; } else if (!strcmp(p, "qcow2")) { *backend = LIBXL_DISK_BACKEND_QDISK; } else if (!strcmp(p, "qed")) { *backend = LIBXL_DISK_BACKEND_QDISK; } } out: return rc; } int libxl_read_file_contents(libxl_ctx *ctx, const char *filename, void **data_r, int *datalen_r) { GC_INIT(ctx); FILE *f = 0; uint8_t *data = 0; int datalen = 0; int e; struct stat stab; ssize_t rs; f = fopen(filename, "r"); if (!f) { if (errno == ENOENT) return ENOENT; LOGE(ERROR, "failed to open %s", filename); goto xe; } if (fstat(fileno(f), &stab)) { LOGE(ERROR, "failed to fstat %s", filename); goto xe; } if (!S_ISREG(stab.st_mode)) { LOGE(ERROR, "%s is not a plain file", filename); errno = ENOTTY; goto xe; } if (stab.st_size > INT_MAX) { LOG(ERROR, "file %s is far too large", filename); errno = EFBIG; goto xe; } datalen = stab.st_size; if (stab.st_size && data_r) { data = malloc(datalen); if (!data) goto xe; rs = fread(data, 1, datalen, f); if (rs != datalen) { if (ferror(f)) LOGE(ERROR, "failed to read %s", filename); else if (feof(f)) LOG(ERROR, "%s changed size while we were reading it", filename); else abort(); goto xe; } } if (fclose(f)) { f = 0; LOGE(ERROR, "failed to close %s", filename); goto xe; } if (data_r) *data_r = data; if (datalen_r) *datalen_r = datalen; GC_FREE; return 0; xe: GC_FREE; e = errno; assert(e != ENOENT); if (f) fclose(f); free(data); return e; } int libxl__read_sysfs_file_contents(libxl__gc *gc, const char *filename, void **data_r, int *datalen_r) { FILE *f = 0; uint8_t *data = 0; int datalen = 0; int e; struct stat stab; ssize_t rs; f = fopen(filename, "r"); if (!f) { if (errno == ENOENT) return ENOENT; LOGE(ERROR, "failed to open %s", filename); goto xe; } if (fstat(fileno(f), &stab)) { LOGE(ERROR, "failed to fstat %s", filename); goto xe; } if (!S_ISREG(stab.st_mode)) { LOGE(ERROR, "%s is not a plain file", filename); errno = ENOTTY; goto xe; } if (stab.st_size > INT_MAX) { LOG(ERROR, "file %s is far too large", filename); errno = EFBIG; goto xe; } datalen = stab.st_size; if (stab.st_size && data_r) { data = libxl__malloc(gc, datalen); /* For sysfs file, datalen is always PAGE_SIZE. 'read' * will return the number of bytes of the actual content, * rs <= datalen is expected. */ rs = fread(data, 1, datalen, f); if (rs < datalen) { if (ferror(f)) { LOGE(ERROR, "failed to read %s", filename); goto xe; } datalen = rs; data = libxl__realloc(gc, data, datalen); } } if (fclose(f)) { f = 0; LOGE(ERROR, "failed to close %s", filename); goto xe; } if (data_r) *data_r = data; if (datalen_r) *datalen_r = datalen; return 0; xe: e = errno; assert(e != ENOENT); if (f) fclose(f); return e; } #define READ_WRITE_EXACTLY(rw, zero_is_eof, constdata) \ \ int libxl_##rw##_exactly(libxl_ctx *ctx, int fd, \ constdata void *data, ssize_t sz, \ const char *source, const char *what) { \ ssize_t got; \ GC_INIT(ctx); \ \ while (sz > 0) { \ got = rw(fd, data, sz); \ if (got == -1) { \ if (errno == EINTR) continue; \ if (!ctx) { GC_FREE; return errno; } \ LOGE(ERROR, "failed to "#rw" %s%s%s", \ what ? what : "", what ? " from " : "", source); \ GC_FREE; \ return errno; \ } \ if (got == 0) { \ if (!ctx) { GC_FREE; return EPROTO; } \ LOG(ERROR, zero_is_eof \ ? "file/stream truncated reading %s%s%s" \ : "file/stream write returned 0! writing %s%s%s", \ what ? what : "", what ? " from " : "", source); \ GC_FREE; \ return EPROTO; \ } \ sz -= got; \ data = (char*)data + got; \ } \ GC_FREE; \ return 0; \ } READ_WRITE_EXACTLY(read, 1, /* */) READ_WRITE_EXACTLY(write, 0, const) int libxl__remove_file(libxl__gc *gc, const char *path) { for (;;) { int r = unlink(path); if (!r) return 0; if (errno == ENOENT) return 0; if (errno == EINTR) continue; LOGE(ERROR, "failed to remove file %s", path); return ERROR_FAIL; } } int libxl__remove_file_or_directory(libxl__gc *gc, const char *path) { for (;;) { int r = rmdir(path); if (!r) return 0; if (errno == ENOENT) return 0; if (errno == ENOTEMPTY) return libxl__remove_directory(gc, path); if (errno == ENOTDIR) return libxl__remove_file(gc, path); if (errno == EINTR) continue; LOGE(ERROR, "failed to remove %s", path); return ERROR_FAIL; } } int libxl__remove_directory(libxl__gc *gc, const char *dirpath) { int rc = 0; DIR *d = 0; d = opendir(dirpath); if (!d) { if (errno == ENOENT) goto out; LOGE(ERROR, "failed to opendir %s for removal", dirpath); rc = ERROR_FAIL; goto out; } struct dirent *de; for (;;) { errno = 0; de = readdir(d); if (!de && errno) { LOGE(ERROR, "failed to readdir %s for removal", dirpath); rc = ERROR_FAIL; break; } if (!de) break; if (!strcmp(de->d_name, ".") || !strcmp(de->d_name, "..")) continue; const char *subpath = GCSPRINTF("%s/%s", dirpath, de->d_name); if (libxl__remove_file_or_directory(gc, subpath)) rc = ERROR_FAIL; } for (;;) { int r = rmdir(dirpath); if (!r) break; if (errno == ENOENT) goto out; if (errno == EINTR) continue; LOGE(ERROR, "failed to remove emptied directory %s", dirpath); rc = ERROR_FAIL; } out: if (d) closedir(d); return rc; } int libxl_pipe(libxl_ctx *ctx, int pipes[2]) { GC_INIT(ctx); int ret = 0; if (pipe(pipes) < 0) { LOG(ERROR, "Failed to create a pipe"); ret = -1; } GC_FREE; return ret; } int libxl_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *bitmap, int n_bits) { GC_INIT(ctx); int sz; sz = (n_bits + 7) / 8; bitmap->map = libxl__calloc(NOGC, sizeof(*bitmap->map), sz); bitmap->size = sz; GC_FREE; return 0; } void libxl_bitmap_init(libxl_bitmap *map) { memset(map, '\0', sizeof(*map)); } void libxl_bitmap_dispose(libxl_bitmap *map) { if (!map) return; free(map->map); map->map = NULL; map->size = 0; } void libxl_bitmap_copy(libxl_ctx *ctx, libxl_bitmap *dptr, const libxl_bitmap *sptr) { int sz; assert(dptr->size == sptr->size); sz = dptr->size = sptr->size; memcpy(dptr->map, sptr->map, sz * sizeof(*dptr->map)); } /* This function copies X bytes from source to destination bitmap, * where X is the smaller of the two sizes. * * If destination's size is larger than source, the extra bytes are * untouched. */ void libxl__bitmap_copy_best_effort(libxl__gc *gc, libxl_bitmap *dptr, const libxl_bitmap *sptr) { int sz; sz = dptr->size < sptr->size ? dptr->size : sptr->size; memcpy(dptr->map, sptr->map, sz * sizeof(*dptr->map)); } void libxl_bitmap_copy_alloc(libxl_ctx *ctx, libxl_bitmap *dptr, const libxl_bitmap *sptr) { GC_INIT(ctx); dptr->map = libxl__calloc(NOGC, sptr->size, sizeof(*sptr->map)); dptr->size = sptr->size; memcpy(dptr->map, sptr->map, sptr->size * sizeof(*sptr->map)); GC_FREE; } int libxl_bitmap_is_full(const libxl_bitmap *bitmap) { int i; for (i = 0; i < bitmap->size; i++) if (bitmap->map[i] != (uint8_t)-1) return 0; return 1; } int libxl_bitmap_is_empty(const libxl_bitmap *bitmap) { int i; for (i = 0; i < bitmap->size; i++) if (bitmap->map[i]) return 0; return 1; } int libxl_bitmap_test(const libxl_bitmap *bitmap, int bit) { if (bit >= bitmap->size * 8 || bit < 0) return 0; return (bitmap->map[bit / 8] & (1 << (bit & 7))) ? 1 : 0; } void libxl_bitmap_set(libxl_bitmap *bitmap, int bit) { if (bit >= bitmap->size * 8 || bit < 0) return; bitmap->map[bit / 8] |= 1 << (bit & 7); } void libxl_bitmap_reset(libxl_bitmap *bitmap, int bit) { if (bit >= bitmap->size * 8 || bit < 0) return; bitmap->map[bit / 8] &= ~(1 << (bit & 7)); } int libxl_bitmap_or(libxl_ctx *ctx, libxl_bitmap *or_map, const libxl_bitmap *map1, const libxl_bitmap *map2) { GC_INIT(ctx); int rc; uint32_t i; const libxl_bitmap *large_map; const libxl_bitmap *small_map; if (map1->size > map2->size) { large_map = map1; small_map = map2; } else { large_map = map2; small_map = map1; } rc = libxl_bitmap_alloc(ctx, or_map, large_map->size * 8); if (rc) goto out; /* * If bitmaps aren't the same size, their union (logical or) will * be size of larger bit map. Any bit past the end of the * smaller bit map, will match the larger one. */ for (i = 0; i < small_map->size; i++) or_map->map[i] = (small_map->map[i] | large_map->map[i]); for (i = small_map->size; i < large_map->size; i++) or_map->map[i] = large_map->map[i]; out: GC_FREE; return rc; } int libxl_bitmap_and(libxl_ctx *ctx, libxl_bitmap *and_map, const libxl_bitmap *map1, const libxl_bitmap *map2) { GC_INIT(ctx); int rc; uint32_t i; const libxl_bitmap *large_map; const libxl_bitmap *small_map; if (map1->size > map2->size) { large_map = map1; small_map = map2; } else { large_map = map2; small_map = map1; } rc = libxl_bitmap_alloc(ctx, and_map, small_map->size * 8); if (rc) goto out; /* * If bitmaps aren't same size, their 'and' will be size of * smaller bit map */ for (i = 0; i < and_map->size; i++) and_map->map[i] = (large_map->map[i] & small_map->map[i]); out: GC_FREE; return rc; } int libxl_bitmap_count_set(const libxl_bitmap *bitmap) { int i, nr_set_bits = 0; libxl_for_each_set_bit(i, *bitmap) nr_set_bits++; return nr_set_bits; } /* NB. caller is responsible for freeing the memory */ char *libxl_bitmap_to_hex_string(libxl_ctx *ctx, const libxl_bitmap *bitmap) { GC_INIT(ctx); int i = bitmap->size; char *p = libxl__zalloc(NOGC, bitmap->size * 2 + 3); char *q = p; strncpy(p, "0x", 3); p += 2; while(--i >= 0) { sprintf(p, "%02x", bitmap->map[i]); p += 2; } *p = '\0'; GC_FREE; return q; } int libxl_cpu_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *cpumap, int max_cpus) { GC_INIT(ctx); int rc = 0; if (max_cpus < 0) { rc = ERROR_INVAL; LOG(ERROR, "invalid number of cpus provided"); goto out; } if (max_cpus == 0) max_cpus = libxl_get_max_cpus(ctx); if (max_cpus < 0) { LOG(ERROR, "failed to retrieve the maximum number of cpus"); rc = max_cpus; goto out; } /* This can't fail: no need to check and log */ libxl_bitmap_alloc(ctx, cpumap, max_cpus); out: GC_FREE; return rc; } int libxl_node_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *nodemap, int max_nodes) { GC_INIT(ctx); int rc = 0; if (max_nodes < 0) { rc = ERROR_INVAL; LOG(ERROR, "invalid number of nodes provided"); goto out; } if (max_nodes == 0) max_nodes = libxl_get_max_nodes(ctx); if (max_nodes < 0) { LOG(ERROR, "failed to retrieve the maximum number of nodes"); rc = max_nodes; goto out; } /* This can't fail: no need to check and log */ libxl_bitmap_alloc(ctx, nodemap, max_nodes); out: GC_FREE; return rc; } int libxl__count_physical_sockets(libxl__gc *gc, int *sockets) { int rc; libxl_physinfo info; libxl_physinfo_init(&info); rc = libxl_get_physinfo(CTX, &info); if (rc) return rc; *sockets = info.nr_cpus / info.threads_per_core / info.cores_per_socket; libxl_physinfo_dispose(&info); return 0; } int libxl_socket_bitmap_alloc(libxl_ctx *ctx, libxl_bitmap *socketmap, int max_sockets) { GC_INIT(ctx); int rc = 0; if (max_sockets < 0) { rc = ERROR_INVAL; LOG(ERROR, "invalid number of sockets provided"); goto out; } if (max_sockets == 0) { rc = libxl__count_physical_sockets(gc, &max_sockets); if (rc) { LOGE(ERROR, "failed to get system socket count"); goto out; } } /* This can't fail: no need to check and log */ libxl_bitmap_alloc(ctx, socketmap, max_sockets); out: GC_FREE; return rc; } int libxl_get_online_socketmap(libxl_ctx *ctx, libxl_bitmap *socketmap) { libxl_cputopology *tinfo = NULL; int nr_cpus = 0, i, rc = 0; tinfo = libxl_get_cpu_topology(ctx, &nr_cpus); if (tinfo == NULL) { rc = ERROR_FAIL; goto out; } libxl_bitmap_set_none(socketmap); for (i = 0; i < nr_cpus; i++) if (tinfo[i].socket != XEN_INVALID_SOCKET_ID && !libxl_bitmap_test(socketmap, tinfo[i].socket)) libxl_bitmap_set(socketmap, tinfo[i].socket); out: libxl_cputopology_list_free(tinfo, nr_cpus); return rc; } int libxl_nodemap_to_cpumap(libxl_ctx *ctx, const libxl_bitmap *nodemap, libxl_bitmap *cpumap) { libxl_cputopology *tinfo = NULL; int nr_cpus = 0, i, rc = 0; tinfo = libxl_get_cpu_topology(ctx, &nr_cpus); if (tinfo == NULL) { rc = ERROR_FAIL; goto out; } libxl_bitmap_set_none(cpumap); for (i = 0; i < nr_cpus; i++) { if (libxl_bitmap_test(nodemap, tinfo[i].node)) libxl_bitmap_set(cpumap, i); } out: libxl_cputopology_list_free(tinfo, nr_cpus); return rc; } int libxl_node_to_cpumap(libxl_ctx *ctx, int node, libxl_bitmap *cpumap) { libxl_bitmap nodemap; int rc = 0; libxl_bitmap_init(&nodemap); rc = libxl_node_bitmap_alloc(ctx, &nodemap, 0); if (rc) goto out; libxl_bitmap_set_none(&nodemap); libxl_bitmap_set(&nodemap, node); rc = libxl_nodemap_to_cpumap(ctx, &nodemap, cpumap); out: libxl_bitmap_dispose(&nodemap); return rc; } int libxl_cpumap_to_nodemap(libxl_ctx *ctx, const libxl_bitmap *cpumap, libxl_bitmap *nodemap) { libxl_cputopology *tinfo = NULL; int nr_cpus = 0, i, rc = 0; tinfo = libxl_get_cpu_topology(ctx, &nr_cpus); if (tinfo == NULL) { rc = ERROR_FAIL; goto out; } libxl_bitmap_set_none(nodemap); libxl_for_each_set_bit(i, *cpumap) { if (i >= nr_cpus) break; libxl_bitmap_set(nodemap, tinfo[i].node); } out: libxl_cputopology_list_free(tinfo, nr_cpus); return rc; } int libxl_get_max_cpus(libxl_ctx *ctx) { int max_cpus = xc_get_max_cpus(ctx->xch); return max_cpus < 0 ? ERROR_FAIL : max_cpus; } int libxl_get_online_cpus(libxl_ctx *ctx) { int online_cpus = xc_get_online_cpus(ctx->xch); return online_cpus < 0 ? ERROR_FAIL : online_cpus; } int libxl_get_max_nodes(libxl_ctx *ctx) { int max_nodes = xc_get_max_nodes(ctx->xch); return max_nodes < 0 ? ERROR_FAIL : max_nodes; } int libxl__enum_from_string(const libxl_enum_string_table *t, const char *s, int *e) { if (!t) return ERROR_INVAL; for( ; t->s; t++) { if (!strcasecmp(t->s, s)) { *e = t->v; return 0; } } return ERROR_FAIL; } void libxl_cputopology_list_free(libxl_cputopology *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_cputopology_dispose(&list[i]); free(list); } void libxl_pcitopology_list_free(libxl_pcitopology *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_pcitopology_dispose(&list[i]); free(list); } void libxl_numainfo_list_free(libxl_numainfo *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_numainfo_dispose(&list[i]); free(list); } void libxl_vcpuinfo_list_free(libxl_vcpuinfo *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_vcpuinfo_dispose(&list[i]); free(list); } int libxl__sendmsg_fds(libxl__gc *gc, int carrier, const char data, int nfds, const int fds[], const char *what) { struct msghdr msg = { 0 }; struct cmsghdr *cmsg; size_t spaceneeded = nfds * sizeof(fds[0]); char control[CMSG_SPACE(spaceneeded)]; const size_t datalen = 1; struct iovec iov; int r; iov.iov_base = (void*)&data; iov.iov_len = datalen; /* compose the message */ msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = control; msg.msg_controllen = sizeof(control); /* attach open fd */ cmsg = CMSG_FIRSTHDR(&msg); cmsg->cmsg_level = SOL_SOCKET; cmsg->cmsg_type = SCM_RIGHTS; cmsg->cmsg_len = CMSG_LEN(spaceneeded); memcpy(CMSG_DATA(cmsg), fds, spaceneeded); msg.msg_controllen = cmsg->cmsg_len; while (1) { r = sendmsg(carrier, &msg, 0); if (r < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK) { return ERROR_NOT_READY; } LOGE(ERROR, "failed to send fd-carrying message (%s)", what); return ERROR_FAIL; } if (r != datalen) { LOG(ERROR, "sendmsg have written %d instead of %zu", r, datalen); return ERROR_FAIL; } break; }; return 0; } int libxl__recvmsg_fds(libxl__gc *gc, int carrier, void *databuf, size_t datalen, int nfds, int fds[], const char *what) { struct msghdr msg = { 0 }; struct cmsghdr *cmsg; size_t spaceneeded = nfds * sizeof(fds[0]); char control[CMSG_SPACE(spaceneeded)]; struct iovec iov; int r; iov.iov_base = databuf; iov.iov_len = datalen; msg.msg_iov = &iov; msg.msg_iovlen = 1; msg.msg_control = control; msg.msg_controllen = sizeof(control); for (;;) { r = recvmsg(carrier, &msg, 0); if (r < 0) { if (errno == EINTR) continue; if (errno == EWOULDBLOCK) return -1; LOGE(ERROR,"recvmsg failed (%s)", what); return ERROR_FAIL; } if (r == 0) { LOG(ERROR,"recvmsg got EOF (%s)", what); return ERROR_FAIL; } cmsg = CMSG_FIRSTHDR(&msg); if (cmsg->cmsg_len <= CMSG_LEN(0)) { LOG(ERROR,"recvmsg got no control msg" " when expecting fds (%s)", what); return ERROR_FAIL; } if (cmsg->cmsg_level != SOL_SOCKET || cmsg->cmsg_type != SCM_RIGHTS) { LOG(ERROR, "recvmsg got unexpected" " cmsg_level %d (!=%d) or _type %d (!=%d) (%s)", cmsg->cmsg_level, SOL_SOCKET, cmsg->cmsg_type, SCM_RIGHTS, what); return ERROR_FAIL; } if (cmsg->cmsg_len != CMSG_LEN(spaceneeded) || msg.msg_controllen != cmsg->cmsg_len) { LOG(ERROR, "recvmsg got unexpected" " number of fds or extra control data" " (%ld bytes' worth, expected %ld) (%s)", (long)CMSG_LEN(spaceneeded), (long)cmsg->cmsg_len, what); int i, fd; unsigned char *p; for (i=0, p=CMSG_DATA(cmsg); CMSG_SPACE(i * sizeof(fds[0])); i++, i+=sizeof(fd)) { memcpy(&fd, p, sizeof(fd)); close(fd); } return ERROR_FAIL; } memcpy(fds, CMSG_DATA(cmsg), spaceneeded); return 0; } } void libxl_dominfo_list_free(libxl_dominfo *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_dominfo_dispose(&list[i]); free(list); } void libxl_vminfo_list_free(libxl_vminfo *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_vminfo_dispose(&list[i]); free(list); } void libxl_cpupoolinfo_list_free(libxl_cpupoolinfo *list, int nr) { int i; for (i = 0; i < nr; i++) libxl_cpupoolinfo_dispose(&list[i]); free(list); } int libxl_domid_valid_guest(uint32_t domid) { /* returns 1 if the value _could_ be a valid guest domid, 0 otherwise * does not check whether the domain actually exists */ return domid > 0 && domid < DOMID_FIRST_RESERVED; } void libxl_string_copy(libxl_ctx *ctx, char **dst, char * const*src) { GC_INIT(ctx); if (*src) *dst = libxl__strdup(NOGC, *src); else *dst = NULL; GC_FREE; } /* * Fill @buf with @len random bytes. */ int libxl__random_bytes(libxl__gc *gc, uint8_t *buf, size_t len) { static const char *dev = "/dev/urandom"; int fd; int ret; fd = open(dev, O_RDONLY); if (fd < 0) { LOGE(ERROR, "failed to open \"%s\"", dev); return ERROR_FAIL; } ret = libxl_fd_set_cloexec(CTX, fd, 1); if (ret) { close(fd); return ERROR_FAIL; } ret = libxl_read_exactly(CTX, fd, buf, len, dev, NULL); close(fd); return ret; } int libxl__prepare_sockaddr_un(libxl__gc *gc, struct sockaddr_un *un, const char *path, const char *what) { if (sizeof(un->sun_path) - 1 <= strlen(path)) { LOG(ERROR, "UNIX socket path '%s' is too long for %s", path, what); LOG(DEBUG, "Path must be less than %zu bytes", sizeof(un->sun_path) - 1); return ERROR_INVAL; } memset(un, 0, sizeof(struct sockaddr_un)); un->sun_family = AF_UNIX; strncpy(un->sun_path, path, sizeof(un->sun_path) - 1); return 0; } /* * Local variables: * mode: C * c-basic-offset: 4 * indent-tabs-mode: nil * End: */