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/>.
28 #include "sd-messages.h"
31 #include "path-util.h"
33 #include "fileio-label.h"
36 #include "unit-name.h"
38 #include "bus-common-errors.h"
39 #include "time-util.h"
40 #include "cgroup-util.h"
44 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
45 _cleanup_free_ char *p = NULL;
46 Manager *m = userdata;
55 r = sd_bus_message_read(message, "s", &name);
59 machine = hashmap_get(m->machines, name);
61 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
63 p = machine_bus_path(machine);
67 return sd_bus_reply_method_return(message, "o", p);
70 static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
71 _cleanup_free_ char *p = NULL;
72 Manager *m = userdata;
80 r = sd_bus_message_read(message, "s", &name);
84 r = image_find(name, NULL);
86 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
90 p = image_bus_path(name);
94 return sd_bus_reply_method_return(message, "o", p);
97 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
98 _cleanup_free_ char *p = NULL;
99 Manager *m = userdata;
100 Machine *machine = NULL;
108 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
110 r = sd_bus_message_read(message, "u", &pid);
115 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
117 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
121 r = sd_bus_creds_get_pid(creds, &pid);
126 r = manager_get_machine_by_pid(m, pid, &machine);
130 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
132 p = machine_bus_path(machine);
136 return sd_bus_reply_method_return(message, "o", p);
139 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
140 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
141 Manager *m = userdata;
150 r = sd_bus_message_new_method_return(message, &reply);
152 return sd_bus_error_set_errno(error, r);
154 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
156 return sd_bus_error_set_errno(error, r);
158 HASHMAP_FOREACH(machine, m->machines, i) {
159 _cleanup_free_ char *p = NULL;
161 p = machine_bus_path(machine);
165 r = sd_bus_message_append(reply, "(ssso)",
167 strempty(machine_class_to_string(machine->class)),
171 return sd_bus_error_set_errno(error, r);
174 r = sd_bus_message_close_container(reply);
176 return sd_bus_error_set_errno(error, r);
178 return sd_bus_send(bus, reply, NULL);
181 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
182 const char *name, *service, *class, *root_directory;
183 const int32_t *netif = NULL;
189 size_t n, n_netif = 0;
196 r = sd_bus_message_read(message, "s", &name);
199 if (!machine_name_is_valid(name))
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
202 r = sd_bus_message_read_array(message, 'y', &v, &n);
210 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
212 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
219 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
223 n_netif /= sizeof(int32_t);
225 for (i = 0; i < n_netif; i++) {
227 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
232 c = _MACHINE_CLASS_INVALID;
234 c = machine_class_from_string(class);
236 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
240 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
242 if (!isempty(root_directory) && !path_is_absolute(root_directory))
243 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
246 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
248 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
252 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
254 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
259 if (hashmap_get(manager->machines, name))
260 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
262 r = manager_add_machine(manager, name, &m);
270 if (!isempty(service)) {
271 m->service = strdup(service);
278 if (!isempty(root_directory)) {
279 m->root_directory = strdup(root_directory);
280 if (!m->root_directory) {
287 assert_cc(sizeof(int32_t) == sizeof(int));
288 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
294 m->n_netif = n_netif;
302 machine_add_to_gc_queue(m);
306 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
307 Manager *manager = userdata;
311 r = method_create_or_register_machine(manager, message, read_network, &m, error);
315 r = sd_bus_message_enter_container(message, 'a', "(sv)");
319 r = machine_start(m, message, error);
323 m->create_message = sd_bus_message_ref(message);
327 machine_add_to_gc_queue(m);
331 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
332 return method_create_machine_internal(bus, message, true, userdata, error);
335 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
336 return method_create_machine_internal(bus, message, false, userdata, error);
339 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
340 Manager *manager = userdata;
341 _cleanup_free_ char *p = NULL;
345 r = method_create_or_register_machine(manager, message, read_network, &m, error);
349 r = cg_pid_get_unit(m->leader, &m->unit);
351 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
355 m->registered = true;
357 r = machine_start(m, NULL, error);
361 p = machine_bus_path(m);
367 return sd_bus_reply_method_return(message, "o", p);
370 machine_add_to_gc_queue(m);
374 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
375 return method_register_machine_internal(bus, message, true, userdata, error);
378 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
379 return method_register_machine_internal(bus, message, false, userdata, error);
382 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
383 Manager *m = userdata;
392 r = sd_bus_message_read(message, "s", &name);
394 return sd_bus_error_set_errno(error, r);
396 machine = hashmap_get(m->machines, name);
398 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
400 return bus_machine_method_terminate(bus, message, machine, error);
403 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
404 Manager *m = userdata;
413 r = sd_bus_message_read(message, "s", &name);
415 return sd_bus_error_set_errno(error, r);
417 machine = hashmap_get(m->machines, name);
419 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
421 return bus_machine_method_kill(bus, message, machine, error);
424 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
425 Manager *m = userdata;
434 r = sd_bus_message_read(message, "s", &name);
436 return sd_bus_error_set_errno(error, r);
438 machine = hashmap_get(m->machines, name);
440 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
442 return bus_machine_method_get_addresses(bus, message, machine, error);
445 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
446 Manager *m = userdata;
455 r = sd_bus_message_read(message, "s", &name);
457 return sd_bus_error_set_errno(error, r);
459 machine = hashmap_get(m->machines, name);
461 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
463 return bus_machine_method_get_os_release(bus, message, machine, error);
466 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
467 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
468 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
469 Manager *m = userdata;
478 images = hashmap_new(&string_hash_ops);
482 r = image_discover(images);
486 r = sd_bus_message_new_method_return(message, &reply);
490 r = sd_bus_message_open_container(reply, 'a', "(ssbtto)");
494 HASHMAP_FOREACH(image, images, i) {
495 _cleanup_free_ char *p = NULL;
497 p = image_bus_path(image->name);
501 r = sd_bus_message_append(reply, "(ssbtto)",
503 image_type_to_string(image->type),
512 r = sd_bus_message_close_container(reply);
516 return sd_bus_send(bus, reply, NULL);
519 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
520 Manager *m = userdata;
529 r = sd_bus_message_read(message, "s", &name);
531 return sd_bus_error_set_errno(error, r);
533 machine = hashmap_get(m->machines, name);
535 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
537 return bus_machine_method_open_pty(bus, message, machine, error);
540 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
541 Manager *m = userdata;
550 r = sd_bus_message_read(message, "s", &name);
552 return sd_bus_error_set_errno(error, r);
554 machine = hashmap_get(m->machines, name);
556 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
558 return bus_machine_method_open_login(bus, message, machine, error);
561 const sd_bus_vtable manager_vtable[] = {
562 SD_BUS_VTABLE_START(0),
563 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
564 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
565 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
566 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
567 SD_BUS_METHOD("ListImages", NULL, "a(ssbtto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
568 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
569 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
570 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
571 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
572 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
573 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
574 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
575 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
576 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
577 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
578 SD_BUS_SIGNAL("MachineNew", "so", 0),
579 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
583 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
584 const char *path, *result, *unit;
585 Manager *m = userdata;
594 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
596 bus_log_parse_error(r);
600 machine = hashmap_get(m->machine_units, unit);
604 if (streq_ptr(path, machine->scope_job)) {
605 free(machine->scope_job);
606 machine->scope_job = NULL;
608 if (machine->started) {
609 if (streq(result, "done"))
610 machine_send_create_reply(machine, NULL);
612 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
614 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
616 machine_send_create_reply(machine, &e);
619 machine_save(machine);
622 machine_add_to_gc_queue(machine);
626 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
627 _cleanup_free_ char *unit = NULL;
628 Manager *m = userdata;
637 path = sd_bus_message_get_path(message);
641 r = unit_name_from_dbus_path(path, &unit);
645 machine = hashmap_get(m->machine_units, unit);
647 machine_add_to_gc_queue(machine);
652 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
653 const char *path, *unit;
654 Manager *m = userdata;
662 r = sd_bus_message_read(message, "so", &unit, &path);
664 bus_log_parse_error(r);
668 machine = hashmap_get(m->machine_units, unit);
670 machine_add_to_gc_queue(machine);
675 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
676 Manager *m = userdata;
683 r = sd_bus_message_read(message, "b", &b);
685 bus_log_parse_error(r);
691 /* systemd finished reloading, let's recheck all our machines */
692 log_debug("System manager has been reloaded, rechecking machines...");
694 HASHMAP_FOREACH(machine, m->machines, i)
695 machine_add_to_gc_queue(machine);
700 int manager_start_scope(
705 const char *description,
706 sd_bus_message *more_properties,
710 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
717 r = sd_bus_message_new_method_call(
720 "org.freedesktop.systemd1",
721 "/org/freedesktop/systemd1",
722 "org.freedesktop.systemd1.Manager",
723 "StartTransientUnit");
727 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
731 r = sd_bus_message_open_container(m, 'a', "(sv)");
735 if (!isempty(slice)) {
736 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
741 if (!isempty(description)) {
742 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
747 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
751 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
755 if (more_properties) {
756 r = sd_bus_message_copy(m, more_properties, true);
761 r = sd_bus_message_close_container(m);
765 r = sd_bus_message_append(m, "a(sa(sv))", 0);
769 r = sd_bus_call(manager->bus, m, 0, error, &reply);
777 r = sd_bus_message_read(reply, "o", &j);
791 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
792 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
798 r = sd_bus_call_method(
800 "org.freedesktop.systemd1",
801 "/org/freedesktop/systemd1",
802 "org.freedesktop.systemd1.Manager",
808 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
809 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
814 sd_bus_error_free(error);
825 r = sd_bus_message_read(reply, "o", &j);
839 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
843 return sd_bus_call_method(
845 "org.freedesktop.systemd1",
846 "/org/freedesktop/systemd1",
847 "org.freedesktop.systemd1.Manager",
851 "ssi", unit, "all", signo);
854 int manager_unit_is_active(Manager *manager, const char *unit) {
855 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
856 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
857 _cleanup_free_ char *path = NULL;
864 path = unit_dbus_path_from_name(unit);
868 r = sd_bus_get_property(
870 "org.freedesktop.systemd1",
872 "org.freedesktop.systemd1.Unit",
878 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
879 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
882 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
883 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
889 r = sd_bus_message_read(reply, "s", &state);
893 return !streq(state, "inactive") && !streq(state, "failed");
896 int manager_job_is_active(Manager *manager, const char *path) {
897 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
898 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
904 r = sd_bus_get_property(
906 "org.freedesktop.systemd1",
908 "org.freedesktop.systemd1.Job",
914 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
915 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
918 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
924 /* We don't actually care about the state really. The fact
925 * that we could read the job state is enough for us */
930 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
931 _cleanup_free_ char *unit = NULL;
939 r = cg_pid_get_unit(pid, &unit);
941 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
943 mm = hashmap_get(m->machine_units, unit);
952 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
958 machine = hashmap_get(m->machines, name);
960 machine = machine_new(m, name);