2 This file is part of systemd.
4 Copyright 2014 Lennart Poettering
6 systemd is free software; you can redistribute it and/or modify it
7 under the terms of the GNU Lesser General Public License as published by
8 the Free Software Foundation; either version 2.1 of the License, or
9 (at your option) any later version.
11 systemd is distributed in the hope that it will be useful, but
12 WITHOUT ANY WARRANTY; without even the implied warranty of
13 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 Lesser General Public License for more details.
16 You should have received a copy of the GNU Lesser General Public License
17 along with systemd; If not, see <http://www.gnu.org/licenses/>.
20 #include "alloc-util.h"
21 #include "bus-label.h"
24 #include "image-dbus.h"
26 #include "machine-image.h"
27 #include "process-util.h"
29 #include "user-util.h"
31 static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type
, image_type
, ImageType
);
33 int bus_image_method_remove(
34 sd_bus_message
*message
,
36 sd_bus_error
*error
) {
38 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
39 Image
*image
= userdata
;
40 Manager
*m
= image
->userdata
;
47 if (m
->n_operations
>= OPERATIONS_MAX
)
48 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
50 r
= bus_verify_polkit_async(
53 "org.freedesktop.machine1.manage-images",
62 return 1; /* Will call us back */
64 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
65 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
69 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
71 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
73 r
= image_remove(image
);
75 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
82 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
84 r
= operation_new(m
, NULL
, child
, message
, errno_pipe_fd
[0], NULL
);
86 (void) sigkill_wait(child
);
90 errno_pipe_fd
[0] = -1;
95 int bus_image_method_rename(
96 sd_bus_message
*message
,
98 sd_bus_error
*error
) {
100 Image
*image
= userdata
;
101 Manager
*m
= image
->userdata
;
102 const char *new_name
;
108 r
= sd_bus_message_read(message
, "s", &new_name
);
112 if (!image_name_is_valid(new_name
))
113 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", new_name
);
115 r
= bus_verify_polkit_async(
118 "org.freedesktop.machine1.manage-images",
127 return 1; /* Will call us back */
129 r
= image_rename(image
, new_name
);
133 return sd_bus_reply_method_return(message
, NULL
);
136 int bus_image_method_clone(
137 sd_bus_message
*message
,
139 sd_bus_error
*error
) {
141 _cleanup_close_pair_
int errno_pipe_fd
[2] = { -1, -1 };
142 Image
*image
= userdata
;
143 Manager
*m
= image
->userdata
;
144 const char *new_name
;
152 if (m
->n_operations
>= OPERATIONS_MAX
)
153 return sd_bus_error_setf(error
, SD_BUS_ERROR_LIMITS_EXCEEDED
, "Too many ongoing operations.");
155 r
= sd_bus_message_read(message
, "sb", &new_name
, &read_only
);
159 if (!image_name_is_valid(new_name
))
160 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "Image name '%s' is invalid.", new_name
);
162 r
= bus_verify_polkit_async(
165 "org.freedesktop.machine1.manage-images",
174 return 1; /* Will call us back */
176 if (pipe2(errno_pipe_fd
, O_CLOEXEC
|O_NONBLOCK
) < 0)
177 return sd_bus_error_set_errnof(error
, errno
, "Failed to create pipe: %m");
181 return sd_bus_error_set_errnof(error
, errno
, "Failed to fork(): %m");
183 errno_pipe_fd
[0] = safe_close(errno_pipe_fd
[0]);
185 r
= image_clone(image
, new_name
, read_only
);
187 (void) write(errno_pipe_fd
[1], &r
, sizeof(r
));
194 errno_pipe_fd
[1] = safe_close(errno_pipe_fd
[1]);
196 r
= operation_new(m
, NULL
, child
, message
, errno_pipe_fd
[0], NULL
);
198 (void) sigkill_wait(child
);
202 errno_pipe_fd
[0] = -1;
207 int bus_image_method_mark_read_only(
208 sd_bus_message
*message
,
210 sd_bus_error
*error
) {
212 Image
*image
= userdata
;
213 Manager
*m
= image
->userdata
;
218 r
= sd_bus_message_read(message
, "b", &read_only
);
222 r
= bus_verify_polkit_async(
225 "org.freedesktop.machine1.manage-images",
234 return 1; /* Will call us back */
236 r
= image_read_only(image
, read_only
);
240 return sd_bus_reply_method_return(message
, NULL
);
243 int bus_image_method_set_limit(
244 sd_bus_message
*message
,
246 sd_bus_error
*error
) {
248 Image
*image
= userdata
;
249 Manager
*m
= image
->userdata
;
255 r
= sd_bus_message_read(message
, "t", &limit
);
258 if (!FILE_SIZE_VALID_OR_INFINITY(limit
))
259 return sd_bus_error_setf(error
, SD_BUS_ERROR_INVALID_ARGS
, "New limit out of range");
261 r
= bus_verify_polkit_async(
264 "org.freedesktop.machine1.manage-images",
273 return 1; /* Will call us back */
275 r
= image_set_limit(image
, limit
);
279 return sd_bus_reply_method_return(message
, NULL
);
282 const sd_bus_vtable image_vtable
[] = {
283 SD_BUS_VTABLE_START(0),
284 SD_BUS_PROPERTY("Name", "s", NULL
, offsetof(Image
, name
), 0),
285 SD_BUS_PROPERTY("Path", "s", NULL
, offsetof(Image
, path
), 0),
286 SD_BUS_PROPERTY("Type", "s", property_get_type
, offsetof(Image
, type
), 0),
287 SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool
, offsetof(Image
, read_only
), 0),
288 SD_BUS_PROPERTY("CreationTimestamp", "t", NULL
, offsetof(Image
, crtime
), 0),
289 SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL
, offsetof(Image
, mtime
), 0),
290 SD_BUS_PROPERTY("Usage", "t", NULL
, offsetof(Image
, usage
), 0),
291 SD_BUS_PROPERTY("Limit", "t", NULL
, offsetof(Image
, limit
), 0),
292 SD_BUS_PROPERTY("UsageExclusive", "t", NULL
, offsetof(Image
, usage_exclusive
), 0),
293 SD_BUS_PROPERTY("LimitExclusive", "t", NULL
, offsetof(Image
, limit_exclusive
), 0),
294 SD_BUS_METHOD("Remove", NULL
, NULL
, bus_image_method_remove
, SD_BUS_VTABLE_UNPRIVILEGED
),
295 SD_BUS_METHOD("Rename", "s", NULL
, bus_image_method_rename
, SD_BUS_VTABLE_UNPRIVILEGED
),
296 SD_BUS_METHOD("Clone", "sb", NULL
, bus_image_method_clone
, SD_BUS_VTABLE_UNPRIVILEGED
),
297 SD_BUS_METHOD("MarkReadOnly", "b", NULL
, bus_image_method_mark_read_only
, SD_BUS_VTABLE_UNPRIVILEGED
),
298 SD_BUS_METHOD("SetLimit", "t", NULL
, bus_image_method_set_limit
, SD_BUS_VTABLE_UNPRIVILEGED
),
302 static int image_flush_cache(sd_event_source
*s
, void *userdata
) {
303 Manager
*m
= userdata
;
309 while ((i
= hashmap_steal_first(m
->image_cache
)))
315 int image_object_find(sd_bus
*bus
, const char *path
, const char *interface
, void *userdata
, void **found
, sd_bus_error
*error
) {
316 _cleanup_free_
char *e
= NULL
;
317 Manager
*m
= userdata
;
327 p
= startswith(path
, "/org/freedesktop/machine1/image/");
331 e
= bus_label_unescape(p
);
335 image
= hashmap_get(m
->image_cache
, e
);
341 r
= hashmap_ensure_allocated(&m
->image_cache
, &string_hash_ops
);
345 if (!m
->image_cache_defer_event
) {
346 r
= sd_event_add_defer(m
->event
, &m
->image_cache_defer_event
, image_flush_cache
, m
);
350 r
= sd_event_source_set_priority(m
->image_cache_defer_event
, SD_EVENT_PRIORITY_IDLE
);
355 r
= sd_event_source_set_enabled(m
->image_cache_defer_event
, SD_EVENT_ONESHOT
);
359 r
= image_find(e
, &image
);
365 r
= hashmap_put(m
->image_cache
, image
->name
, image
);
375 char *image_bus_path(const char *name
) {
376 _cleanup_free_
char *e
= NULL
;
380 e
= bus_label_escape(name
);
384 return strappend("/org/freedesktop/machine1/image/", e
);
387 int image_node_enumerator(sd_bus
*bus
, const char *path
, void *userdata
, char ***nodes
, sd_bus_error
*error
) {
388 _cleanup_(image_hashmap_freep
) Hashmap
*images
= NULL
;
389 _cleanup_strv_free_
char **l
= NULL
;
398 images
= hashmap_new(&string_hash_ops
);
402 r
= image_discover(images
);
406 HASHMAP_FOREACH(image
, images
, i
) {
409 p
= image_bus_path(image
->name
);
413 r
= strv_consume(&l
, p
);