chiark / gitweb /
machined: don't look for images on each property get, but cache the image object...
[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 "bus-util.h"
26 #include "machine-image.h"
27 #include "image-dbus.h"
28
29 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
30
31 int bus_image_method_remove(
32                 sd_bus *bus,
33                 sd_bus_message *message,
34                 void *userdata,
35                 sd_bus_error *error) {
36
37         Image *image = userdata;
38         int r;
39
40         assert(bus);
41         assert(message);
42         assert(image);
43
44         r = image_remove(image);
45         if (r < 0)
46                 return r;
47
48         return sd_bus_reply_method_return(message, NULL);
49 }
50
51 int bus_image_method_rename(
52                 sd_bus *bus,
53                 sd_bus_message *message,
54                 void *userdata,
55                 sd_bus_error *error) {
56
57         Image *image = userdata;
58         const char *new_name;
59         int r;
60
61         assert(bus);
62         assert(message);
63         assert(image);
64
65         r = sd_bus_message_read(message, "s", &new_name);
66         if (r < 0)
67                 return r;
68
69         if (!image_name_is_valid(new_name))
70                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
71
72         r = image_rename(image, new_name);
73         if (r < 0)
74                 return r;
75
76         return sd_bus_reply_method_return(message, NULL);
77 }
78
79 int bus_image_method_clone(
80                 sd_bus *bus,
81                 sd_bus_message *message,
82                 void *userdata,
83                 sd_bus_error *error) {
84
85         Image *image = userdata;
86         const char *new_name;
87         int r, read_only;
88
89         assert(bus);
90         assert(message);
91         assert(image);
92
93         r = sd_bus_message_read(message, "sb", &new_name, &read_only);
94         if (r < 0)
95                 return r;
96
97         if (!image_name_is_valid(new_name))
98                 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
99
100         r = image_clone(image, new_name, read_only);
101         if (r < 0)
102                 return r;
103
104         return sd_bus_reply_method_return(message, NULL);
105 }
106
107 int bus_image_method_mark_read_only(
108                 sd_bus *bus,
109                 sd_bus_message *message,
110                 void *userdata,
111                 sd_bus_error *error) {
112
113         Image *image = userdata;
114         int r, read_only;
115
116         assert(bus);
117         assert(message);
118
119         r = sd_bus_message_read(message, "b", &read_only);
120         if (r < 0)
121                 return r;
122
123         r = image_read_only(image, read_only);
124         if (r < 0)
125                 return r;
126
127         return sd_bus_reply_method_return(message, NULL);
128 }
129
130 const sd_bus_vtable image_vtable[] = {
131         SD_BUS_VTABLE_START(0),
132         SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
133         SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
134         SD_BUS_PROPERTY("Type", "s", property_get_type,  offsetof(Image, type), 0),
135         SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
136         SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
137         SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
138         SD_BUS_PROPERTY("Size", "t", NULL, offsetof(Image, size), 0),
139         SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
140         SD_BUS_PROPERTY("SizeExclusive", "t", NULL, offsetof(Image, size_exclusive), 0),
141         SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
142         SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, 0),
143         SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, 0),
144         SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, 0),
145         SD_BUS_METHOD("MarkeReadOnly", "b", NULL, bus_image_method_mark_read_only, 0),
146         SD_BUS_VTABLE_END
147 };
148
149 static int image_flush_cache(sd_event_source *s, void *userdata) {
150         Manager *m = userdata;
151         Image *i;
152
153         assert(s);
154         assert(m);
155
156         while ((i = hashmap_steal_first(m->image_cache)))
157                 image_unref(i);
158
159         return 0;
160 }
161
162 int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
163         _cleanup_free_ char *e = NULL;
164         Manager *m = userdata;
165         Image *image = NULL;
166         const char *p;
167         int r;
168
169         assert(bus);
170         assert(path);
171         assert(interface);
172         assert(found);
173
174         p = startswith(path, "/org/freedesktop/machine1/image/");
175         if (!p)
176                 return 0;
177
178         e = bus_label_unescape(p);
179         if (!e)
180                 return -ENOMEM;
181
182         image = hashmap_get(m->image_cache, e);
183         if (image) {
184                 *found = image;
185                 return 1;
186         }
187
188         r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
189         if (r < 0)
190                 return r;
191
192         if (!m->image_cache_defer_event) {
193                 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
194                 if (r < 0)
195                         return r;
196
197                 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
198                 if (r < 0)
199                         return r;
200         }
201
202         r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
203         if (r < 0)
204                 return r;
205
206         r = image_find(e, &image);
207         if (r <= 0)
208                 return r;
209
210         r = hashmap_put(m->image_cache, image->name, image);
211         if (r < 0) {
212                 image_unref(image);
213                 return r;
214         }
215
216         *found = image;
217         return 1;
218 }
219
220 char *image_bus_path(const char *name) {
221         _cleanup_free_ char *e = NULL;
222
223         assert(name);
224
225         e = bus_label_escape(name);
226         if (!e)
227                 return NULL;
228
229         return strappend("/org/freedesktop/machine1/image/", e);
230 }
231
232 int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
233         _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
234         _cleanup_strv_free_ char **l = NULL;
235         Image *image;
236         Iterator i;
237         int r;
238
239         assert(bus);
240         assert(path);
241         assert(nodes);
242
243         images = hashmap_new(&string_hash_ops);
244         if (!images)
245                 return -ENOMEM;
246
247         r = image_discover(images);
248         if (r < 0)
249                 return r;
250
251         HASHMAP_FOREACH(image, images, i) {
252                 char *p;
253
254                 p = image_bus_path(image->name);
255                 if (!p)
256                         return -ENOMEM;
257
258                 r = strv_consume(&l, p);
259                 if (r < 0)
260                         return r;
261         }
262
263         *nodes = l;
264         l = NULL;
265
266         return 1;
267 }