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 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
540 Manager *m = userdata;
549 r = sd_bus_message_read(message, "s", &name);
551 return sd_bus_error_set_errno(error, r);
553 machine = hashmap_get(m->machines, name);
555 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
557 return bus_machine_method_open_login(bus, message, machine, error);
560 const sd_bus_vtable manager_vtable[] = {
561 SD_BUS_VTABLE_START(0),
562 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
563 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
564 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
565 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
566 SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
567 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
568 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
569 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
570 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
571 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
572 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
573 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
574 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
575 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
576 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, 0),
577 SD_BUS_SIGNAL("MachineNew", "so", 0),
578 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
582 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
583 const char *path, *result, *unit;
584 Manager *m = userdata;
593 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
595 bus_log_parse_error(r);
599 machine = hashmap_get(m->machine_units, unit);
603 if (streq_ptr(path, machine->scope_job)) {
604 free(machine->scope_job);
605 machine->scope_job = NULL;
607 if (machine->started) {
608 if (streq(result, "done"))
609 machine_send_create_reply(machine, NULL);
611 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
613 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
615 machine_send_create_reply(machine, &e);
618 machine_save(machine);
621 machine_add_to_gc_queue(machine);
625 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
626 _cleanup_free_ char *unit = NULL;
627 Manager *m = userdata;
636 path = sd_bus_message_get_path(message);
640 r = unit_name_from_dbus_path(path, &unit);
644 machine = hashmap_get(m->machine_units, unit);
646 machine_add_to_gc_queue(machine);
651 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
652 const char *path, *unit;
653 Manager *m = userdata;
661 r = sd_bus_message_read(message, "so", &unit, &path);
663 bus_log_parse_error(r);
667 machine = hashmap_get(m->machine_units, unit);
669 machine_add_to_gc_queue(machine);
674 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
675 Manager *m = userdata;
682 r = sd_bus_message_read(message, "b", &b);
684 bus_log_parse_error(r);
690 /* systemd finished reloading, let's recheck all our machines */
691 log_debug("System manager has been reloaded, rechecking machines...");
693 HASHMAP_FOREACH(machine, m->machines, i)
694 machine_add_to_gc_queue(machine);
699 int manager_start_scope(
704 const char *description,
705 sd_bus_message *more_properties,
709 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
716 r = sd_bus_message_new_method_call(
719 "org.freedesktop.systemd1",
720 "/org/freedesktop/systemd1",
721 "org.freedesktop.systemd1.Manager",
722 "StartTransientUnit");
726 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
730 r = sd_bus_message_open_container(m, 'a', "(sv)");
734 if (!isempty(slice)) {
735 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
740 if (!isempty(description)) {
741 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
746 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
750 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
754 if (more_properties) {
755 r = sd_bus_message_copy(m, more_properties, true);
760 r = sd_bus_message_close_container(m);
764 r = sd_bus_message_append(m, "a(sa(sv))", 0);
768 r = sd_bus_call(manager->bus, m, 0, error, &reply);
776 r = sd_bus_message_read(reply, "o", &j);
790 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
791 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
797 r = sd_bus_call_method(
799 "org.freedesktop.systemd1",
800 "/org/freedesktop/systemd1",
801 "org.freedesktop.systemd1.Manager",
807 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
808 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
813 sd_bus_error_free(error);
824 r = sd_bus_message_read(reply, "o", &j);
838 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
842 return sd_bus_call_method(
844 "org.freedesktop.systemd1",
845 "/org/freedesktop/systemd1",
846 "org.freedesktop.systemd1.Manager",
850 "ssi", unit, "all", signo);
853 int manager_unit_is_active(Manager *manager, const char *unit) {
854 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
855 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
856 _cleanup_free_ char *path = NULL;
863 path = unit_dbus_path_from_name(unit);
867 r = sd_bus_get_property(
869 "org.freedesktop.systemd1",
871 "org.freedesktop.systemd1.Unit",
877 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
878 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
881 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
882 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
888 r = sd_bus_message_read(reply, "s", &state);
892 return !streq(state, "inactive") && !streq(state, "failed");
895 int manager_job_is_active(Manager *manager, const char *path) {
896 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
897 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
903 r = sd_bus_get_property(
905 "org.freedesktop.systemd1",
907 "org.freedesktop.systemd1.Job",
913 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
914 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
917 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
923 /* We don't actually care about the state really. The fact
924 * that we could read the job state is enough for us */
929 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
930 _cleanup_free_ char *unit = NULL;
938 r = cg_pid_get_unit(pid, &unit);
940 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
942 mm = hashmap_get(m->machine_units, unit);
951 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
957 machine = hashmap_get(m->machines, name);
959 machine = machine_new(m, name);