qemuDomainObjPrivatePtr priv;
struct stat sb;
int is_reg = 0;
+ unsigned long long offset;
memset(&header, 0, sizeof(header));
memcpy(header.magic, QEMUD_SAVE_MAGIC, sizeof(header.magic));
hdata.path = path;
hdata.xml = xml;
hdata.header = &header;
+ offset = sizeof(header) + header.xml_len;
+
+ /* Due to way we append QEMU state on our header with dd,
+ * we need to ensure there's a 512 byte boundary. Unfortunately
+ * we don't have an explicit offset in the header, so we fake
+ * it by padding the XML string with NULLs */
+ if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
+ unsigned long long pad =
+ QEMU_MONITOR_MIGRATE_TO_FILE_BS -
+ (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS);
+
+ if (VIR_REALLOC_N(xml, header.xml_len + pad) < 0) {
+ virReportOOMError();
+ goto endjob;
+ }
+ memset(xml + header.xml_len, 0, pad);
+ offset += pad;
+ header.xml_len += pad;
+ }
/* Write header to file, followed by XML */
/* First try creating the file as root */
- if (is_reg &&
- (rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
- S_IRUSR|S_IWUSR,
- getuid(), getgid(),
- qemudDomainSaveFileOpHook, &hdata,
- 0)) != 0) {
-
- /* If we failed as root, and the error was permission-denied
- (EACCES), assume it's on a network-connected share where
- root access is restricted (eg, root-squashed NFS). If the
- qemu user (driver->user) is non-root, just set a flag to
- bypass security driver shenanigans, and retry the operation
- after doing setuid to qemu user */
-
- if ((rc != EACCES) ||
- driver->user == getuid()) {
- virReportSystemError(rc, _("Failed to create domain save file '%s'"),
- path);
+ if (!is_reg) {
+ int fd = open(path, O_WRONLY | O_TRUNC);
+ if (fd < 0) {
+ virReportSystemError(errno, _("unable to open %s"), path);
goto endjob;
}
-
-#ifdef __linux__
- /* On Linux we can also verify the FS-type of the directory. */
- char *dirpath, *p;
- struct statfs st;
- int statfs_ret;
-
- if ((dirpath = strdup(path)) == NULL) {
- virReportOOMError();
+ if ((rc = qemudDomainSaveFileOpHook(fd, &hdata)) != 0) {
+ close(fd);
+ goto endjob;
+ }
+ if (close(fd) < 0) {
+ virReportSystemError(errno, _("unable to close %s"), path);
goto endjob;
}
+ } else {
+ if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
+ S_IRUSR|S_IWUSR,
+ getuid(), getgid(),
+ qemudDomainSaveFileOpHook, &hdata,
+ 0)) != 0) {
+ /* If we failed as root, and the error was permission-denied
+ (EACCES), assume it's on a network-connected share where
+ root access is restricted (eg, root-squashed NFS). If the
+ qemu user (driver->user) is non-root, just set a flag to
+ bypass security driver shenanigans, and retry the operation
+ after doing setuid to qemu user */
+
+ if ((rc != EACCES) ||
+ driver->user == getuid()) {
+ virReportSystemError(rc, _("Failed to create domain save file '%s'"),
+ path);
+ goto endjob;
+ }
- do {
- // Try less and less of the path until we get to a
- // directory we can stat. Even if we don't have 'x'
- // permission on any directory in the path on the NFS
- // server (assuming it's NFS), we will be able to stat the
- // mount point, and that will properly tell us if the
- // fstype is NFS.
+#ifdef __linux__
+ /* On Linux we can also verify the FS-type of the directory. */
+ char *dirpath, *p;
+ struct statfs st;
+ int statfs_ret;
- if ((p = strrchr(dirpath, '/')) == NULL) {
- qemuReportError(VIR_ERR_INVALID_ARG,
- _("Invalid relative path '%s' for domain save file"),
- path);
- VIR_FREE(dirpath);
+ if ((dirpath = strdup(path)) == NULL) {
+ virReportOOMError();
goto endjob;
}
- if (p == dirpath)
- *(p+1) = '\0';
- else
- *p = '\0';
+ do {
+ // Try less and less of the path until we get to a
+ // directory we can stat. Even if we don't have 'x'
+ // permission on any directory in the path on the NFS
+ // server (assuming it's NFS), we will be able to stat the
+ // mount point, and that will properly tell us if the
+ // fstype is NFS.
+
+ if ((p = strrchr(dirpath, '/')) == NULL) {
+ qemuReportError(VIR_ERR_INVALID_ARG,
+ _("Invalid relative path '%s' for domain save file"),
+ path);
+ VIR_FREE(dirpath);
+ goto endjob;
+ }
- statfs_ret = statfs(dirpath, &st);
+ if (p == dirpath)
+ *(p+1) = '\0';
+ else
+ *p = '\0';
- } while ((statfs_ret == -1) && (p != dirpath));
+ statfs_ret = statfs(dirpath, &st);
- if (statfs_ret == -1) {
- virReportSystemError(errno,
- _("Failed to create domain save file '%s'"
- " statfs of all elements of path failed."),
- path);
- VIR_FREE(dirpath);
- goto endjob;
- }
+ } while ((statfs_ret == -1) && (p != dirpath));
- if (st.f_type != NFS_SUPER_MAGIC) {
- virReportSystemError(rc,
- _("Failed to create domain save file '%s'"
- " (fstype of '%s' is 0x%X"),
- path, dirpath, (unsigned int) st.f_type);
+ if (statfs_ret == -1) {
+ virReportSystemError(errno,
+ _("Failed to create domain save file '%s'"
+ " statfs of all elements of path failed."),
+ path);
+ VIR_FREE(dirpath);
+ goto endjob;
+ }
+
+ if (st.f_type != NFS_SUPER_MAGIC) {
+ virReportSystemError(rc,
+ _("Failed to create domain save file '%s'"
+ " (fstype of '%s' is 0x%X"),
+ path, dirpath, (unsigned int) st.f_type);
+ VIR_FREE(dirpath);
+ goto endjob;
+ }
VIR_FREE(dirpath);
- goto endjob;
- }
- VIR_FREE(dirpath);
#endif
- /* Retry creating the file as driver->user */
+ /* Retry creating the file as driver->user */
- if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
- S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
- driver->user, driver->group,
- qemudDomainSaveFileOpHook, &hdata,
- VIR_FILE_OP_AS_UID)) != 0) {
- virReportSystemError(rc, _("Error from child process creating '%s'"),
+ if ((rc = virFileOperation(path, O_CREAT|O_TRUNC|O_WRONLY,
+ S_IRUSR|S_IWUSR|S_IRGRP|S_IWGRP,
+ driver->user, driver->group,
+ qemudDomainSaveFileOpHook, &hdata,
+ VIR_FILE_OP_AS_UID)) != 0) {
+ virReportSystemError(rc, _("Error from child process creating '%s'"),
path);
- goto endjob;
- }
+ goto endjob;
+ }
- /* Since we had to setuid to create the file, and the fstype
- is NFS, we assume it's a root-squashing NFS share, and that
- the security driver stuff would have failed anyway */
+ /* Since we had to setuid to create the file, and the fstype
+ is NFS, we assume it's a root-squashing NFS share, and that
+ the security driver stuff would have failed anyway */
- bypassSecurityDriver = 1;
+ bypassSecurityDriver = 1;
+ }
}
if (header.compressed == QEMUD_SAVE_FORMAT_RAW) {
const char *args[] = { "cat", NULL };
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- rc = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
+ rc = qemuMonitorMigrateToFile(priv->mon, 1, args, path, offset);
qemuDomainObjExitMonitorWithDriver(driver, vm);
} else {
const char *prog = qemudSaveCompressionTypeToString(header.compressed);
NULL
};
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- rc = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
+ rc = qemuMonitorMigrateToFile(priv->mon, 1, args, path, offset);
qemuDomainObjExitMonitorWithDriver(driver, vm);
}
}
qemuDomainObjEnterMonitorWithDriver(driver, vm);
- ret = qemuMonitorMigrateToCommand(priv->mon, 1, args, path);
+ ret = qemuMonitorMigrateToFile(priv->mon, 1, args, path, 0);
qemuDomainObjExitMonitorWithDriver(driver, vm);
if (ret < 0)
internalret = qemuMonitorMigrateToUnix(priv->mon, 1, unixfile);
else if (qemuCmdFlags & QEMUD_CMD_FLAG_MIGRATE_QEMU_EXEC) {
const char *args[] = { "nc", "-U", unixfile, NULL };
- internalret = qemuMonitorMigrateToCommand(priv->mon, 1, args, "/dev/null");
+ internalret = qemuMonitorMigrateToCommand(priv->mon, 1, args);
} else {
internalret = -1;
}
int qemuMonitorMigrateToCommand(qemuMonitorPtr mon,
int background,
- const char * const *argv,
- const char *target)
+ const char * const *argv)
{
int ret;
- DEBUG("mon=%p, fd=%d argv=%p target=%s",
- mon, mon->fd, argv, target);
+ DEBUG("mon=%p, fd=%d argv=%p",
+ mon, mon->fd, argv);
if (mon->json)
- ret = qemuMonitorJSONMigrateToCommand(mon, background, argv, target);
+ ret = qemuMonitorJSONMigrateToCommand(mon, background, argv);
else
- ret = qemuMonitorTextMigrateToCommand(mon, background, argv, target);
+ ret = qemuMonitorTextMigrateToCommand(mon, background, argv);
+ return ret;
+}
+
+int qemuMonitorMigrateToFile(qemuMonitorPtr mon,
+ int background,
+ const char * const *argv,
+ const char *target,
+ unsigned long long offset)
+{
+ int ret;
+ DEBUG("mon=%p, fd=%d argv=%p target=%s offset=%llu",
+ mon, mon->fd, argv, target, offset);
+
+ if (offset % QEMU_MONITOR_MIGRATE_TO_FILE_BS) {
+ qemuReportError(VIR_ERR_INTERNAL_ERROR,
+ _("file offset must be a multiple of %llu"),
+ QEMU_MONITOR_MIGRATE_TO_FILE_BS);
+ return -1;
+ }
+
+ if (mon->json)
+ ret = qemuMonitorJSONMigrateToFile(mon, background, argv, target, offset);
+ else
+ ret = qemuMonitorTextMigrateToFile(mon, background, argv, target, offset);
return ret;
}