]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
udev: gracefully handle ENODEV or friends in opening device node
[thirdparty/systemd.git] / src / machine / machined-dbus.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
1ee306e1 2
1ee306e1 3#include <unistd.h>
1ee306e1 4
64943cac 5#include "sd-bus.h"
c3350683 6#include "sd-id128.h"
3ffd4af2 7
b5efdb8a 8#include "alloc-util.h"
3ffd4af2 9#include "btrfs-util.h"
96aad8d1 10#include "bus-common-errors.h"
40af3d02 11#include "bus-get-properties.h"
9b71e4ab 12#include "bus-locator.h"
ab33edb0 13#include "bus-message-util.h"
64943cac 14#include "bus-object.h"
269e4d2d 15#include "bus-polkit.h"
ff43267c 16#include "bus-util.h"
23c80348 17#include "cgroup-util.h"
57f1b61b 18#include "discover-image.h"
66855de7 19#include "errno-util.h"
3ffd4af2 20#include "fd-util.h"
03c2b288 21#include "fileio.h"
f97b34a6 22#include "format-util.h"
64943cac 23#include "hashmap.h"
25300b5a 24#include "hostname-util.h"
5a99c9d7 25#include "image.h"
3ffd4af2 26#include "image-dbus.h"
a90fb858 27#include "io-util.h"
1cf40697 28#include "machine.h"
3ffd4af2 29#include "machine-dbus.h"
4cee5eed 30#include "machine-pool.h"
c3350683 31#include "machined.h"
ff43267c 32#include "operation.h"
6ef06723 33#include "os-util.h"
3ffd4af2 34#include "path-util.h"
64943cac 35#include "string-util.h"
3ffd4af2 36#include "strv.h"
64943cac 37#include "unit-def.h"
b1d4f8e1 38#include "user-util.h"
1ee306e1 39
74c308ae 40static BUS_DEFINE_PROPERTY_GET_GLOBAL(property_get_pool_path, "s", "/var/lib/machines");
160e3793
LP
41
42static int property_get_pool_usage(
43 sd_bus *bus,
44 const char *path,
45 const char *interface,
46 const char *property,
47 sd_bus_message *reply,
48 void *userdata,
49 sd_bus_error *error) {
50
254d1313 51 _cleanup_close_ int fd = -EBADF;
f5fbe71d 52 uint64_t usage = UINT64_MAX;
160e3793
LP
53
54 assert(bus);
55 assert(reply);
56
160e3793
LP
57 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
58 if (fd >= 0) {
59 BtrfsQuotaInfo q;
60
5bcd08db 61 if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
cb81cd80 62 usage = q.referenced;
160e3793
LP
63 }
64
160e3793
LP
65 return sd_bus_message_append(reply, "t", usage);
66}
67
68static int property_get_pool_limit(
69 sd_bus *bus,
70 const char *path,
71 const char *interface,
72 const char *property,
73 sd_bus_message *reply,
74 void *userdata,
75 sd_bus_error *error) {
76
254d1313 77 _cleanup_close_ int fd = -EBADF;
f5fbe71d 78 uint64_t size = UINT64_MAX;
160e3793
LP
79
80 assert(bus);
81 assert(reply);
82
160e3793
LP
83 fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
84 if (fd >= 0) {
85 BtrfsQuotaInfo q;
86
5bcd08db 87 if (btrfs_subvol_get_subtree_quota_fd(fd, 0, &q) >= 0)
cb81cd80 88 size = q.referenced_max;
160e3793
LP
89 }
90
160e3793
LP
91 return sd_bus_message_append(reply, "t", size);
92}
93
19070062 94static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 95 _cleanup_free_ char *p = NULL;
99534007 96 Manager *m = ASSERT_PTR(userdata);
c3350683
LP
97 Machine *machine;
98 const char *name;
99 int r;
100
c3350683 101 assert(message);
c3350683
LP
102
103 r = sd_bus_message_read(message, "s", &name);
104 if (r < 0)
ebcf1f97 105 return r;
c3350683
LP
106
107 machine = hashmap_get(m->machines, name);
108 if (!machine)
ebcf1f97 109 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
110
111 p = machine_bus_path(machine);
112 if (!p)
ebcf1f97 113 return -ENOMEM;
c3350683 114
df2d202e 115 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
116}
117
19070062 118static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c2ce6a3d 119 _cleanup_free_ char *p = NULL;
99534007 120 _unused_ Manager *m = ASSERT_PTR(userdata);
c2ce6a3d
LP
121 const char *name;
122 int r;
123
c2ce6a3d 124 assert(message);
c2ce6a3d
LP
125
126 r = sd_bus_message_read(message, "s", &name);
127 if (r < 0)
128 return r;
129
1c0ade2e 130 r = image_find(m->runtime_scope, IMAGE_MACHINE, name, NULL, NULL);
3a6ce860 131 if (r == -ENOENT)
c2ce6a3d
LP
132 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
133 if (r < 0)
134 return r;
135
136 p = image_bus_path(name);
137 if (!p)
138 return -ENOMEM;
139
140 return sd_bus_reply_method_return(message, "o", p);
141}
142
19070062 143static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
f6cb4d4a 144 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
c3350683 145 _cleanup_free_ char *p = NULL;
99534007 146 Manager *m = ASSERT_PTR(userdata);
c3350683 147 Machine *machine = NULL;
4e724d9c 148 pid_t pid;
c3350683
LP
149 int r;
150
c3350683 151 assert(message);
c3350683 152
4e724d9c
LP
153 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
154
c3350683
LP
155 r = sd_bus_message_read(message, "u", &pid);
156 if (r < 0)
ebcf1f97 157 return r;
c3350683 158
07b38ba5 159 if (pid < 0)
06820eaf
LP
160 return -EINVAL;
161
f6cb4d4a
IK
162 pidref = PIDREF_MAKE_FROM_PID(pid);
163
4e724d9c 164 if (pid == 0) {
4afd3348 165 _cleanup_(sd_bus_creds_unrefp) sd_bus_creds *creds = NULL;
5b12334d 166
f6cb4d4a 167 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID|SD_BUS_CREDS_PIDFD, &creds);
5b12334d
LP
168 if (r < 0)
169 return r;
170
f6cb4d4a 171 r = bus_creds_get_pidref(creds, &pidref);
4e724d9c 172 if (r < 0)
ebcf1f97 173 return r;
4e724d9c
LP
174 }
175
f6cb4d4a 176 r = manager_get_machine_by_pidref(m, &pidref, &machine);
c3350683 177 if (r < 0)
ebcf1f97 178 return r;
85ab917b 179 if (r == 0)
de0671ee 180 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
c3350683
LP
181
182 p = machine_bus_path(machine);
183 if (!p)
ebcf1f97 184 return -ENOMEM;
c3350683 185
df2d202e 186 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
187}
188
19070062 189static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 190 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
99534007 191 Manager *m = ASSERT_PTR(userdata);
c3350683 192 Machine *machine;
c3350683
LP
193 int r;
194
c3350683 195 assert(message);
c3350683 196
df2d202e 197 r = sd_bus_message_new_method_return(message, &reply);
c3350683 198 if (r < 0)
ebcf1f97 199 return sd_bus_error_set_errno(error, r);
c3350683
LP
200
201 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
202 if (r < 0)
ebcf1f97 203 return sd_bus_error_set_errno(error, r);
c3350683 204
90e74a66 205 HASHMAP_FOREACH(machine, m->machines) {
c3350683
LP
206 _cleanup_free_ char *p = NULL;
207
208 p = machine_bus_path(machine);
209 if (!p)
ebcf1f97 210 return -ENOMEM;
c3350683
LP
211
212 r = sd_bus_message_append(reply, "(ssso)",
213 machine->name,
214 strempty(machine_class_to_string(machine->class)),
215 machine->service,
216 p);
217 if (r < 0)
ebcf1f97 218 return sd_bus_error_set_errno(error, r);
c3350683 219 }
1ee306e1 220
c3350683
LP
221 r = sd_bus_message_close_container(reply);
222 if (r < 0)
ebcf1f97 223 return sd_bus_error_set_errno(error, r);
c3350683 224
51cc3825 225 return sd_bus_message_send(reply);
c3350683
LP
226}
227
4198ff4c
LP
228static int method_create_or_register_machine(
229 Manager *manager,
230 sd_bus_message *message,
231 bool read_network,
232 Machine **ret,
233 sd_bus_error *error) {
234
d8854ff1 235 _cleanup_(pidref_done) PidRef pidref = PIDREF_NULL;
8aec412f 236 const char *name, *service, *class, *root_directory;
9b5ed6fe 237 const int32_t *netif = NULL;
1ee306e1
LP
238 MachineClass c;
239 uint32_t leader;
240 sd_id128_t id;
241 Machine *m;
4db747b0 242 size_t n_netif = 0;
c3350683 243 int r;
1ee306e1 244
c3350683 245 assert(manager);
89f7c846 246 assert(message);
4198ff4c 247 assert(ret);
1ee306e1 248
c3350683
LP
249 r = sd_bus_message_read(message, "s", &name);
250 if (r < 0)
ebcf1f97 251 return r;
52ef5dd7 252 if (!hostname_is_valid(name, 0))
1b09b81c 253 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 254
4db747b0 255 r = bus_message_read_id128(message, &id);
c3350683 256 if (r < 0)
1b09b81c 257 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 258
c3350683
LP
259 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
260 if (r < 0)
ebcf1f97 261 return r;
1ee306e1 262
9b5ed6fe 263 if (read_network) {
9b5ed6fe
LP
264 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
265 if (r < 0)
266 return r;
267
268 n_netif /= sizeof(int32_t);
269
d007c583 270 for (size_t i = 0; i < n_netif; i++) {
9b5ed6fe
LP
271 if (netif[i] <= 0)
272 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
273 }
274 }
275
1ee306e1
LP
276 if (isempty(class))
277 c = _MACHINE_CLASS_INVALID;
278 else {
279 c = machine_class_from_string(class);
280 if (c < 0)
1b09b81c 281 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
282 }
283
c3350683 284 if (leader == 1)
1b09b81c 285 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 286
0c18c0de 287 if (!isempty(root_directory) && (!path_is_absolute(root_directory) || !path_is_valid(root_directory)))
1b09b81c 288 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 289
c3350683 290 if (leader == 0) {
92a6f214 291 r = bus_query_sender_pidref(message, &pidref);
5b12334d 292 if (r < 0)
92a6f214
LP
293 return sd_bus_error_set_errnof(error, r, "Failed to pin client process: %m");
294 } else {
295 r = pidref_set_pid(&pidref, leader);
c3350683 296 if (r < 0)
92a6f214 297 return sd_bus_error_set_errnof(error, r, "Failed to pin process " PID_FMT ": %m", (pid_t) leader);
c3350683 298 }
554604b3 299
1ee306e1 300 if (hashmap_get(manager->machines, name))
ebcf1f97 301 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1 302
790f5162
LP
303 const char *details[] = {
304 "name", name,
305 "class", machine_class_to_string(c),
306 NULL
307 };
308
309 r = bus_verify_polkit_async(
310 message,
311 "org.freedesktop.machine1.create-machine",
312 details,
313 &manager->polkit_registry,
314 error);
315 if (r < 0)
316 return r;
317 if (r == 0)
318 return 0; /* Will call us back */
319
1ee306e1
LP
320 r = manager_add_machine(manager, name, &m);
321 if (r < 0)
ebcf1f97 322 return r;
1ee306e1 323
d8854ff1 324 m->leader = TAKE_PIDREF(pidref);
1ee306e1
LP
325 m->class = c;
326 m->id = id;
327
328 if (!isempty(service)) {
329 m->service = strdup(service);
330 if (!m->service) {
ebcf1f97 331 r = -ENOMEM;
1ee306e1
LP
332 goto fail;
333 }
334 }
335
336 if (!isempty(root_directory)) {
337 m->root_directory = strdup(root_directory);
338 if (!m->root_directory) {
ebcf1f97 339 r = -ENOMEM;
1ee306e1
LP
340 goto fail;
341 }
342 }
343
9b5ed6fe
LP
344 if (n_netif > 0) {
345 assert_cc(sizeof(int32_t) == sizeof(int));
346 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
347 if (!m->netif) {
348 r = -ENOMEM;
349 goto fail;
350 }
351
352 m->n_netif = n_netif;
353 }
354
4198ff4c 355 *ret = m;
89f7c846
LP
356 return 1;
357
358fail:
359 machine_add_to_gc_queue(m);
360 return r;
361}
362
19070062 363static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
99534007 364 Manager *manager = ASSERT_PTR(userdata);
89f7c846
LP
365 Machine *m = NULL;
366 int r;
367
19070062 368 assert(message);
19070062 369
9b5ed6fe 370 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
371 if (r < 0)
372 return r;
790f5162
LP
373 if (r == 0)
374 return 1; /* Will call us back */
89f7c846
LP
375
376 r = sd_bus_message_enter_container(message, 'a', "(sv)");
377 if (r < 0)
378 goto fail;
379
ebcf1f97
LP
380 r = machine_start(m, message, error);
381 if (r < 0)
1ee306e1
LP
382 goto fail;
383
c3350683 384 m->create_message = sd_bus_message_ref(message);
c3350683 385 return 1;
1ee306e1
LP
386
387fail:
a3e7f417 388 machine_add_to_gc_queue(m);
89f7c846
LP
389 return r;
390}
1ee306e1 391
19070062
LP
392static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
393 return method_create_machine_internal(message, true, userdata, error);
9b5ed6fe
LP
394}
395
19070062
LP
396static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
397 return method_create_machine_internal(message, false, userdata, error);
9b5ed6fe
LP
398}
399
19070062 400static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
99534007 401 Manager *manager = ASSERT_PTR(userdata);
89f7c846
LP
402 _cleanup_free_ char *p = NULL;
403 Machine *m = NULL;
404 int r;
405
19070062 406 assert(message);
19070062 407
9b5ed6fe 408 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
409 if (r < 0)
410 return r;
790f5162
LP
411 if (r == 0)
412 return 1; /* Will call us back */
89f7c846 413
08706542 414 r = cg_pidref_get_unit(&m->leader, &m->unit);
89f7c846 415 if (r < 0) {
048c386e
ZJS
416 r = sd_bus_error_set_errnof(error, r,
417 "Failed to determine unit of process "PID_FMT" : %m",
d8854ff1 418 m->leader.pid);
89f7c846
LP
419 goto fail;
420 }
421
422 r = machine_start(m, NULL, error);
423 if (r < 0)
424 goto fail;
425
426 p = machine_bus_path(m);
427 if (!p) {
428 r = -ENOMEM;
429 goto fail;
430 }
431
432 return sd_bus_reply_method_return(message, "o", p);
433
434fail:
435 machine_add_to_gc_queue(m);
1ee306e1
LP
436 return r;
437}
438
19070062
LP
439static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
440 return method_register_machine_internal(message, true, userdata, error);
9b5ed6fe
LP
441}
442
19070062
LP
443static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
444 return method_register_machine_internal(message, false, userdata, error);
9b5ed6fe
LP
445}
446
eecf0181 447static int redirect_method_to_machine(sd_bus_message *message, Manager *m, sd_bus_error *error, sd_bus_message_handler_t method) {
c3350683
LP
448 Machine *machine;
449 const char *name;
1ee306e1
LP
450 int r;
451
1ee306e1
LP
452 assert(message);
453 assert(m);
eecf0181 454 assert(method);
1ee306e1 455
c3350683
LP
456 r = sd_bus_message_read(message, "s", &name);
457 if (r < 0)
ebcf1f97 458 return sd_bus_error_set_errno(error, r);
1ee306e1 459
c3350683
LP
460 machine = hashmap_get(m->machines, name);
461 if (!machine)
ebcf1f97 462 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 463
eecf0181 464 return method(message, machine, error);
c3350683 465}
1ee306e1 466
ef8ff92e
ZJS
467static int method_unregister_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 return redirect_method_to_machine(message, userdata, error, bus_machine_method_unregister);
469}
470
eecf0181
LP
471static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
472 return redirect_method_to_machine(message, userdata, error, bus_machine_method_terminate);
473}
1ee306e1 474
eecf0181
LP
475static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
476 return redirect_method_to_machine(message, userdata, error, bus_machine_method_kill);
878cd7e9
LP
477}
478
19070062 479static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 480 return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_addresses);
c3350683 481}
1ee306e1 482
1f815bf1
SL
483static int method_get_machine_ssh_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
484 return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_ssh_info);
485}
486
19070062 487static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 488 return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_os_release);
717603e3
LP
489}
490
19070062 491static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
4afd3348 492 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
624d3698 493 Manager *m = ASSERT_PTR(userdata);
cd61c3bf
LP
494 int r;
495
cd61c3bf 496 assert(message);
cd61c3bf 497
624d3698
YW
498 _cleanup_hashmap_free_ Hashmap *images = NULL;
499 r = image_discover(m->runtime_scope, IMAGE_MACHINE, NULL, &images);
cd61c3bf
LP
500 if (r < 0)
501 return r;
502
503 r = sd_bus_message_new_method_return(message, &reply);
504 if (r < 0)
505 return r;
506
b6b18498 507 r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
cd61c3bf
LP
508 if (r < 0)
509 return r;
510
624d3698 511 Image *image;
90e74a66 512 HASHMAP_FOREACH(image, images) {
cd61c3bf
LP
513 _cleanup_free_ char *p = NULL;
514
515 p = image_bus_path(image->name);
516 if (!p)
517 return -ENOMEM;
518
b6b18498 519 r = sd_bus_message_append(reply, "(ssbttto)",
cd61c3bf
LP
520 image->name,
521 image_type_to_string(image->type),
522 image->read_only,
10f9c755
LP
523 image->crtime,
524 image->mtime,
c19de711 525 image->usage,
cd61c3bf
LP
526 p);
527 if (r < 0)
528 return r;
529 }
530
531 r = sd_bus_message_close_container(reply);
532 if (r < 0)
533 return r;
534
51cc3825 535 return sd_bus_message_send(reply);
cd61c3bf
LP
536}
537
19070062 538static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 539 return redirect_method_to_machine(message, userdata, error, bus_machine_method_open_pty);
40205d70
LP
540}
541
19070062 542static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 543 return redirect_method_to_machine(message, userdata, error, bus_machine_method_open_login);
5f8cc96a
LP
544}
545
49af9e13 546static int method_open_machine_shell(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 547 return redirect_method_to_machine(message, userdata, error, bus_machine_method_open_shell);
49af9e13
LP
548}
549
19070062 550static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 551 return redirect_method_to_machine(message, userdata, error, bus_machine_method_bind_mount);
90adaa25
LP
552}
553
19070062 554static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 555 return redirect_method_to_machine(message, userdata, error, bus_machine_method_copy);
0370612e
LP
556}
557
ae203207 558static int method_open_machine_root_directory(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 559 return redirect_method_to_machine(message, userdata, error, bus_machine_method_open_root_directory);
ae203207
LP
560}
561
3401419b 562static int method_get_machine_uid_shift(sd_bus_message *message, void *userdata, sd_bus_error *error) {
eecf0181 563 return redirect_method_to_machine(message, userdata, error, bus_machine_method_get_uid_shift);
3401419b
LP
564}
565
9b06c1e1 566static int redirect_method_to_image(sd_bus_message *message, Manager *m, sd_bus_error *error, sd_bus_message_handler_t method) {
08682124 567 const char *name;
c6aeb9b5 568 Image *i;
08682124
LP
569 int r;
570
08682124 571 assert(message);
9b06c1e1
LP
572 assert(m);
573 assert(method);
08682124
LP
574
575 r = sd_bus_message_read(message, "s", &name);
576 if (r < 0)
577 return r;
578
579 if (!image_name_is_valid(name))
580 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
581
c6aeb9b5 582 r = manager_acquire_image(m, name, &i);
3a6ce860
LP
583 if (r == -ENOENT)
584 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
08682124
LP
585 if (r < 0)
586 return r;
08682124 587
9b06c1e1 588 return method(message, i, error);
08682124
LP
589}
590
9b06c1e1
LP
591static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
592 return redirect_method_to_image(message, userdata, error, bus_image_method_remove);
593}
ebd93cb6 594
9b06c1e1
LP
595static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
596 return redirect_method_to_image(message, userdata, error, bus_image_method_rename);
ebd93cb6
LP
597}
598
19070062 599static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 600 return redirect_method_to_image(message, userdata, error, bus_image_method_clone);
ebd93cb6
LP
601}
602
19070062 603static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 604 return redirect_method_to_image(message, userdata, error, bus_image_method_mark_read_only);
ebd93cb6
LP
605}
606
cf30a8c1 607static int method_get_image_hostname(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 608 return redirect_method_to_image(message, userdata, error, bus_image_method_get_hostname);
cf30a8c1
LP
609}
610
611static int method_get_image_machine_id(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 612 return redirect_method_to_image(message, userdata, error, bus_image_method_get_machine_id);
cf30a8c1
LP
613}
614
615static int method_get_image_machine_info(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 616 return redirect_method_to_image(message, userdata, error, bus_image_method_get_machine_info);
cf30a8c1
LP
617}
618
9153b02b 619static int method_get_image_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 620 return redirect_method_to_image(message, userdata, error, bus_image_method_get_os_release);
9153b02b
LP
621}
622
5a99c9d7 623static int clean_pool_done(Operation *operation, int child_error, sd_bus_error *error) {
03c2b288 624 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
5a99c9d7 625 _cleanup_fclose_ FILE *file = NULL;
03c2b288
LP
626 int r;
627
628 assert(operation);
5a99c9d7 629 assert(operation->message);
03c2b288
LP
630 assert(operation->extra_fd >= 0);
631
5a99c9d7
IK
632 file = take_fdopen(&operation->extra_fd, "r");
633 if (!file)
634 return log_debug_errno(errno, "Failed to take opened tmp file's fd: %m");
03c2b288 635
5a99c9d7
IK
636 r = clean_pool_read_first_entry(file, child_error, error);
637 if (r < 0)
638 return r;
03c2b288
LP
639
640 r = sd_bus_message_new_method_return(operation->message, &reply);
641 if (r < 0)
642 return r;
643
644 r = sd_bus_message_open_container(reply, 'a', "(st)");
645 if (r < 0)
646 return r;
647
648 /* On success the resulting temporary file will contain a list of image names that were removed followed by
649 * their size on disk. Let's read that and turn it into a bus message. */
650 for (;;) {
651 _cleanup_free_ char *name = NULL;
5a99c9d7 652 uint64_t usage;
03c2b288 653
5a99c9d7 654 r = clean_pool_read_next_entry(file, &name, &usage);
03c2b288
LP
655 if (r < 0)
656 return r;
5a99c9d7 657 if (r == 0)
03c2b288
LP
658 break;
659
5a99c9d7 660 r = sd_bus_message_append(reply, "(st)", name, usage);
03c2b288
LP
661 if (r < 0)
662 return r;
663 }
664
665 r = sd_bus_message_close_container(reply);
666 if (r < 0)
667 return r;
668
51cc3825 669 return sd_bus_message_send(reply);
03c2b288
LP
670}
671
d94c2b06 672static int method_clean_pool(sd_bus_message *message, void *userdata, sd_bus_error *error) {
5a99c9d7 673 ImageCleanPoolMode mode;
d94c2b06 674 Manager *m = userdata;
03c2b288 675 Operation *operation;
d94c2b06 676 const char *mm;
d94c2b06
LP
677 int r;
678
679 assert(message);
680
03c2b288 681 if (m->n_operations >= OPERATIONS_MAX)
1b09b81c 682 return sd_bus_error_set(error, SD_BUS_ERROR_LIMITS_EXCEEDED, "Too many ongoing operations.");
03c2b288 683
d94c2b06
LP
684 r = sd_bus_message_read(message, "s", &mm);
685 if (r < 0)
686 return r;
687
688 if (streq(mm, "all"))
5a99c9d7 689 mode = IMAGE_CLEAN_POOL_REMOVE_ALL;
d94c2b06 690 else if (streq(mm, "hidden"))
5a99c9d7 691 mode = IMAGE_CLEAN_POOL_REMOVE_HIDDEN;
d94c2b06
LP
692 else
693 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown mode '%s'.", mm);
694
8dd3f6a3
LN
695 const char *details[] = {
696 "verb", "clean_pool",
697 "mode", mm,
698 NULL
699 };
700
d94c2b06
LP
701 r = bus_verify_polkit_async(
702 message,
d94c2b06 703 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 704 details,
d94c2b06
LP
705 &m->polkit_registry,
706 error);
707 if (r < 0)
708 return r;
709 if (r == 0)
710 return 1; /* Will call us back */
711
5a99c9d7 712 r = image_clean_pool_operation(m, mode, &operation);
4c253ed1 713 if (r < 0)
5a99c9d7 714 return log_debug_errno(r, "Failed to clean pool of images: %m");
03c2b288 715
5a99c9d7 716 operation_attach_bus_reply(operation, message);
03c2b288 717 operation->done = clean_pool_done;
03c2b288 718 return 1;
d94c2b06
LP
719}
720
19070062 721static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
d6ce17c7
LP
722 Manager *m = userdata;
723 uint64_t limit;
724 int r;
725
19070062
LP
726 assert(message);
727
d6ce17c7
LP
728 r = sd_bus_message_read(message, "t", &limit);
729 if (r < 0)
730 return r;
a90fb858 731 if (!FILE_SIZE_VALID_OR_INFINITY(limit))
1b09b81c 732 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "New limit out of range");
d6ce17c7 733
8dd3f6a3
LN
734 const char *details[] = {
735 "verb", "set_pool_limit",
736 NULL
737 };
738
d6ce17c7
LP
739 r = bus_verify_polkit_async(
740 message,
d6ce17c7 741 "org.freedesktop.machine1.manage-machines",
8dd3f6a3 742 details,
d6ce17c7
LP
743 &m->polkit_registry,
744 error);
745 if (r < 0)
746 return r;
747 if (r == 0)
748 return 1; /* Will call us back */
749
4cee5eed 750 /* Set up the machine directory if necessary */
c7779a61 751 r = setup_machine_directory(error, /* use_btrfs_subvol= */ true, /* use_btrfs_quota= */ true);
4cee5eed
LP
752 if (r < 0)
753 return r;
754
efe47f58
IK
755 r = image_set_pool_limit(IMAGE_MACHINE, limit);
756 if (ERRNO_IS_NEG_NOT_SUPPORTED(r))
1b09b81c 757 return sd_bus_error_set(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
26166c88 758 if (r < 0)
d6ce17c7
LP
759 return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
760
761 return sd_bus_reply_method_return(message, NULL);
762}
763
19070062 764static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
9b06c1e1 765 return redirect_method_to_image(message, userdata, error, bus_image_method_set_limit);
d6ce17c7
LP
766}
767
c01ff965 768static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c01ff965 769 Manager *m = userdata;
74d1b7d2 770 const char *name;
c01ff965
LP
771 Machine *machine;
772 uint32_t uid;
74d1b7d2 773 uid_t converted;
c01ff965
LP
774 int r;
775
776 r = sd_bus_message_read(message, "su", &name, &uid);
777 if (r < 0)
778 return r;
779
c077529b 780 if (!uid_is_valid(uid))
c01ff965
LP
781 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
782
783 machine = hashmap_get(m->machines, name);
784 if (!machine)
785 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
786
a79366e2 787 if (machine->class != MACHINE_CONTAINER)
1b09b81c 788 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
a79366e2 789
74d1b7d2
LP
790 r = machine_translate_uid(machine, uid, &converted);
791 if (r == -ESRCH)
792 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
793 if (r < 0)
794 return r;
c01ff965 795
74d1b7d2 796 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
c01ff965
LP
797}
798
799static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
74d1b7d2 800 _cleanup_free_ char *o = NULL;
c01ff965
LP
801 Manager *m = userdata;
802 Machine *machine;
74d1b7d2 803 uid_t uid, converted;
c01ff965
LP
804 int r;
805
806 r = sd_bus_message_read(message, "u", &uid);
807 if (r < 0)
808 return r;
c077529b 809 if (!uid_is_valid(uid))
c01ff965
LP
810 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
811 if (uid < 0x10000)
812 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
813
74d1b7d2
LP
814 r = manager_find_machine_for_uid(m, uid, &machine, &converted);
815 if (r < 0)
816 return r;
817 if (!r)
818 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
c01ff965 819
74d1b7d2
LP
820 o = machine_bus_path(machine);
821 if (!o)
822 return -ENOMEM;
c01ff965 823
74d1b7d2 824 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
c01ff965
LP
825}
826
74d1b7d2
LP
827static int method_map_from_machine_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
828 Manager *m = userdata;
829 const char *name;
c01ff965 830 Machine *machine;
74d1b7d2 831 gid_t converted;
c01ff965
LP
832 uint32_t gid;
833 int r;
834
835 r = sd_bus_message_read(message, "su", &name, &gid);
836 if (r < 0)
837 return r;
838
c077529b 839 if (!gid_is_valid(gid))
c01ff965
LP
840 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
841
842 machine = hashmap_get(m->machines, name);
843 if (!machine)
844 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
845
a79366e2 846 if (machine->class != MACHINE_CONTAINER)
1b09b81c 847 return sd_bus_error_set(error, SD_BUS_ERROR_INVALID_ARGS, "Not supported for non-container machines.");
a79366e2 848
74d1b7d2
LP
849 r = machine_translate_gid(machine, gid, &converted);
850 if (r == -ESRCH)
851 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching group mappings.", name);
852 if (r < 0)
853 return r;
c01ff965 854
74d1b7d2 855 return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
c01ff965
LP
856}
857
74d1b7d2
LP
858static int method_map_to_machine_group(sd_bus_message *message, void *userdata, sd_bus_error *error) {
859 _cleanup_free_ char *o = NULL;
860 Manager *m = userdata;
c01ff965 861 Machine *machine;
74d1b7d2 862 gid_t gid, converted;
c01ff965
LP
863 int r;
864
865 r = sd_bus_message_read(message, "u", &gid);
866 if (r < 0)
867 return r;
c077529b 868 if (!gid_is_valid(gid))
c01ff965
LP
869 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
870 if (gid < 0x10000)
871 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
872
74d1b7d2
LP
873 r = manager_find_machine_for_gid(m, gid, &machine, &converted);
874 if (r < 0)
875 return r;
876 if (!r)
877 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
c01ff965 878
74d1b7d2
LP
879 o = machine_bus_path(machine);
880 if (!o)
881 return -ENOMEM;
c01ff965 882
74d1b7d2 883 return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
c01ff965
LP
884}
885
c3350683
LP
886const sd_bus_vtable manager_vtable[] = {
887 SD_BUS_VTABLE_START(0),
bbe17ca1 888
160e3793
LP
889 SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
890 SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
891 SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
bbe17ca1 892
d5e4e60b
A
893 SD_BUS_METHOD_WITH_ARGS("GetMachine",
894 SD_BUS_ARGS("s", name),
895 SD_BUS_RESULT("o", machine),
896 method_get_machine,
897 SD_BUS_VTABLE_UNPRIVILEGED),
898 SD_BUS_METHOD_WITH_ARGS("GetImage",
899 SD_BUS_ARGS("s", name),
900 SD_BUS_RESULT("o", image),
901 method_get_image,
902 SD_BUS_VTABLE_UNPRIVILEGED),
903 SD_BUS_METHOD_WITH_ARGS("GetMachineByPID",
904 SD_BUS_ARGS("u", pid),
905 SD_BUS_RESULT("o", machine),
906 method_get_machine_by_pid,
907 SD_BUS_VTABLE_UNPRIVILEGED),
908 SD_BUS_METHOD_WITH_ARGS("ListMachines",
909 SD_BUS_NO_ARGS,
910 SD_BUS_RESULT("a(ssso)", machines),
911 method_list_machines,
912 SD_BUS_VTABLE_UNPRIVILEGED),
913 SD_BUS_METHOD_WITH_ARGS("ListImages",
914 SD_BUS_NO_ARGS,
915 SD_BUS_RESULT("a(ssbttto)", images),
916 method_list_images,
917 SD_BUS_VTABLE_UNPRIVILEGED),
918 SD_BUS_METHOD_WITH_ARGS("CreateMachine",
919 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "a(sv)", scope_properties),
920 SD_BUS_RESULT("o", path),
790f5162
LP
921 method_create_machine,
922 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
923 SD_BUS_METHOD_WITH_ARGS("CreateMachineWithNetwork",
924 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices, "a(sv)", scope_properties),
925 SD_BUS_RESULT("o", path),
790f5162
LP
926 method_create_machine_with_network,
927 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
928 SD_BUS_METHOD_WITH_ARGS("RegisterMachine",
929 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory),
930 SD_BUS_RESULT("o", path),
790f5162
LP
931 method_register_machine,
932 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
933 SD_BUS_METHOD_WITH_ARGS("RegisterMachineWithNetwork",
934 SD_BUS_ARGS("s", name, "ay", id, "s", service, "s", class, "u", leader, "s", root_directory, "ai", ifindices),
935 SD_BUS_RESULT("o", path),
790f5162
LP
936 method_register_machine_with_network,
937 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
938 SD_BUS_METHOD_WITH_ARGS("UnregisterMachine",
939 SD_BUS_ARGS("s", name),
940 SD_BUS_NO_RESULT,
941 method_unregister_machine,
942 SD_BUS_VTABLE_UNPRIVILEGED),
943 SD_BUS_METHOD_WITH_ARGS("TerminateMachine",
944 SD_BUS_ARGS("s", id),
945 SD_BUS_NO_RESULT,
946 method_terminate_machine,
947 SD_BUS_VTABLE_UNPRIVILEGED),
948 SD_BUS_METHOD_WITH_ARGS("KillMachine",
3ae0e545 949 SD_BUS_ARGS("s", name, "s", whom, "i", signal),
d5e4e60b
A
950 SD_BUS_NO_RESULT,
951 method_kill_machine,
952 SD_BUS_VTABLE_UNPRIVILEGED),
953 SD_BUS_METHOD_WITH_ARGS("GetMachineAddresses",
954 SD_BUS_ARGS("s", name),
955 SD_BUS_RESULT("a(iay)", addresses),
956 method_get_machine_addresses,
957 SD_BUS_VTABLE_UNPRIVILEGED),
1f815bf1
SL
958 SD_BUS_METHOD_WITH_ARGS("GetMachineSSHInfo",
959 SD_BUS_ARGS("s", name),
960 SD_BUS_RESULT("s", ssh_address, "s", ssh_private_key_path),
961 method_get_machine_ssh_info,
962 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
963 SD_BUS_METHOD_WITH_ARGS("GetMachineOSRelease",
964 SD_BUS_ARGS("s", name),
965 SD_BUS_RESULT("a{ss}", fields),
966 method_get_machine_os_release,
967 SD_BUS_VTABLE_UNPRIVILEGED),
968 SD_BUS_METHOD_WITH_ARGS("OpenMachinePTY",
969 SD_BUS_ARGS("s", name),
970 SD_BUS_RESULT("h", pty, "s", pty_path),
971 method_open_machine_pty,
020d6c1d 972 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
973 SD_BUS_METHOD_WITH_ARGS("OpenMachineLogin",
974 SD_BUS_ARGS("s", name),
975 SD_BUS_RESULT("h", pty, "s", pty_path),
976 method_open_machine_login,
977 SD_BUS_VTABLE_UNPRIVILEGED),
978 SD_BUS_METHOD_WITH_ARGS("OpenMachineShell",
979 SD_BUS_ARGS("s", name, "s", user, "s", path, "as", args, "as", environment),
980 SD_BUS_RESULT("h", pty, "s", pty_path),
981 method_open_machine_shell,
982 SD_BUS_VTABLE_UNPRIVILEGED),
983 SD_BUS_METHOD_WITH_ARGS("BindMountMachine",
984 SD_BUS_ARGS("s", name, "s", source, "s", destination, "b", read_only, "b", mkdir),
985 SD_BUS_NO_RESULT,
986 method_bind_mount_machine,
987 SD_BUS_VTABLE_UNPRIVILEGED),
988 SD_BUS_METHOD_WITH_ARGS("CopyFromMachine",
989 SD_BUS_ARGS("s", name, "s", source, "s", destination),
990 SD_BUS_NO_RESULT,
991 method_copy_machine,
992 SD_BUS_VTABLE_UNPRIVILEGED),
993 SD_BUS_METHOD_WITH_ARGS("CopyToMachine",
994 SD_BUS_ARGS("s", name, "s", source, "s", destination),
995 SD_BUS_NO_RESULT,
996 method_copy_machine,
997 SD_BUS_VTABLE_UNPRIVILEGED),
ae03e1a9
AW
998 SD_BUS_METHOD_WITH_ARGS("CopyFromMachineWithFlags",
999 SD_BUS_ARGS("s", name, "s", source, "s", destination, "t", flags),
1000 SD_BUS_NO_RESULT,
1001 method_copy_machine,
1002 SD_BUS_VTABLE_UNPRIVILEGED),
1003 SD_BUS_METHOD_WITH_ARGS("CopyToMachineWithFlags",
1004 SD_BUS_ARGS("s", name, "s", source, "s", destination, "t", flags),
1005 SD_BUS_NO_RESULT,
1006 method_copy_machine,
1007 SD_BUS_VTABLE_UNPRIVILEGED),
d5e4e60b
A
1008 SD_BUS_METHOD_WITH_ARGS("OpenMachineRootDirectory",
1009 SD_BUS_ARGS("s", name),
1010 SD_BUS_RESULT("h", fd),
1011 method_open_machine_root_directory,
1012 SD_BUS_VTABLE_UNPRIVILEGED),
1013 SD_BUS_METHOD_WITH_ARGS("GetMachineUIDShift",
1014 SD_BUS_ARGS("s", name),
1015 SD_BUS_RESULT("u", shift),
1016 method_get_machine_uid_shift,
1017 SD_BUS_VTABLE_UNPRIVILEGED),
1018 SD_BUS_METHOD_WITH_ARGS("RemoveImage",
1019 SD_BUS_ARGS("s", name),
1020 SD_BUS_NO_RESULT,
1021 method_remove_image,
1022 SD_BUS_VTABLE_UNPRIVILEGED),
1023 SD_BUS_METHOD_WITH_ARGS("RenameImage",
1024 SD_BUS_ARGS("s", name, "s", new_name),
1025 SD_BUS_NO_RESULT,
1026 method_rename_image,
1027 SD_BUS_VTABLE_UNPRIVILEGED),
1028 SD_BUS_METHOD_WITH_ARGS("CloneImage",
1029 SD_BUS_ARGS("s", name, "s", new_name, "b", read_only),
1030 SD_BUS_NO_RESULT,
1031 method_clone_image,
1032 SD_BUS_VTABLE_UNPRIVILEGED),
1033 SD_BUS_METHOD_WITH_ARGS("MarkImageReadOnly",
1034 SD_BUS_ARGS("s", name, "b", read_only),
1035 SD_BUS_NO_RESULT,
1036 method_mark_image_read_only,
1037 SD_BUS_VTABLE_UNPRIVILEGED),
1038 SD_BUS_METHOD_WITH_ARGS("GetImageHostname",
1039 SD_BUS_ARGS("s", name),
1040 SD_BUS_RESULT("s", hostname),
1041 method_get_image_hostname,
1042 SD_BUS_VTABLE_UNPRIVILEGED),
1043 SD_BUS_METHOD_WITH_ARGS("GetImageMachineID",
1044 SD_BUS_ARGS("s", name),
1045 SD_BUS_RESULT("ay", id),
1046 method_get_image_machine_id,
1047 SD_BUS_VTABLE_UNPRIVILEGED),
1048 SD_BUS_METHOD_WITH_ARGS("GetImageMachineInfo",
1049 SD_BUS_ARGS("s", name),
1050 SD_BUS_RESULT("a{ss}", machine_info),
1051 method_get_image_machine_info,
1052 SD_BUS_VTABLE_UNPRIVILEGED),
1053 SD_BUS_METHOD_WITH_ARGS("GetImageOSRelease",
1054 SD_BUS_ARGS("s", name),
1055 SD_BUS_RESULT("a{ss}", os_release),
1056 method_get_image_os_release,
1057 SD_BUS_VTABLE_UNPRIVILEGED),
1058 SD_BUS_METHOD_WITH_ARGS("SetPoolLimit",
1059 SD_BUS_ARGS("t", size),
1060 SD_BUS_NO_RESULT,
1061 method_set_pool_limit,
1062 SD_BUS_VTABLE_UNPRIVILEGED),
1063 SD_BUS_METHOD_WITH_ARGS("SetImageLimit",
1064 SD_BUS_ARGS("s", name, "t", size),
1065 SD_BUS_NO_RESULT,
1066 method_set_image_limit,
1067 SD_BUS_VTABLE_UNPRIVILEGED),
1068 SD_BUS_METHOD_WITH_ARGS("CleanPool",
1069 SD_BUS_ARGS("s", mode),
1070 SD_BUS_RESULT("a(st)",images),
1071 method_clean_pool,
1072 SD_BUS_VTABLE_UNPRIVILEGED),
1073 SD_BUS_METHOD_WITH_ARGS("MapFromMachineUser",
1074 SD_BUS_ARGS("s", name, "u", uid_inner),
1075 SD_BUS_RESULT("u", uid_outer),
1076 method_map_from_machine_user,
1077 SD_BUS_VTABLE_UNPRIVILEGED),
1078 SD_BUS_METHOD_WITH_ARGS("MapToMachineUser",
1079 SD_BUS_ARGS("u", uid_outer),
1080 SD_BUS_RESULT("s", machine_name, "o", machine_path, "u", uid_inner),
1081 method_map_to_machine_user,
1082 SD_BUS_VTABLE_UNPRIVILEGED),
1083 SD_BUS_METHOD_WITH_ARGS("MapFromMachineGroup",
1084 SD_BUS_ARGS("s", name, "u", gid_inner),
1085 SD_BUS_RESULT("u", gid_outer),
1086 method_map_from_machine_group,
1087 SD_BUS_VTABLE_UNPRIVILEGED),
1088 SD_BUS_METHOD_WITH_ARGS("MapToMachineGroup",
1089 SD_BUS_ARGS("u", gid_outer),
1090 SD_BUS_RESULT("s", machine_name, "o", machine_path, "u", gid_inner),
1091 method_map_to_machine_group,
1092 SD_BUS_VTABLE_UNPRIVILEGED),
1093
1094 SD_BUS_SIGNAL_WITH_ARGS("MachineNew",
1095 SD_BUS_ARGS("s", machine, "o", path),
1096 0),
1097 SD_BUS_SIGNAL_WITH_ARGS("MachineRemoved",
1098 SD_BUS_ARGS("s", machine, "o", path),
1099 0),
bbe17ca1 1100
c3350683
LP
1101 SD_BUS_VTABLE_END
1102};
1ee306e1 1103
4faa530c
ZJS
1104const BusObjectImplementation manager_object = {
1105 "/org/freedesktop/machine1",
1106 "org.freedesktop.machine1.Manager",
1107 .vtables = BUS_VTABLES(manager_vtable),
1108 .children = BUS_IMPLEMENTATIONS( &machine_object,
1109 &image_object ),
1110};
1111
19070062 1112int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1113 const char *path, *result, *unit;
99534007 1114 Manager *m = ASSERT_PTR(userdata);
c3350683
LP
1115 Machine *machine;
1116 uint32_t id;
1117 int r;
1ee306e1 1118
1ee306e1
LP
1119 assert(message);
1120
c3350683
LP
1121 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1122 if (r < 0) {
ebcf1f97 1123 bus_log_parse_error(r);
65d73cf0 1124 return 0;
c3350683 1125 }
6797c324 1126
85ab917b 1127 machine = hashmap_get(m->machines_by_unit, unit);
c3350683
LP
1128 if (!machine)
1129 return 0;
6797c324 1130
c3350683 1131 if (streq_ptr(path, machine->scope_job)) {
491ac9f2 1132 machine->scope_job = mfree(machine->scope_job);
6797c324 1133
c3350683
LP
1134 if (machine->started) {
1135 if (streq(result, "done"))
1136 machine_send_create_reply(machine, NULL);
1137 else {
4afd3348 1138 _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 1139
ebcf1f97 1140 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 1141
ebcf1f97 1142 machine_send_create_reply(machine, &e);
c3350683 1143 }
49f3fffd
LP
1144 }
1145
1146 machine_save(machine);
1ee306e1
LP
1147 }
1148
c3350683
LP
1149 machine_add_to_gc_queue(machine);
1150 return 0;
1ee306e1
LP
1151}
1152
19070062 1153int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1154 _cleanup_free_ char *unit = NULL;
49f3fffd 1155 const char *path;
99534007 1156 Manager *m = ASSERT_PTR(userdata);
c3350683 1157 Machine *machine;
ebcf1f97 1158 int r;
554604b3 1159
c3350683 1160 assert(message);
554604b3 1161
c3350683
LP
1162 path = sd_bus_message_get_path(message);
1163 if (!path)
554604b3 1164 return 0;
554604b3 1165
ebcf1f97 1166 r = unit_name_from_dbus_path(path, &unit);
e5f5b5b9
LP
1167 if (r == -EINVAL) /* not for a unit */
1168 return 0;
9ed794a3 1169 if (r < 0) {
9b420b3c
LP
1170 log_oom();
1171 return 0;
1172 }
554604b3 1173
85ab917b 1174 machine = hashmap_get(m->machines_by_unit, unit);
9b420b3c
LP
1175 if (!machine)
1176 return 0;
1177
9b420b3c 1178 machine_add_to_gc_queue(machine);
c3350683
LP
1179 return 0;
1180}
554604b3 1181
19070062 1182int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 1183 const char *path, *unit;
99534007 1184 Manager *m = ASSERT_PTR(userdata);
c3350683
LP
1185 Machine *machine;
1186 int r;
554604b3 1187
c3350683 1188 assert(message);
554604b3 1189
c3350683
LP
1190 r = sd_bus_message_read(message, "so", &unit, &path);
1191 if (r < 0) {
ebcf1f97 1192 bus_log_parse_error(r);
9b420b3c 1193 return 0;
554604b3
LP
1194 }
1195
85ab917b 1196 machine = hashmap_get(m->machines_by_unit, unit);
9b420b3c
LP
1197 if (!machine)
1198 return 0;
1199
9b420b3c 1200 machine_add_to_gc_queue(machine);
c3350683
LP
1201 return 0;
1202}
554604b3 1203
19070062 1204int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
99534007 1205 Manager *m = ASSERT_PTR(userdata);
a658cafa 1206 Machine *machine;
c3350683 1207 int b, r;
554604b3 1208
19070062 1209 assert(message);
554604b3 1210
c3350683
LP
1211 r = sd_bus_message_read(message, "b", &b);
1212 if (r < 0) {
ebcf1f97 1213 bus_log_parse_error(r);
65d73cf0 1214 return 0;
554604b3 1215 }
a658cafa
LP
1216 if (b)
1217 return 0;
554604b3 1218
a658cafa
LP
1219 /* systemd finished reloading, let's recheck all our machines */
1220 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 1221
90e74a66 1222 HASHMAP_FOREACH(machine, m->machines)
a658cafa 1223 machine_add_to_gc_queue(machine);
554604b3
LP
1224
1225 return 0;
1226}
1227
b92d0b4c
LP
1228int manager_unref_unit(
1229 Manager *m,
1230 const char *unit,
1231 sd_bus_error *error) {
1232
1233 assert(m);
1234 assert(unit);
1235
14456f76 1236 return bus_call_method(m->bus, bus_systemd_mgr, "UnrefUnit", error, NULL, "s", unit);
b92d0b4c
LP
1237}
1238
c3350683 1239int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
4afd3348 1240 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1ee306e1
LP
1241 int r;
1242
1243 assert(manager);
1244 assert(unit);
1245
14456f76 1246 r = bus_call_method(manager->bus, bus_systemd_mgr, "StopUnit", error, &reply, "ss", unit, "fail");
1ee306e1 1247 if (r < 0) {
955a6329
ZJS
1248 if (sd_bus_error_has_names(error, BUS_ERROR_NO_SUCH_UNIT,
1249 BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
1250
1251 if (job)
1252 *job = NULL;
1253
c3350683 1254 sd_bus_error_free(error);
6797c324
LP
1255 return 0;
1256 }
1257
1ee306e1
LP
1258 return r;
1259 }
1260
1261 if (job) {
1262 const char *j;
1263 char *copy;
1264
c3350683
LP
1265 r = sd_bus_message_read(reply, "o", &j);
1266 if (r < 0)
1267 return r;
1ee306e1
LP
1268
1269 copy = strdup(j);
1270 if (!copy)
1271 return -ENOMEM;
1272
1273 *job = copy;
1274 }
1275
6797c324 1276 return 1;
1ee306e1
LP
1277}
1278
de58a50e 1279int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
1280 assert(manager);
1281 assert(unit);
1282
14456f76 1283 return bus_call_method(manager->bus, bus_systemd_mgr, "KillUnit", error, NULL, "ssi", unit, "all", signo);
1ee306e1
LP
1284}
1285
ca02f658 1286int manager_unit_is_active(Manager *manager, const char *unit, sd_bus_error *reterr_error) {
4afd3348
LP
1287 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1288 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
1ee306e1 1289 _cleanup_free_ char *path = NULL;
1ee306e1 1290 const char *state;
1ee306e1
LP
1291 int r;
1292
1293 assert(manager);
1294 assert(unit);
1295
1ee306e1
LP
1296 path = unit_dbus_path_from_name(unit);
1297 if (!path)
1298 return -ENOMEM;
1299
c3350683 1300 r = sd_bus_get_property(
1ee306e1
LP
1301 manager->bus,
1302 "org.freedesktop.systemd1",
1303 path,
c3350683
LP
1304 "org.freedesktop.systemd1.Unit",
1305 "ActiveState",
1ee306e1 1306 &error,
c3350683
LP
1307 &reply,
1308 "s");
1ee306e1 1309 if (r < 0) {
ac004f4c 1310 if (bus_error_is_connection(&error))
6797c324 1311 return true;
6797c324 1312
955a6329
ZJS
1313 if (sd_bus_error_has_names(&error, BUS_ERROR_NO_SUCH_UNIT,
1314 BUS_ERROR_LOAD_FAILED))
6797c324 1315 return false;
6797c324 1316
ca02f658 1317 sd_bus_error_move(reterr_error, &error);
1ee306e1
LP
1318 return r;
1319 }
1320
c3350683
LP
1321 r = sd_bus_message_read(reply, "s", &state);
1322 if (r < 0)
1ee306e1 1323 return -EINVAL;
1ee306e1 1324
9b420b3c 1325 return !STR_IN_SET(state, "inactive", "failed");
1ee306e1 1326}
bd16acf3 1327
ca02f658 1328int manager_job_is_active(Manager *manager, const char *path, sd_bus_error *reterr_error) {
4afd3348
LP
1329 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1330 _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL;
c3350683 1331 int r;
bd16acf3 1332
c3350683
LP
1333 assert(manager);
1334 assert(path);
bd16acf3 1335
c3350683
LP
1336 r = sd_bus_get_property(
1337 manager->bus,
1338 "org.freedesktop.systemd1",
1339 path,
1340 "org.freedesktop.systemd1.Job",
1341 "State",
1342 &error,
1343 &reply,
1344 "s");
1345 if (r < 0) {
ac004f4c 1346 if (bus_error_is_connection(&error))
c3350683 1347 return true;
bd16acf3 1348
c3350683
LP
1349 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1350 return false;
bd16acf3 1351
ca02f658 1352 sd_bus_error_move(reterr_error, &error);
bd16acf3 1353 return r;
c3350683 1354 }
bd16acf3 1355
c3350683
LP
1356 /* We don't actually care about the state really. The fact
1357 * that we could read the job state is enough for us */
bd16acf3 1358
c3350683 1359 return true;
bd16acf3 1360}