* @to: path for the output file
*
* This method will suspend a domain and save its memory contents to
- * a file on disk. Use virDomainRestore() to restore a domain after
- * saving.
+ * a file on disk. After the call, if successful, the domain is not
+ * listed as running anymore (this may be a problem).
+ * Use virDomainRestore() to restore a domain after saving.
*
* Returns 0 in case of success and -1 in case of failure.
*/
int
virDomainSave(virDomainPtr domain, const char *to) {
int ret;
+ char filepath[4096];
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return(-1);
- if ((to == NULL) || (to[0] != '/'))
+ if ((!VIR_IS_CONNECTED_DOMAIN(domain)) || (to == NULL))
return(-1);
+ /*
+ * We must absolutize the file path as the save is done out of process
+ * TODO: check for URI when libxml2 is linked in.
+ */
+ if (to[0] != '/') {
+ unsigned int len, t;
+
+ t = strlen(to);
+ if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
+ return(-1);
+ len = strlen(filepath);
+ /* that should be covered by getcwd() semantic, but be 100% sure */
+ if (len > sizeof(filepath) - (t + 3))
+ return(-1);
+ filepath[len] = '/';
+ strcpy(&filepath[len + 1], to);
+ to = &filepath[0];
+
+ }
+
ret = xend_save(domain->conn, domain->name, to);
return(ret);
}
/**
* virDomainRestore:
- * @domain: a domain object
+ * @conn: pointer to the hypervisor connection
* @from: path to the
*
* This method will restore a domain saved to disk by virDomainSave().
* Returns 0 in case of success and -1 in case of failure.
*/
int
-virDomainRestore(virDomainPtr domain, const char *from) {
+virDomainRestore(virConnectPtr conn, const char *from) {
int ret;
+ char filepath[4096];
- if (!VIR_IS_CONNECTED_DOMAIN(domain))
- return(-1);
- if ((from == NULL) || (from[0] != '/'))
+ if ((!VIR_IS_CONNECT(conn)) || (from == NULL))
return(-1);
+ /*
+ * We must absolutize the file path as the restore is done out of process
+ * TODO: check for URI when libxml2 is linked in.
+ */
+ if (from[0] != '/') {
+ unsigned int len, t;
+
+ t = strlen(from);
+ if (getcwd(filepath, sizeof(filepath) - (t + 3)) == NULL)
+ return(-1);
+ len = strlen(filepath);
+ /* that should be covered by getcwd() semantic, but be 100% sure */
+ if (len > sizeof(filepath) - (t + 3))
+ return(-1);
+ filepath[len] = '/';
+ strcpy(&filepath[len + 1], from);
+ from = &filepath[0];
+ }
- ret = xend_restore(domain->conn, from);
+ ret = xend_restore(conn, from);
return(ret);
}
return ret;
}
+/*
+ * "save" command
+ */
+static vshCmdInfo info_save[] = {
+ { "syntax", "save <domain> to <file>" },
+ { "help", "save a domain state to a file" },
+ { "desc", "Save a running domain." },
+ { NULL, NULL }
+};
+
+static vshCmdOptDef opts_save[] = {
+ { "file", VSH_OT_STRING, VSH_OFLAG_REQ, "where to save the data" },
+ { "domain", VSH_OT_DATA, 0, "domain name or id" },
+ { NULL, 0, 0, NULL }
+};
+
+static int
+cmdSave(vshControl *ctl, vshCmd *cmd) {
+ virDomainPtr dom;
+ char *name;
+ char *to;
+ int found;
+ int ret = TRUE;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ to = vshCommandOptString(cmd, "file", &found);
+ if (!found)
+ return FALSE;
+
+ if (!(dom = vshCommandOptDomain(ctl, cmd, "domain", &name)))
+ return FALSE;
+
+ if (virDomainSave(dom, to)==0) {
+ vshPrint(ctl, VSH_MESG, "Domain %s saved\n", name);
+ } else {
+ vshError(ctl, FALSE, "Failed to save domain\n");
+ ret = FALSE;
+ }
+
+ virDomainFree(dom);
+ return ret;
+}
+
+/*
+ * "restore" command
+ */
+static vshCmdInfo info_restore[] = {
+ { "syntax", "restore a domain from <file>" },
+ { "help", "restore a domain from a saved state in a file" },
+ { "desc", "Restore a domain." },
+ { NULL, NULL }
+};
+
+static vshCmdOptDef opts_restore[] = {
+ { "file", VSH_OT_DATA, 0, "the state to restore" },
+ { NULL, 0, 0, NULL }
+};
+
+static int
+cmdRestore(vshControl *ctl, vshCmd *cmd) {
+ char *from;
+ int found;
+ int ret = TRUE;
+
+ if (!vshConnectionUsability(ctl, ctl->conn, TRUE))
+ return FALSE;
+
+ from = vshCommandOptString(cmd, "file", &found);
+ if (!found)
+ return FALSE;
+
+ if (virDomainRestore(ctl->conn, from)==0) {
+ vshPrint(ctl, VSH_MESG, "Domain restored from %s\n", from);
+ } else {
+ vshError(ctl, FALSE, "Failed to restore domain\n");
+ ret = FALSE;
+ }
+ return ret;
+}
+
/*
* "resume" command
*/
static vshCmdOptDef opts_nameof[] = {
{ "id", VSH_OT_DATA, 0, "domain Id" },
- { NULL, 0, 0, NULL }
+ { NULL, 0, 0, NULL }
};
static int
{ "dstate", cmdDstate, opts_dstate, info_dstate },
{ "suspend", cmdSuspend, opts_suspend, info_suspend },
{ "resume", cmdResume, opts_resume, info_resume },
+ { "save", cmdSave, opts_save, info_save },
+ { "restore", cmdRestore, opts_restore, info_restore },
{ "shutdown", cmdShutdown, opts_shutdown, info_shutdown },
{ "destroy", cmdDestroy, opts_destroy, info_destroy },
{ "help", cmdHelp, opts_help, info_help },