1*5010cec2SMarc-André Lureau /* 2*5010cec2SMarc-André Lureau * QEMU dbus-vmstate 3*5010cec2SMarc-André Lureau * 4*5010cec2SMarc-André Lureau * Copyright (C) 2019 Red Hat Inc 5*5010cec2SMarc-André Lureau * 6*5010cec2SMarc-André Lureau * Authors: 7*5010cec2SMarc-André Lureau * Marc-André Lureau <marcandre.lureau@redhat.com> 8*5010cec2SMarc-André Lureau * 9*5010cec2SMarc-André Lureau * This work is licensed under the terms of the GNU GPL, version 2 or later. 10*5010cec2SMarc-André Lureau * See the COPYING file in the top-level directory. 11*5010cec2SMarc-André Lureau */ 12*5010cec2SMarc-André Lureau 13*5010cec2SMarc-André Lureau #include "qemu/osdep.h" 14*5010cec2SMarc-André Lureau #include "qemu/units.h" 15*5010cec2SMarc-André Lureau #include "qemu/dbus.h" 16*5010cec2SMarc-André Lureau #include "qemu/error-report.h" 17*5010cec2SMarc-André Lureau #include "qapi/error.h" 18*5010cec2SMarc-André Lureau #include "qom/object_interfaces.h" 19*5010cec2SMarc-André Lureau #include "qapi/qmp/qerror.h" 20*5010cec2SMarc-André Lureau #include "migration/vmstate.h" 21*5010cec2SMarc-André Lureau #include "trace.h" 22*5010cec2SMarc-André Lureau 23*5010cec2SMarc-André Lureau typedef struct DBusVMState DBusVMState; 24*5010cec2SMarc-André Lureau typedef struct DBusVMStateClass DBusVMStateClass; 25*5010cec2SMarc-André Lureau 26*5010cec2SMarc-André Lureau #define TYPE_DBUS_VMSTATE "dbus-vmstate" 27*5010cec2SMarc-André Lureau #define DBUS_VMSTATE(obj) \ 28*5010cec2SMarc-André Lureau OBJECT_CHECK(DBusVMState, (obj), TYPE_DBUS_VMSTATE) 29*5010cec2SMarc-André Lureau #define DBUS_VMSTATE_GET_CLASS(obj) \ 30*5010cec2SMarc-André Lureau OBJECT_GET_CLASS(DBusVMStateClass, (obj), TYPE_DBUS_VMSTATE) 31*5010cec2SMarc-André Lureau #define DBUS_VMSTATE_CLASS(klass) \ 32*5010cec2SMarc-André Lureau OBJECT_CLASS_CHECK(DBusVMStateClass, (klass), TYPE_DBUS_VMSTATE) 33*5010cec2SMarc-André Lureau 34*5010cec2SMarc-André Lureau struct DBusVMStateClass { 35*5010cec2SMarc-André Lureau ObjectClass parent_class; 36*5010cec2SMarc-André Lureau }; 37*5010cec2SMarc-André Lureau 38*5010cec2SMarc-André Lureau struct DBusVMState { 39*5010cec2SMarc-André Lureau Object parent; 40*5010cec2SMarc-André Lureau 41*5010cec2SMarc-André Lureau GDBusConnection *bus; 42*5010cec2SMarc-André Lureau char *dbus_addr; 43*5010cec2SMarc-André Lureau char *id_list; 44*5010cec2SMarc-André Lureau 45*5010cec2SMarc-André Lureau uint32_t data_size; 46*5010cec2SMarc-André Lureau uint8_t *data; 47*5010cec2SMarc-André Lureau }; 48*5010cec2SMarc-André Lureau 49*5010cec2SMarc-André Lureau static const GDBusPropertyInfo vmstate_property_info[] = { 50*5010cec2SMarc-André Lureau { -1, (char *) "Id", (char *) "s", 51*5010cec2SMarc-André Lureau G_DBUS_PROPERTY_INFO_FLAGS_READABLE, NULL }, 52*5010cec2SMarc-André Lureau }; 53*5010cec2SMarc-André Lureau 54*5010cec2SMarc-André Lureau static const GDBusPropertyInfo * const vmstate_property_info_pointers[] = { 55*5010cec2SMarc-André Lureau &vmstate_property_info[0], 56*5010cec2SMarc-André Lureau NULL 57*5010cec2SMarc-André Lureau }; 58*5010cec2SMarc-André Lureau 59*5010cec2SMarc-André Lureau static const GDBusInterfaceInfo vmstate1_interface_info = { 60*5010cec2SMarc-André Lureau -1, 61*5010cec2SMarc-André Lureau (char *) "org.qemu.VMState1", 62*5010cec2SMarc-André Lureau (GDBusMethodInfo **) NULL, 63*5010cec2SMarc-André Lureau (GDBusSignalInfo **) NULL, 64*5010cec2SMarc-André Lureau (GDBusPropertyInfo **) &vmstate_property_info_pointers, 65*5010cec2SMarc-André Lureau NULL, 66*5010cec2SMarc-André Lureau }; 67*5010cec2SMarc-André Lureau 68*5010cec2SMarc-André Lureau #define DBUS_VMSTATE_SIZE_LIMIT (1 * MiB) 69*5010cec2SMarc-André Lureau 70*5010cec2SMarc-André Lureau static GHashTable * 71*5010cec2SMarc-André Lureau get_id_list_set(DBusVMState *self) 72*5010cec2SMarc-André Lureau { 73*5010cec2SMarc-André Lureau g_auto(GStrv) ids = NULL; 74*5010cec2SMarc-André Lureau g_autoptr(GHashTable) set = NULL; 75*5010cec2SMarc-André Lureau int i; 76*5010cec2SMarc-André Lureau 77*5010cec2SMarc-André Lureau if (!self->id_list) { 78*5010cec2SMarc-André Lureau return NULL; 79*5010cec2SMarc-André Lureau } 80*5010cec2SMarc-André Lureau 81*5010cec2SMarc-André Lureau ids = g_strsplit(self->id_list, ",", -1); 82*5010cec2SMarc-André Lureau set = g_hash_table_new_full(g_str_hash, g_str_equal, g_free, NULL); 83*5010cec2SMarc-André Lureau for (i = 0; ids[i]; i++) { 84*5010cec2SMarc-André Lureau g_hash_table_add(set, ids[i]); 85*5010cec2SMarc-André Lureau ids[i] = NULL; 86*5010cec2SMarc-André Lureau } 87*5010cec2SMarc-André Lureau 88*5010cec2SMarc-André Lureau return g_steal_pointer(&set); 89*5010cec2SMarc-André Lureau } 90*5010cec2SMarc-André Lureau 91*5010cec2SMarc-André Lureau static GHashTable * 92*5010cec2SMarc-André Lureau dbus_get_proxies(DBusVMState *self, GError **err) 93*5010cec2SMarc-André Lureau { 94*5010cec2SMarc-André Lureau g_autoptr(GHashTable) proxies = NULL; 95*5010cec2SMarc-André Lureau g_autoptr(GHashTable) ids = NULL; 96*5010cec2SMarc-André Lureau g_auto(GStrv) names = NULL; 97*5010cec2SMarc-André Lureau Error *error = NULL; 98*5010cec2SMarc-André Lureau size_t i; 99*5010cec2SMarc-André Lureau 100*5010cec2SMarc-André Lureau ids = get_id_list_set(self); 101*5010cec2SMarc-André Lureau proxies = g_hash_table_new_full(g_str_hash, g_str_equal, 102*5010cec2SMarc-André Lureau g_free, g_object_unref); 103*5010cec2SMarc-André Lureau 104*5010cec2SMarc-André Lureau names = qemu_dbus_get_queued_owners(self->bus, "org.qemu.VMState1", &error); 105*5010cec2SMarc-André Lureau if (!names) { 106*5010cec2SMarc-André Lureau g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, "%s", 107*5010cec2SMarc-André Lureau error_get_pretty(error)); 108*5010cec2SMarc-André Lureau error_free(error); 109*5010cec2SMarc-André Lureau return NULL; 110*5010cec2SMarc-André Lureau } 111*5010cec2SMarc-André Lureau 112*5010cec2SMarc-André Lureau for (i = 0; names[i]; i++) { 113*5010cec2SMarc-André Lureau g_autoptr(GDBusProxy) proxy = NULL; 114*5010cec2SMarc-André Lureau g_autoptr(GVariant) result = NULL; 115*5010cec2SMarc-André Lureau g_autofree char *id = NULL; 116*5010cec2SMarc-André Lureau size_t size; 117*5010cec2SMarc-André Lureau 118*5010cec2SMarc-André Lureau proxy = g_dbus_proxy_new_sync(self->bus, G_DBUS_PROXY_FLAGS_NONE, 119*5010cec2SMarc-André Lureau (GDBusInterfaceInfo *) &vmstate1_interface_info, 120*5010cec2SMarc-André Lureau names[i], 121*5010cec2SMarc-André Lureau "/org/qemu/VMState1", 122*5010cec2SMarc-André Lureau "org.qemu.VMState1", 123*5010cec2SMarc-André Lureau NULL, err); 124*5010cec2SMarc-André Lureau if (!proxy) { 125*5010cec2SMarc-André Lureau return NULL; 126*5010cec2SMarc-André Lureau } 127*5010cec2SMarc-André Lureau 128*5010cec2SMarc-André Lureau result = g_dbus_proxy_get_cached_property(proxy, "Id"); 129*5010cec2SMarc-André Lureau if (!result) { 130*5010cec2SMarc-André Lureau g_set_error_literal(err, G_IO_ERROR, G_IO_ERROR_FAILED, 131*5010cec2SMarc-André Lureau "VMState Id property is missing."); 132*5010cec2SMarc-André Lureau return NULL; 133*5010cec2SMarc-André Lureau } 134*5010cec2SMarc-André Lureau 135*5010cec2SMarc-André Lureau id = g_variant_dup_string(result, &size); 136*5010cec2SMarc-André Lureau if (ids && !g_hash_table_remove(ids, id)) { 137*5010cec2SMarc-André Lureau g_clear_pointer(&id, g_free); 138*5010cec2SMarc-André Lureau g_clear_object(&proxy); 139*5010cec2SMarc-André Lureau continue; 140*5010cec2SMarc-André Lureau } 141*5010cec2SMarc-André Lureau if (size == 0 || size >= 256) { 142*5010cec2SMarc-André Lureau g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, 143*5010cec2SMarc-André Lureau "VMState Id '%s' is invalid.", id); 144*5010cec2SMarc-André Lureau return NULL; 145*5010cec2SMarc-André Lureau } 146*5010cec2SMarc-André Lureau 147*5010cec2SMarc-André Lureau if (!g_hash_table_insert(proxies, id, proxy)) { 148*5010cec2SMarc-André Lureau g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, 149*5010cec2SMarc-André Lureau "Duplicated VMState Id '%s'", id); 150*5010cec2SMarc-André Lureau return NULL; 151*5010cec2SMarc-André Lureau } 152*5010cec2SMarc-André Lureau id = NULL; 153*5010cec2SMarc-André Lureau proxy = NULL; 154*5010cec2SMarc-André Lureau 155*5010cec2SMarc-André Lureau g_clear_pointer(&result, g_variant_unref); 156*5010cec2SMarc-André Lureau } 157*5010cec2SMarc-André Lureau 158*5010cec2SMarc-André Lureau if (ids) { 159*5010cec2SMarc-André Lureau g_autofree char **left = NULL; 160*5010cec2SMarc-André Lureau 161*5010cec2SMarc-André Lureau left = (char **)g_hash_table_get_keys_as_array(ids, NULL); 162*5010cec2SMarc-André Lureau if (*left) { 163*5010cec2SMarc-André Lureau g_autofree char *leftids = g_strjoinv(",", left); 164*5010cec2SMarc-André Lureau g_set_error(err, G_IO_ERROR, G_IO_ERROR_FAILED, 165*5010cec2SMarc-André Lureau "Required VMState Id are missing: %s", leftids); 166*5010cec2SMarc-André Lureau return NULL; 167*5010cec2SMarc-André Lureau } 168*5010cec2SMarc-André Lureau } 169*5010cec2SMarc-André Lureau 170*5010cec2SMarc-André Lureau return g_steal_pointer(&proxies); 171*5010cec2SMarc-André Lureau } 172*5010cec2SMarc-André Lureau 173*5010cec2SMarc-André Lureau static int 174*5010cec2SMarc-André Lureau dbus_load_state_proxy(GDBusProxy *proxy, const uint8_t *data, size_t size) 175*5010cec2SMarc-André Lureau { 176*5010cec2SMarc-André Lureau g_autoptr(GError) err = NULL; 177*5010cec2SMarc-André Lureau g_autoptr(GVariant) result = NULL; 178*5010cec2SMarc-André Lureau g_autoptr(GVariant) value = NULL; 179*5010cec2SMarc-André Lureau 180*5010cec2SMarc-André Lureau value = g_variant_new_fixed_array(G_VARIANT_TYPE_BYTE, 181*5010cec2SMarc-André Lureau data, size, sizeof(char)); 182*5010cec2SMarc-André Lureau result = g_dbus_proxy_call_sync(proxy, "Load", 183*5010cec2SMarc-André Lureau g_variant_new("(@ay)", 184*5010cec2SMarc-André Lureau g_steal_pointer(&value)), 185*5010cec2SMarc-André Lureau G_DBUS_CALL_FLAGS_NO_AUTO_START, 186*5010cec2SMarc-André Lureau -1, NULL, &err); 187*5010cec2SMarc-André Lureau if (!result) { 188*5010cec2SMarc-André Lureau error_report("%s: Failed to Load: %s", __func__, err->message); 189*5010cec2SMarc-André Lureau return -1; 190*5010cec2SMarc-André Lureau } 191*5010cec2SMarc-André Lureau 192*5010cec2SMarc-André Lureau return 0; 193*5010cec2SMarc-André Lureau } 194*5010cec2SMarc-André Lureau 195*5010cec2SMarc-André Lureau static int dbus_vmstate_post_load(void *opaque, int version_id) 196*5010cec2SMarc-André Lureau { 197*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(opaque); 198*5010cec2SMarc-André Lureau g_autoptr(GInputStream) m = NULL; 199*5010cec2SMarc-André Lureau g_autoptr(GDataInputStream) s = NULL; 200*5010cec2SMarc-André Lureau g_autoptr(GError) err = NULL; 201*5010cec2SMarc-André Lureau g_autoptr(GHashTable) proxies = NULL; 202*5010cec2SMarc-André Lureau uint32_t nelem; 203*5010cec2SMarc-André Lureau 204*5010cec2SMarc-André Lureau trace_dbus_vmstate_post_load(version_id); 205*5010cec2SMarc-André Lureau 206*5010cec2SMarc-André Lureau proxies = dbus_get_proxies(self, &err); 207*5010cec2SMarc-André Lureau if (!proxies) { 208*5010cec2SMarc-André Lureau error_report("%s: Failed to get proxies: %s", __func__, err->message); 209*5010cec2SMarc-André Lureau return -1; 210*5010cec2SMarc-André Lureau } 211*5010cec2SMarc-André Lureau 212*5010cec2SMarc-André Lureau m = g_memory_input_stream_new_from_data(self->data, self->data_size, NULL); 213*5010cec2SMarc-André Lureau s = g_data_input_stream_new(m); 214*5010cec2SMarc-André Lureau g_data_input_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); 215*5010cec2SMarc-André Lureau 216*5010cec2SMarc-André Lureau nelem = g_data_input_stream_read_uint32(s, NULL, &err); 217*5010cec2SMarc-André Lureau if (err) { 218*5010cec2SMarc-André Lureau goto error; 219*5010cec2SMarc-André Lureau } 220*5010cec2SMarc-André Lureau 221*5010cec2SMarc-André Lureau while (nelem > 0) { 222*5010cec2SMarc-André Lureau GDBusProxy *proxy = NULL; 223*5010cec2SMarc-André Lureau uint32_t len; 224*5010cec2SMarc-André Lureau gsize bytes_read, avail; 225*5010cec2SMarc-André Lureau char id[256]; 226*5010cec2SMarc-André Lureau 227*5010cec2SMarc-André Lureau len = g_data_input_stream_read_uint32(s, NULL, &err); 228*5010cec2SMarc-André Lureau if (err) { 229*5010cec2SMarc-André Lureau goto error; 230*5010cec2SMarc-André Lureau } 231*5010cec2SMarc-André Lureau if (len >= 256) { 232*5010cec2SMarc-André Lureau error_report("%s: Invalid DBus vmstate proxy name %u", 233*5010cec2SMarc-André Lureau __func__, len); 234*5010cec2SMarc-André Lureau return -1; 235*5010cec2SMarc-André Lureau } 236*5010cec2SMarc-André Lureau if (!g_input_stream_read_all(G_INPUT_STREAM(s), id, len, 237*5010cec2SMarc-André Lureau &bytes_read, NULL, &err)) { 238*5010cec2SMarc-André Lureau goto error; 239*5010cec2SMarc-André Lureau } 240*5010cec2SMarc-André Lureau g_return_val_if_fail(bytes_read == len, -1); 241*5010cec2SMarc-André Lureau id[len] = 0; 242*5010cec2SMarc-André Lureau 243*5010cec2SMarc-André Lureau trace_dbus_vmstate_loading(id); 244*5010cec2SMarc-André Lureau 245*5010cec2SMarc-André Lureau proxy = g_hash_table_lookup(proxies, id); 246*5010cec2SMarc-André Lureau if (!proxy) { 247*5010cec2SMarc-André Lureau error_report("%s: Failed to find proxy Id '%s'", __func__, id); 248*5010cec2SMarc-André Lureau return -1; 249*5010cec2SMarc-André Lureau } 250*5010cec2SMarc-André Lureau 251*5010cec2SMarc-André Lureau len = g_data_input_stream_read_uint32(s, NULL, &err); 252*5010cec2SMarc-André Lureau avail = g_buffered_input_stream_get_available( 253*5010cec2SMarc-André Lureau G_BUFFERED_INPUT_STREAM(s)); 254*5010cec2SMarc-André Lureau 255*5010cec2SMarc-André Lureau if (len > DBUS_VMSTATE_SIZE_LIMIT || len > avail) { 256*5010cec2SMarc-André Lureau error_report("%s: Invalid vmstate size: %u", __func__, len); 257*5010cec2SMarc-André Lureau return -1; 258*5010cec2SMarc-André Lureau } 259*5010cec2SMarc-André Lureau 260*5010cec2SMarc-André Lureau if (dbus_load_state_proxy(proxy, 261*5010cec2SMarc-André Lureau g_buffered_input_stream_peek_buffer(G_BUFFERED_INPUT_STREAM(s), 262*5010cec2SMarc-André Lureau NULL), 263*5010cec2SMarc-André Lureau len) < 0) { 264*5010cec2SMarc-André Lureau error_report("%s: Failed to restore Id '%s'", __func__, id); 265*5010cec2SMarc-André Lureau return -1; 266*5010cec2SMarc-André Lureau } 267*5010cec2SMarc-André Lureau 268*5010cec2SMarc-André Lureau if (!g_seekable_seek(G_SEEKABLE(s), len, G_SEEK_CUR, NULL, &err)) { 269*5010cec2SMarc-André Lureau goto error; 270*5010cec2SMarc-André Lureau } 271*5010cec2SMarc-André Lureau 272*5010cec2SMarc-André Lureau nelem -= 1; 273*5010cec2SMarc-André Lureau } 274*5010cec2SMarc-André Lureau 275*5010cec2SMarc-André Lureau return 0; 276*5010cec2SMarc-André Lureau 277*5010cec2SMarc-André Lureau error: 278*5010cec2SMarc-André Lureau error_report("%s: Failed to read from stream: %s", __func__, err->message); 279*5010cec2SMarc-André Lureau return -1; 280*5010cec2SMarc-André Lureau } 281*5010cec2SMarc-André Lureau 282*5010cec2SMarc-André Lureau static void 283*5010cec2SMarc-André Lureau dbus_save_state_proxy(gpointer key, 284*5010cec2SMarc-André Lureau gpointer value, 285*5010cec2SMarc-André Lureau gpointer user_data) 286*5010cec2SMarc-André Lureau { 287*5010cec2SMarc-André Lureau GDataOutputStream *s = user_data; 288*5010cec2SMarc-André Lureau const char *id = key; 289*5010cec2SMarc-André Lureau GDBusProxy *proxy = value; 290*5010cec2SMarc-André Lureau g_autoptr(GVariant) result = NULL; 291*5010cec2SMarc-André Lureau g_autoptr(GVariant) child = NULL; 292*5010cec2SMarc-André Lureau g_autoptr(GError) err = NULL; 293*5010cec2SMarc-André Lureau const uint8_t *data; 294*5010cec2SMarc-André Lureau gsize size; 295*5010cec2SMarc-André Lureau 296*5010cec2SMarc-André Lureau trace_dbus_vmstate_saving(id); 297*5010cec2SMarc-André Lureau 298*5010cec2SMarc-André Lureau result = g_dbus_proxy_call_sync(proxy, "Save", 299*5010cec2SMarc-André Lureau NULL, G_DBUS_CALL_FLAGS_NO_AUTO_START, 300*5010cec2SMarc-André Lureau -1, NULL, &err); 301*5010cec2SMarc-André Lureau if (!result) { 302*5010cec2SMarc-André Lureau error_report("%s: Failed to Save: %s", __func__, err->message); 303*5010cec2SMarc-André Lureau return; 304*5010cec2SMarc-André Lureau } 305*5010cec2SMarc-André Lureau 306*5010cec2SMarc-André Lureau child = g_variant_get_child_value(result, 0); 307*5010cec2SMarc-André Lureau data = g_variant_get_fixed_array(child, &size, sizeof(char)); 308*5010cec2SMarc-André Lureau if (!data) { 309*5010cec2SMarc-André Lureau error_report("%s: Failed to Save: not a byte array", __func__); 310*5010cec2SMarc-André Lureau return; 311*5010cec2SMarc-André Lureau } 312*5010cec2SMarc-André Lureau if (size > DBUS_VMSTATE_SIZE_LIMIT) { 313*5010cec2SMarc-André Lureau error_report("%s: Too large vmstate data to save: %zu", 314*5010cec2SMarc-André Lureau __func__, (size_t)size); 315*5010cec2SMarc-André Lureau return; 316*5010cec2SMarc-André Lureau } 317*5010cec2SMarc-André Lureau 318*5010cec2SMarc-André Lureau if (!g_data_output_stream_put_uint32(s, strlen(id), NULL, &err) || 319*5010cec2SMarc-André Lureau !g_data_output_stream_put_string(s, id, NULL, &err) || 320*5010cec2SMarc-André Lureau !g_data_output_stream_put_uint32(s, size, NULL, &err) || 321*5010cec2SMarc-André Lureau !g_output_stream_write_all(G_OUTPUT_STREAM(s), 322*5010cec2SMarc-André Lureau data, size, NULL, NULL, &err)) { 323*5010cec2SMarc-André Lureau error_report("%s: Failed to write to stream: %s", 324*5010cec2SMarc-André Lureau __func__, err->message); 325*5010cec2SMarc-André Lureau } 326*5010cec2SMarc-André Lureau } 327*5010cec2SMarc-André Lureau 328*5010cec2SMarc-André Lureau static int dbus_vmstate_pre_save(void *opaque) 329*5010cec2SMarc-André Lureau { 330*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(opaque); 331*5010cec2SMarc-André Lureau g_autoptr(GOutputStream) m = NULL; 332*5010cec2SMarc-André Lureau g_autoptr(GDataOutputStream) s = NULL; 333*5010cec2SMarc-André Lureau g_autoptr(GHashTable) proxies = NULL; 334*5010cec2SMarc-André Lureau g_autoptr(GError) err = NULL; 335*5010cec2SMarc-André Lureau 336*5010cec2SMarc-André Lureau trace_dbus_vmstate_pre_save(); 337*5010cec2SMarc-André Lureau 338*5010cec2SMarc-André Lureau proxies = dbus_get_proxies(self, &err); 339*5010cec2SMarc-André Lureau if (!proxies) { 340*5010cec2SMarc-André Lureau error_report("%s: Failed to get proxies: %s", __func__, err->message); 341*5010cec2SMarc-André Lureau return -1; 342*5010cec2SMarc-André Lureau } 343*5010cec2SMarc-André Lureau 344*5010cec2SMarc-André Lureau m = g_memory_output_stream_new_resizable(); 345*5010cec2SMarc-André Lureau s = g_data_output_stream_new(m); 346*5010cec2SMarc-André Lureau g_data_output_stream_set_byte_order(s, G_DATA_STREAM_BYTE_ORDER_BIG_ENDIAN); 347*5010cec2SMarc-André Lureau 348*5010cec2SMarc-André Lureau if (!g_data_output_stream_put_uint32(s, g_hash_table_size(proxies), 349*5010cec2SMarc-André Lureau NULL, &err)) { 350*5010cec2SMarc-André Lureau error_report("%s: Failed to write to stream: %s", 351*5010cec2SMarc-André Lureau __func__, err->message); 352*5010cec2SMarc-André Lureau return -1; 353*5010cec2SMarc-André Lureau } 354*5010cec2SMarc-André Lureau 355*5010cec2SMarc-André Lureau g_hash_table_foreach(proxies, dbus_save_state_proxy, s); 356*5010cec2SMarc-André Lureau 357*5010cec2SMarc-André Lureau if (g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m)) 358*5010cec2SMarc-André Lureau > UINT32_MAX) { 359*5010cec2SMarc-André Lureau error_report("%s: DBus vmstate buffer is too large", __func__); 360*5010cec2SMarc-André Lureau return -1; 361*5010cec2SMarc-André Lureau } 362*5010cec2SMarc-André Lureau 363*5010cec2SMarc-André Lureau if (!g_output_stream_close(G_OUTPUT_STREAM(m), NULL, &err)) { 364*5010cec2SMarc-André Lureau error_report("%s: Failed to close stream: %s", __func__, err->message); 365*5010cec2SMarc-André Lureau return -1; 366*5010cec2SMarc-André Lureau } 367*5010cec2SMarc-André Lureau 368*5010cec2SMarc-André Lureau g_free(self->data); 369*5010cec2SMarc-André Lureau self->data_size = 370*5010cec2SMarc-André Lureau g_memory_output_stream_get_size(G_MEMORY_OUTPUT_STREAM(m)); 371*5010cec2SMarc-André Lureau self->data = 372*5010cec2SMarc-André Lureau g_memory_output_stream_steal_data(G_MEMORY_OUTPUT_STREAM(m)); 373*5010cec2SMarc-André Lureau 374*5010cec2SMarc-André Lureau return 0; 375*5010cec2SMarc-André Lureau } 376*5010cec2SMarc-André Lureau 377*5010cec2SMarc-André Lureau static const VMStateDescription dbus_vmstate = { 378*5010cec2SMarc-André Lureau .name = TYPE_DBUS_VMSTATE, 379*5010cec2SMarc-André Lureau .version_id = 0, 380*5010cec2SMarc-André Lureau .pre_save = dbus_vmstate_pre_save, 381*5010cec2SMarc-André Lureau .post_load = dbus_vmstate_post_load, 382*5010cec2SMarc-André Lureau .fields = (VMStateField[]) { 383*5010cec2SMarc-André Lureau VMSTATE_UINT32(data_size, DBusVMState), 384*5010cec2SMarc-André Lureau VMSTATE_VBUFFER_ALLOC_UINT32(data, DBusVMState, 0, 0, data_size), 385*5010cec2SMarc-André Lureau VMSTATE_END_OF_LIST() 386*5010cec2SMarc-André Lureau } 387*5010cec2SMarc-André Lureau }; 388*5010cec2SMarc-André Lureau 389*5010cec2SMarc-André Lureau static void 390*5010cec2SMarc-André Lureau dbus_vmstate_complete(UserCreatable *uc, Error **errp) 391*5010cec2SMarc-André Lureau { 392*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(uc); 393*5010cec2SMarc-André Lureau g_autoptr(GError) err = NULL; 394*5010cec2SMarc-André Lureau 395*5010cec2SMarc-André Lureau if (!object_resolve_path_type("", TYPE_DBUS_VMSTATE, NULL)) { 396*5010cec2SMarc-André Lureau error_setg(errp, "There is already an instance of %s", 397*5010cec2SMarc-André Lureau TYPE_DBUS_VMSTATE); 398*5010cec2SMarc-André Lureau return; 399*5010cec2SMarc-André Lureau } 400*5010cec2SMarc-André Lureau 401*5010cec2SMarc-André Lureau if (!self->dbus_addr) { 402*5010cec2SMarc-André Lureau error_setg(errp, QERR_MISSING_PARAMETER, "addr"); 403*5010cec2SMarc-André Lureau return; 404*5010cec2SMarc-André Lureau } 405*5010cec2SMarc-André Lureau 406*5010cec2SMarc-André Lureau self->bus = g_dbus_connection_new_for_address_sync(self->dbus_addr, 407*5010cec2SMarc-André Lureau G_DBUS_CONNECTION_FLAGS_AUTHENTICATION_CLIENT | 408*5010cec2SMarc-André Lureau G_DBUS_CONNECTION_FLAGS_MESSAGE_BUS_CONNECTION, 409*5010cec2SMarc-André Lureau NULL, NULL, &err); 410*5010cec2SMarc-André Lureau if (err) { 411*5010cec2SMarc-André Lureau error_setg(errp, "failed to connect to DBus: '%s'", err->message); 412*5010cec2SMarc-André Lureau return; 413*5010cec2SMarc-André Lureau } 414*5010cec2SMarc-André Lureau 415*5010cec2SMarc-André Lureau if (vmstate_register(VMSTATE_IF(self), -1, &dbus_vmstate, self) < 0) { 416*5010cec2SMarc-André Lureau error_setg(errp, "Failed to register vmstate"); 417*5010cec2SMarc-André Lureau } 418*5010cec2SMarc-André Lureau } 419*5010cec2SMarc-André Lureau 420*5010cec2SMarc-André Lureau static void 421*5010cec2SMarc-André Lureau dbus_vmstate_finalize(Object *o) 422*5010cec2SMarc-André Lureau { 423*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(o); 424*5010cec2SMarc-André Lureau 425*5010cec2SMarc-André Lureau vmstate_unregister(VMSTATE_IF(self), &dbus_vmstate, self); 426*5010cec2SMarc-André Lureau 427*5010cec2SMarc-André Lureau g_clear_object(&self->bus); 428*5010cec2SMarc-André Lureau g_free(self->dbus_addr); 429*5010cec2SMarc-André Lureau g_free(self->id_list); 430*5010cec2SMarc-André Lureau g_free(self->data); 431*5010cec2SMarc-André Lureau } 432*5010cec2SMarc-André Lureau 433*5010cec2SMarc-André Lureau static char * 434*5010cec2SMarc-André Lureau get_dbus_addr(Object *o, Error **errp) 435*5010cec2SMarc-André Lureau { 436*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(o); 437*5010cec2SMarc-André Lureau 438*5010cec2SMarc-André Lureau return g_strdup(self->dbus_addr); 439*5010cec2SMarc-André Lureau } 440*5010cec2SMarc-André Lureau 441*5010cec2SMarc-André Lureau static void 442*5010cec2SMarc-André Lureau set_dbus_addr(Object *o, const char *str, Error **errp) 443*5010cec2SMarc-André Lureau { 444*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(o); 445*5010cec2SMarc-André Lureau 446*5010cec2SMarc-André Lureau g_free(self->dbus_addr); 447*5010cec2SMarc-André Lureau self->dbus_addr = g_strdup(str); 448*5010cec2SMarc-André Lureau } 449*5010cec2SMarc-André Lureau 450*5010cec2SMarc-André Lureau static char * 451*5010cec2SMarc-André Lureau get_id_list(Object *o, Error **errp) 452*5010cec2SMarc-André Lureau { 453*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(o); 454*5010cec2SMarc-André Lureau 455*5010cec2SMarc-André Lureau return g_strdup(self->id_list); 456*5010cec2SMarc-André Lureau } 457*5010cec2SMarc-André Lureau 458*5010cec2SMarc-André Lureau static void 459*5010cec2SMarc-André Lureau set_id_list(Object *o, const char *str, Error **errp) 460*5010cec2SMarc-André Lureau { 461*5010cec2SMarc-André Lureau DBusVMState *self = DBUS_VMSTATE(o); 462*5010cec2SMarc-André Lureau 463*5010cec2SMarc-André Lureau g_free(self->id_list); 464*5010cec2SMarc-André Lureau self->id_list = g_strdup(str); 465*5010cec2SMarc-André Lureau } 466*5010cec2SMarc-André Lureau 467*5010cec2SMarc-André Lureau static char * 468*5010cec2SMarc-André Lureau dbus_vmstate_get_id(VMStateIf *vmif) 469*5010cec2SMarc-André Lureau { 470*5010cec2SMarc-André Lureau return g_strdup(TYPE_DBUS_VMSTATE); 471*5010cec2SMarc-André Lureau } 472*5010cec2SMarc-André Lureau 473*5010cec2SMarc-André Lureau static void 474*5010cec2SMarc-André Lureau dbus_vmstate_class_init(ObjectClass *oc, void *data) 475*5010cec2SMarc-André Lureau { 476*5010cec2SMarc-André Lureau UserCreatableClass *ucc = USER_CREATABLE_CLASS(oc); 477*5010cec2SMarc-André Lureau VMStateIfClass *vc = VMSTATE_IF_CLASS(oc); 478*5010cec2SMarc-André Lureau 479*5010cec2SMarc-André Lureau ucc->complete = dbus_vmstate_complete; 480*5010cec2SMarc-André Lureau vc->get_id = dbus_vmstate_get_id; 481*5010cec2SMarc-André Lureau 482*5010cec2SMarc-André Lureau object_class_property_add_str(oc, "addr", 483*5010cec2SMarc-André Lureau get_dbus_addr, set_dbus_addr, 484*5010cec2SMarc-André Lureau &error_abort); 485*5010cec2SMarc-André Lureau object_class_property_add_str(oc, "id-list", 486*5010cec2SMarc-André Lureau get_id_list, set_id_list, 487*5010cec2SMarc-André Lureau &error_abort); 488*5010cec2SMarc-André Lureau } 489*5010cec2SMarc-André Lureau 490*5010cec2SMarc-André Lureau static const TypeInfo dbus_vmstate_info = { 491*5010cec2SMarc-André Lureau .name = TYPE_DBUS_VMSTATE, 492*5010cec2SMarc-André Lureau .parent = TYPE_OBJECT, 493*5010cec2SMarc-André Lureau .instance_size = sizeof(DBusVMState), 494*5010cec2SMarc-André Lureau .instance_finalize = dbus_vmstate_finalize, 495*5010cec2SMarc-André Lureau .class_size = sizeof(DBusVMStateClass), 496*5010cec2SMarc-André Lureau .class_init = dbus_vmstate_class_init, 497*5010cec2SMarc-André Lureau .interfaces = (InterfaceInfo[]) { 498*5010cec2SMarc-André Lureau { TYPE_USER_CREATABLE }, 499*5010cec2SMarc-André Lureau { TYPE_VMSTATE_IF }, 500*5010cec2SMarc-André Lureau { } 501*5010cec2SMarc-André Lureau } 502*5010cec2SMarc-André Lureau }; 503*5010cec2SMarc-André Lureau 504*5010cec2SMarc-André Lureau static void 505*5010cec2SMarc-André Lureau register_types(void) 506*5010cec2SMarc-André Lureau { 507*5010cec2SMarc-André Lureau type_register_static(&dbus_vmstate_info); 508*5010cec2SMarc-André Lureau } 509*5010cec2SMarc-André Lureau 510*5010cec2SMarc-André Lureau type_init(register_types); 511