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