1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2011 Lennart Poettering
8 systemd is free software; you can redistribute it and/or modify it
9 under the terms of the GNU Lesser General Public License as published by
10 the Free Software Foundation; either version 2.1 of the License, or
11 (at your option) any later version.
13 systemd is distributed in the hope that it will be useful, but
14 WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
16 Lesser General Public License for more details.
18 You should have received a copy of the GNU Lesser General Public License
19 along with systemd; If not, see <http://www.gnu.org/licenses/>.
26 #include <sys/capability.h>
29 #include "sd-messages.h"
32 #include "path-util.h"
34 #include "fileio-label.h"
37 #include "unit-name.h"
39 #include "bus-common-errors.h"
40 #include "time-util.h"
41 #include "cgroup-util.h"
45 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
46 _cleanup_free_ char *p = NULL;
47 Manager *m = userdata;
56 r = sd_bus_message_read(message, "s", &name);
60 machine = hashmap_get(m->machines, name);
62 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
64 p = machine_bus_path(machine);
68 return sd_bus_reply_method_return(message, "o", p);
71 static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
72 _cleanup_free_ char *p = NULL;
73 Manager *m = userdata;
81 r = sd_bus_message_read(message, "s", &name);
85 r = image_find(name, NULL);
87 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
91 p = image_bus_path(name);
95 return sd_bus_reply_method_return(message, "o", p);
98 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
99 _cleanup_free_ char *p = NULL;
100 Manager *m = userdata;
101 Machine *machine = NULL;
109 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
111 r = sd_bus_message_read(message, "u", &pid);
116 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
118 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
122 r = sd_bus_creds_get_pid(creds, &pid);
127 r = manager_get_machine_by_pid(m, pid, &machine);
131 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
133 p = machine_bus_path(machine);
137 return sd_bus_reply_method_return(message, "o", p);
140 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
141 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
142 Manager *m = userdata;
151 r = sd_bus_message_new_method_return(message, &reply);
153 return sd_bus_error_set_errno(error, r);
155 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
157 return sd_bus_error_set_errno(error, r);
159 HASHMAP_FOREACH(machine, m->machines, i) {
160 _cleanup_free_ char *p = NULL;
162 p = machine_bus_path(machine);
166 r = sd_bus_message_append(reply, "(ssso)",
168 strempty(machine_class_to_string(machine->class)),
172 return sd_bus_error_set_errno(error, r);
175 r = sd_bus_message_close_container(reply);
177 return sd_bus_error_set_errno(error, r);
179 return sd_bus_send(bus, reply, NULL);
182 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
183 const char *name, *service, *class, *root_directory;
184 const int32_t *netif = NULL;
190 size_t n, n_netif = 0;
197 r = sd_bus_message_read(message, "s", &name);
200 if (!machine_name_is_valid(name))
201 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
203 r = sd_bus_message_read_array(message, 'y', &v, &n);
211 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
213 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
220 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
224 n_netif /= sizeof(int32_t);
226 for (i = 0; i < n_netif; i++) {
228 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
233 c = _MACHINE_CLASS_INVALID;
235 c = machine_class_from_string(class);
237 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
241 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
243 if (!isempty(root_directory) && !path_is_absolute(root_directory))
244 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
247 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
249 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
253 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
255 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
260 if (hashmap_get(manager->machines, name))
261 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
263 r = manager_add_machine(manager, name, &m);
271 if (!isempty(service)) {
272 m->service = strdup(service);
279 if (!isempty(root_directory)) {
280 m->root_directory = strdup(root_directory);
281 if (!m->root_directory) {
288 assert_cc(sizeof(int32_t) == sizeof(int));
289 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
295 m->n_netif = n_netif;
303 machine_add_to_gc_queue(m);
307 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
308 Manager *manager = userdata;
312 r = method_create_or_register_machine(manager, message, read_network, &m, error);
316 r = sd_bus_message_enter_container(message, 'a', "(sv)");
320 r = machine_start(m, message, error);
324 m->create_message = sd_bus_message_ref(message);
328 machine_add_to_gc_queue(m);
332 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
333 return method_create_machine_internal(bus, message, true, userdata, error);
336 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
337 return method_create_machine_internal(bus, message, false, userdata, error);
340 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
341 Manager *manager = userdata;
342 _cleanup_free_ char *p = NULL;
346 r = method_create_or_register_machine(manager, message, read_network, &m, error);
350 r = cg_pid_get_unit(m->leader, &m->unit);
352 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
356 m->registered = true;
358 r = machine_start(m, NULL, error);
362 p = machine_bus_path(m);
368 return sd_bus_reply_method_return(message, "o", p);
371 machine_add_to_gc_queue(m);
375 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
376 return method_register_machine_internal(bus, message, true, userdata, error);
379 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
380 return method_register_machine_internal(bus, message, false, userdata, error);
383 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
384 Manager *m = userdata;
393 r = sd_bus_message_read(message, "s", &name);
395 return sd_bus_error_set_errno(error, r);
397 machine = hashmap_get(m->machines, name);
399 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
401 return bus_machine_method_terminate(bus, message, machine, error);
404 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
405 Manager *m = userdata;
414 r = sd_bus_message_read(message, "s", &name);
416 return sd_bus_error_set_errno(error, r);
418 machine = hashmap_get(m->machines, name);
420 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
422 return bus_machine_method_kill(bus, message, machine, error);
425 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
426 Manager *m = userdata;
435 r = sd_bus_message_read(message, "s", &name);
437 return sd_bus_error_set_errno(error, r);
439 machine = hashmap_get(m->machines, name);
441 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
443 return bus_machine_method_get_addresses(bus, message, machine, error);
446 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
447 Manager *m = userdata;
456 r = sd_bus_message_read(message, "s", &name);
458 return sd_bus_error_set_errno(error, r);
460 machine = hashmap_get(m->machines, name);
462 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
464 return bus_machine_method_get_os_release(bus, message, machine, error);
467 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
469 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
470 Manager *m = userdata;
479 images = hashmap_new(&string_hash_ops);
483 r = image_discover(images);
487 r = sd_bus_message_new_method_return(message, &reply);
491 r = sd_bus_message_open_container(reply, 'a', "(ssbo)");
495 HASHMAP_FOREACH(image, images, i) {
496 _cleanup_free_ char *p = NULL;
498 p = image_bus_path(image->name);
502 r = sd_bus_message_append(reply, "(ssbo)",
504 image_type_to_string(image->type),
511 r = sd_bus_message_close_container(reply);
515 return sd_bus_send(bus, reply, NULL);
518 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
519 Manager *m = userdata;
528 r = sd_bus_message_read(message, "s", &name);
530 return sd_bus_error_set_errno(error, r);
532 machine = hashmap_get(m->machines, name);
534 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
536 return bus_machine_method_open_pty(bus, message, machine, error);
539 const sd_bus_vtable manager_vtable[] = {
540 SD_BUS_VTABLE_START(0),
541 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
542 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
543 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
544 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
545 SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
546 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
547 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
548 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
549 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
550 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
551 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
552 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
553 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
554 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
555 SD_BUS_SIGNAL("MachineNew", "so", 0),
556 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
560 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
561 const char *path, *result, *unit;
562 Manager *m = userdata;
571 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
573 bus_log_parse_error(r);
577 machine = hashmap_get(m->machine_units, unit);
581 if (streq_ptr(path, machine->scope_job)) {
582 free(machine->scope_job);
583 machine->scope_job = NULL;
585 if (machine->started) {
586 if (streq(result, "done"))
587 machine_send_create_reply(machine, NULL);
589 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
591 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
593 machine_send_create_reply(machine, &e);
596 machine_save(machine);
599 machine_add_to_gc_queue(machine);
603 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
604 _cleanup_free_ char *unit = NULL;
605 Manager *m = userdata;
614 path = sd_bus_message_get_path(message);
618 r = unit_name_from_dbus_path(path, &unit);
622 machine = hashmap_get(m->machine_units, unit);
624 machine_add_to_gc_queue(machine);
629 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
630 const char *path, *unit;
631 Manager *m = userdata;
639 r = sd_bus_message_read(message, "so", &unit, &path);
641 bus_log_parse_error(r);
645 machine = hashmap_get(m->machine_units, unit);
647 machine_add_to_gc_queue(machine);
652 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
653 Manager *m = userdata;
660 r = sd_bus_message_read(message, "b", &b);
662 bus_log_parse_error(r);
668 /* systemd finished reloading, let's recheck all our machines */
669 log_debug("System manager has been reloaded, rechecking machines...");
671 HASHMAP_FOREACH(machine, m->machines, i)
672 machine_add_to_gc_queue(machine);
677 int manager_start_scope(
682 const char *description,
683 sd_bus_message *more_properties,
687 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
694 r = sd_bus_message_new_method_call(
697 "org.freedesktop.systemd1",
698 "/org/freedesktop/systemd1",
699 "org.freedesktop.systemd1.Manager",
700 "StartTransientUnit");
704 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
708 r = sd_bus_message_open_container(m, 'a', "(sv)");
712 if (!isempty(slice)) {
713 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
718 if (!isempty(description)) {
719 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
724 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
728 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
732 if (more_properties) {
733 r = sd_bus_message_copy(m, more_properties, true);
738 r = sd_bus_message_close_container(m);
742 r = sd_bus_message_append(m, "a(sa(sv))", 0);
746 r = sd_bus_call(manager->bus, m, 0, error, &reply);
754 r = sd_bus_message_read(reply, "o", &j);
768 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
769 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
775 r = sd_bus_call_method(
777 "org.freedesktop.systemd1",
778 "/org/freedesktop/systemd1",
779 "org.freedesktop.systemd1.Manager",
785 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
786 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
791 sd_bus_error_free(error);
802 r = sd_bus_message_read(reply, "o", &j);
816 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
820 return sd_bus_call_method(
822 "org.freedesktop.systemd1",
823 "/org/freedesktop/systemd1",
824 "org.freedesktop.systemd1.Manager",
828 "ssi", unit, "all", signo);
831 int manager_unit_is_active(Manager *manager, const char *unit) {
832 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
833 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
834 _cleanup_free_ char *path = NULL;
841 path = unit_dbus_path_from_name(unit);
845 r = sd_bus_get_property(
847 "org.freedesktop.systemd1",
849 "org.freedesktop.systemd1.Unit",
855 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
856 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
859 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
860 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
866 r = sd_bus_message_read(reply, "s", &state);
870 return !streq(state, "inactive") && !streq(state, "failed");
873 int manager_job_is_active(Manager *manager, const char *path) {
874 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
875 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
881 r = sd_bus_get_property(
883 "org.freedesktop.systemd1",
885 "org.freedesktop.systemd1.Job",
891 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
892 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
895 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
901 /* We don't actually care about the state really. The fact
902 * that we could read the job state is enough for us */
907 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
908 _cleanup_free_ char *unit = NULL;
916 r = cg_pid_get_unit(pid, &unit);
918 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
920 mm = hashmap_get(m->machine_units, unit);
929 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
935 machine = hashmap_get(m->machines, name);
937 machine = machine_new(m, name);