]> git.proxmox.com Git - systemd.git/blame - src/machine/image-dbus.c
New upstream version 236
[systemd.git] / src / machine / image-dbus.c
CommitLineData
52ad194e 1/* SPDX-License-Identifier: LGPL-2.1+ */
e735f4d4
MP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
81c58355 21#include <sys/file.h>
2897b343
MP
22#include <sys/mount.h>
23
db2df898 24#include "alloc-util.h"
e735f4d4 25#include "bus-label.h"
e735f4d4 26#include "bus-util.h"
2897b343
MP
27#include "copy.h"
28#include "dissect-image.h"
aa27b158 29#include "fd-util.h"
2897b343
MP
30#include "fileio.h"
31#include "fs-util.h"
e735f4d4 32#include "image-dbus.h"
4c89c718 33#include "io-util.h"
2897b343 34#include "loop-util.h"
db2df898 35#include "machine-image.h"
2897b343 36#include "mount-util.h"
aa27b158 37#include "process-util.h"
2897b343 38#include "raw-clone.h"
db2df898
MP
39#include "strv.h"
40#include "user-util.h"
e735f4d4
MP
41
42static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
43
44int bus_image_method_remove(
e735f4d4
MP
45 sd_bus_message *message,
46 void *userdata,
47 sd_bus_error *error) {
48
aa27b158 49 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
e735f4d4 50 Image *image = userdata;
e3bff60a 51 Manager *m = image->userdata;
aa27b158 52 pid_t child;
e735f4d4
MP
53 int r;
54
e735f4d4
MP
55 assert(message);
56 assert(image);
57
aa27b158
MP
58 if (m->n_operations >= OPERATIONS_MAX)
59 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
60
e3bff60a
MP
61 r = bus_verify_polkit_async(
62 message,
63 CAP_SYS_ADMIN,
64 "org.freedesktop.machine1.manage-images",
d9dfd233 65 NULL,
e3bff60a
MP
66 false,
67 UID_INVALID,
68 &m->polkit_registry,
69 error);
70 if (r < 0)
71 return r;
72 if (r == 0)
73 return 1; /* Will call us back */
74
aa27b158
MP
75 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
76 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
77
78 child = fork();
79 if (child < 0)
80 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
81 if (child == 0) {
82 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
83
84 r = image_remove(image);
85 if (r < 0) {
86 (void) write(errno_pipe_fd[1], &r, sizeof(r));
87 _exit(EXIT_FAILURE);
88 }
89
90 _exit(EXIT_SUCCESS);
91 }
92
93 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
94
5a920b42 95 r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL);
aa27b158
MP
96 if (r < 0) {
97 (void) sigkill_wait(child);
e735f4d4 98 return r;
aa27b158 99 }
e735f4d4 100
aa27b158
MP
101 errno_pipe_fd[0] = -1;
102
103 return 1;
e735f4d4
MP
104}
105
106int bus_image_method_rename(
e735f4d4
MP
107 sd_bus_message *message,
108 void *userdata,
109 sd_bus_error *error) {
110
111 Image *image = userdata;
e3bff60a 112 Manager *m = image->userdata;
e735f4d4
MP
113 const char *new_name;
114 int r;
115
e735f4d4
MP
116 assert(message);
117 assert(image);
118
119 r = sd_bus_message_read(message, "s", &new_name);
120 if (r < 0)
121 return r;
122
123 if (!image_name_is_valid(new_name))
124 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
125
e3bff60a
MP
126 r = bus_verify_polkit_async(
127 message,
128 CAP_SYS_ADMIN,
129 "org.freedesktop.machine1.manage-images",
d9dfd233 130 NULL,
e3bff60a
MP
131 false,
132 UID_INVALID,
133 &m->polkit_registry,
134 error);
135 if (r < 0)
136 return r;
137 if (r == 0)
138 return 1; /* Will call us back */
139
e735f4d4
MP
140 r = image_rename(image, new_name);
141 if (r < 0)
142 return r;
143
144 return sd_bus_reply_method_return(message, NULL);
145}
146
147int bus_image_method_clone(
e735f4d4
MP
148 sd_bus_message *message,
149 void *userdata,
150 sd_bus_error *error) {
151
aa27b158 152 _cleanup_close_pair_ int errno_pipe_fd[2] = { -1, -1 };
e735f4d4 153 Image *image = userdata;
e3bff60a 154 Manager *m = image->userdata;
e735f4d4
MP
155 const char *new_name;
156 int r, read_only;
aa27b158 157 pid_t child;
e735f4d4 158
e735f4d4
MP
159 assert(message);
160 assert(image);
aa27b158
MP
161 assert(m);
162
163 if (m->n_operations >= OPERATIONS_MAX)
164 return sd_bus_error_setf(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
e735f4d4
MP
165
166 r = sd_bus_message_read(message, "sb", &new_name, &read_only);
167 if (r < 0)
168 return r;
169
170 if (!image_name_is_valid(new_name))
171 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
172
e3bff60a
MP
173 r = bus_verify_polkit_async(
174 message,
175 CAP_SYS_ADMIN,
176 "org.freedesktop.machine1.manage-images",
d9dfd233 177 NULL,
e3bff60a
MP
178 false,
179 UID_INVALID,
180 &m->polkit_registry,
181 error);
182 if (r < 0)
183 return r;
184 if (r == 0)
185 return 1; /* Will call us back */
186
aa27b158
MP
187 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
188 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
189
190 child = fork();
191 if (child < 0)
192 return sd_bus_error_set_errnof(error, errno, "Failed to fork(): %m");
193 if (child == 0) {
194 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
195
196 r = image_clone(image, new_name, read_only);
197 if (r < 0) {
198 (void) write(errno_pipe_fd[1], &r, sizeof(r));
199 _exit(EXIT_FAILURE);
200 }
201
202 _exit(EXIT_SUCCESS);
203 }
204
205 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
206
5a920b42 207 r = operation_new(m, NULL, child, message, errno_pipe_fd[0], NULL);
aa27b158
MP
208 if (r < 0) {
209 (void) sigkill_wait(child);
e735f4d4 210 return r;
aa27b158 211 }
e735f4d4 212
aa27b158
MP
213 errno_pipe_fd[0] = -1;
214
215 return 1;
e735f4d4
MP
216}
217
218int bus_image_method_mark_read_only(
e735f4d4
MP
219 sd_bus_message *message,
220 void *userdata,
221 sd_bus_error *error) {
222
223 Image *image = userdata;
e3bff60a 224 Manager *m = image->userdata;
e735f4d4
MP
225 int r, read_only;
226
e735f4d4
MP
227 assert(message);
228
229 r = sd_bus_message_read(message, "b", &read_only);
230 if (r < 0)
231 return r;
232
e3bff60a
MP
233 r = bus_verify_polkit_async(
234 message,
235 CAP_SYS_ADMIN,
236 "org.freedesktop.machine1.manage-images",
d9dfd233 237 NULL,
e3bff60a
MP
238 false,
239 UID_INVALID,
240 &m->polkit_registry,
241 error);
242 if (r < 0)
243 return r;
244 if (r == 0)
245 return 1; /* Will call us back */
246
e735f4d4
MP
247 r = image_read_only(image, read_only);
248 if (r < 0)
249 return r;
250
251 return sd_bus_reply_method_return(message, NULL);
252}
253
e3bff60a
MP
254int bus_image_method_set_limit(
255 sd_bus_message *message,
256 void *userdata,
257 sd_bus_error *error) {
258
259 Image *image = userdata;
260 Manager *m = image->userdata;
261 uint64_t limit;
262 int r;
263
264 assert(message);
265
266 r = sd_bus_message_read(message, "t", &limit);
267 if (r < 0)
268 return r;
4c89c718
MP
269 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
270 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
e3bff60a
MP
271
272 r = bus_verify_polkit_async(
273 message,
274 CAP_SYS_ADMIN,
275 "org.freedesktop.machine1.manage-images",
d9dfd233 276 NULL,
e3bff60a
MP
277 false,
278 UID_INVALID,
279 &m->polkit_registry,
280 error);
281 if (r < 0)
282 return r;
283 if (r == 0)
284 return 1; /* Will call us back */
285
286 r = image_set_limit(image, limit);
287 if (r < 0)
288 return r;
289
290 return sd_bus_reply_method_return(message, NULL);
291}
292
52ad194e
MB
293int bus_image_method_get_hostname(
294 sd_bus_message *message,
295 void *userdata,
296 sd_bus_error *error) {
2897b343 297
52ad194e 298 Image *image = userdata;
2897b343
MP
299 int r;
300
52ad194e
MB
301 if (!image->metadata_valid) {
302 r = image_read_metadata(image);
303 if (r < 0)
304 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
305 }
2897b343 306
52ad194e 307 return sd_bus_reply_method_return(message, "s", image->hostname);
2897b343
MP
308}
309
52ad194e
MB
310int bus_image_method_get_machine_id(
311 sd_bus_message *message,
312 void *userdata,
313 sd_bus_error *error) {
2897b343 314
52ad194e
MB
315 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
316 Image *image = userdata;
317 int r;
2897b343 318
52ad194e
MB
319 if (!image->metadata_valid) {
320 r = image_read_metadata(image);
2897b343 321 if (r < 0)
52ad194e 322 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
2897b343
MP
323 }
324
52ad194e 325 r = sd_bus_message_new_method_return(message, &reply);
2897b343
MP
326 if (r < 0)
327 return r;
328
52ad194e
MB
329 if (sd_id128_is_null(image->machine_id)) /* Add an empty array if the ID is zero */
330 r = sd_bus_message_append(reply, "ay", 0);
331 else
332 r = sd_bus_message_append_array(reply, 'y', image->machine_id.bytes, 16);
2897b343 333 if (r < 0)
52ad194e 334 return r;
2897b343 335
52ad194e 336 return sd_bus_send(NULL, reply, NULL);
2897b343
MP
337}
338
52ad194e 339int bus_image_method_get_machine_info(
2897b343
MP
340 sd_bus_message *message,
341 void *userdata,
342 sd_bus_error *error) {
343
2897b343
MP
344 Image *image = userdata;
345 int r;
346
52ad194e
MB
347 if (!image->metadata_valid) {
348 r = image_read_metadata(image);
349 if (r < 0)
350 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
351 }
2897b343 352
52ad194e
MB
353 return bus_reply_pair_array(message, image->machine_info);
354}
2897b343 355
52ad194e
MB
356int bus_image_method_get_os_release(
357 sd_bus_message *message,
358 void *userdata,
359 sd_bus_error *error) {
2897b343 360
52ad194e
MB
361 Image *image = userdata;
362 int r;
2897b343 363
52ad194e
MB
364 if (!image->metadata_valid) {
365 r = image_read_metadata(image);
366 if (r < 0)
367 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
2897b343 368 }
2897b343 369
52ad194e 370 return bus_reply_pair_array(message, image->os_release);
2897b343
MP
371}
372
e735f4d4
MP
373const sd_bus_vtable image_vtable[] = {
374 SD_BUS_VTABLE_START(0),
375 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
376 SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
377 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
378 SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
379 SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
380 SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
381 SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
382 SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
383 SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
384 SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
e3bff60a
MP
385 SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
386 SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
387 SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
388 SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
389 SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
52ad194e
MB
390 SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
391 SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
392 SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
2897b343 393 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
e735f4d4
MP
394 SD_BUS_VTABLE_END
395};
396
397static int image_flush_cache(sd_event_source *s, void *userdata) {
398 Manager *m = userdata;
e735f4d4
MP
399
400 assert(s);
401 assert(m);
402
52ad194e 403 hashmap_clear_with_destructor(m->image_cache, image_unref);
e735f4d4
MP
404 return 0;
405}
406
407int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
408 _cleanup_free_ char *e = NULL;
409 Manager *m = userdata;
410 Image *image = NULL;
411 const char *p;
412 int r;
413
414 assert(bus);
415 assert(path);
416 assert(interface);
417 assert(found);
418
419 p = startswith(path, "/org/freedesktop/machine1/image/");
420 if (!p)
421 return 0;
422
423 e = bus_label_unescape(p);
424 if (!e)
425 return -ENOMEM;
426
427 image = hashmap_get(m->image_cache, e);
428 if (image) {
429 *found = image;
430 return 1;
431 }
432
433 r = hashmap_ensure_allocated(&m->image_cache, &string_hash_ops);
434 if (r < 0)
435 return r;
436
437 if (!m->image_cache_defer_event) {
438 r = sd_event_add_defer(m->event, &m->image_cache_defer_event, image_flush_cache, m);
439 if (r < 0)
440 return r;
441
442 r = sd_event_source_set_priority(m->image_cache_defer_event, SD_EVENT_PRIORITY_IDLE);
443 if (r < 0)
444 return r;
445 }
446
447 r = sd_event_source_set_enabled(m->image_cache_defer_event, SD_EVENT_ONESHOT);
448 if (r < 0)
449 return r;
450
451 r = image_find(e, &image);
452 if (r <= 0)
453 return r;
454
e3bff60a
MP
455 image->userdata = m;
456
e735f4d4
MP
457 r = hashmap_put(m->image_cache, image->name, image);
458 if (r < 0) {
459 image_unref(image);
460 return r;
461 }
462
463 *found = image;
464 return 1;
465}
466
467char *image_bus_path(const char *name) {
468 _cleanup_free_ char *e = NULL;
469
470 assert(name);
471
472 e = bus_label_escape(name);
473 if (!e)
474 return NULL;
475
476 return strappend("/org/freedesktop/machine1/image/", e);
477}
478
479int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
480 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
481 _cleanup_strv_free_ char **l = NULL;
482 Image *image;
483 Iterator i;
484 int r;
485
486 assert(bus);
487 assert(path);
488 assert(nodes);
489
490 images = hashmap_new(&string_hash_ops);
491 if (!images)
492 return -ENOMEM;
493
494 r = image_discover(images);
495 if (r < 0)
496 return r;
497
498 HASHMAP_FOREACH(image, images, i) {
499 char *p;
500
501 p = image_bus_path(image->name);
502 if (!p)
503 return -ENOMEM;
504
505 r = strv_consume(&l, p);
506 if (r < 0)
507 return r;
508 }
509
510 *nodes = l;
511 l = NULL;
512
513 return 1;
514}