示例#1
0
static void bootloader_finished(libxl__egc *egc, libxl__ev_child *child,
                                pid_t pid, int status)
{
    libxl__bootloader_state *bl = CONTAINER_OF(child, *bl, child);
    STATE_AO_GC(bl->ao);
    int rc;

    libxl__datacopier_kill(&bl->keystrokes);
    libxl__datacopier_kill(&bl->display);

    if (status) {
        if (bl->got_pollhup && WIFSIGNALED(status) && WTERMSIG(status)==SIGTERM)
            LOG(ERROR, "got POLLHUP, sent SIGTERM");
        LOG(ERROR, "bootloader failed - consult logfile %s", bl->logfile);
        libxl_report_child_exitstatus(CTX, XTL_ERROR, "bootloader",
                                      pid, status);
        rc = ERROR_FAIL;
        goto out;
    } else {
        LOG(DEBUG, "bootloader completed");
    }

    if (bl->rc) {
        /* datacopier went wrong */
        rc = bl->rc;
        goto out;
    }

    rc = parse_bootloader_result(egc, bl);
    if (rc) goto out;

    rc = 0;
    LOG(DEBUG, "bootloader execution successful");

out:
    bootloader_callback(egc, bl, rc);
}
int libxl_run_bootloader(libxl_ctx *ctx,
                         libxl_domain_build_info *info,
                         libxl_device_disk *disk,
                         uint32_t domid)
{
    libxl__gc gc = LIBXL_INIT_GC(ctx);
    int ret, rc = 0;
    char *fifo = NULL;
    char *diskpath = NULL;
    char **args = NULL;

    char tempdir_template[] = "/var/run/libxl/bl.XXXXXX";
    char *tempdir;

    char *dom_console_xs_path;
    char dom_console_slave_tty_path[PATH_MAX];

    int xenconsoled_fd = -1, xenconsoled_slave = -1;
    int bootloader_fd = -1, fifo_fd = -1;

    int blrc;
    pid_t pid;
    char *blout;

    struct stat st_buf;

    if (info->hvm || !info->u.pv.bootloader)
        goto out;

    rc = ERROR_INVAL;
    if (!disk)
        goto out;

    rc = ERROR_FAIL;
    ret = mkdir("/var/run/libxl/", S_IRWXU);
    if (ret < 0 && errno != EEXIST)
        goto out;

    ret = stat("/var/run/libxl/", &st_buf);
    if (ret < 0)
        goto out;

    if (!S_ISDIR(st_buf.st_mode))
        goto out;

    tempdir = mkdtemp(tempdir_template);
    if (tempdir == NULL)
        goto out;

    ret = asprintf(&fifo, "%s/fifo", tempdir);
    if (ret < 0) {
        fifo = NULL;
        goto out_close;
    }

    ret = mkfifo(fifo, 0600);
    if (ret < 0) {
        goto out_close;
    }

    diskpath = libxl_device_disk_local_attach(ctx, disk);
    if (!diskpath) {
        goto out_close;
    }

    args = make_bootloader_args(&gc, info, domid, fifo, diskpath);
    if (args == NULL) {
        rc = ERROR_NOMEM;
        goto out_close;
    }

    /*
     * 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.
     */
    ret = open_xenconsoled_pty(&xenconsoled_fd, &xenconsoled_slave,
                               &dom_console_slave_tty_path[0],
                               sizeof(dom_console_slave_tty_path));
    if (ret < 0) {
        goto out_close;
    }

    dom_console_xs_path = libxl__sprintf(&gc, "%s/console/tty", libxl__xs_get_dompath(&gc, domid));
    libxl__xs_write(&gc, XBT_NULL, dom_console_xs_path, "%s", dom_console_slave_tty_path);

    pid = fork_exec_bootloader(&bootloader_fd, info->u.pv.bootloader, args);
    if (pid < 0) {
        goto out_close;
    }

    while (1) {
        fifo_fd = open(fifo, O_RDONLY);
        if (fifo_fd > -1)
            break;

        if (errno == EINTR)
            continue;

        goto out_close;
    }

    fcntl(fifo_fd, F_SETFL, O_NDELAY);

    blout = bootloader_interact(&gc, xenconsoled_fd, bootloader_fd, fifo_fd);
    if (blout == NULL) {
        goto out_close;
    }

    pid = waitpid(pid, &blrc, 0);
    if (pid == -1 || (pid > 0 && WIFEXITED(blrc) && WEXITSTATUS(blrc) != 0)) {
        goto out_close;
    }

    parse_bootloader_result(ctx, info, blout);

    rc = 0;
out_close:
    if (diskpath) {
        libxl_device_disk_local_detach(ctx, disk);
        free(diskpath);
    }
    if (fifo_fd > -1)
        close(fifo_fd);
    if (bootloader_fd > -1)
        close(bootloader_fd);
    if (xenconsoled_fd > -1)
        close(xenconsoled_fd);
    if (xenconsoled_slave > -1)
        close(xenconsoled_slave);

    if (fifo) {
        unlink(fifo);
        free(fifo);
    }

    rmdir(tempdir);

    free(args);

out:
    libxl__free_all(&gc);
    return rc;
}