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_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
72 _cleanup_free_ char *p = NULL;
73 Manager *m = userdata;
74 Machine *machine = NULL;
82 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
84 r = sd_bus_message_read(message, "u", &pid);
89 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
91 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
95 r = sd_bus_creds_get_pid(creds, &pid);
100 r = manager_get_machine_by_pid(m, pid, &machine);
104 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
106 p = machine_bus_path(machine);
110 return sd_bus_reply_method_return(message, "o", p);
113 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
114 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
115 Manager *m = userdata;
124 r = sd_bus_message_new_method_return(message, &reply);
126 return sd_bus_error_set_errno(error, r);
128 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
130 return sd_bus_error_set_errno(error, r);
132 HASHMAP_FOREACH(machine, m->machines, i) {
133 _cleanup_free_ char *p = NULL;
135 p = machine_bus_path(machine);
139 r = sd_bus_message_append(reply, "(ssso)",
141 strempty(machine_class_to_string(machine->class)),
145 return sd_bus_error_set_errno(error, r);
148 r = sd_bus_message_close_container(reply);
150 return sd_bus_error_set_errno(error, r);
152 return sd_bus_send(bus, reply, NULL);
155 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
156 const char *name, *service, *class, *root_directory;
157 const int32_t *netif = NULL;
163 size_t n, n_netif = 0;
170 r = sd_bus_message_read(message, "s", &name);
173 if (!machine_name_is_valid(name))
174 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
176 r = sd_bus_message_read_array(message, 'y', &v, &n);
184 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
186 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
193 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
197 n_netif /= sizeof(int32_t);
199 for (i = 0; i < n_netif; i++) {
201 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
206 c = _MACHINE_CLASS_INVALID;
208 c = machine_class_from_string(class);
210 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
214 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
216 if (!isempty(root_directory) && !path_is_absolute(root_directory))
217 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
220 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
222 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
226 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
228 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
233 if (hashmap_get(manager->machines, name))
234 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
236 r = manager_add_machine(manager, name, &m);
244 if (!isempty(service)) {
245 m->service = strdup(service);
252 if (!isempty(root_directory)) {
253 m->root_directory = strdup(root_directory);
254 if (!m->root_directory) {
261 assert_cc(sizeof(int32_t) == sizeof(int));
262 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
268 m->n_netif = n_netif;
276 machine_add_to_gc_queue(m);
280 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
281 Manager *manager = userdata;
285 r = method_create_or_register_machine(manager, message, read_network, &m, error);
289 r = sd_bus_message_enter_container(message, 'a', "(sv)");
293 r = machine_start(m, message, error);
297 m->create_message = sd_bus_message_ref(message);
301 machine_add_to_gc_queue(m);
305 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
306 return method_create_machine_internal(bus, message, true, userdata, error);
309 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
310 return method_create_machine_internal(bus, message, false, userdata, error);
313 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
314 Manager *manager = userdata;
315 _cleanup_free_ char *p = NULL;
319 r = method_create_or_register_machine(manager, message, read_network, &m, error);
323 r = cg_pid_get_unit(m->leader, &m->unit);
325 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
329 m->registered = true;
331 r = machine_start(m, NULL, error);
335 p = machine_bus_path(m);
341 return sd_bus_reply_method_return(message, "o", p);
344 machine_add_to_gc_queue(m);
348 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
349 return method_register_machine_internal(bus, message, true, userdata, error);
352 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
353 return method_register_machine_internal(bus, message, false, userdata, error);
356 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
357 Manager *m = userdata;
366 r = sd_bus_message_read(message, "s", &name);
368 return sd_bus_error_set_errno(error, r);
370 machine = hashmap_get(m->machines, name);
372 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
374 return bus_machine_method_terminate(bus, message, machine, error);
377 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
378 Manager *m = userdata;
387 r = sd_bus_message_read(message, "s", &name);
389 return sd_bus_error_set_errno(error, r);
391 machine = hashmap_get(m->machines, name);
393 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
395 return bus_machine_method_kill(bus, message, machine, error);
398 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
399 Manager *m = userdata;
408 r = sd_bus_message_read(message, "s", &name);
410 return sd_bus_error_set_errno(error, r);
412 machine = hashmap_get(m->machines, name);
414 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
416 return bus_machine_method_get_addresses(bus, message, machine, error);
419 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
420 Manager *m = userdata;
429 r = sd_bus_message_read(message, "s", &name);
431 return sd_bus_error_set_errno(error, r);
433 machine = hashmap_get(m->machines, name);
435 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
437 return bus_machine_method_get_os_release(bus, message, machine, error);
440 static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
441 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
442 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
443 Manager *m = userdata;
452 images = hashmap_new(&string_hash_ops);
456 r = image_discover(images);
460 r = sd_bus_message_new_method_return(message, &reply);
464 r = sd_bus_message_open_container(reply, 'a', "(ssbo)");
468 HASHMAP_FOREACH(image, images, i) {
469 _cleanup_free_ char *p = NULL;
471 p = image_bus_path(image->name);
475 r = sd_bus_message_append(reply, "(ssbo)",
477 image_type_to_string(image->type),
484 r = sd_bus_message_close_container(reply);
488 return sd_bus_send(bus, reply, NULL);
491 const sd_bus_vtable manager_vtable[] = {
492 SD_BUS_VTABLE_START(0),
493 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
494 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
495 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
496 SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
497 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
498 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
499 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
500 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
501 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
502 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
503 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
504 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
505 SD_BUS_SIGNAL("MachineNew", "so", 0),
506 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
510 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
511 const char *path, *result, *unit;
512 Manager *m = userdata;
521 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
523 bus_log_parse_error(r);
527 machine = hashmap_get(m->machine_units, unit);
531 if (streq_ptr(path, machine->scope_job)) {
532 free(machine->scope_job);
533 machine->scope_job = NULL;
535 if (machine->started) {
536 if (streq(result, "done"))
537 machine_send_create_reply(machine, NULL);
539 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
541 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
543 machine_send_create_reply(machine, &e);
546 machine_save(machine);
549 machine_add_to_gc_queue(machine);
553 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
554 _cleanup_free_ char *unit = NULL;
555 Manager *m = userdata;
564 path = sd_bus_message_get_path(message);
568 r = unit_name_from_dbus_path(path, &unit);
572 machine = hashmap_get(m->machine_units, unit);
574 machine_add_to_gc_queue(machine);
579 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
580 const char *path, *unit;
581 Manager *m = userdata;
589 r = sd_bus_message_read(message, "so", &unit, &path);
591 bus_log_parse_error(r);
595 machine = hashmap_get(m->machine_units, unit);
597 machine_add_to_gc_queue(machine);
602 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
603 Manager *m = userdata;
610 r = sd_bus_message_read(message, "b", &b);
612 bus_log_parse_error(r);
618 /* systemd finished reloading, let's recheck all our machines */
619 log_debug("System manager has been reloaded, rechecking machines...");
621 HASHMAP_FOREACH(machine, m->machines, i)
622 machine_add_to_gc_queue(machine);
627 int manager_start_scope(
632 const char *description,
633 sd_bus_message *more_properties,
637 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
644 r = sd_bus_message_new_method_call(
647 "org.freedesktop.systemd1",
648 "/org/freedesktop/systemd1",
649 "org.freedesktop.systemd1.Manager",
650 "StartTransientUnit");
654 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
658 r = sd_bus_message_open_container(m, 'a', "(sv)");
662 if (!isempty(slice)) {
663 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
668 if (!isempty(description)) {
669 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
674 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
678 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
682 if (more_properties) {
683 r = sd_bus_message_copy(m, more_properties, true);
688 r = sd_bus_message_close_container(m);
692 r = sd_bus_message_append(m, "a(sa(sv))", 0);
696 r = sd_bus_call(manager->bus, m, 0, error, &reply);
704 r = sd_bus_message_read(reply, "o", &j);
718 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
719 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
725 r = sd_bus_call_method(
727 "org.freedesktop.systemd1",
728 "/org/freedesktop/systemd1",
729 "org.freedesktop.systemd1.Manager",
735 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
736 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
741 sd_bus_error_free(error);
752 r = sd_bus_message_read(reply, "o", &j);
766 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
770 return sd_bus_call_method(
772 "org.freedesktop.systemd1",
773 "/org/freedesktop/systemd1",
774 "org.freedesktop.systemd1.Manager",
778 "ssi", unit, "all", signo);
781 int manager_unit_is_active(Manager *manager, const char *unit) {
782 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
783 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
784 _cleanup_free_ char *path = NULL;
791 path = unit_dbus_path_from_name(unit);
795 r = sd_bus_get_property(
797 "org.freedesktop.systemd1",
799 "org.freedesktop.systemd1.Unit",
805 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
806 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
809 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
810 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
816 r = sd_bus_message_read(reply, "s", &state);
820 return !streq(state, "inactive") && !streq(state, "failed");
823 int manager_job_is_active(Manager *manager, const char *path) {
824 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
825 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
831 r = sd_bus_get_property(
833 "org.freedesktop.systemd1",
835 "org.freedesktop.systemd1.Job",
841 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
842 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
845 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
851 /* We don't actually care about the state really. The fact
852 * that we could read the job state is enough for us */
857 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
858 _cleanup_free_ char *unit = NULL;
866 r = cg_pid_get_unit(pid, &unit);
868 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
870 mm = hashmap_get(m->machine_units, unit);
879 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
885 machine = hashmap_get(m->machines, name);
887 machine = machine_new(m, name);