diff --git a/tools/virsh.c b/tools/virsh.c index 993dba69eb1c589ed140f652bc7a9ecc29297c85..aa9c6795a6482298df64ac08efde31ee89b7d93d 100644 --- a/tools/virsh.c +++ b/tools/virsh.c @@ -2409,25 +2409,35 @@ static const vshCmdOptDef opts_save[] = { N_("filename containing updated XML for the target")}, {"running", VSH_OT_BOOL, 0, N_("set domain to be running on restore")}, {"paused", VSH_OT_BOOL, 0, N_("set domain to be paused on restore")}, + {"verbose", VSH_OT_BOOL, 0, N_("display the progress of save")}, {NULL, 0, 0, NULL} }; -static bool -cmdSave(vshControl *ctl, const vshCmd *cmd) +static void +doSave(void *opaque) { - virDomainPtr dom; + vshCtrlData *data = opaque; + vshControl *ctl = data->ctl; + const vshCmd *cmd = data->cmd; + char ret = '1'; + virDomainPtr dom = NULL; const char *name = NULL; const char *to = NULL; - bool ret = false; unsigned int flags = 0; const char *xmlfile = NULL; char *xml = NULL; + sigset_t sigmask, oldsigmask; + + sigemptyset(&sigmask); + sigaddset(&sigmask, SIGINT); + if (pthread_sigmask(SIG_BLOCK, &sigmask, &oldsigmask) < 0) + goto out_sig; if (!vshConnectionUsability(ctl, ctl->conn)) - return false; + goto out; if (vshCommandOptString(cmd, "file", &to) <= 0) - return false; + goto out; if (vshCommandOptBool(cmd, "bypass-cache")) flags |= VIR_DOMAIN_SAVE_BYPASS_CACHE; @@ -2438,29 +2448,77 @@ cmdSave(vshControl *ctl, const vshCmd *cmd) if (vshCommandOptString(cmd, "xml", &xmlfile) < 0) { vshError(ctl, "%s", _("malformed xml argument")); - return false; + goto out; } if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) - return false; + goto out; if (xmlfile && virFileReadAll(xmlfile, 8192, &xml) < 0) - goto cleanup; + goto out; if (((flags || xml) ? virDomainSaveFlags(dom, to, xml, flags) : virDomainSave(dom, to)) < 0) { vshError(ctl, _("Failed to save domain %s to %s"), name, to); - goto cleanup; + goto out; } - vshPrint(ctl, _("Domain %s saved to %s\n"), name, to); - ret = true; + ret = '0'; -cleanup: +out: + pthread_sigmask(SIG_SETMASK, &oldsigmask, NULL); +out_sig: + if (dom) virDomainFree (dom); VIR_FREE(xml); - virDomainFree(dom); + ignore_value(safewrite(data->writefd, &ret, sizeof(ret))); +} + +static bool +cmdSave(vshControl *ctl, const vshCmd *cmd) +{ + bool ret = false; + virDomainPtr dom = NULL; + int p[2] = {-1. -1}; + virThread workerThread; + bool verbose = false; + vshCtrlData data; + const char *to = NULL; + const char *name = NULL; + + if (!(dom = vshCommandOptDomain(ctl, cmd, &name))) + return false; + + if (vshCommandOptString(cmd, "file", &to) <= 0) + goto cleanup; + + if (vshCommandOptBool (cmd, "verbose")) + verbose = true; + + if (pipe(p) < 0) + goto cleanup; + + data.ctl = ctl; + data.cmd = cmd; + data.writefd = p[1]; + + if (virThreadCreate(&workerThread, + true, + doSave, + &data) < 0) + goto cleanup; + + ret = vshWatchJob(ctl, dom, verbose, p[0], 0, NULL, NULL, _("Save")); + + virThreadJoin(&workerThread); + + if (ret) + vshPrint(ctl, _("\nDomain %s saved to %s\n"), name, to); + +cleanup: + if (dom) + virDomainFree(dom); return ret; } diff --git a/tools/virsh.pod b/tools/virsh.pod index 0c43ffae702c6068453a3225980d1a0d3b486c3d..6ae78d365821869dc5b513ef6545361b40d0f43c 100644 --- a/tools/virsh.pod +++ b/tools/virsh.pod @@ -898,7 +898,7 @@ have also reverted all storage volumes back to the same contents as when the state file was created. =item B I I [I<--bypass-cache>] [I<--xml> B] -[{I<--running> | I<--paused>}] +[{I<--running> | I<--paused>}] [I<--verbose>] Saves a running domain (RAM, but not disk state) to a state file so that it can be restored @@ -909,9 +909,9 @@ If I<--bypass-cache> is specified, the save will avoid the file system cache, although this may slow down the operation. The progress may be monitored using B virsh command and canceled -with B command (sent by another virsh instance). Interrupting -(usually with C) the virsh process which runs B command is not -enough to actually cancel the operation. +with B command (sent by another virsh instance). Another option +is to send SIGINT (usually with C) to the virsh process running +B command. I<--verbose> displays the progress of save. This is roughly equivalent to doing a hibernate on a running computer, with all the same limitations. Open network connections may be