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