chiark / gitweb /
machined: add support for reporting image size via btrfs quota
[elogind.git] / src / machine / image-dbus.c
1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3 /***
4   This file is part of systemd.
5
6   Copyright 2014 Lennart Poettering
7
8   systemd is free software; you can redistribute it and/or modify it
9   under the terms of the GNU Lesser General Public License as published by
10   the Free Software Foundation; either version 2.1 of the License, or
11   (at your option) any later version.
12
13   systemd is distributed in the hope that it will be useful, but
14   WITHOUT ANY WARRANTY; without even the implied warranty of
15   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16   Lesser General Public License for more details.
17
18   You should have received a copy of the GNU Lesser General Public License
19   along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 ***/
21
22 #include "bus-label.h"
23 #include "bus-common-errors.h"
24 #include "strv.h"
25 #include "machine-image.h"
26 #include "image-dbus.h"
27
28 static int image_find_by_bus_path(const char *path, Image **ret) {
29         _cleanup_free_ char *e = NULL;
30         const char *p;
31
32         assert(path);
33
34         p = startswith(path, "/org/freedesktop/machine1/image/");
35         if (!p)
36                 return 0;
37
38         e = bus_label_unescape(p);
39         if (!e)
40                 return -ENOMEM;
41
42         return image_find(e, ret);
43 }
44
45 static int image_find_by_bus_path_with_error(const char *path, Image **ret, sd_bus_error *error) {
46         int r;
47
48         assert(path);
49
50         r = image_find_by_bus_path(path, ret);
51         if (r == 0)
52                 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "Image doesn't exist.");
53
54         return r;
55 }
56
57 static int property_get_name(
58                 sd_bus *bus,
59                 const char *path,
60                 const char *interface,
61                 const char *property,
62                 sd_bus_message *reply,
63                 void *userdata,
64                 sd_bus_error *error) {
65
66         _cleanup_(image_unrefp) Image *image = NULL;
67         int r;
68
69         assert(bus);
70         assert(reply);
71
72         r = image_find_by_bus_path_with_error(path, &image, error);
73         if (r < 0)
74                 return r;
75
76         r = sd_bus_message_append(reply, "s", image->name);
77         if (r < 0)
78                 return r;
79
80         return 1;
81 }
82
83 static int property_get_path(
84                 sd_bus *bus,
85                 const char *path,
86                 const char *interface,
87                 const char *property,
88                 sd_bus_message *reply,
89                 void *userdata,
90                 sd_bus_error *error) {
91
92         _cleanup_(image_unrefp) Image *image = NULL;
93         int r;
94
95         assert(bus);
96         assert(reply);
97
98         r = image_find_by_bus_path_with_error(path, &image, error);
99         if (r < 0)
100                 return r;
101
102         r = sd_bus_message_append(reply, "s", image->path);
103         if (r < 0)
104                 return r;
105
106         return 1;
107 }
108
109 static int property_get_type(
110                 sd_bus *bus,
111                 const char *path,
112                 const char *interface,
113                 const char *property,
114                 sd_bus_message *reply,
115                 void *userdata,
116                 sd_bus_error *error) {
117
118
119         _cleanup_(image_unrefp) Image *image = NULL;
120         int r;
121
122         assert(bus);
123         assert(reply);
124
125         r = image_find_by_bus_path_with_error(path, &image, error);
126         if (r < 0)
127                 return r;
128
129         r = sd_bus_message_append(reply, "s", image_type_to_string(image->type));
130         if (r < 0)
131                 return r;
132
133         return 1;
134 }
135
136 static int property_get_read_only(
137                 sd_bus *bus,
138                 const char *path,
139                 const char *interface,
140                 const char *property,
141                 sd_bus_message *reply,
142                 void *userdata,
143                 sd_bus_error *error) {
144
145
146         _cleanup_(image_unrefp) Image *image = NULL;
147         int r;
148
149         assert(bus);
150         assert(reply);
151
152         r = image_find_by_bus_path_with_error(path, &image, error);
153         if (r < 0)
154                 return r;
155
156         r = sd_bus_message_append(reply, "b", image->read_only);
157         if (r < 0)
158                 return r;
159
160         return 1;
161 }
162
163 static int property_get_crtime(
164                 sd_bus *bus,
165                 const char *path,
166                 const char *interface,
167                 const char *property,
168                 sd_bus_message *reply,
169                 void *userdata,
170                 sd_bus_error *error) {
171
172
173         _cleanup_(image_unrefp) Image *image = NULL;
174         int r;
175
176         assert(bus);
177         assert(reply);
178
179         r = image_find_by_bus_path_with_error(path, &image, error);
180         if (r < 0)
181                 return r;
182
183         r = sd_bus_message_append(reply, "t", image->crtime);
184         if (r < 0)
185                 return r;
186
187         return 1;
188 }
189
190 static int property_get_mtime(
191                 sd_bus *bus,
192                 const char *path,
193                 const char *interface,
194                 const char *property,
195                 sd_bus_message *reply,
196                 void *userdata,
197                 sd_bus_error *error) {
198
199         _cleanup_(image_unrefp) Image *image = NULL;
200         int r;
201
202         assert(bus);
203         assert(reply);
204
205         r = image_find_by_bus_path_with_error(path, &image, error);
206         if (r < 0)
207                 return r;
208
209         r = sd_bus_message_append(reply, "t", image->mtime);
210         if (r < 0)
211                 return r;
212
213         return 1;
214 }
215
216 static int property_get_size(
217                 sd_bus *bus,
218                 const char *path,
219                 const char *interface,
220                 const char *property,
221                 sd_bus_message *reply,
222                 void *userdata,
223                 sd_bus_error *error) {
224
225         _cleanup_(image_unrefp) Image *image = NULL;
226         int r;
227
228         assert(bus);
229         assert(reply);
230
231         r = image_find_by_bus_path_with_error(path, &image, error);
232         if (r < 0)
233                 return r;
234
235         r = sd_bus_message_append(reply, "t", image->size);
236         if (r < 0)
237                 return r;
238
239         return 1;
240 }
241
242
243 static int property_get_limit(
244                 sd_bus *bus,
245                 const char *path,
246                 const char *interface,
247                 const char *property,
248                 sd_bus_message *reply,
249                 void *userdata,
250                 sd_bus_error *error) {
251
252         _cleanup_(image_unrefp) Image *image = NULL;
253         int r;
254
255         assert(bus);
256         assert(reply);
257
258         r = image_find_by_bus_path_with_error(path, &image, error);
259         if (r < 0)
260                 return r;
261
262         r = sd_bus_message_append(reply, "t", image->limit);
263         if (r < 0)
264                 return r;
265
266         return 1;
267 }
268
269 static int property_get_size_exclusive(
270                 sd_bus *bus,
271                 const char *path,
272                 const char *interface,
273                 const char *property,
274                 sd_bus_message *reply,
275                 void *userdata,
276                 sd_bus_error *error) {
277
278         _cleanup_(image_unrefp) Image *image = NULL;
279         int r;
280
281         assert(bus);
282         assert(reply);
283
284         r = image_find_by_bus_path_with_error(path, &image, error);
285         if (r < 0)
286                 return r;
287
288         r = sd_bus_message_append(reply, "t", image->size_exclusive);
289         if (r < 0)
290                 return r;
291
292         return 1;
293 }
294
295 static int property_get_limit_exclusive(
296                 sd_bus *bus,
297                 const char *path,
298                 const char *interface,
299                 const char *property,
300                 sd_bus_message *reply,
301                 void *userdata,
302                 sd_bus_error *error) {
303
304         _cleanup_(image_unrefp) Image *image = NULL;
305         int r;
306
307         assert(bus);
308         assert(reply);
309
310         r = image_find_by_bus_path_with_error(path, &image, error);
311         if (r < 0)
312                 return r;
313
314         r = sd_bus_message_append(reply, "t", image->limit_exclusive);
315         if (r < 0)
316                 return r;
317
318         return 1;
319 }
320
321 static int method_remove(
322                 sd_bus *bus,
323                 sd_bus_message *message,
324                 void *userdata,
325                 sd_bus_error *error) {
326
327         _cleanup_(image_unrefp) Image *image = NULL;
328         int r;
329
330         assert(bus);
331         assert(message);
332
333         r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
334         if (r < 0)
335                 return r;
336
337         r = image_remove(image);
338         if (r < 0)
339                 return r;
340
341         return sd_bus_reply_method_return(message, NULL);
342 }
343
344 static int method_rename(
345                 sd_bus *bus,
346                 sd_bus_message *message,
347                 void *userdata,
348                 sd_bus_error *error) {
349
350         _cleanup_(image_unrefp) Image *image = NULL;
351         const char *new_name;
352         int r;
353
354         assert(bus);
355         assert(message);
356
357         r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
358         if (r < 0)
359                 return r;
360
361         r = sd_bus_message_read(message, "s", &new_name);
362         if (r < 0)
363                 return r;
364
365         if (!image_name_is_valid(new_name))
366                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
367
368         r = image_rename(image, new_name);
369         if (r < 0)
370                 return r;
371
372         return sd_bus_reply_method_return(message, NULL);
373 }
374
375 static int method_clone(
376                 sd_bus *bus,
377                 sd_bus_message *message,
378                 void *userdata,
379                 sd_bus_error *error) {
380
381         _cleanup_(image_unrefp) Image *image = NULL;
382         const char *new_name;
383         int r, read_only;
384
385         assert(bus);
386         assert(message);
387
388         r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
389         if (r < 0)
390                 return r;
391
392         r = sd_bus_message_read(message, "sb", &new_name, &read_only);
393         if (r < 0)
394                 return r;
395
396         if (!image_name_is_valid(new_name))
397                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
398
399         r = image_clone(image, new_name, read_only);
400         if (r < 0)
401                 return r;
402
403         return sd_bus_reply_method_return(message, NULL);
404 }
405
406 static int method_mark_read_only(
407                 sd_bus *bus,
408                 sd_bus_message *message,
409                 void *userdata,
410                 sd_bus_error *error) {
411
412         _cleanup_(image_unrefp) Image *image = NULL;
413         int r, read_only;
414
415         assert(bus);
416         assert(message);
417
418         r = image_find_by_bus_path_with_error(sd_bus_message_get_path(message), &image, error);
419         if (r < 0)
420                 return r;
421
422         r = sd_bus_message_read(message, "b", &read_only);
423         if (r < 0)
424                 return r;
425
426         r = image_read_only(image, read_only);
427         if (r < 0)
428                 return r;
429
430         return sd_bus_reply_method_return(message, NULL);
431 }
432
433 const sd_bus_vtable image_vtable[] = {
434         SD_BUS_VTABLE_START(0),
435         SD_BUS_PROPERTY("Name",                  "s", property_get_name,            0, 0),
436         SD_BUS_PROPERTY("Path",                  "s", property_get_path,            0, 0),
437         SD_BUS_PROPERTY("Type",                  "s", property_get_type,            0, 0),
438         SD_BUS_PROPERTY("ReadOnly",              "b", property_get_read_only,       0, 0),
439         SD_BUS_PROPERTY("CreationTimestamp",     "t", property_get_crtime,          0, 0),
440         SD_BUS_PROPERTY("ModificationTimestamp", "t", property_get_mtime,           0, 0),
441         SD_BUS_PROPERTY("Size",                  "t", property_get_size,            0, 0),
442         SD_BUS_PROPERTY("Limit",                 "t", property_get_limit,           0, 0),
443         SD_BUS_PROPERTY("SizeExclusive",         "t", property_get_size_exclusive,  0, 0),
444         SD_BUS_PROPERTY("LimitExclusive",        "t", property_get_limit_exclusive, 0, 0),
445         SD_BUS_METHOD("Remove", NULL, NULL, method_remove, 0),
446         SD_BUS_METHOD("Rename", "s", NULL, method_rename, 0),
447         SD_BUS_METHOD("Clone", "sb", NULL, method_clone, 0),
448         SD_BUS_METHOD("MarkeReadOnly", "b", NULL, method_mark_read_only, 0),
449         SD_BUS_VTABLE_END
450 };
451
452 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
453         int r;
454
455         assert(bus);
456         assert(path);
457         assert(interface);
458         assert(found);
459
460         r = image_find_by_bus_path(path, NULL);
461         if (r <= 0)
462                 return r;
463
464         *found = NULL;
465         return 1;
466 }
467
468 char *image_bus_path(const char *name) {
469         _cleanup_free_ char *e = NULL;
470
471         assert(name);
472
473         e = bus_label_escape(name);
474         if (!e)
475                 return NULL;
476
477         return strappend("/org/freedesktop/machine1/image/", e);
478 }
479
480 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
481         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
482         _cleanup_strv_free_ char **l = NULL;
483         Image *image;
484         Iterator i;
485         int r;
486
487         assert(bus);
488         assert(path);
489         assert(nodes);
490
491         images = hashmap_new(&string_hash_ops);
492         if (!images)
493                 return -ENOMEM;
494
495         r = image_discover(images);
496         if (r < 0)
497                 return r;
498
499         HASHMAP_FOREACH(image, images, i) {
500                 char *p;
501
502                 p = image_bus_path(image->name);
503                 if (!p)
504                         return -ENOMEM;
505
506                 r = strv_consume(&l, p);
507                 if (r < 0)
508                         return r;
509         }
510
511         *nodes = l;
512         l = NULL;
513
514         return 1;
515 }