void libxl__bootloader_run(libxl__egc *egc, libxl__bootloader_state *bl) { STATE_AO_GC(bl->ao); const libxl_domain_build_info *info = bl->info; uint32_t domid = bl->domid; char *logfile_tmp = NULL; int rc, r; libxl__bootloader_init(bl); if (info->type != LIBXL_DOMAIN_TYPE_PV) { LOG(DEBUG, "not a PV domain, skipping bootloader"); rc = 0; goto out_ok; } if (!info->u.pv.bootloader) { LOG(DEBUG, "no bootloader configured, using user supplied kernel"); bl->kernel->path = bl->info->u.pv.kernel; bl->ramdisk->path = bl->info->u.pv.ramdisk; bl->cmdline = bl->info->u.pv.cmdline; rc = 0; goto out_ok; } if (!bl->disk) { LOG(ERROR, "cannot run bootloader with no boot disk"); rc = ERROR_FAIL; goto out; } bootloader_setpaths(gc, bl); const char *logfile_leaf = GCSPRINTF("bootloader.%"PRIu32, domid); rc = libxl_create_logfile(CTX, logfile_leaf, &logfile_tmp); if (rc) goto out; /* Transfer ownership of log filename to bl and the gc */ bl->logfile = logfile_tmp; libxl__ptr_add(gc, logfile_tmp); logfile_tmp = NULL; bl->display.log = fopen(bl->logfile, "a"); if (!bl->display.log) { LOGE(ERROR, "failed to create bootloader logfile %s", bl->logfile); rc = ERROR_FAIL; goto out; } for (;;) { r = mkdir(bl->outputdir, 0600); if (!r) break; if (errno == EINTR) continue; if (errno == EEXIST) break; LOGE(ERROR, "failed to create bootloader dir %s", bl->outputdir); rc = ERROR_FAIL; goto out; } for (;;) { r = open(bl->outputpath, O_WRONLY|O_CREAT|O_TRUNC, 0600); if (r>=0) { close(r); break; } if (errno == EINTR) continue; LOGE(ERROR, "failed to precreate bootloader output %s", bl->outputpath); rc = ERROR_FAIL; goto out; } /* This sets the state of the dls struct from Undefined to Idle */ libxl__device_disk_local_init(&bl->dls); bl->dls.ao = ao; bl->dls.in_disk = bl->disk; bl->dls.blkdev_start = info->blkdev_start; bl->dls.callback = bootloader_disk_attached_cb; libxl__device_disk_local_initiate_attach(egc, &bl->dls); return; out: assert(rc); out_ok: free(logfile_tmp); bootloader_callback(egc, bl, rc); }
static void spawn_stub_launch_dm(libxl__egc *egc, libxl__multidev *multidev, int ret) { libxl__stub_dm_spawn_state *sdss = CONTAINER_OF(multidev, *sdss, multidev); STATE_AO_GC(sdss->dm.spawn.ao); libxl_ctx *ctx = libxl__gc_owner(gc); int i, num_console = STUBDOM_SPECIAL_CONSOLES; libxl__device_console *console; /* 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; uint32_t dm_domid = sdss->pvqemu.guest_domid; if (ret) { LOG(ERROR, "error connecting disk devices"); goto out; } for (i = 0; i < dm_config->num_nics; i++) { /* We have to init the nic here, because we still haven't * called libxl_device_nic_add at this point, but qemu needs * the nic information to be complete. */ ret = libxl__device_nic_setdefault(gc, &dm_config->nics[i], dm_domid); if (ret) goto out; } ret = libxl__device_vfb_add(gc, dm_domid, &dm_config->vfbs[0]); if (ret) goto out; ret = libxl__device_vkb_add(gc, dm_domid, &dm_config->vkbs[0]); if (ret) goto out; if (guest_config->b_info.u.hvm.serial) num_console++; console = libxl__calloc(gc, num_console, sizeof(libxl__device_console)); if (!console) { ret = ERROR_NOMEM; goto out; } for (i = 0; i < num_console; i++) { console[i].devid = i; console[i].consback = LIBXL__CONSOLE_BACKEND_IOEMU; /* 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, guest_domid)); libxl_create_logfile(ctx, name, &filename); console[i].output = libxl__sprintf(gc, "file:%s", filename); free(filename); break; case STUBDOM_CONSOLE_SAVE: console[i].output = libxl__sprintf(gc, "file:%s", libxl__device_model_savefile(gc, guest_domid)); break; case STUBDOM_CONSOLE_RESTORE: if (d_state->saved_state) console[i].output = libxl__sprintf(gc, "pipe:%s", d_state->saved_state); break; default: console[i].output = "pty"; break; } ret = libxl__device_console_add(gc, dm_domid, &console[i], i == STUBDOM_CONSOLE_LOGGING ? stubdom_state : NULL); if (ret) goto out; } sdss->pvqemu.spawn.ao = ao; sdss->pvqemu.guest_domid = dm_domid; sdss->pvqemu.guest_config = &sdss->dm_config; sdss->pvqemu.build_state = &sdss->dm_state; sdss->pvqemu.callback = spawn_stubdom_pvqemu_cb; libxl__spawn_local_dm(egc, &sdss->pvqemu); return; out: assert(ret); spawn_stubdom_pvqemu_cb(egc, &sdss->pvqemu, ret); }
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; }
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); }
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; }