]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/image-dbus.c
ssh-generator: generate /etc/issue.d/ with VSOCK ssh info data (#37819)
[thirdparty/systemd.git] / src / machine / image-dbus.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
ebeccf9e 2
4f18ff2e
YW
3#include <unistd.h>
4
64943cac 5#include "sd-bus.h"
9153b02b 6
b5efdb8a 7#include "alloc-util.h"
40af3d02 8#include "bus-get-properties.h"
ebeccf9e 9#include "bus-label.h"
64943cac 10#include "bus-object.h"
269e4d2d 11#include "bus-polkit.h"
ff43267c 12#include "bus-util.h"
57f1b61b 13#include "discover-image.h"
56599585 14#include "fd-util.h"
64943cac 15#include "hashmap.h"
003dffde 16#include "image-dbus.h"
64943cac 17#include "image-policy.h"
a90fb858 18#include "io-util.h"
ff43267c 19#include "machined.h"
ff43267c 20#include "operation.h"
6ef06723 21#include "os-util.h"
56599585 22#include "process-util.h"
ee104e11 23#include "strv.h"
ebeccf9e 24
1ddb263d 25static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_type, image_type, ImageType);
ebeccf9e 26
1ddb263d 27int bus_image_method_remove(
08682124
LP
28 sd_bus_message *message,
29 void *userdata,
30 sd_bus_error *error) {
31
71136404 32 _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
99534007 33 Image *image = ASSERT_PTR(userdata);
70244d1d 34 Manager *m = image->userdata;
5d2036b5 35 pid_t child;
08682124
LP
36 int r;
37
08682124 38 assert(message);
08682124 39
5d2036b5 40 if (m->n_operations >= OPERATIONS_MAX)
1b09b81c 41 return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
5d2036b5 42
8dd3f6a3
LN
43 const char *details[] = {
44 "image", image->name,
45 "verb", "remove",
46 NULL
47 };
48
70244d1d
LP
49 r = bus_verify_polkit_async(
50 message,
70244d1d 51 "org.freedesktop.machine1.manage-images",
8dd3f6a3 52 details,
70244d1d
LP
53 &m->polkit_registry,
54 error);
55 if (r < 0)
56 return r;
57 if (r == 0)
58 return 1; /* Will call us back */
59
5d2036b5
LP
60 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
61 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
62
4c253ed1
LP
63 r = safe_fork("(sd-imgrm)", FORK_RESET_SIGNALS, &child);
64 if (r < 0)
65 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
66 if (r == 0) {
5d2036b5 67 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
5d2036b5 68 r = image_remove(image);
95d5b909 69 report_errno_and_exit(errno_pipe_fd[1], r);
5d2036b5
LP
70 }
71
72 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
73
d8964f9d 74 r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], /* ret= */ NULL);
5d2036b5
LP
75 if (r < 0) {
76 (void) sigkill_wait(child);
08682124 77 return r;
5d2036b5
LP
78 }
79
254d1313 80 errno_pipe_fd[0] = -EBADF;
08682124 81
5d2036b5 82 return 1;
08682124
LP
83}
84
1ddb263d 85int bus_image_method_rename(
ebd93cb6
LP
86 sd_bus_message *message,
87 void *userdata,
88 sd_bus_error *error) {
89
99534007 90 Image *image = ASSERT_PTR(userdata);
70244d1d 91 Manager *m = image->userdata;
ebd93cb6
LP
92 const char *new_name;
93 int r;
94
ebd93cb6 95 assert(message);
ebd93cb6
LP
96
97 r = sd_bus_message_read(message, "s", &new_name);
98 if (r < 0)
99 return r;
100
101 if (!image_name_is_valid(new_name))
102 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
103
8dd3f6a3
LN
104 const char *details[] = {
105 "image", image->name,
106 "verb", "rename",
107 "new_name", new_name,
108 NULL
109 };
110
70244d1d
LP
111 r = bus_verify_polkit_async(
112 message,
70244d1d 113 "org.freedesktop.machine1.manage-images",
8dd3f6a3 114 details,
70244d1d
LP
115 &m->polkit_registry,
116 error);
117 if (r < 0)
118 return r;
119 if (r == 0)
120 return 1; /* Will call us back */
121
dd2d5952
IK
122 r = rename_image_and_update_cache(m, image, new_name);
123 if (r < 0)
124 return sd_bus_error_set_errnof(error, r, "Failed to rename image: %m");
ebd93cb6
LP
125
126 return sd_bus_reply_method_return(message, NULL);
127}
128
1ddb263d 129int bus_image_method_clone(
ebd93cb6
LP
130 sd_bus_message *message,
131 void *userdata,
132 sd_bus_error *error) {
133
71136404 134 _cleanup_close_pair_ int errno_pipe_fd[2] = EBADF_PAIR;
99534007
DT
135 Image *image = ASSERT_PTR(userdata);
136 Manager *m = ASSERT_PTR(image->userdata);
ebd93cb6
LP
137 const char *new_name;
138 int r, read_only;
56599585 139 pid_t child;
ebd93cb6 140
ebd93cb6 141 assert(message);
56599585
LP
142
143 if (m->n_operations >= OPERATIONS_MAX)
1b09b81c 144 return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
ebd93cb6
LP
145
146 r = sd_bus_message_read(message, "sb", &new_name, &read_only);
147 if (r < 0)
148 return r;
149
150 if (!image_name_is_valid(new_name))
151 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", new_name);
152
8dd3f6a3
LN
153 const char *details[] = {
154 "image", image->name,
155 "verb", "clone",
156 "new_name", new_name,
157 NULL
158 };
159
70244d1d
LP
160 r = bus_verify_polkit_async(
161 message,
70244d1d 162 "org.freedesktop.machine1.manage-images",
8dd3f6a3 163 details,
70244d1d
LP
164 &m->polkit_registry,
165 error);
166 if (r < 0)
167 return r;
168 if (r == 0)
169 return 1; /* Will call us back */
170
56599585
LP
171 if (pipe2(errno_pipe_fd, O_CLOEXEC|O_NONBLOCK) < 0)
172 return sd_bus_error_set_errnof(error, errno, "Failed to create pipe: %m");
173
f2747bf5 174 r = safe_fork("(sd-imgclone)", FORK_RESET_SIGNALS, &child);
4c253ed1
LP
175 if (r < 0)
176 return sd_bus_error_set_errnof(error, r, "Failed to fork(): %m");
177 if (r == 0) {
56599585 178 errno_pipe_fd[0] = safe_close(errno_pipe_fd[0]);
1c0ade2e 179 r = image_clone(image, new_name, read_only, m->runtime_scope);
95d5b909 180 report_errno_and_exit(errno_pipe_fd[1], r);
56599585
LP
181 }
182
183 errno_pipe_fd[1] = safe_close(errno_pipe_fd[1]);
184
d8964f9d 185 r = operation_new_with_bus_reply(m, /* machine= */ NULL, child, message, errno_pipe_fd[0], /* ret= */ NULL);
56599585 186 if (r < 0) {
89c9030d 187 (void) sigkill_wait(child);
ebd93cb6 188 return r;
56599585 189 }
ebd93cb6 190
254d1313 191 errno_pipe_fd[0] = -EBADF;
56599585
LP
192
193 return 1;
ebd93cb6
LP
194}
195
1ddb263d 196int bus_image_method_mark_read_only(
ebd93cb6
LP
197 sd_bus_message *message,
198 void *userdata,
199 sd_bus_error *error) {
200
1ddb263d 201 Image *image = userdata;
70244d1d 202 Manager *m = image->userdata;
2e1ae325 203 int read_only, r;
ebd93cb6 204
ebd93cb6
LP
205 assert(message);
206
ebd93cb6
LP
207 r = sd_bus_message_read(message, "b", &read_only);
208 if (r < 0)
209 return r;
210
8dd3f6a3
LN
211 const char *details[] = {
212 "image", image->name,
213 "verb", "mark_read_only",
2c7bcdd5 214 "read_only", one_zero(read_only),
8dd3f6a3
LN
215 NULL
216 };
217
70244d1d
LP
218 r = bus_verify_polkit_async(
219 message,
70244d1d 220 "org.freedesktop.machine1.manage-images",
8dd3f6a3 221 details,
70244d1d
LP
222 &m->polkit_registry,
223 error);
224 if (r < 0)
225 return r;
226 if (r == 0)
227 return 1; /* Will call us back */
228
ebd93cb6
LP
229 r = image_read_only(image, read_only);
230 if (r < 0)
231 return r;
232
233 return sd_bus_reply_method_return(message, NULL);
234}
235
d6ce17c7 236int bus_image_method_set_limit(
d6ce17c7
LP
237 sd_bus_message *message,
238 void *userdata,
239 sd_bus_error *error) {
240
241 Image *image = userdata;
242 Manager *m = image->userdata;
243 uint64_t limit;
244 int r;
245
d6ce17c7
LP
246 assert(message);
247
248 r = sd_bus_message_read(message, "t", &limit);
249 if (r < 0)
250 return r;
a90fb858 251 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
1b09b81c 252 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
d6ce17c7 253
8dd3f6a3
LN
254 const char *details[] = {
255 "machine", image->name,
256 "verb", "set_limit",
257 NULL
258 };
259
d6ce17c7
LP
260 r = bus_verify_polkit_async(
261 message,
d6ce17c7 262 "org.freedesktop.machine1.manage-images",
8dd3f6a3 263 details,
d6ce17c7
LP
264 &m->polkit_registry,
265 error);
266 if (r < 0)
267 return r;
268 if (r == 0)
269 return 1; /* Will call us back */
270
271 r = image_set_limit(image, limit);
272 if (r < 0)
273 return r;
274
275 return sd_bus_reply_method_return(message, NULL);
276}
277
cf30a8c1
LP
278int bus_image_method_get_hostname(
279 sd_bus_message *message,
280 void *userdata,
281 sd_bus_error *error) {
9153b02b 282
cf30a8c1 283 Image *image = userdata;
9153b02b
LP
284 int r;
285
cf30a8c1 286 if (!image->metadata_valid) {
84be0c71 287 r = image_read_metadata(image, &image_policy_container);
cf30a8c1
LP
288 if (r < 0)
289 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
290 }
9153b02b 291
cf30a8c1 292 return sd_bus_reply_method_return(message, "s", image->hostname);
9153b02b
LP
293}
294
cf30a8c1
LP
295int bus_image_method_get_machine_id(
296 sd_bus_message *message,
297 void *userdata,
298 sd_bus_error *error) {
9153b02b 299
cf30a8c1
LP
300 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
301 Image *image = userdata;
302 int r;
9153b02b 303
cf30a8c1 304 if (!image->metadata_valid) {
84be0c71 305 r = image_read_metadata(image, &image_policy_container);
9153b02b 306 if (r < 0)
cf30a8c1 307 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
9153b02b
LP
308 }
309
cf30a8c1 310 r = sd_bus_message_new_method_return(message, &reply);
9153b02b
LP
311 if (r < 0)
312 return r;
313
cf30a8c1
LP
314 if (sd_id128_is_null(image->machine_id)) /* Add an empty array if the ID is zero */
315 r = sd_bus_message_append(reply, "ay", 0);
316 else
317 r = sd_bus_message_append_array(reply, 'y', image->machine_id.bytes, 16);
9153b02b 318 if (r < 0)
cf30a8c1 319 return r;
9153b02b 320
51cc3825 321 return sd_bus_message_send(reply);
9153b02b
LP
322}
323
cf30a8c1 324int bus_image_method_get_machine_info(
9153b02b
LP
325 sd_bus_message *message,
326 void *userdata,
327 sd_bus_error *error) {
328
9153b02b
LP
329 Image *image = userdata;
330 int r;
331
cf30a8c1 332 if (!image->metadata_valid) {
84be0c71 333 r = image_read_metadata(image, &image_policy_container);
cf30a8c1
LP
334 if (r < 0)
335 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
336 }
9153b02b 337
cf30a8c1
LP
338 return bus_reply_pair_array(message, image->machine_info);
339}
9153b02b 340
cf30a8c1
LP
341int bus_image_method_get_os_release(
342 sd_bus_message *message,
343 void *userdata,
344 sd_bus_error *error) {
9153b02b 345
cf30a8c1
LP
346 Image *image = userdata;
347 int r;
9153b02b 348
cf30a8c1 349 if (!image->metadata_valid) {
84be0c71 350 r = image_read_metadata(image, &image_policy_container);
cf30a8c1
LP
351 if (r < 0)
352 return sd_bus_error_set_errnof(error, r, "Failed to read image metadata: %m");
9153b02b 353 }
9153b02b 354
cf30a8c1 355 return bus_reply_pair_array(message, image->os_release);
9153b02b
LP
356}
357
6d917da1
YW
358static int image_object_find(sd_bus *bus, const char *path, const char *interface, void *userdata, void **found, sd_bus_error *error) {
359 _cleanup_free_ char *e = NULL;
360 Manager *m = userdata;
361 Image *image;
362 const char *p;
363 int r;
364
365 assert(bus);
366 assert(path);
367 assert(interface);
368 assert(found);
369
370 p = startswith(path, "/org/freedesktop/machine1/image/");
371 if (!p)
372 return 0;
373
374 e = bus_label_unescape(p);
375 if (!e)
376 return -ENOMEM;
377
378 r = manager_acquire_image(m, e, &image);
379 if (r == -ENOENT)
380 return 0;
381 if (r < 0)
1ddb263d 382 return r;
1ddb263d
LP
383
384 *found = image;
ebeccf9e
LP
385 return 1;
386}
387
ff3f2953 388char* image_bus_path(const char *name) {
ebeccf9e
LP
389 _cleanup_free_ char *e = NULL;
390
391 assert(name);
392
393 e = bus_label_escape(name);
394 if (!e)
395 return NULL;
396
b910cc72 397 return strjoin("/org/freedesktop/machine1/image/", e);
ebeccf9e
LP
398}
399
4faa530c 400static int image_node_enumerator(sd_bus *bus, const char *path, void *userdata, char ***nodes, sd_bus_error *error) {
1c0ade2e 401 Manager *m = ASSERT_PTR(userdata);
ebeccf9e
LP
402 int r;
403
404 assert(bus);
405 assert(path);
406 assert(nodes);
407
624d3698
YW
408 _cleanup_hashmap_free_ Hashmap *images = NULL;
409 r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, &images);
ebeccf9e
LP
410 if (r < 0)
411 return r;
412
624d3698
YW
413 _cleanup_strv_free_ char **l = NULL;
414 Image *image;
90e74a66 415 HASHMAP_FOREACH(image, images) {
ebeccf9e
LP
416 char *p;
417
418 p = image_bus_path(image->name);
419 if (!p)
420 return -ENOMEM;
421
422 r = strv_consume(&l, p);
423 if (r < 0)
424 return r;
425 }
426
1cc6c93a 427 *nodes = TAKE_PTR(l);
ebeccf9e
LP
428
429 return 1;
430}
4faa530c
ZJS
431
432const sd_bus_vtable image_vtable[] = {
433 SD_BUS_VTABLE_START(0),
434 SD_BUS_PROPERTY("Name", "s", NULL, offsetof(Image, name), 0),
435 SD_BUS_PROPERTY("Path", "s", NULL, offsetof(Image, path), 0),
436 SD_BUS_PROPERTY("Type", "s", property_get_type, offsetof(Image, type), 0),
437 SD_BUS_PROPERTY("ReadOnly", "b", bus_property_get_bool, offsetof(Image, read_only), 0),
438 SD_BUS_PROPERTY("CreationTimestamp", "t", NULL, offsetof(Image, crtime), 0),
439 SD_BUS_PROPERTY("ModificationTimestamp", "t", NULL, offsetof(Image, mtime), 0),
440 SD_BUS_PROPERTY("Usage", "t", NULL, offsetof(Image, usage), 0),
441 SD_BUS_PROPERTY("Limit", "t", NULL, offsetof(Image, limit), 0),
442 SD_BUS_PROPERTY("UsageExclusive", "t", NULL, offsetof(Image, usage_exclusive), 0),
443 SD_BUS_PROPERTY("LimitExclusive", "t", NULL, offsetof(Image, limit_exclusive), 0),
444 SD_BUS_METHOD("Remove", NULL, NULL, bus_image_method_remove, SD_BUS_VTABLE_UNPRIVILEGED),
445 SD_BUS_METHOD("Rename", "s", NULL, bus_image_method_rename, SD_BUS_VTABLE_UNPRIVILEGED),
446 SD_BUS_METHOD("Clone", "sb", NULL, bus_image_method_clone, SD_BUS_VTABLE_UNPRIVILEGED),
447 SD_BUS_METHOD("MarkReadOnly", "b", NULL, bus_image_method_mark_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
448 SD_BUS_METHOD("SetLimit", "t", NULL, bus_image_method_set_limit, SD_BUS_VTABLE_UNPRIVILEGED),
449 SD_BUS_METHOD("GetHostname", NULL, "s", bus_image_method_get_hostname, SD_BUS_VTABLE_UNPRIVILEGED),
450 SD_BUS_METHOD("GetMachineID", NULL, "ay", bus_image_method_get_machine_id, SD_BUS_VTABLE_UNPRIVILEGED),
451 SD_BUS_METHOD("GetMachineInfo", NULL, "a{ss}", bus_image_method_get_machine_info, SD_BUS_VTABLE_UNPRIVILEGED),
452 SD_BUS_METHOD("GetOSRelease", NULL, "a{ss}", bus_image_method_get_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
453 SD_BUS_VTABLE_END
454};
455
456const BusObjectImplementation image_object = {
457 "/org/freedesktop/machine1/image",
458 "org.freedesktop.machine1.Image",
459 .fallback_vtables = BUS_FALLBACK_VTABLES({image_vtable, image_object_find}),
460 .node_enumerator = image_node_enumerator,
461};