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); }
int libxl__openptys(libxl__openpty_state *op, struct termios *termp, struct winsize *winp) { /* * This is completely crazy. openpty calls grantpt which the spec * says may fork, and may not be called with a SIGCHLD handler. * Now our application may have a SIGCHLD handler so that's bad. * We could perhaps block it but we'd need to block it on all * threads. This is just Too Hard. * * So instead, we run openpty in a child process. That child * process then of course has only our own thread and our own * signal handlers. We pass the fds back. * * Since our only current caller actually wants two ptys, we * support calling openpty multiple times for a single fork. */ STATE_AO_GC(op->ao); int count = op->count; int r, i, rc, sockets[2], ptyfds[count][2]; libxl__carefd *for_child = 0; pid_t pid = -1; for (i=0; i<count; i++) { ptyfds[i][0] = ptyfds[i][1] = -1; libxl__openpty_result *res = &op->results[i]; assert(!res->master); assert(!res->slave); } sockets[0] = sockets[1] = -1; /* 0 is for us, 1 for our child */ libxl__carefd_begin(); r = socketpair(AF_UNIX, SOCK_STREAM, 0, sockets); if (r) { sockets[0] = sockets[1] = -1; } for_child = libxl__carefd_opened(CTX, sockets[1]); if (r) { LOGE(ERROR,"socketpair failed"); rc = ERROR_FAIL; goto out; } pid = libxl__ev_child_fork(gc, &op->child, openpty_exited); if (pid == -1) { rc = ERROR_FAIL; goto out; } if (!pid) { /* child */ close(sockets[0]); signal(SIGCHLD, SIG_DFL); for (i=0; i<count; i++) { r = openpty(&ptyfds[i][0], &ptyfds[i][1], NULL, termp, winp); if (r) { LOGE(ERROR,"openpty failed"); _exit(-1); } } rc = libxl__sendmsg_fds(gc, sockets[1], "",1, 2*count, &ptyfds[0][0], "ptys"); if (rc) { LOGE(ERROR,"sendmsg to parent failed"); _exit(-1); } _exit(0); } libxl__carefd_close(for_child); for_child = 0; /* this should be fast so do it synchronously */ libxl__carefd_begin(); char buf[1]; rc = libxl__recvmsg_fds(gc, sockets[0], buf,1, 2*count, &ptyfds[0][0], "ptys"); if (!rc) { for (i=0; i<count; i++) { libxl__openpty_result *res = &op->results[i]; res->master = libxl__carefd_record(CTX, ptyfds[i][0]); res->slave = libxl__carefd_record(CTX, ptyfds[i][1]); } } /* now the pty fds are in the carefds, if they were ever open */ libxl__carefd_unlock(); if (rc) goto out; rc = 0; out: if (sockets[0] >= 0) close(sockets[0]); libxl__carefd_close(for_child); if (libxl__ev_child_inuse(&op->child)) { op->rc = rc; /* we will get a callback when the child dies */ return 0; } assert(rc); openpty_cleanup(op); return rc; }
/* Portability note: this lock utilises flock(2) so a proper implementation of * flock(2) is required. */ libxl__domain_userdata_lock *libxl__lock_domain_userdata(libxl__gc *gc, uint32_t domid) { libxl__domain_userdata_lock *lock = NULL; const char *lockfile; int fd; struct stat stab, fstab; lockfile = libxl__userdata_path(gc, domid, "domain-userdata-lock", "l"); if (!lockfile) goto out; lock = libxl__zalloc(NOGC, sizeof(libxl__domain_userdata_lock)); lock->path = libxl__strdup(NOGC, lockfile); while (true) { libxl__carefd_begin(); fd = open(lockfile, O_RDWR|O_CREAT, 0666); if (fd < 0) LOGE(ERROR, "cannot open lockfile %s, errno=%d", lockfile, errno); lock->lock_carefd = libxl__carefd_opened(CTX, fd); if (fd < 0) goto out; /* Lock the file in exclusive mode, wait indefinitely to * acquire the lock */ while (flock(fd, LOCK_EX)) { switch (errno) { case EINTR: /* Signal received, retry */ continue; default: /* All other errno: EBADF, EINVAL, ENOLCK, EWOULDBLOCK */ LOGE(ERROR, "unexpected error while trying to lock %s, fd=%d, errno=%d", lockfile, fd, errno); goto out; } } if (fstat(fd, &fstab)) { LOGE(ERROR, "cannot fstat %s, fd=%d, errno=%d", lockfile, fd, errno); goto out; } if (stat(lockfile, &stab)) { if (errno != ENOENT) { LOGE(ERROR, "cannot stat %s, errno=%d", lockfile, errno); goto out; } } else { if (stab.st_dev == fstab.st_dev && stab.st_ino == fstab.st_ino) break; } libxl__carefd_close(lock->lock_carefd); } /* Check the domain is still there, if not we should release the * lock and clean up. */ if (libxl_domain_info(CTX, NULL, domid)) goto out; return lock; out: if (lock) libxl__unlock_domain_userdata(lock); return NULL; }