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; }