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