1 #include "domainsnapshot.h"
2 #include "domain.h"
3 #include "util.h"
4 
5 #include <libvirt/libvirt.h>
6 
7 static virDomainSnapshotPtr
virtDBusDomainSnapshotGetVirDomainSnapshot(virtDBusConnect * connect,const gchar * objectPath,GError ** error)8 virtDBusDomainSnapshotGetVirDomainSnapshot(virtDBusConnect *connect,
9                                            const gchar *objectPath,
10                                            GError **error)
11 {
12     virDomainSnapshotPtr domSnap;
13 
14     if (!virtDBusConnectOpen(connect, error))
15         return NULL;
16 
17     domSnap = virtDBusUtilVirDomainSnapshotFromBusPath(connect->connection,
18                                                        objectPath,
19                                                        connect->domainSnapshotPath);
20     if (!domSnap) {
21         virtDBusUtilSetLastVirtError(error);
22         return NULL;
23     }
24 
25     return domSnap;
26 }
27 
28 static void
virtDBusDomainSnapshotDelete(GVariant * inArgs,GUnixFDList * inFDs G_GNUC_UNUSED,const gchar * objectPath,gpointer userData,GVariant ** outArgs G_GNUC_UNUSED,GUnixFDList ** outFDs G_GNUC_UNUSED,GError ** error)29 virtDBusDomainSnapshotDelete(GVariant *inArgs,
30                              GUnixFDList *inFDs G_GNUC_UNUSED,
31                              const gchar *objectPath,
32                              gpointer userData,
33                              GVariant **outArgs G_GNUC_UNUSED,
34                              GUnixFDList **outFDs G_GNUC_UNUSED,
35                              GError **error)
36 {
37     virtDBusConnect *connect = userData;
38     g_autoptr(virDomainSnapshot) domainSnapshot = NULL;
39     guint flags;
40 
41     g_variant_get(inArgs, "(u)", &flags);
42 
43     domainSnapshot = virtDBusDomainSnapshotGetVirDomainSnapshot(connect,
44                                                                 objectPath,
45                                                                 error);
46     if (!domainSnapshot)
47         return;
48 
49     if (virDomainSnapshotDelete(domainSnapshot, flags) < 0)
50         return virtDBusUtilSetLastVirtError(error);
51 }
52 
53 static void
virtDBusDomainSnapshotGetParent(GVariant * inArgs,GUnixFDList * inFDs G_GNUC_UNUSED,const gchar * objectPath,gpointer userData,GVariant ** outArgs G_GNUC_UNUSED,GUnixFDList ** outFDs G_GNUC_UNUSED,GError ** error)54 virtDBusDomainSnapshotGetParent(GVariant *inArgs,
55                                 GUnixFDList *inFDs G_GNUC_UNUSED,
56                                 const gchar *objectPath,
57                                 gpointer userData,
58                                 GVariant **outArgs G_GNUC_UNUSED,
59                                 GUnixFDList **outFDs G_GNUC_UNUSED,
60                                 GError **error)
61 {
62     virtDBusConnect *connect = userData;
63     g_autoptr(virDomainSnapshot) domainSnapshot = NULL;
64     g_autoptr(virDomainSnapshot) parent = NULL;
65     guint flags;
66     virDomainPtr domain = NULL;
67     g_autofree gchar *parentPath = NULL;
68 
69     g_variant_get(inArgs, "(u)", &flags);
70 
71     domainSnapshot = virtDBusDomainSnapshotGetVirDomainSnapshot(connect,
72                                                                 objectPath,
73                                                                 error);
74     if (!domainSnapshot)
75         return;
76 
77     parent = virDomainSnapshotGetParent(domainSnapshot, flags);
78     if (!parent)
79         return virtDBusUtilSetLastVirtError(error);
80 
81     domain = virDomainSnapshotGetDomain(domainSnapshot);
82     parentPath = virtDBusUtilBusPathForVirDomainSnapshot(domain,
83                                                          parent,
84                                                          connect->domainSnapshotPath);
85 
86     *outArgs = g_variant_new("(o)", parentPath);
87 }
88 
89 static void
virtDBusDomainSnapshotGetXMLDesc(GVariant * inArgs,GUnixFDList * inFDs G_GNUC_UNUSED,const gchar * objectPath,gpointer userData,GVariant ** outArgs G_GNUC_UNUSED,GUnixFDList ** outFDs G_GNUC_UNUSED,GError ** error)90 virtDBusDomainSnapshotGetXMLDesc(GVariant *inArgs,
91                                  GUnixFDList *inFDs G_GNUC_UNUSED,
92                                  const gchar *objectPath,
93                                  gpointer userData,
94                                  GVariant **outArgs G_GNUC_UNUSED,
95                                  GUnixFDList **outFDs G_GNUC_UNUSED,
96                                  GError **error)
97 {
98     virtDBusConnect *connect = userData;
99     g_autoptr(virDomainSnapshot) domainSnapshot = NULL;
100     guint flags;
101     g_autofree gchar *xml = NULL;
102 
103     g_variant_get(inArgs, "(u)", &flags);
104 
105     domainSnapshot = virtDBusDomainSnapshotGetVirDomainSnapshot(connect,
106                                                                 objectPath,
107                                                                 error);
108     if (!domainSnapshot)
109         return;
110 
111     xml = virDomainSnapshotGetXMLDesc(domainSnapshot, flags);
112     if (!xml)
113         return virtDBusUtilSetLastVirtError(error);
114 
115     *outArgs = g_variant_new("(s)", xml);
116 }
117 
118 static void
virtDBusDomainSnapshotIsCurrent(GVariant * inArgs,GUnixFDList * inFDs G_GNUC_UNUSED,const gchar * objectPath,gpointer userData,GVariant ** outArgs G_GNUC_UNUSED,GUnixFDList ** outFDs G_GNUC_UNUSED,GError ** error)119 virtDBusDomainSnapshotIsCurrent(GVariant *inArgs,
120                                 GUnixFDList *inFDs G_GNUC_UNUSED,
121                                 const gchar *objectPath,
122                                 gpointer userData,
123                                 GVariant **outArgs G_GNUC_UNUSED,
124                                 GUnixFDList **outFDs G_GNUC_UNUSED,
125                                 GError **error)
126 {
127     virtDBusConnect *connect = userData;
128     g_autoptr(virDomainSnapshot) domainSnapshot = NULL;
129     guint flags;
130     gint isCurrent;
131 
132     g_variant_get(inArgs, "(u)", &flags);
133 
134     domainSnapshot = virtDBusDomainSnapshotGetVirDomainSnapshot(connect,
135                                                                 objectPath,
136                                                                 error);
137     if (!domainSnapshot)
138         return;
139 
140     isCurrent = virDomainSnapshotIsCurrent(domainSnapshot, flags);
141     if (isCurrent < 0)
142         return virtDBusUtilSetLastVirtError(error);
143 
144     *outArgs = g_variant_new("(b)", !!isCurrent);
145 }
146 
147 static void
virtDBusDomainSnapshotListAllChildren(GVariant * inArgs,GUnixFDList * inFDs G_GNUC_UNUSED,const gchar * objectPath,gpointer userData,GVariant ** outArgs G_GNUC_UNUSED,GUnixFDList ** outFDs G_GNUC_UNUSED,GError ** error)148 virtDBusDomainSnapshotListAllChildren(GVariant *inArgs,
149                                       GUnixFDList *inFDs G_GNUC_UNUSED,
150                                       const gchar *objectPath,
151                                       gpointer userData,
152                                       GVariant **outArgs G_GNUC_UNUSED,
153                                       GUnixFDList **outFDs G_GNUC_UNUSED,
154                                       GError **error)
155 {
156     virtDBusConnect *connect = userData;
157     g_autoptr(virDomainSnapshot) domainSnapshot = NULL;
158     g_autoptr(virDomainSnapshotPtr) snaps = NULL;
159     guint flags;
160     GVariantBuilder builder;
161     GVariant *gdomainSnapshots;
162     virDomainPtr domain = NULL;
163 
164     g_variant_get(inArgs, "(u)", &flags);
165 
166     domainSnapshot = virtDBusDomainSnapshotGetVirDomainSnapshot(connect,
167                                                                 objectPath,
168                                                                 error);
169     if (!domainSnapshot)
170         return;
171 
172     if (virDomainSnapshotListAllChildren(domainSnapshot, &snaps, flags) < 0)
173         return virtDBusUtilSetLastVirtError(error);
174 
175     g_variant_builder_init(&builder, G_VARIANT_TYPE("ao"));
176 
177     domain = virDomainSnapshotGetDomain(domainSnapshot);
178     for (gint i = 0; snaps[i]; i++) {
179         g_autofree gchar *path = NULL;
180         path = virtDBusUtilBusPathForVirDomainSnapshot(domain,
181                                                        snaps[i],
182                                                        connect->domainSnapshotPath);
183 
184         g_variant_builder_add(&builder, "o", path);
185     }
186 
187     gdomainSnapshots = g_variant_builder_end(&builder);
188     *outArgs = g_variant_new_tuple(&gdomainSnapshots, 1);
189 }
190 
191 static void
virtDBusDomainSnapshotRevert(GVariant * inArgs,GUnixFDList * inFDs G_GNUC_UNUSED,const gchar * objectPath,gpointer userData,GVariant ** outArgs G_GNUC_UNUSED,GUnixFDList ** outFDs G_GNUC_UNUSED,GError ** error)192 virtDBusDomainSnapshotRevert(GVariant *inArgs,
193                              GUnixFDList *inFDs G_GNUC_UNUSED,
194                              const gchar *objectPath,
195                              gpointer userData,
196                              GVariant **outArgs G_GNUC_UNUSED,
197                              GUnixFDList **outFDs G_GNUC_UNUSED,
198                              GError **error)
199 {
200     virtDBusConnect *connect = userData;
201     g_autoptr(virDomainSnapshot) domainSnapshot = NULL;
202     guint flags;
203 
204     g_variant_get(inArgs, "(u)", &flags);
205 
206     domainSnapshot = virtDBusDomainSnapshotGetVirDomainSnapshot(connect,
207                                                                 objectPath,
208                                                                 error);
209     if (!domainSnapshot)
210         return;
211 
212     if (virDomainRevertToSnapshot(domainSnapshot, flags) < 0)
213         return virtDBusUtilSetLastVirtError(error);
214 }
215 
216 static virtDBusGDBusPropertyTable virtDBusDomainSnapshotPropertyTable[] = {
217     { 0 }
218 };
219 
220 static virtDBusGDBusMethodTable virtDBusDomainSnapshotMethodTable[] = {
221     { "Delete", virtDBusDomainSnapshotDelete },
222     { "GetParent", virtDBusDomainSnapshotGetParent },
223     { "GetXMLDesc", virtDBusDomainSnapshotGetXMLDesc },
224     { "IsCurrent", virtDBusDomainSnapshotIsCurrent },
225     { "ListChildren", virtDBusDomainSnapshotListAllChildren },
226     { "Revert", virtDBusDomainSnapshotRevert },
227     { 0 }
228 };
229 
230 static gchar **
virtDBusDomainSnapshotEnumerate(gpointer userData)231 virtDBusDomainSnapshotEnumerate(gpointer userData)
232 {
233     virtDBusConnect *connect = userData;
234     g_autoptr(virDomainPtr) domains = NULL;
235     gint numDoms = 0;
236     GPtrArray *list = NULL;
237 
238     if (!virtDBusConnectOpen(connect, NULL))
239         return NULL;
240 
241     numDoms = virConnectListAllDomains(connect->connection, &domains, 0);
242     if (numDoms <= 0)
243         return NULL;
244 
245     list = g_ptr_array_new();
246 
247     for (gint i = 0; i < numDoms; i++) {
248         g_autoptr(virDomainSnapshotPtr) domainSnapshots = NULL;
249         gint numSnaps;
250 
251         numSnaps = virDomainListAllSnapshots(domains[i], &domainSnapshots, 0);
252         if (numSnaps <= 0)
253             continue;
254 
255         for (gint j = 0; j < numSnaps; j++) {
256             gchar *snapPath = virtDBusUtilBusPathForVirDomainSnapshot(domains[i],
257                                                                       domainSnapshots[j],
258                                                                       connect->domainSnapshotPath);
259             g_ptr_array_add(list, snapPath);
260         }
261     }
262 
263     if (list->len > 0)
264         g_ptr_array_add(list, NULL);
265 
266     return (gchar **)g_ptr_array_free(list, FALSE);
267 }
268 
269 static GDBusInterfaceInfo *interfaceInfo = NULL;
270 
271 void
virtDBusDomainSnapshotRegister(virtDBusConnect * connect,GError ** error)272 virtDBusDomainSnapshotRegister(virtDBusConnect *connect,
273                                GError **error)
274 {
275     connect->domainSnapshotPath = g_strdup_printf("%s/domainsnapshot", connect->connectPath);
276 
277     if (!interfaceInfo) {
278         interfaceInfo = virtDBusGDBusLoadIntrospectData(VIRT_DBUS_DOMAIN_SNAPSHOT_INTERFACE,
279                                                         error);
280         if (!interfaceInfo)
281             return;
282     }
283 
284     virtDBusGDBusRegisterSubtree(connect->bus,
285                                  connect->domainSnapshotPath,
286                                  interfaceInfo,
287                                  virtDBusDomainSnapshotEnumerate,
288                                  virtDBusDomainSnapshotMethodTable,
289                                  virtDBusDomainSnapshotPropertyTable,
290                                  connect);
291 }
292