return 0;
}
+static int
+virCHMonitorBuildKeyValueStringJson(char **jsonstr,
+ const char *key,
+ const char *value)
+{
+ g_autoptr(virJSONValue) content = virJSONValueNewObject();
+
+ if (virJSONValueObjectAppendString(content, key, value) < 0)
+ return -1;
+
+ if (!(*jsonstr = virJSONValueToString(content, false)))
+ return -1;
+
+ return 0;
+}
+
static int
chMonitorCreateSocket(const char *socket_path)
{
return virCHMonitorPutNoContent(mon, URL_VM_RESUME);
}
+static int
+virCHMonitorSaveRestoreVM(virCHMonitor *mon, const char *path, bool save)
+{
+ g_autofree char *url = NULL;
+ int responseCode = 0;
+ int ret = -1;
+ g_autofree char *payload = NULL;
+ g_autofree char *path_url = NULL;
+ struct curl_slist *headers = NULL;
+ struct curl_data data = {0};
+
+ if (save)
+ url = g_strdup_printf("%s/%s", URL_ROOT, URL_VM_SAVE);
+ else
+ url = g_strdup_printf("%s/%s", URL_ROOT, URL_VM_RESTORE);
+
+ headers = curl_slist_append(headers, "Accept: application/json");
+ headers = curl_slist_append(headers, "Content-Type: application/json");
+
+ path_url = g_strdup_printf("file://%s", path);
+ if (save) {
+ if (virCHMonitorBuildKeyValueStringJson(&payload, "destination_url", path_url) != 0)
+ return -1;
+ } else {
+ if (virCHMonitorBuildKeyValueStringJson(&payload, "source_url", path_url) != 0)
+ return -1;
+ }
+
+ VIR_WITH_OBJECT_LOCK_GUARD(mon) {
+ /* reset all options of a libcurl session handle at first */
+ curl_easy_reset(mon->handle);
+
+ curl_easy_setopt(mon->handle, CURLOPT_UNIX_SOCKET_PATH, mon->socketpath);
+ curl_easy_setopt(mon->handle, CURLOPT_URL, url);
+ curl_easy_setopt(mon->handle, CURLOPT_CUSTOMREQUEST, "PUT");
+ curl_easy_setopt(mon->handle, CURLOPT_HTTPHEADER, headers);
+ curl_easy_setopt(mon->handle, CURLOPT_POSTFIELDS, payload);
+ curl_easy_setopt(mon->handle, CURLOPT_WRITEFUNCTION, curl_callback);
+ curl_easy_setopt(mon->handle, CURLOPT_WRITEDATA, (void *)&data);
+
+ responseCode = virCHMonitorCurlPerform(mon->handle);
+ }
+
+ if (responseCode == 200 || responseCode == 204) {
+ ret = 0;
+ } else {
+ data.content = g_realloc(data.content, data.size + 1);
+ data.content[data.size] = 0;
+ virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
+ data.content);
+ g_free(data.content);
+ }
+
+ /* reset the libcurl handle to avoid leaking a stack pointer to data */
+ curl_easy_reset(mon->handle);
+ curl_slist_free_all(headers);
+ return ret;
+}
+
+int
+virCHMonitorSaveVM(virCHMonitor *mon, const char *to)
+{
+ return virCHMonitorSaveRestoreVM(mon, to, true);
+}
+
+int
+virCHMonitorRestoreVM(virCHMonitor *mon, const char *from)
+{
+ return virCHMonitorSaveRestoreVM(mon, from, false);
+}
+
/**
* virCHMonitorGetInfo:
* @mon: Pointer to the monitor
#define URL_VM_Suspend "vm.pause"
#define URL_VM_RESUME "vm.resume"
#define URL_VM_INFO "vm.info"
+#define URL_VM_SAVE "vm.snapshot"
+#define URL_VM_RESTORE "vm.restore"
#define VIRCH_THREAD_NAME_LEN 16
int virCHMonitorRebootVM(virCHMonitor *mon);
int virCHMonitorSuspendVM(virCHMonitor *mon);
int virCHMonitorResumeVM(virCHMonitor *mon);
+int virCHMonitorSaveVM(virCHMonitor *mon, const char *to);
+int virCHMonitorRestoreVM(virCHMonitor *mon, const char *from);
int virCHMonitorGetInfo(virCHMonitor *mon, virJSONValue **info);
void virCHMonitorCPUInfoFree(virCHMonitorCPUInfo *cpus);