static void write_emulator_blob(libxl__egc *egc, libxl__stream_read_state *stream, libxl__sr_record_buf *rec) { libxl__domain_create_state *dcs = stream->dcs; libxl__datacopier_state *dc = &stream->emu_dc; libxl__sr_emulator_hdr *emu_hdr; STATE_AO_GC(stream->ao); char path[256]; int rc = 0, writefd; if (rec->hdr.length < sizeof(*emu_hdr)) { rc = ERROR_FAIL; LOG(ERROR, "Emulator record too short to contain header"); goto err; } emu_hdr = rec->body; sprintf(path, LIBXL_DEVICE_MODEL_RESTORE_FILE".%u", dcs->guest_domid); assert(stream->emu_carefd == NULL); libxl__carefd_begin(); writefd = open(path, O_WRONLY | O_CREAT | O_TRUNC, 0600); stream->emu_carefd = libxl__carefd_opened(CTX, writefd); if (writefd == -1) { rc = ERROR_FAIL; LOGE(ERROR, "unable to open %s", path); goto err; } FILLZERO(*dc); dc->ao = stream->ao; dc->writewhat = "qemu save file"; dc->copywhat = "restore v2 stream"; dc->writefd = writefd; dc->readfd = -1; dc->maxsz = -1; dc->callback = write_emulator_done; rc = libxl__datacopier_start(dc); if (rc) goto err; libxl__datacopier_prefixdata(egc, dc, rec->body + sizeof(*emu_hdr), rec->hdr.length - sizeof(*emu_hdr)); return; err: assert(rc); stream_complete(egc, stream, rc); }
/* Helper to set up reading some data from the stream. */ static int setup_read(libxl__stream_read_state *stream, const char *what, void *ptr, size_t nr_bytes, libxl__datacopier_callback cb) { libxl__datacopier_state *dc = &stream->dc; dc->readwhat = what; dc->readbuf = ptr; dc->bytes_to_read = nr_bytes; dc->used = 0; dc->callback = cb; return libxl__datacopier_start(dc); }
static void bootloader_gotptys(libxl__egc *egc, libxl__openpty_state *op) { libxl__bootloader_state *bl = CONTAINER_OF(op, *bl, openpty); STATE_AO_GC(bl->ao); int rc, r; char *const env[] = { "TERM", "vt100", NULL }; if (bl->openpty.rc) { rc = bl->openpty.rc; goto out; } /* * We need to present the bootloader's tty as a pty slave that xenconsole * can access. Since the bootloader itself needs a pty slave, * we end up with a connection like this: * * xenconsole -- (slave pty1 master) <-> (master pty2 slave) -- bootloader * * where we copy characters between the two master fds, as well as * listening on the bootloader's fifo for the results. */ char *dom_console_xs_path; char dom_console_slave_tty_path[PATH_MAX]; rc = setup_xenconsoled_pty(egc, bl, &dom_console_slave_tty_path[0], sizeof(dom_console_slave_tty_path)); if (rc) goto out; char *dompath = libxl__xs_get_dompath(gc, bl->domid); if (!dompath) { rc = ERROR_FAIL; goto out; } dom_console_xs_path = GCSPRINTF("%s/console/tty", dompath); rc = libxl__xs_write(gc, XBT_NULL, dom_console_xs_path, "%s", dom_console_slave_tty_path); if (rc) { LOGE(ERROR,"xs write console path %s := %s failed", dom_console_xs_path, dom_console_slave_tty_path); rc = ERROR_FAIL; goto out; } bl->deathcheck.what = "stopping bootloader"; bl->deathcheck.domid = bl->domid; bl->deathcheck.callback = bootloader_domaindeath; rc = libxl__domaindeathcheck_start(gc, &bl->deathcheck); if (rc) goto out; if (bl->console_available) bl->console_available(egc, bl); int bootloader_master = libxl__carefd_fd(bl->ptys[0].master); int xenconsole_master = libxl__carefd_fd(bl->ptys[1].master); libxl_fd_set_nonblock(CTX, bootloader_master, 1); libxl_fd_set_nonblock(CTX, xenconsole_master, 1); bl->keystrokes.writefd = bl->display.readfd = bootloader_master; bl->keystrokes.writewhat = bl->display.readwhat = "bootloader pty"; bl->keystrokes.readfd = bl->display.writefd = xenconsole_master; bl->keystrokes.readwhat = bl->display.writewhat = "xenconsole client pty"; bl->keystrokes.ao = ao; bl->keystrokes.maxsz = BOOTLOADER_BUF_OUT; bl->keystrokes.copywhat = GCSPRINTF("bootloader input for domain %"PRIu32, bl->domid); bl->keystrokes.callback = bootloader_keystrokes_copyfail; bl->keystrokes.callback_pollhup = bootloader_keystrokes_copyfail; /* pollhup gets called with errnoval==-1 which is not otherwise * possible since errnos are nonnegative, so it's unambiguous */ rc = libxl__datacopier_start(&bl->keystrokes); if (rc) goto out; bl->display.ao = ao; bl->display.maxsz = BOOTLOADER_BUF_IN; bl->display.copywhat = GCSPRINTF("bootloader output for domain %"PRIu32, bl->domid); bl->display.callback = bootloader_display_copyfail; bl->display.callback_pollhup = bootloader_display_copyfail; rc = libxl__datacopier_start(&bl->display); if (rc) goto out; LOG(DEBUG, "executing bootloader: %s", bl->args[0]); for (const char **blarg = bl->args; *blarg; blarg++) LOG(DEBUG, " bootloader arg: %s", *blarg); struct termios termattr; pid_t pid = libxl__ev_child_fork(gc, &bl->child, bootloader_finished); if (pid == -1) { rc = ERROR_FAIL; goto out; } if (!pid) { /* child */ r = login_tty(libxl__carefd_fd(bl->ptys[0].slave)); if (r) { LOGE(ERROR, "login_tty failed"); exit(-1); } libxl__exec(gc, -1, -1, -1, bl->args[0], (char **) bl->args, env); exit(-1); } /* parent */ /* * On Solaris, the master pty side does not have terminal semantics, * so don't try to set any attributes, as it will fail. */ #if !defined(__sun__) tcgetattr(bootloader_master, &termattr); cfmakeraw(&termattr); tcsetattr(bootloader_master, TCSANOW, &termattr); #endif return; out: bootloader_callback(egc, bl, rc); }