char* clickos_read_handler(int domid, char *elem, char *attr) { char *ctrlpath = NULL, *elempath = NULL; char *rpath = NULL, *wpath = NULL; char *value; int err; unsigned int len = 0; struct pollfd fds[1]; if (!xs) { xenstore_init(domid); } asprintf(&ctrlpath, "/local/domain/%d/clickos/0/control", domid); asprintf(&elempath, "/local/domain/%d/clickos/0/elements", domid); asprintf(&wpath, "%s/read/%s/%s", ctrlpath, elem, attr); asprintf(&rpath, "%s/%s/%s", elempath, elem, attr); th = xs_transaction_start(xs); xenstore_write(wpath, " "); xs_transaction_end(xs, th, 0); err = xs_watch(xs, rpath, "lock"); if (!err) { printf("Error setting a watch\n"); return NULL; } fds[0].fd = xs_fileno(xs); fds[0].events = (POLLIN); while (len <= 0) { if (poll(fds, 1, 1000) <= 0) { continue; } retry_wh: th = xs_transaction_start(xs); //value = xenstore_read(rpath); value = xs_read(xs, XBT_NULL, rpath, &len); //printf("read: len %d value %s\n", len, value); if (!xs_transaction_end(xs, th, 0)) { if (errno == EAGAIN) goto retry_wh; } usleep(5000); } err = xs_unwatch(xs, rpath, "lock"); th = xs_transaction_start(xs); xs_write(xs, th, rpath, "", 0); err = xs_transaction_end(xs, th, 0); return value; }
char *getval(struct xs_handle *h, const char *path) { char *p = NULL; xs_transaction_t xth; unsigned int len; if ((xth = xs_transaction_start(h)) == XBT_NULL) { printf("unable to start xs trasanction\n"); return p; } p = xs_read(h, xth, path, &len); xs_transaction_end(h, xth, 0); return p; }
static int libxl__write_stub_dmargs(libxl__gc *gc, int dm_domid, int guest_domid, char **args) { libxl_ctx *ctx = libxl__gc_owner(gc); int i; char *vm_path; char *dmargs, *path; int dmargs_size; struct xs_permissions roperm[2]; xs_transaction_t t; roperm[0].id = 0; roperm[0].perms = XS_PERM_NONE; roperm[1].id = dm_domid; roperm[1].perms = XS_PERM_READ; vm_path = libxl__xs_read(gc, XBT_NULL, libxl__sprintf(gc, "/local/domain/%d/vm", guest_domid)); i = 0; dmargs_size = 0; while (args[i] != NULL) { dmargs_size = dmargs_size + strlen(args[i]) + 1; i++; } dmargs_size++; dmargs = (char *) malloc(dmargs_size); i = 1; dmargs[0] = '\0'; while (args[i] != NULL) { if (strcmp(args[i], "-sdl") && strcmp(args[i], "-M") && strcmp(args[i], "xenfv")) { strcat(dmargs, " "); strcat(dmargs, args[i]); } i++; } path = libxl__sprintf(gc, "%s/image/dmargs", vm_path); retry_transaction: t = xs_transaction_start(ctx->xsh); xs_write(ctx->xsh, t, path, dmargs, strlen(dmargs)); xs_set_permissions(ctx->xsh, t, path, roperm, ARRAY_SIZE(roperm)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(gc, "%s/rtc/timeoffset", vm_path), roperm, ARRAY_SIZE(roperm)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; free(dmargs); return 0; }
int setval(struct xs_handle *h, const char *path, const char *val) { int ret = 0; xs_transaction_t xth; unsigned int len; if ((xth = xs_transaction_start(h)) == XBT_NULL) { printf("unable to start xs trasanction\n"); return ret; } len = strlen(val); ret = (xs_write(h, xth, path, val, len)? 1 : 0); xs_transaction_end(h, xth, 0); return ret; }
char *xenstore_read(const char *format, ...) { char *buff = NULL; char *ret = NULL; va_list arg; xs_transaction_t t; va_start(arg, format); vasprintf(&buff, format, arg); va_end(arg); t = xs_transaction_start(xs); ret = xs_read(xs, t, buff, NULL); xs_transaction_end(xs, t, false); free(buff); return ret; }
/* * Start XenStore transaction. * If successful, return @true. * On error, return @false and log error message. . */ static bool begin_xs(void) { int nretries = 0; if (xst != XS_TRANSACTION_NULL) fatal_msg("bug: begin_xs inside a transaction"); for (;;) { xst = xs_transaction_start(xs); if (xst != XS_TRANSACTION_NULL) break; /* * ENOSPC means too many concurrent transactions from the domain */ if (errno == ENOSPC) { if (++nretries > max_xs_retries) { error_perror("unable to start xenstore transaction (retry limit exceeded)"); break; } retry_wait(nretries); debug_msg(2, "retrying to start xenstore transaction"); } else { error_perror("unable to start xenstore transaction"); break; } } if (xst != XS_TRANSACTION_NULL) { debug_msg(15, "started transaction"); return true; } else { return false; } }
int clickos_stop(int domid, int configid) { char *statuspath = NULL; if (!xs) { xenstore_init(domid); } asprintf(&statuspath, "/local/domain/%d/clickos/%d/status", domid, configid); retry_stop: th = xs_transaction_start(xs); xenstore_write(statuspath, "Halted"); if (!xs_transaction_end(xs, th, 0)) { if (errno == EAGAIN) goto retry_stop; } return 0; }
int xs_exists(struct xs_handle *h, const char *path) { char **d; unsigned int num; xs_transaction_t xth; if ((xth = xs_transaction_start(h)) == XBT_NULL) { printf("unable to start xs trasanction\n"); return 0; } d = xs_directory(h, xth, path, &num); xs_transaction_end(h, xth, 0); if (!d) return 0; free(d); return 1; }
char *dirlist(struct xs_handle *h, const char *path) { char **d, *p, *ptr; xs_transaction_t xth; unsigned int num, j=0, count = 0; if ((p = calloc(1,MAXDIRBUF))==NULL) { printf("unable to allocate memory\n"); return NULL; } if ((xth = xs_transaction_start(h)) == XBT_NULL) { printf("unable to start xs trasanction\n"); return p; } d = xs_directory(h, xth, path, &num); xs_transaction_end(h, xth, 0); if (!d) return p; ptr = p; while(j < num) { ptr = p + count; if ((count + strlen(d[j]) + 1) > MAXDIRBUF) { printf("Reached max dir entry\n"); return p; } if (j) { *ptr = '|'; *ptr++; count++; } count += sprintf(ptr, d[j]); j++; } free(d); return p; }
int xenstore_init(void) { unsigned int len, domid; char *buf; char *end; xs = xs_domain_open(); if (xs == NULL) { RTE_LOG(ERR, PMD,"%s: xs_domain_open failed\n", __func__); return -1; } buf = xs_read(xs, XBT_NULL, "domid", &len); if (buf == NULL) { RTE_LOG(ERR, PMD, "%s: failed read domid\n", __func__); return -1; } errno = 0; domid = strtoul(buf, &end, 0); if (errno != 0 || end == NULL || end == buf || domid == 0) return -1; RTE_LOG(INFO, PMD, "retrieved dom ID = %d\n", domid); dompath = xs_get_domain_path(xs, domid); if (dompath == NULL) return -1; xs_transaction_start(xs); /* When to stop transaction */ if (is_xenstore_cleaned_up == 0) { if (xenstore_cleanup()) return -1; is_xenstore_cleaned_up = 1; } return 0; }
void libxl__spawn_local_dm(libxl__egc *egc, libxl__dm_spawn_state *dmss) { /* convenience aliases */ const int domid = dmss->guest_domid; libxl__domain_build_state *const state = dmss->build_state; libxl__spawn_state *const spawn = &dmss->spawn; STATE_AO_GC(dmss->spawn.ao); libxl_ctx *ctx = CTX; libxl_domain_config *guest_config = dmss->guest_config; const libxl_domain_create_info *c_info = &guest_config->c_info; const libxl_domain_build_info *b_info = &guest_config->b_info; const libxl_vnc_info *vnc = libxl__dm_vnc(guest_config); char *path, *logfile; int logfile_w, null; int rc; char **args, **arg; xs_transaction_t t; char *vm_path; char **pass_stuff; const char *dm; if (libxl_defbool_val(b_info->device_model_stubdomain)) { abort(); } dm = libxl__domain_device_model(gc, b_info); if (!dm) { rc = ERROR_FAIL; goto out; } if (access(dm, X_OK) < 0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "device model %s is not executable", dm); rc = ERROR_FAIL; goto out; } args = libxl__build_device_model_args(gc, dm, domid, guest_config, state); if (!args) { rc = ERROR_FAIL; goto out; } if (b_info->type == LIBXL_DOMAIN_TYPE_HVM) { path = xs_get_domain_path(ctx->xsh, domid); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/hvmloader/bios", path), "%s", libxl_bios_type_to_string(b_info->u.hvm.bios)); /* Disable relocating memory to make the MMIO hole larger * unless we're running qemu-traditional */ libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/hvmloader/allow-memory-relocate", path), "%d", b_info->device_model_version==LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL); free(path); } path = libxl__sprintf(gc, "/local/domain/0/device-model/%d", domid); xs_mkdir(ctx->xsh, XBT_NULL, path); if (b_info->type == LIBXL_DOMAIN_TYPE_HVM && b_info->device_model_version == LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL) libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/disable_pf", path), "%d", !libxl_defbool_val(b_info->u.hvm.xen_platform_pci)); libxl_create_logfile(ctx, libxl__sprintf(gc, "qemu-dm-%s", c_info->name), &logfile); logfile_w = open(logfile, O_WRONLY|O_CREAT|O_APPEND, 0644); free(logfile); null = open("/dev/null", O_RDONLY); const char *dom_path = libxl__xs_get_dompath(gc, domid); spawn->pidpath = GCSPRINTF("%s/%s", dom_path, "image/device-model-pid"); if (vnc && vnc->passwd) { /* This xenstore key will only be used by qemu-xen-traditionnal. * The code to supply vncpasswd to qemu-xen is later. */ retry_transaction: /* Find uuid and the write the vnc password to xenstore for qemu. */ t = xs_transaction_start(ctx->xsh); vm_path = libxl__xs_read(gc,t,libxl__sprintf(gc, "%s/vm", dom_path)); if (vm_path) { /* Now write the vncpassword into it. */ pass_stuff = libxl__calloc(gc, 3, sizeof(char *)); pass_stuff[0] = "vncpasswd"; pass_stuff[1] = vnc->passwd; libxl__xs_writev(gc,t,vm_path,pass_stuff); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; } } LIBXL__LOG(CTX, XTL_DEBUG, "Spawning device-model %s with arguments:", dm); for (arg = args; *arg; arg++) LIBXL__LOG(CTX, XTL_DEBUG, " %s", *arg); spawn->what = GCSPRINTF("domain %d device model", domid); spawn->xspath = GCSPRINTF("/local/domain/0/device-model/%d/state", domid); spawn->timeout_ms = LIBXL_DEVICE_MODEL_START_TIMEOUT * 1000; spawn->pidpath = GCSPRINTF("%s/image/device-model-pid", dom_path); spawn->midproc_cb = libxl__spawn_record_pid; spawn->confirm_cb = device_model_confirm; spawn->failure_cb = device_model_startup_failed; spawn->detached_cb = device_model_detached; rc = libxl__spawn_spawn(egc, spawn); if (rc < 0) goto out_close; if (!rc) { /* inner child */ setsid(); libxl__exec(gc, null, logfile_w, logfile_w, dm, args, NULL); } rc = 0; out_close: close(null); close(logfile_w); out: if (rc) device_model_spawn_outcome(egc, dmss, rc); }
main(int argc, char **argv) { int ret; pthread_t rcv_thread; uint64_t threadid; uint32_t redirect_input = 0; char *parse_string; char send_buf[RSH_BUF_SIZE]; char input_file_name[MAX_FILE_STRING]; int option = 0; int target_endpoint = 0; int input_commands; int i,j; if (argc < 2) { printf("\n\nusage ... \n\n"); printf("\tvxt_rsh <name>\n\n"); return -1; } i = 1; j = 0; input_commands = 0; input_file_name[0] = '\0'; parse_string = NULL; while(i < argc) { /* * We may parse multiple flags or options into * one token if there are no spaces. Hence * the while loop below. */ while ((i < argc) && (argv[i][j] != '\0')) { VXTPRINT(4, "switch on, %c\n", argv[i][j]); switch(argv[i][j]) { case '-': { if (option) { VXTPRINT(4, "double option \"-\"\n"); return command_line_error(); } option = 1; j++; break; } case 'I': { if (option == 1) { VXTPRINT(4, "case I, " "Input redirection\n"); parse_string = input_file_name; } /* * We are now in an option parse * for a string, go to the option * string reader, we may not have a * space to separate the option letter from * its string. */ ret = vxtdb_parse_option_parm(argv, argc, parse_string, &option, &i, &j); if (ret != 0) { return ret; } if (option == 0) { parse_string = NULL; } break; } default: { VXTPRINT(4, "default, i %d, j %d\n",i,j); if (option) { VXTPRINT(4, "in option parsing\n"); if (parse_string == input_file_name) { VXTPRINT(4, "in filestring " "aquisition\n"); strncpy(parse_string, &(argv[i][j]), MAX_FILE_STRING); option = 0; j=0; i++; parse_string [MAX_FILE_STRING - 1] = 0; parse_string = NULL; VXTPRINT(4, "finished getting " "filename after " "space\n"); break; } else { printf("\n\nUnknown Option\n"); return command_line_error(); } } else { if (j != 0) { VXTPRINT(4, "starting in the" "middle of default " "string\n"); return command_line_error(); } if (target_endpoint != 0) { return command_line_error(); } target_endpoint = 1; target_domain = atoi(&argv[i][j]); i++; } } if (i >= argc) { break; } } } option = 0; j = 0; i++; } pthread_mutex_init(&rcv_sync_lock, NULL); pthread_cond_init(&rcv_sync_var, NULL); VXTPRINT(4, "redirect file name: %s\n", input_file_name); if (target_domain == 0) { /* * Default connection to the HUB */ strncpy(target_uuid, VXTDB_DOM0_ENDPOINT, MAX_VXT_UUID); } else { vxt_db_query_arg_t query_arg; int authdev; VXTPRINT(3, "Open VxT Authorization Database\n"); authdev = open("/dev/vxtdb-auth", O_RDWR); if(authdev < 0) { VXTPRINT(0, "\n\nFailed to open the Vxt authorization " "database device\n\n"); return -1; } query_arg.hub = 1; ioctl(authdev, VXT_AUTH_DB_QUERY, (void *)(long)&query_arg); if (!query_arg.hub) { /* * Get the routing and authorization through the * auth db intermediary. */ VXTPRINT(3, "We are not a hub, use default routing." " If in future we utilize a physical device" " With internal routing, code may go here\n"); strncpy(target_uuid, VXTDB_DOM0_ENDPOINT, MAX_VXT_UUID); } else { #ifdef XSTOOLS struct xs_handle *xs; xs_transaction_t th; int len; char ep_id_path[32]; char *xenstore_uuid_path; xs = xs_domain_open(); if (!xs) { perror("xs_domain_open failure"); return -1; } sprintf(ep_id_path, "/local/domain/%d/vm", target_domain); th = xs_transaction_start(xs); xenstore_uuid_path = (char *) xs_read(xs, th, ep_id_path, &len); if (!xenstore_uuid_path) { VXTPRINT(0, "Target domain %d not valid. " "Exiting...\n", target_domain); return -1; } strncpy(target_uuid, &(xenstore_uuid_path[4]), MAX_VXT_UUID-4); free(xenstore_uuid_path); target_uuid[MAX_VXT_UUID-1] = 0; if(!xs_transaction_end(xs, th, 0)) { VXTPRINT(0, "Could not read xenstore database\n"); return -1; } #else strncpy(target_uuid, VXTDB_DOM0_ENDPOINT, MAX_VXT_UUID); #endif } } vrsh_set_sig_handler(); ret = vrsh_create_device(&vsock); if (ret != VXT_SUCCESS) { return -1; } vxt_mb(); ret = pthread_create(&rcv_thread, NULL, (void *) &rsh_rcv_thread, (void *)&vsock); if (ret == -1) { endwin(); return -1; } /* * Starting local interpreter */ while(TRUE) { char buf[1024]; int vxt_send_len; int read_len; size_t len = 0; ssize_t read_size; /* char *line = NULL; read_size = getline(&line, &len, stdin); VXTPRINT(4, "Picked up command: %s of length %d\n", line, read_size); */ if (strnlen(input_file_name, MAX_FILE_STRING) != 0) { input_commands = open(input_file_name, O_RDWR); if(input_commands < 0) { VXTPRINT(0, "\n\n\tFailed to open the Vxt " "input redirection command file\n\n"); return -1; } while ((read_len = read(input_commands, &buf, 1024)) > 0) { vxt_send_len = read_len; while (vxt_send_len != 0) { ret = vxt_send(vsock, buf, &vxt_send_len, VXT_SOCK_SIGNAL | VXT_SOCK_WAIT); read_len -= vxt_send_len; vxt_send_len = read_len; } } pthread_mutex_lock(&rcv_sync_lock); pthread_cond_wait(&rcv_sync_var, &rcv_sync_lock); pthread_mutex_unlock(&rcv_sync_lock); return 0; } while ((read_len = read(STDOUT_FILENO, &buf, 1024)) > 0) { /* * Local debug trace, writes stream bound for * remote to stdout * write(STDOUT_FILENO, &buf, sendlen); */ vxt_send_len = read_len; while (vxt_send_len != 0) { ret = vxt_send(vsock, buf, &vxt_send_len, VXT_SOCK_SIGNAL | VXT_SOCK_WAIT); read_len -= vxt_send_len; vxt_send_len = read_len; } } } }
int libxl__domain_make(libxl__gc *gc, libxl_domain_create_info *info, uint32_t *domid) { libxl_ctx *ctx = libxl__gc_owner(gc); int flags, ret, rc, nb_vm; char *uuid_string; char *dom_path, *vm_path, *libxl_path; struct xs_permissions roperm[2]; struct xs_permissions rwperm[1]; struct xs_permissions noperm[1]; xs_transaction_t t = 0; xen_domain_handle_t handle; libxl_vminfo *vm_list; assert(!libxl_domid_valid_guest(*domid)); uuid_string = libxl__uuid2string(gc, info->uuid); if (!uuid_string) { rc = ERROR_NOMEM; goto out; } flags = 0; if (info->type == LIBXL_DOMAIN_TYPE_HVM) { flags |= XEN_DOMCTL_CDF_hvm_guest; flags |= libxl_defbool_val(info->hap) ? XEN_DOMCTL_CDF_hap : 0; flags |= libxl_defbool_val(info->oos) ? 0 : XEN_DOMCTL_CDF_oos_off; } *domid = -1; /* Ultimately, handle is an array of 16 uint8_t, same as uuid */ libxl_uuid_copy((libxl_uuid *)handle, &info->uuid); ret = xc_domain_create(ctx->xch, info->ssidref, handle, flags, domid); if (ret < 0) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain creation fail"); rc = ERROR_FAIL; goto out; } ret = xc_cpupool_movedomain(ctx->xch, info->poolid, *domid); if (ret < 0) { LIBXL__LOG_ERRNOVAL(ctx, LIBXL__LOG_ERROR, ret, "domain move fail"); rc = ERROR_FAIL; goto out; } dom_path = libxl__xs_get_dompath(gc, *domid); if (!dom_path) { rc = ERROR_FAIL; goto out; } vm_path = libxl__sprintf(gc, "/vm/%s", uuid_string); if (!vm_path) { LIBXL__LOG(ctx, LIBXL__LOG_ERROR, "cannot allocate create paths"); rc = ERROR_FAIL; goto out; } libxl_path = libxl__xs_libxl_path(gc, *domid); if (!libxl_path) { rc = ERROR_FAIL; goto out; } noperm[0].id = 0; noperm[0].perms = XS_PERM_NONE; roperm[0].id = 0; roperm[0].perms = XS_PERM_NONE; roperm[1].id = *domid; roperm[1].perms = XS_PERM_READ; rwperm[0].id = *domid; rwperm[0].perms = XS_PERM_NONE; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_rm(ctx->xsh, t, dom_path); libxl__xs_mkdir(gc, t, dom_path, roperm, ARRAY_SIZE(roperm)); xs_rm(ctx->xsh, t, vm_path); libxl__xs_mkdir(gc, t, vm_path, roperm, ARRAY_SIZE(roperm)); xs_rm(ctx->xsh, t, libxl_path); libxl__xs_mkdir(gc, t, libxl_path, noperm, ARRAY_SIZE(noperm)); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/vm", dom_path), vm_path, strlen(vm_path)); rc = libxl__domain_rename(gc, *domid, 0, info->name, t); if (rc) goto out; libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/cpu", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/memory", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/device", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/control", dom_path), roperm, ARRAY_SIZE(roperm)); if (info->type == LIBXL_DOMAIN_TYPE_HVM) libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/hvmloader", dom_path), roperm, ARRAY_SIZE(roperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/control/shutdown", dom_path), rwperm, ARRAY_SIZE(rwperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/device/suspend/event-channel", dom_path), rwperm, ARRAY_SIZE(rwperm)); libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/data", dom_path), rwperm, ARRAY_SIZE(rwperm)); if (info->type == LIBXL_DOMAIN_TYPE_HVM) libxl__xs_mkdir(gc, t, libxl__sprintf(gc, "%s/hvmloader/generation-id-address", dom_path), rwperm, ARRAY_SIZE(rwperm)); vm_list = libxl_list_vm(ctx, &nb_vm); if (!vm_list) { LOG(ERROR, "cannot get number of running guests"); rc = ERROR_FAIL; goto out; } libxl_vminfo_list_free(vm_list, nb_vm); int hotplug_setting = libxl__hotplug_settings(gc, t); if (hotplug_setting < 0) { LOG(ERROR, "unable to get current hotplug scripts execution setting"); rc = ERROR_FAIL; goto out; } if (libxl_defbool_val(info->run_hotplug_scripts) != hotplug_setting && (nb_vm - 1)) { LOG(ERROR, "cannot change hotplug execution option once set, " "please shutdown all guests before changing it"); rc = ERROR_FAIL; goto out; } if (libxl_defbool_val(info->run_hotplug_scripts)) { rc = libxl__xs_write_checked(gc, t, DISABLE_UDEV_PATH, "1"); if (rc) { LOGE(ERROR, "unable to write %s = 1", DISABLE_UDEV_PATH); goto out; } } else { rc = libxl__xs_rm_checked(gc, t, DISABLE_UDEV_PATH); if (rc) { LOGE(ERROR, "unable to delete %s", DISABLE_UDEV_PATH); goto out; } } xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/uuid", vm_path), uuid_string, strlen(uuid_string)); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/name", vm_path), info->name, strlen(info->name)); libxl__xs_writev(gc, t, dom_path, info->xsdata); libxl__xs_writev(gc, t, libxl__sprintf(gc, "%s/platform", dom_path), info->platformdata); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-multiprocessor-suspend", dom_path), "1", 1); xs_write(ctx->xsh, t, libxl__sprintf(gc, "%s/control/platform-feature-xs_reset_watches", dom_path), "1", 1); if (!xs_transaction_end(ctx->xsh, t, 0)) { if (errno == EAGAIN) { t = 0; goto retry_transaction; } LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "domain creation " "xenstore transaction commit failed"); rc = ERROR_FAIL; goto out; } t = 0; rc = 0; out: if (t) xs_transaction_end(ctx->xsh, t, 1); return rc; }
/** * Returns 0 on success, a negative error code otherwise. */ static inline int connect_frontend(vbd_t *device) { int err = 0; xs_transaction_t xst = XBT_NULL; bool abort_transaction = false; ASSERT(device); do { if (!(xst = xs_transaction_start(device->backend->xs))) { err = -errno; WARN(device, "failed to start transaction: %s\n", strerror(err)); goto out; } abort_transaction = true; /* * FIXME blkback writes discard-granularity, discard-alignment, * discard-secure, feature-discard, feature-barrier but we don't. */ /* * Write the number of sectors, sector size, and info to the * back-end path in XenStore so that the front-end creates a VBD * with the appropriate characteristics. */ if ((err = tapback_device_printf(device, xst, "sector-size", true, "%u", device->sector_size))) { WARN(device, "failed to write sector-size: %s\n", strerror(-err)); break; } if ((err = tapback_device_printf(device, xst, "sectors", true, "%llu", device->sectors))) { WARN(device, "failed to write sectors: %s\n", strerror(-err)); break; } if ((err = tapback_device_printf(device, xst, "info", true, "%u", device->info))) { WARN(device, "failed to write info: %s\n", strerror(-err)); break; } abort_transaction = false; if (!xs_transaction_end(device->backend->xs, xst, 0)) { err = -errno; ASSERT(err); } } while (err == -EAGAIN); if (abort_transaction) { if (!xs_transaction_end(device->backend->xs, xst, 1)) { int err2 = errno; WARN(device, "failed to abort transaction: %s\n", strerror(err2)); } goto out; } if (err) { WARN(device, "failed to end transaction: %s\n", strerror(-err)); goto out; } err = -xenbus_switch_state(device, XenbusStateConnected); if (err) WARN(device, "failed to switch back-end state to connected: %s\n", strerror(-err)); out: return err; }
static int libxl__fill_dom0_memory_info(libxl__gc *gc, uint64_t *target_memkb, uint64_t *max_memkb) { int rc; libxl_dominfo info; libxl_physinfo physinfo; char *target = NULL, *staticmax = NULL, *endptr = NULL; char *target_path = "/local/domain/0/memory/target"; char *max_path = "/local/domain/0/memory/static-max"; xs_transaction_t t; libxl_ctx *ctx = libxl__gc_owner(gc); libxl_dominfo_init(&info); retry_transaction: t = xs_transaction_start(ctx->xsh); target = libxl__xs_read(gc, t, target_path); staticmax = libxl__xs_read(gc, t, max_path); if (target && staticmax) { rc = 0; goto out; } if (target) { *target_memkb = strtoull(target, &endptr, 10); if (*endptr != '\0') { LOGED(ERROR, 0, "Invalid memory target %s from %s\n", target, target_path); rc = ERROR_FAIL; goto out; } } if (staticmax) { *max_memkb = strtoull(staticmax, &endptr, 10); if (*endptr != '\0') { LOGED(ERROR, 0, "Invalid memory static-max %s from %s\n", staticmax, max_path); rc = ERROR_FAIL; goto out; } } libxl_dominfo_dispose(&info); libxl_dominfo_init(&info); rc = libxl_domain_info(ctx, &info, 0); if (rc < 0) goto out; rc = libxl_get_physinfo(ctx, &physinfo); if (rc < 0) goto out; if (target == NULL) { libxl__xs_printf(gc, t, target_path, "%"PRIu64, info.current_memkb); *target_memkb = info.current_memkb; } if (staticmax == NULL) { libxl__xs_printf(gc, t, max_path, "%"PRIu64, info.max_memkb); *max_memkb = info.max_memkb; } rc = 0; out: if (!xs_transaction_end(ctx->xsh, t, 0)) { if (errno == EAGAIN) goto retry_transaction; else rc = ERROR_FAIL; } libxl_dominfo_dispose(&info); return rc; }
int main(int argc, char **argv) { struct xs_handle *xsh; xs_transaction_t xth = XBT_NULL; int ret = 0, socket = 0; int prefix = 0; int tidy = 0; int upto = 0; int recurse = 0; int nr_watches = -1; int transaction; struct winsize ws; enum mode mode; const char *_command = strrchr(argv[0], '/'); const char *command = _command ? &_command[1] : argv[0]; int switch_argv = -1; /* which element of argv did we switch on */ if (strncmp(command, "xenstore-", strlen("xenstore-")) == 0) { switch_argv = 0; command = command + strlen("xenstore-"); } else if (argc < 2) usage(MODE_unknown, 0, argv[0]); else { command = argv[1]; switch_argv = 1; } mode = lookup_mode(command); while (1) { int c, index = 0; static struct option long_options[] = { {"help", 0, 0, 'h'}, {"flat", 0, 0, 'f'}, /* MODE_ls */ {"socket", 0, 0, 's'}, {"prefix", 0, 0, 'p'}, /* MODE_read || MODE_list || MODE_ls */ {"tidy", 0, 0, 't'}, /* MODE_rm */ {"upto", 0, 0, 'u'}, /* MODE_chmod */ {"recurse", 0, 0, 'r'}, /* MODE_chmod */ {"number", 1, 0, 'n'}, /* MODE_watch */ {0, 0, 0, 0} }; c = getopt_long(argc - switch_argv, argv + switch_argv, "hfspturn:", long_options, &index); if (c == -1) break; switch (c) { case 'h': usage(mode, switch_argv, argv[0]); /* NOTREACHED */ case 'f': if ( mode == MODE_ls ) { max_width = INT_MAX/2; desired_width = 0; show_whole_path = 1; } else { usage(mode, switch_argv, argv[0]); } break; case 's': socket = 1; break; case 'p': if ( mode == MODE_read || mode == MODE_list || mode == MODE_ls ) prefix = 1; else usage(mode, switch_argv, argv[0]); break; case 't': if ( mode == MODE_rm ) tidy = 1; else usage(mode, switch_argv, argv[0]); break; case 'u': if ( mode == MODE_chmod ) upto = 1; else usage(mode, switch_argv, argv[0]); break; case 'r': if ( mode == MODE_chmod ) recurse = 1; else usage(mode, switch_argv, argv[0]); break; case 'n': if ( mode == MODE_watch ) nr_watches = atoi(optarg); else usage(mode, switch_argv, argv[0]); break; } } switch (mode) { case MODE_ls: break; case MODE_write: if ((argc - switch_argv - optind) % 2 == 1) { usage(mode, switch_argv, argv[0]); /* NOTREACHED */ } /* DROP-THRU */ default: if (optind == argc - switch_argv) { usage(mode, switch_argv, argv[0]); /* NOTREACHED */ } } switch (mode) { case MODE_read: transaction = (argc - switch_argv - optind) > 1; break; case MODE_write: transaction = (argc - switch_argv - optind) > 2; break; case MODE_ls: case MODE_watch: transaction = 0; break; default: transaction = 1; break; } if ( mode == MODE_ls ) { memset(&ws, 0, sizeof(ws)); ret = ioctl(STDOUT_FILENO, TIOCGWINSZ, &ws); if (!ret) max_width = ws.ws_col - 2; } xsh = xs_open(socket ? XS_OPEN_SOCKETONLY : 0); if (xsh == NULL) err(1, "xs_open"); again: if (transaction) { xth = xs_transaction_start(xsh); if (xth == XBT_NULL) errx(1, "couldn't start transaction"); } ret = perform(mode, optind, argc - switch_argv, argv + switch_argv, xsh, xth, prefix, tidy, upto, recurse, nr_watches); if (transaction && !xs_transaction_end(xsh, xth, ret)) { if (ret == 0 && errno == EAGAIN) { output_pos = 0; goto again; } errx(1, "couldn't end transaction"); } if (output_pos) printf("%s", output_buf); return ret; }
int main (int argc, char **argv) { int i; struct xs_handle *xs; xs_transaction_t th; char *path; int fd; fd_set set; int er; char **vec; unsigned int num_strings; char * buf; unsigned int len; char *program; char **arguments; int arguments_count; pid_t pid; int j; char *last_value = NULL; int status; program_name = argv[0]; i = decode_switches (argc, argv); if (argc - i < 1) usage(1); path = argv[i++]; if (argc - i > 0) { program = argv[i++]; arguments_count = argc - i; arguments = malloc(sizeof(char*) * (argc - i + 2)); arguments[0] = program; for (j=0; j<arguments_count; j++) arguments[j + 1] = argv[i + j]; arguments[j + 1] = NULL; } else { program = NULL; arguments = NULL; arguments_count = 0; } if (want_verbose) { printf("Path: %s\n", path); if (program) { printf("Program: %s", program); for (i=1; i<arguments_count + 1; i++) printf(" %s", arguments[i]); printf("\n"); } } /* Get a connection to the daemon */ xs = xs_daemon_open(); if ( xs == NULL ) xs = xs_domain_open(); if ( xs == NULL ) { error("Unable to connect to XenStore"); exit(1); } /* Create a watch on /local/domain/0/mynode. */ er = xs_watch(xs, path, "token"); if ( er == 0 ) { error("Unable to create watch"); exit(1); } /* We are notified of read availability on the watch via the * file descriptor. */ fd = xs_fileno(xs); while (1) { FD_ZERO(&set); FD_SET(fd, &set); /* Poll for data. */ if ( select(fd + 1, &set, NULL, NULL, NULL) > 0 && FD_ISSET(fd, &set)) { /* num_strings will be set to the number of elements in vec * (typically, 2 - the watched path and the token) */ vec = xs_read_watch(xs, &num_strings); if ( !vec ) { error("Unable to read watch"); continue; } if (want_verbose) printf("Path changed: %s\n", vec[XS_WATCH_PATH]); /* Prepare a transaction and do a read. */ th = xs_transaction_start(xs); buf = xs_read(xs, th, vec[XS_WATCH_PATH], &len); xs_transaction_end(xs, th, false); if (buf) { if (last_value && strcmp(buf, last_value) == 0) { if (want_verbose) printf("Value did not change\n"); continue; } if (want_verbose) printf("New value: %s\n", buf); if (program) { pid = fork(); if (pid == 0) { setenv("XENSTORE_WATCH_PATH", vec[XS_WATCH_PATH], 1); setenv("XENSTORE_WATCH_VALUE", buf, 1); for (i=0; arguments[i]; i++) { if (strcmp(arguments[i], "%v") == 0) arguments[i] = buf; else if (strcmp(arguments[i], "%p") == 0) arguments[i] = vec[XS_WATCH_PATH]; } execvp(program, arguments); error("Unable to start program"); exit(1); } else { waitpid(pid, &status, 0); } } else { if (!want_verbose) printf("%s\n", buf); } if (last_value) free(last_value); last_value = buf; } } } /* Cleanup */ close(fd); xs_daemon_close(xs); free(path); exit(0); }
/* * Populate Xenstore with the information about a usb device for this domain */ int xenstore_create_usb(dominfo_t *domp, usbinfo_t *usbp) { char *bepath, *fepath; char value[32]; xs_transaction_t trans; xd_log(LOG_DEBUG, "Creating VUSB node for %d.%d", usbp->usb_bus, usbp->usb_device); /* * Construct Xenstore paths for both the front and back ends. */ fepath = xs_dev_fepath(domp, "vusb", usbp->usb_virtid); bepath = xs_dev_bepath(domp, "vusb", usbp->usb_virtid); for (;;) { trans = xs_transaction_start(xs_handle); /* * Make directories for both front and back ends */ if (xs_add_dir(trans, bepath, 0, XS_PERM_NONE, domp->di_domid, XS_PERM_READ)) break; if (xs_add_dir(trans, fepath, domp->di_domid, XS_PERM_NONE, 0, XS_PERM_READ)) break; /* * Populate frontend device info */ if (xs_set_keyval(trans, fepath, "backend-id", "0")) break; snprintf(value, sizeof (value), "%d", usbp->usb_virtid); if (xs_set_keyval(trans, fepath, "virtual-device", value)) break; if (xs_set_keyval(trans, fepath, "backend", bepath)) break; snprintf(value, sizeof (value), "%d", XB_INITTING); if (xs_set_keyval(trans, fepath, "state", value)) break; /* * Populate backend device info */ if (xs_set_keyval(trans, bepath, "domain", domp->di_name)) break; if (xs_set_keyval(trans, bepath, "frontend", fepath)) break; snprintf(value, sizeof (value), "%d", XB_INITTING); if (xs_set_keyval(trans, bepath, "state", value)) break; if (xs_set_keyval(trans, bepath, "online", "1")) break; snprintf(value, sizeof (value), "%d", domp->di_domid); if (xs_set_keyval(trans, bepath, "frontend-id", value)) break; snprintf(value, sizeof (value), "%d.%d", usbp->usb_bus, usbp->usb_device); if (xs_set_keyval(trans, bepath, "physical-device", value)) break; if (xs_transaction_end(xs_handle, trans, false) == false) { if (errno == EAGAIN) continue; break; } free(fepath); free(bepath); xd_log(LOG_DEBUG, "Finished creating VUSB node for %d.%d", usbp->usb_bus, usbp->usb_device); return (0); } xs_transaction_end(xs_handle, trans, true); xd_log(LOG_ERR, "Failed to write usb info to XenStore"); free(fepath); free(bepath); return (-1); }
static int libxl_create_stubdom(libxl_ctx *ctx, libxl_device_model_info *info, libxl_device_disk *disks, int num_disks, libxl_device_nic *vifs, int num_vifs, libxl_device_vfb *vfb, libxl_device_vkb *vkb, libxl__device_model_starting **starting_r) { libxl__gc gc = LIBXL_INIT_GC(ctx); int i, num_console = STUBDOM_SPECIAL_CONSOLES, ret; libxl_device_console *console; libxl_domain_create_info c_info; libxl_domain_build_info b_info; libxl_domain_build_state state; uint32_t domid; char **args; struct xs_permissions perm[2]; xs_transaction_t t; libxl__device_model_starting *dm_starting = 0; args = libxl_build_device_model_args(&gc, info, vifs, num_vifs); if (!args) { ret = ERROR_FAIL; goto out; } memset(&c_info, 0x00, sizeof(libxl_domain_create_info)); c_info.hvm = 0; c_info.name = libxl__sprintf(&gc, "%s-dm", libxl__domid_to_name(&gc, info->domid)); libxl_uuid_copy(&c_info.uuid, &info->uuid); memset(&b_info, 0x00, sizeof(libxl_domain_build_info)); b_info.max_vcpus = 1; b_info.max_memkb = 32 * 1024; b_info.target_memkb = b_info.max_memkb; b_info.kernel.path = libxl__abs_path(&gc, "ioemu-stubdom.gz", libxl_xenfirmwaredir_path()); b_info.u.pv.cmdline = libxl__sprintf(&gc, " -d %d", info->domid); b_info.u.pv.ramdisk.path = ""; b_info.u.pv.features = ""; b_info.hvm = 0; /* fixme: this function can leak the stubdom if it fails */ ret = libxl__domain_make(ctx, &c_info, &domid); if (ret) goto out_free; ret = libxl__domain_build(ctx, &b_info, domid, &state); if (ret) goto out_free; libxl_write_dmargs(ctx, domid, info->domid, args); libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/image/device-model-domid", libxl__xs_get_dompath(&gc, info->domid)), "%d", domid); libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/target", libxl__xs_get_dompath(&gc, domid)), "%d", info->domid); ret = xc_domain_set_target(ctx->xch, domid, info->domid); if (ret<0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting target domain %d -> %d", domid, info->domid); ret = ERROR_FAIL; goto out_free; } xs_set_target(ctx->xsh, domid, info->domid); perm[0].id = domid; perm[0].perms = XS_PERM_NONE; perm[1].id = info->domid; perm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid), perm, ARRAY_SIZE(perm)); xs_mkdir(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/%d/device/vfs", domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(&gc, "/local/domain/%d/device/vfs",domid), perm, ARRAY_SIZE(perm)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; for (i = 0; i < num_disks; i++) { disks[i].domid = domid; ret = libxl_device_disk_add(ctx, domid, &disks[i]); if (ret) goto out_free; } for (i = 0; i < num_vifs; i++) { vifs[i].domid = domid; ret = libxl_device_nic_add(ctx, domid, &vifs[i]); if (ret) goto out_free; } vfb->domid = domid; ret = libxl_device_vfb_add(ctx, domid, vfb); if (ret) goto out_free; vkb->domid = domid; ret = libxl_device_vkb_add(ctx, domid, vkb); if (ret) goto out_free; if (info->serial) num_console++; console = libxl__calloc(&gc, num_console, sizeof(libxl_device_console)); if (!console) { ret = ERROR_NOMEM; goto out_free; } for (i = 0; i < num_console; i++) { console[i].devid = i; console[i].consback = LIBXL_CONSBACK_IOEMU; console[i].domid = domid; /* STUBDOM_CONSOLE_LOGGING (console 0) is for minios logging * STUBDOM_CONSOLE_SAVE (console 1) is for writing the save file * STUBDOM_CONSOLE_RESTORE (console 2) is for reading the save file */ switch (i) { char *filename; char *name; case STUBDOM_CONSOLE_LOGGING: name = libxl__sprintf(&gc, "qemu-dm-%s", libxl_domid_to_name(ctx, info->domid)); libxl_create_logfile(ctx, name, &filename); console[i].output = libxl__sprintf(&gc, "file:%s", filename); console[i].build_state = &state; free(filename); break; case STUBDOM_CONSOLE_SAVE: console[i].output = libxl__sprintf(&gc, "file:"SAVEFILE".%d", info->domid); break; case STUBDOM_CONSOLE_RESTORE: if (info->saved_state) console[i].output = libxl__sprintf(&gc, "pipe:%s", info->saved_state); break; default: console[i].output = "pty"; break; } ret = libxl_device_console_add(ctx, domid, &console[i]); if (ret) goto out_free; } if (libxl__create_xenpv_qemu(ctx, domid, vfb, &dm_starting) < 0) { ret = ERROR_FAIL; goto out_free; } if (libxl__confirm_device_model_startup(ctx, dm_starting) < 0) { ret = ERROR_FAIL; goto out_free; } libxl_domain_unpause(ctx, domid); if (starting_r) { *starting_r = calloc(sizeof(libxl__device_model_starting), 1); (*starting_r)->domid = info->domid; (*starting_r)->dom_path = libxl__xs_get_dompath(&gc, info->domid); (*starting_r)->for_spawn = NULL; } ret = 0; out_free: free(args); out: libxl__free_all(&gc); return ret; }
int clickos_start(int domid, const char *name, const char *script) { const char *clickos_config_path_tail = "/config/"; char clickos_script_chunk[1501]; char *clickos_root_path = NULL; char *clickos_elem_path = NULL; char *clickos_ctl_path = NULL; char *clickos_config_name_path = NULL; char *clickos_config_path = NULL; char *clickos_status_path = NULL; char *clickos_router_path = NULL; int clickos_config_id = 0; default_domain_perms.id = domid; default_domain_perms.perms = XS_PERM_READ | XS_PERM_WRITE; if (!xs) { xenstore_init(domid); } retry_clickos: // Transaction for ClickOS th = xs_transaction_start(xs); asprintf(&domain_root_path, "/local/domain/%d", domid); do { asprintf(&clickos_root_path, "%s/clickos/%d", domain_root_path, clickos_config_id); clickos_router_path = xenstore_read(clickos_root_path); if (clickos_router_path) clickos_config_id++; } while (clickos_router_path != NULL); asprintf(&clickos_elem_path, "%s/elements", clickos_root_path); asprintf(&clickos_ctl_path, "%s/control", clickos_root_path); asprintf(&clickos_config_name_path, "%s/config_name", clickos_root_path); asprintf(&clickos_status_path, "%s/status", clickos_root_path); xenstore_write(clickos_elem_path, ""); xenstore_write(clickos_ctl_path, ""); xenstore_chmod(clickos_elem_path, &default_domain_perms); xenstore_chmod(clickos_ctl_path, &default_domain_perms); xenstore_write(clickos_config_name_path, name); // we need one character for each chunk int config_path_len = strlen(clickos_root_path) + strlen(clickos_config_path_tail) + 1; clickos_config_path = malloc(config_path_len + 1); int chunk = 0; int scriptSize = strlen(script); int remainingScriptSize = scriptSize; do { snprintf(clickos_config_path, config_path_len + 1, "%s%s%d", clickos_root_path, clickos_config_path_tail, chunk); int chunkSize = MAX_CHUNK_LENGTH; if (remainingScriptSize < MAX_CHUNK_LENGTH) { chunkSize = remainingScriptSize; } memcpy(clickos_script_chunk, script + (chunk * MAX_CHUNK_LENGTH), chunkSize); clickos_script_chunk[chunkSize] = '\0'; xenstore_write(clickos_config_path, clickos_script_chunk); chunk++; remainingScriptSize -= chunkSize; } while (remainingScriptSize > 0); if (!xs_transaction_end(xs, th, 0)) { if (errno == EAGAIN) goto retry_clickos; } retry_status: // Transaction for ClickOS state th = xs_transaction_start(xs); xenstore_write(clickos_status_path, "Running"); if (!xs_transaction_end(xs, th, 0)) { if (errno == EAGAIN) goto retry_status; } return 0; }
int libxl_set_memory_target(libxl_ctx *ctx, uint32_t domid, int64_t target_memkb, int relative, int enforce) { GC_INIT(ctx); int rc, r, lrc, abort_transaction = 0; uint64_t memorykb, size; uint64_t videoram = 0; uint64_t current_target_memkb = 0, new_target_memkb = 0; uint64_t current_max_memkb = 0; char *memmax, *endptr, *videoram_s = NULL, *target = NULL; char *dompath = libxl__xs_get_dompath(gc, domid); xc_domaininfo_t info; libxl_dominfo ptr; char *uuid; xs_transaction_t t; libxl__domain_userdata_lock *lock; libxl_domain_config d_config; libxl_domain_config_init(&d_config); CTX_LOCK; lock = libxl__lock_domain_userdata(gc, domid); if (!lock) { rc = ERROR_LOCK_FAIL; goto out_no_transaction; } rc = libxl__get_domain_configuration(gc, domid, &d_config); if (rc < 0) { LOGE(ERROR, "unable to retrieve domain configuration"); goto out_no_transaction; } rc = libxl__arch_extra_memory(gc, &d_config.b_info, &size); if (rc < 0) { LOGE(ERROR, "Couldn't get arch extra constant memory size"); goto out_no_transaction; } retry_transaction: t = xs_transaction_start(ctx->xsh); target = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/target", dompath)); if (!target && !domid) { if (!xs_transaction_end(ctx->xsh, t, 1)) { rc = ERROR_FAIL; goto out_no_transaction; } lrc = libxl__fill_dom0_memory_info(gc, ¤t_target_memkb, ¤t_max_memkb); if (lrc < 0) { rc = ERROR_FAIL; goto out_no_transaction; } goto retry_transaction; } else if (!target) { LOGED(ERROR, domid, "Cannot get target memory info from %s/memory/target", dompath); abort_transaction = 1; rc = ERROR_FAIL; goto out; } else { current_target_memkb = strtoull(target, &endptr, 10); if (*endptr != '\0') { LOGED(ERROR, domid, "Invalid memory target %s from %s/memory/target\n", target, dompath); abort_transaction = 1; rc = ERROR_FAIL; goto out; } } memmax = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/static-max", dompath)); if (!memmax) { LOGED(ERROR, domid, "Cannot get memory info from %s/memory/static-max", dompath); abort_transaction = 1; rc = ERROR_FAIL; goto out; } memorykb = strtoull(memmax, &endptr, 10); if (*endptr != '\0') { LOGED(ERROR, domid, "Invalid max memory %s from %s/memory/static-max\n", memmax, dompath); abort_transaction = 1; rc = ERROR_FAIL; goto out; } videoram_s = libxl__xs_read(gc, t, GCSPRINTF("%s/memory/videoram", dompath)); videoram = videoram_s ? atoi(videoram_s) : 0; if (relative) { if (target_memkb < 0 && llabs(target_memkb) > current_target_memkb) new_target_memkb = 0; else new_target_memkb = current_target_memkb + target_memkb; } else new_target_memkb = target_memkb - videoram; if (new_target_memkb > memorykb) { LOGD(ERROR, domid, "memory_dynamic_max must be less than or equal to" " memory_static_max\n"); abort_transaction = 1; rc = ERROR_INVAL; goto out; } if (!domid && new_target_memkb < LIBXL_MIN_DOM0_MEM) { LOGD(ERROR, domid, "New target %"PRIu64" for dom0 is below the minimum threshold", new_target_memkb); abort_transaction = 1; rc = ERROR_INVAL; goto out; } if (enforce) { memorykb = new_target_memkb + videoram; r = xc_domain_setmaxmem(ctx->xch, domid, memorykb + size); if (r != 0) { LOGED(ERROR, domid, "xc_domain_setmaxmem memkb=%"PRIu64" failed ""rc=%d\n", memorykb + size, r); abort_transaction = 1; rc = ERROR_FAIL; goto out; } } r = xc_domain_set_pod_target(ctx->xch, domid, (new_target_memkb + size) / 4, NULL, NULL, NULL); if (r != 0) { LOGED(ERROR, domid, "xc_domain_set_pod_target memkb=%"PRIu64" failed rc=%d\n", (new_target_memkb + size) / 4, r); abort_transaction = 1; rc = ERROR_FAIL; goto out; } libxl__xs_printf(gc, t, GCSPRINTF("%s/memory/target", dompath), "%"PRIu64, new_target_memkb); r = xc_domain_getinfolist(ctx->xch, domid, 1, &info); if (r != 1 || info.domain != domid) { abort_transaction = 1; rc = ERROR_FAIL; goto out; } libxl_dominfo_init(&ptr); libxl__xcinfo2xlinfo(ctx, &info, &ptr); uuid = libxl__uuid2string(gc, ptr.uuid); libxl__xs_printf(gc, t, GCSPRINTF("/vm/%s/memory", uuid), "%"PRIu64, new_target_memkb / 1024); libxl_dominfo_dispose(&ptr); rc = 0; out: if (!xs_transaction_end(ctx->xsh, t, abort_transaction) && !abort_transaction) if (errno == EAGAIN) goto retry_transaction; out_no_transaction: libxl_domain_config_dispose(&d_config); if (lock) libxl__unlock_domain_userdata(lock); CTX_UNLOCK; GC_FREE; return rc; }
int libxl__create_device_model(libxl_ctx *ctx, libxl_device_model_info *info, libxl_device_disk *disks, int num_disks, libxl_device_nic *vifs, int num_vifs, libxl__device_model_starting **starting_r) { libxl__gc gc = LIBXL_INIT_GC(ctx); char *path, *logfile; int logfile_w, null; int rc; char **args; libxl__device_model_starting buf_starting, *p; xs_transaction_t t; char *vm_path; char **pass_stuff; if (strstr(info->device_model, "stubdom-dm")) { libxl_device_vfb vfb; libxl_device_vkb vkb; libxl_vfb_and_vkb_from_device_model_info(ctx, info, &vfb, &vkb); rc = libxl_create_stubdom(ctx, info, disks, num_disks, vifs, num_vifs, &vfb, &vkb, starting_r); goto out; } args = libxl_build_device_model_args(&gc, info, vifs, num_vifs); if (!args) { rc = ERROR_FAIL; goto out; } path = libxl__sprintf(&gc, "/local/domain/0/device-model/%d", info->domid); xs_mkdir(ctx->xsh, XBT_NULL, path); libxl__xs_write(&gc, XBT_NULL, libxl__sprintf(&gc, "%s/disable_pf", path), "%d", !info->xen_platform_pci); libxl_create_logfile(ctx, libxl__sprintf(&gc, "qemu-dm-%s", info->dom_name), &logfile); logfile_w = open(logfile, O_WRONLY|O_CREAT, 0644); free(logfile); null = open("/dev/null", O_RDONLY); if (starting_r) { rc = ERROR_NOMEM; *starting_r = calloc(sizeof(libxl__device_model_starting), 1); if (!*starting_r) goto out_close; p = *starting_r; p->for_spawn = calloc(sizeof(libxl__spawn_starting), 1); } else { p = &buf_starting; p->for_spawn = NULL; } p->domid = info->domid; p->dom_path = libxl__xs_get_dompath(&gc, info->domid); if (!p->dom_path) { rc = ERROR_FAIL; goto out_close; } if (info->vncpasswd) { retry_transaction: /* Find uuid and the write the vnc password to xenstore for qemu. */ t = xs_transaction_start(ctx->xsh); vm_path = libxl__xs_read(&gc,t,libxl__sprintf(&gc, "%s/vm", p->dom_path)); if (vm_path) { /* Now write the vncpassword into it. */ pass_stuff = libxl__calloc(&gc, 3, sizeof(char *)); pass_stuff[0] = "vncpasswd"; pass_stuff[1] = info->vncpasswd; libxl__xs_writev(&gc,t,vm_path,pass_stuff); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; } } rc = libxl__spawn_spawn(ctx, p, "device model", dm_xenstore_record_pid); if (rc < 0) goto out_close; if (!rc) { /* inner child */ setsid(); libxl__exec(null, logfile_w, logfile_w, libxl__abs_path(&gc, info->device_model, libxl_libexec_path()), args); } rc = 0; out_close: close(null); close(logfile_w); free(args); out: libxl__free_all(&gc); return rc; }
/* * Preserves a domain but rewrites xenstore etc to make it unique so * that the domain can be restarted. * * Does not modify info so that it may be reused. */ int libxl_domain_preserve(libxl_ctx *ctx, uint32_t domid, libxl_domain_create_info *info, const char *name_suffix, libxl_uuid new_uuid) { GC_INIT(ctx); struct xs_permissions roperm[2]; xs_transaction_t t; char *preserved_name; char *uuid_string; char *vm_path; char *dom_path; int rc; preserved_name = GCSPRINTF("%s%s", info->name, name_suffix); if (!preserved_name) { GC_FREE; return ERROR_NOMEM; } uuid_string = libxl__uuid2string(gc, new_uuid); if (!uuid_string) { GC_FREE; return ERROR_NOMEM; } dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) { GC_FREE; return ERROR_FAIL; } vm_path = GCSPRINTF("/vm/%s", uuid_string); if (!vm_path) { GC_FREE; return ERROR_FAIL; } roperm[0].id = 0; roperm[0].perms = XS_PERM_NONE; roperm[1].id = domid; roperm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_rm(ctx->xsh, t, vm_path); xs_mkdir(ctx->xsh, t, vm_path); xs_set_permissions(ctx->xsh, t, vm_path, roperm, ARRAY_SIZE(roperm)); xs_write(ctx->xsh, t, GCSPRINTF("%s/vm", dom_path), vm_path, strlen(vm_path)); rc = libxl__domain_rename(gc, domid, info->name, preserved_name, t); if (rc) { GC_FREE; return rc; } xs_write(ctx->xsh, t, GCSPRINTF("%s/uuid", vm_path), uuid_string, strlen(uuid_string)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; GC_FREE; return 0; }
void libxl__spawn_stub_dm(libxl__egc *egc, libxl__stub_dm_spawn_state *sdss) { STATE_AO_GC(sdss->dm.spawn.ao); libxl_ctx *ctx = libxl__gc_owner(gc); int ret; libxl_device_vfb *vfb; libxl_device_vkb *vkb; char **args; struct xs_permissions perm[2]; xs_transaction_t t; /* convenience aliases */ libxl_domain_config *const dm_config = &sdss->dm_config; libxl_domain_config *const guest_config = sdss->dm.guest_config; const int guest_domid = sdss->dm.guest_domid; libxl__domain_build_state *const d_state = sdss->dm.build_state; libxl__domain_build_state *const stubdom_state = &sdss->dm_state; if (guest_config->b_info.device_model_version != LIBXL_DEVICE_MODEL_VERSION_QEMU_XEN_TRADITIONAL) { ret = ERROR_INVAL; goto out; } sdss->pvqemu.guest_domid = 0; libxl_domain_create_info_init(&dm_config->c_info); dm_config->c_info.type = LIBXL_DOMAIN_TYPE_PV; dm_config->c_info.name = libxl__stub_dm_name(gc, libxl__domid_to_name(gc, guest_domid)); dm_config->c_info.ssidref = guest_config->b_info.device_model_ssidref; libxl_uuid_generate(&dm_config->c_info.uuid); libxl_domain_build_info_init(&dm_config->b_info); libxl_domain_build_info_init_type(&dm_config->b_info, LIBXL_DOMAIN_TYPE_PV); dm_config->b_info.max_vcpus = 1; dm_config->b_info.max_memkb = 32 * 1024; dm_config->b_info.target_memkb = dm_config->b_info.max_memkb; dm_config->b_info.u.pv.features = ""; dm_config->b_info.device_model_version = guest_config->b_info.device_model_version; dm_config->b_info.device_model = guest_config->b_info.device_model; dm_config->b_info.extra = guest_config->b_info.extra; dm_config->b_info.extra_pv = guest_config->b_info.extra_pv; dm_config->b_info.extra_hvm = guest_config->b_info.extra_hvm; dm_config->disks = guest_config->disks; dm_config->num_disks = guest_config->num_disks; libxl__dm_vifs_from_hvm_guest_config(gc, guest_config, dm_config); dm_config->c_info.run_hotplug_scripts = guest_config->c_info.run_hotplug_scripts; ret = libxl__domain_create_info_setdefault(gc, &dm_config->c_info); if (ret) goto out; ret = libxl__domain_build_info_setdefault(gc, &dm_config->b_info); if (ret) goto out; GCNEW(vfb); GCNEW(vkb); libxl__vfb_and_vkb_from_hvm_guest_config(gc, guest_config, vfb, vkb); dm_config->vfbs = vfb; dm_config->num_vfbs = 1; dm_config->vkbs = vkb; dm_config->num_vkbs = 1; stubdom_state->pv_kernel.path = libxl__abs_path(gc, "ioemu-stubdom.gz", libxl__xenfirmwaredir_path()); stubdom_state->pv_cmdline = libxl__sprintf(gc, " -d %d", guest_domid); stubdom_state->pv_ramdisk.path = ""; /* fixme: this function can leak the stubdom if it fails */ ret = libxl__domain_make(gc, &dm_config->c_info, &sdss->pvqemu.guest_domid); if (ret) goto out; uint32_t dm_domid = sdss->pvqemu.guest_domid; ret = libxl__domain_build(gc, dm_config, dm_domid, stubdom_state); if (ret) goto out; args = libxl__build_device_model_args(gc, "stubdom-dm", guest_domid, guest_config, d_state); if (!args) { ret = ERROR_FAIL; goto out; } libxl__write_stub_dmargs(gc, dm_domid, guest_domid, args); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/image/device-model-domid", libxl__xs_get_dompath(gc, guest_domid)), "%d", dm_domid); libxl__xs_write(gc, XBT_NULL, libxl__sprintf(gc, "%s/target", libxl__xs_get_dompath(gc, dm_domid)), "%d", guest_domid); ret = xc_domain_set_target(ctx->xch, dm_domid, guest_domid); if (ret<0) { LIBXL__LOG_ERRNO(ctx, LIBXL__LOG_ERROR, "setting target domain %d -> %d", dm_domid, guest_domid); ret = ERROR_FAIL; goto out; } xs_set_target(ctx->xsh, dm_domid, guest_domid); perm[0].id = dm_domid; perm[0].perms = XS_PERM_NONE; perm[1].id = guest_domid; perm[1].perms = XS_PERM_READ; retry_transaction: t = xs_transaction_start(ctx->xsh); xs_mkdir(ctx->xsh, t, libxl__sprintf(gc, "/local/domain/0/device-model/%d", guest_domid)); xs_set_permissions(ctx->xsh, t, libxl__sprintf(gc, "/local/domain/0/device-model/%d", guest_domid), perm, ARRAY_SIZE(perm)); if (!xs_transaction_end(ctx->xsh, t, 0)) if (errno == EAGAIN) goto retry_transaction; libxl__multidev_begin(ao, &sdss->multidev); sdss->multidev.callback = spawn_stub_launch_dm; libxl__add_disks(egc, ao, dm_domid, dm_config, &sdss->multidev); libxl__multidev_prepared(egc, &sdss->multidev, 0); return; out: assert(ret); spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret); }
int libxl__domain_rename(libxl__gc *gc, uint32_t domid, const char *old_name, const char *new_name, xs_transaction_t trans) { libxl_ctx *ctx = libxl__gc_owner(gc); char *dom_path = 0; const char *name_path; char *got_old_name; unsigned int got_old_len; xs_transaction_t our_trans = 0; uint32_t stub_dm_domid; const char *stub_dm_old_name = NULL, *stub_dm_new_name = NULL; int rc; libxl_dominfo info; char *uuid; const char *vm_name_path; libxl_dominfo_init(&info); dom_path = libxl__xs_get_dompath(gc, domid); if (!dom_path) goto x_nomem; name_path= GCSPRINTF("%s/name", dom_path); if (!name_path) goto x_nomem; stub_dm_domid = libxl_get_stubdom_id(CTX, domid); if (stub_dm_domid) { stub_dm_old_name = libxl__stub_dm_name(gc, old_name); stub_dm_new_name = libxl__stub_dm_name(gc, new_name); } retry_transaction: if (!trans) { trans = our_trans = xs_transaction_start(ctx->xsh); if (!our_trans) { LOGEVD(ERROR, errno, domid, "Create xs transaction for domain (re)name"); goto x_fail; } } if (!new_name) { LOGD(ERROR, domid, "New domain name not specified"); rc = ERROR_INVAL; goto x_rc; } if (new_name[0]) { /* nonempty names must be unique */ uint32_t domid_e; rc = libxl_name_to_domid(ctx, new_name, &domid_e); if (rc == ERROR_INVAL) { /* no such domain, good */ } else if (rc != 0) { LOGD(ERROR, domid, "Unexpected error checking for existing domain"); goto x_rc; } else if (domid_e == domid) { /* domain already has this name, ok (but we do still * need the rest of the code as we may need to check * old_name, for example). */ } else { LOGD(ERROR, domid, "Domain with name \"%s\" already exists.", new_name); rc = ERROR_INVAL; goto x_rc; } } if (old_name) { got_old_name = xs_read(ctx->xsh, trans, name_path, &got_old_len); if (!got_old_name) { LOGEVD(ERROR, errno, domid, "Check old name for domain allegedly named `%s'", old_name); goto x_fail; } if (strcmp(old_name, got_old_name)) { LOGD(ERROR, domid, "Allegedly named `%s' is actually named `%s' - racing ?", old_name, got_old_name); free(got_old_name); goto x_fail; } free(got_old_name); } if (!xs_write(ctx->xsh, trans, name_path, new_name, strlen(new_name))) { LOGD(ERROR, domid, "Failed to write new name `%s'" " for domain previously named `%s'", new_name, old_name); goto x_fail; } /* update /vm/<uuid>/name */ rc = libxl_domain_info(ctx, &info, domid); if (rc) goto x_rc; uuid = GCSPRINTF(LIBXL_UUID_FMT, LIBXL_UUID_BYTES(info.uuid)); vm_name_path = GCSPRINTF("/vm/%s/name", uuid); if (libxl__xs_write_checked(gc, trans, vm_name_path, new_name)) goto x_fail; if (stub_dm_domid) { rc = libxl__domain_rename(gc, stub_dm_domid, stub_dm_old_name, stub_dm_new_name, trans); if (rc) { LOGED(ERROR, domid, "Unable to rename stub-domain"); goto x_rc; } } if (our_trans) { if (!xs_transaction_end(ctx->xsh, our_trans, 0)) { trans = our_trans = 0; if (errno != EAGAIN) { LOGD(ERROR, domid, "Failed to commit new name `%s'" " for domain previously named `%s'", new_name, old_name); goto x_fail; } LOGD(DEBUG, domid, "Need to retry rename transaction" " for domain (name_path=\"%s\", new_name=\"%s\")", name_path, new_name); goto retry_transaction; } our_trans = 0; } rc = 0; x_rc: if (our_trans) xs_transaction_end(ctx->xsh, our_trans, 1); libxl_dominfo_dispose(&info); return rc; x_fail: rc = ERROR_FAIL; goto x_rc; x_nomem: rc = ERROR_NOMEM; goto x_rc; }
int xsd_provision_controller(struct xs_handle *xs, int domid) { xs_transaction_t t; struct xs_permissions xsperms[2]; xsperms[0].id = domid; xsperms[0].perms = XS_PERM_READ | XS_PERM_WRITE; struct stat buf; char s[MAX_PATH]; char s2[MAX_PATH]; char domname[20]; char backend[MAX_PATH]; char frontend[MAX_PATH]; int devno = 0; int result; char* home; char* dom0_home; int provision_status = 0; home = xs_get_domain_path(xs,domid); dom0_home = xs_get_domain_path(xs,0); retry_provision: /* printf("xsd_provision_controller Domain-%d, home %s, dom0_home %s\n", domid, home, dom0_home); */ /* * * Create the vxtcom_controller records Dom0 and the * target domain. The code that follows will: * * * Write the backend vxt controller entry and place it * in Dom-0. i.e. /local/domain/0 .. * * backend = "" * vxtcom_ctrlr = "" * <Domain-id> (9) = "" * <Device-id> (0) = "" * domain = <Domain name> "Domain-9" * frontend = "/local/domain/9/device/vxtcom_ctrlr/0" * frontend-id = "9" * state = "3" * version = "1" * * * Write the front end record in the target domain device * subdirectory: ... e.g. * * device = "" * vxtcom_ctrlr = "" * 0 = "" * backend = "/local/domain/0/backend/vxtcom_ctrlr/9/0" * backend-id = "0" * state = "1" */ t = xs_transaction_start(xs); /* printf("xsd_provision_controller Domain-%d, transaction token %d\n", domid, t); */ sprintf(backend, "%s/backend/vxtcom_ctrlr/%d/%d", dom0_home, domid, devno); sprintf(frontend, "%s/device/vxtcom_ctrlr/%d", home, devno); /* * Create Dom0 device directory for target domain: * ../device/vxtcom_ctrlr/ */ xs_mkdir(xs, t, backend); result = xs_set_permissions(xs, t, backend, xsperms, 1); /* printf("xsd_privision_controller: xs_set_permissions result %d\n", result); */ /* * create the target domain device record * /local/domain/<domain #>/device/vxtcom_ctrlr/<domain #>/backend = * "/local/domain/0/backend/vxtcom_ctrlr/<domain #>/0" * */ sprintf(s, "%s/backend", frontend); xs_write(xs, t, s, backend, strlen(backend)); /* * create target domian backend-id record: * /local/domain/<domain #>/device/vxtcom_ctrlr/<domain #>/backend = 0 * */ sprintf(s, "%s/backend-id", frontend); xs_write(xs, t, s, "0", 1); /* * create target domian state record: * /local/domain/<domain #>/device/vxtcom_ctrlr/<domain #>/state = 1 * */ sprintf(s, "%s/state", frontend); xs_write(xs, t, s, "1", 1); /* * create Dom0 domname (domain-name) record for target domain: * /local/domain/0/backend/vxtcom_ctrlr/<domain#>/0/domname * = Domain-<domain#> */ sprintf(domname, "Domain-%d", domid); sprintf(s, "%s/domain", backend); xs_write(xs, t, s, domname, strlen(domname)); /* * Create Dom0 target vxtctlr device record - "frontend" * * /local/domain/0/device/vxtcom_ctrlr/9/0/frontend = * /local/domain/<domain #>/device/vxtcom_ctrlr/0 * */ sprintf(s, "%s/frontend", backend); xs_write(xs, t, s, frontend, strlen(frontend)); /* * Create Dom0 target vxtctlr device record - "frontend-id" * * /local/domain/0/device/vxtcom_ctrlr/9/0/frontend-id = * <domid> e.g. 9 * */ sprintf(s, "%s/frontend-id", backend); sprintf(s2,"%d",domid); xs_write(xs, t, s, s2, strlen(s2)); /* * Create Dom0 target vxtctlr device record - "state" * * /local/domain/0/device/vxtcom_ctrlr/9/0/state = 1 * */ sprintf(s, "%s/state", backend); xs_write(xs, t, s, "1", 1); /* * Create Dom0 target vxtctlr device record - "frontend" * * /local/domain/0/device/vxtcom_ctrlr/<domain #>/0/frontend = * /local/domain/<domain #>/device/vxtcom_ctrlr/0 * */ sprintf(s, "%s/frontend", backend); xs_write(xs, t, s, frontend, strlen(frontend)); if(!xs_transaction_end(xs, t, 0)) { printf("xsd_privision_controller: xs_transaction_end failed\n"); goto retry_provision; } else { provision_status = 1; } free(home); free(dom0_home); return (provision_status); }
int __cdecl main() { char *vm_path, *uuid, *t; size_t l; char **contents; unsigned count; HANDLE xs_handle2; HANDLE event; HANDLE event2; int watch_h; int watch_h2; int i; DWORD status; xs_handle = xs_domain_open(); if (!xs_handle) win_err(1, "openning xenstore interface"); /* Try to give ourselves a clean place to start */ xs_remove(xs_handle, "data/test"); /* Check basic xenstore reads with relative path... */ vm_path = xs_read(xs_handle, "vm", NULL); if (!vm_path) win_err(1, "reading vm path"); if (vm_path[0] != '/') { fail_test(__LINE__, "expected vm path to be absolute, got %s", vm_path); } /* and with an absolute path. */ uuid = gather_read(&l, vm_path, "uuid", NULL); if (!uuid) win_err(1, "reading uuid"); if (l != 36) { fail_test(__LINE__, "uuid length was %d bytes, expected 36"); } if (strlen(uuid) != 36) { fail_test(__LINE__, "uuid was %s, not right length (%d, should be 36), returned length %d", uuid, strlen(uuid), l); } /* Make sure read error sets a suitable code. */ xs_read_expected_error(__LINE__, "non_existent", ERROR_FILE_NOT_FOUND); xs_read_expected_error(__LINE__, "invalid\\path", ERROR_INVALID_PARAMETER); xs_read_expected_error(__LINE__, "/local/domain/0/name", ERROR_ACCESS_DENIED); /* Test basic xs_write functionality. */ if (!xs_write(xs_handle, "data/test/key1", "data1")) { fail_test(__LINE__, "write data/test/key1 failed with %lx", GetLastError()); } else { t = xs_read(xs_handle, "data/test/key1", &l); if (!t) { fail_test(__LINE__, "error reading from data/test/key1: %lx", GetLastError()); } else { if (l != 5) { fail_test(__LINE__, "manifest length wrong reading data/test/key1: %d should be 5.", l); } if (strcmp(t, "data1")) { fail_test(__LINE__, "got wrong data reading data/test/key1: %s should be data1.", t); } free(t); } } xs_write_expected_error(__LINE__, "foo", "bar", ERROR_ACCESS_DENIED); xs_write_expected_error(__LINE__, "/foo", "bar", ERROR_ACCESS_DENIED); /* Try a very large write and make sure that it fails in the expected way. */ t = malloc(65536); memset(t, 'a', 65536); t[65535] = 0; xs_write_expected_error(__LINE__,"data/test/key1", t, ERROR_DISK_FULL); free(t); /* Test that read and write work for keys containing nul bytes. */ if (!xs_write_bin(xs_handle, "data/test/key1", "xxx\0yyy", 7)) { fail_test(__LINE__, "failed to write nul bytes (%d)", GetLastError()); } t = xs_read(xs_handle, "data/test/key1", &l); if (!t) { fail_test(__LINE__, "failed to read nul bytes (%d)", GetLastError()); } else { if (l != 7) { fail_test(__LINE__, "read with nuls: expected 7, got %d.\n", l); } else if (memcmp(t, "xxx\0yyy", 7)) { fail_test(__LINE__, "bad data from read with nuls: %s", t); } free(t); } if (!xs_remove(xs_handle, "data/test/key1")) { fail_test(__LINE__, "failed to remove data/test/key1 (%d)", GetLastError()); } xs_read_expected_error(__LINE__, "data/test/key1", ERROR_FILE_NOT_FOUND); xs_ls_expected_error(__LINE__, "data/test/key1", ERROR_FILE_NOT_FOUND); if (!xs_write(xs_handle, "data/test/key1", "data1")) { fail_test(__LINE__, "failed to rewrite data/test/key1"); } contents = xs_directory(xs_handle, "data/test/key1", &count); if (!contents) { fail_test(__LINE__, "failed to ls data/test/key1: %x", GetLastError()); } else if (count != 0) { fail_test(__LINE__, "ls data/test/key1 had %d items", count); free(contents); } else { free(contents); } if (!xs_write(xs_handle, "data/test/key1/key2", "data2")) { fail_test(__LINE__, "failed to rewrite data/test/key1/key2"); } contents = xs_directory(xs_handle, "data/test/key1", &count); if (!contents) { fail_test(__LINE__, "failed to ls data/test/key1: %x", GetLastError()); } else if (count != 1) { fail_test(__LINE__, "ls data/test/key1 had %d items", count); free(contents); } else if (strcmp(contents[0], "key2")) { fail_test(__LINE__, "ls data/test/key1 gave unexpected result %s", contents[0]); } xs_remove(xs_handle, "data/test"); /* Looks like most of the basic functionality works. Try * transactions. */ xs_handle2 = xs_domain_open(); if (!xs_handle2) win_err(1, "couldn't re-open domain interface"); if (!xs_write(xs_handle, "data/test/key1", "before")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); if (!xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "failed to write to end transaction: %x", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "after")) fail_test(__LINE__, "transaction didn't stick"); /* Now try aborting the transaction. */ if (!xs_write(xs_handle, "data/test/key1", "before")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); if (!xs_transaction_end(xs_handle2, TRUE)) fail_test(__LINE__, "failed to write to end transaction: %x", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "before")) fail_test(__LINE__, "transaction didn't abort"); /* Try to arrange that the transaction fails. */ if (!xs_write(xs_handle, "data/test/key1", "before")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); if (!xs_write(xs_handle, "data/test/key1", "other")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "transaction succeeded when it shouldn't", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "other")) fail_test(__LINE__, "transaction did something strange"); if (!xs_write(xs_handle, "data/test/key1", "before1")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (!xs_write(xs_handle, "data/test/key2", "before2")) fail_test(__LINE__, "failed to write to data/test/key2: %x", GetLastError()); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction on second handle"); if (!xs_write(xs_handle2, "data/test/key1", "after")) fail_test(__LINE__, "failed to write to data/test/key1 under transaction: %x", GetLastError()); t = xs_read(xs_handle2, "data/test/key2", NULL); if (!t) { fail_test(__LINE__, "failed to read data/test/key2 under transaction: %x", GetLastError()); } else { if (strcmp(t, "before2")) fail_test(__LINE__, "got wrong thing reading dtaa/test/key2 (%s)", t); free(t); } if (!xs_write(xs_handle, "data/test/key2", "other")) fail_test(__LINE__, "failed to write to data/test/key1: %x", GetLastError()); if (xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "transaction succeeded when it shouldn't", GetLastError()); if (strcmp(xs_read(xs_handle, "data/test/key1", NULL), "before1")) fail_test(__LINE__, "transaction did something strange"); xs_daemon_close(xs_handle2); /* Try a couple of transaction error cases. */ xs_handle2 = xs_domain_open(); if (!xs_handle2) win_err(1, "couldn't re-open domain interface a second time"); if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction for re-test"); if (xs_transaction_start(xs_handle2)) { fail_test(__LINE__, "openned two transactions on same handle"); } xs_daemon_close(xs_handle2); xs_handle2 = xs_domain_open(); if (!xs_handle2) win_err(1, "couldn't re-open domain interface a third time"); if (xs_transaction_end(xs_handle2, FALSE)) { fail_test(__LINE__, "ended transaction without starting it"); } if (!xs_transaction_start(xs_handle2)) win_err(1, "couldn't open a transaction for re-test"); if (!xs_transaction_end(xs_handle2, FALSE)) fail_test(__LINE__, "failed to end transaction"); if (xs_transaction_end(xs_handle2, FALSE)) { fail_test(__LINE__, "double-ended transaction"); } xs_daemon_close(xs_handle2); /* Transactions appear to be working, at least in their most basic form. Have a go at watches. */ event = CreateEvent(NULL, FALSE, FALSE, NULL); watch_h = xs_watch(xs_handle, "data/test/key1", event); if (watch_h < 0) { fail_test(__LINE__, "couldn't watch data/test/key1"); } else { while (WaitForSingleObject(event, 100) != WAIT_TIMEOUT) ; xs_write(xs_handle, "data/test/key1", "foo"); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); xs_write(xs_handle, "data/test/key1", "foo"); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); xs_write(xs_handle, "data/test/key1", "foo"); if (WaitForSingleObject(event, INFINITE) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); status = WaitForSingleObject(event, 2000); if (status != WAIT_TIMEOUT) fail_test(__LINE__, "should have timed out waiting for data/test/key1 (%d, %d)", status, GetLastError()); if (!xs_unwatch(xs_handle, watch_h)) fail_test(__LINE__, "failed to unwatch"); } /* Create two watches on the same key, kill one of them, and then make sure that the other one still works. */ watch_h = xs_watch(xs_handle, "data/test/key1/subkey", event); if (watch_h < 0) { fail_test(__LINE__, "couldn't watch data/test/key1/subkey"); } else { event2 = CreateEvent(NULL, FALSE, FALSE, NULL); watch_h2 = xs_watch(xs_handle, "data/test/key1/subkey", event); if (watch_h2 < 0) { fail_test(__LINE__, "couldn't double watch data/test/key1/subkey"); } else { if (!xs_unwatch(xs_handle, watch_h2)) fail_test(__LINE__, "failed to unwatch h2"); ResetEvent(event); xs_remove(xs_handle, "data/test/key1"); if (WaitForSingleObject(event, 5000) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1: %x", GetLastError()); if (!xs_unwatch(xs_handle, watch_h)) fail_test(__LINE__, "failed to unwatch"); } } /* Watch a node, then modify it in a transaction, and check that the watch fires. */ watch_h = xs_watch(xs_handle, "data/test/key1", event); if (watch_h < 0) { fail_test(__LINE__, "couldn't watch data/test/key1"); } else { for (i = 0; i < 100; i++) { ResetEvent(event); do { if (!xs_transaction_start(xs_handle)) win_err(1, "couldn't open a transaction for watch test"); xs_write(xs_handle, "data/test/key1", "foo"); } while (!xs_transaction_end(xs_handle, FALSE)); if (WaitForSingleObject(event, 5000) != WAIT_OBJECT_0) fail_test(__LINE__, "failed wait for data/test/key1(%d): %x", i, GetLastError()); } if (!xs_unwatch(xs_handle, watch_h)) fail_test(__LINE__, "failed to unwatch"); } /* Make a lot of watches, make sure they all work. */ test_many_watches(); /* Try some different sized requests */ test_write_sizes(4096); xs_daemon_close(xs_handle); run_stress(); if (failed) { printf("failed\n"); return 1; } else { printf("passed\n"); return 0; } }