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', "(ssbtto)");
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, "(ssbtto)",
504 image_type_to_string(image->type),
513 r = sd_bus_message_close_container(reply);
517 return sd_bus_send(bus, reply, NULL);
520 static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
521 Manager *m = userdata;
530 r = sd_bus_message_read(message, "s", &name);
532 return sd_bus_error_set_errno(error, r);
534 machine = hashmap_get(m->machines, name);
536 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
538 return bus_machine_method_open_pty(bus, message, machine, error);
541 static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
542 Manager *m = userdata;
551 r = sd_bus_message_read(message, "s", &name);
553 return sd_bus_error_set_errno(error, r);
555 machine = hashmap_get(m->machines, name);
557 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
559 return bus_machine_method_open_login(bus, message, machine, error);
562 const sd_bus_vtable manager_vtable[] = {
563 SD_BUS_VTABLE_START(0),
564 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
565 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
566 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
567 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
568 SD_BUS_METHOD("ListImages", NULL, "a(ssbtto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
569 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
570 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
571 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
572 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
573 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
574 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
575 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
576 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
577 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
578 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
579 SD_BUS_SIGNAL("MachineNew", "so", 0),
580 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
584 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
585 const char *path, *result, *unit;
586 Manager *m = userdata;
595 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
597 bus_log_parse_error(r);
601 machine = hashmap_get(m->machine_units, unit);
605 if (streq_ptr(path, machine->scope_job)) {
606 free(machine->scope_job);
607 machine->scope_job = NULL;
609 if (machine->started) {
610 if (streq(result, "done"))
611 machine_send_create_reply(machine, NULL);
613 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
615 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
617 machine_send_create_reply(machine, &e);
620 machine_save(machine);
623 machine_add_to_gc_queue(machine);
627 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
628 _cleanup_free_ char *unit = NULL;
629 Manager *m = userdata;
638 path = sd_bus_message_get_path(message);
642 r = unit_name_from_dbus_path(path, &unit);
646 machine = hashmap_get(m->machine_units, unit);
648 machine_add_to_gc_queue(machine);
653 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
654 const char *path, *unit;
655 Manager *m = userdata;
663 r = sd_bus_message_read(message, "so", &unit, &path);
665 bus_log_parse_error(r);
669 machine = hashmap_get(m->machine_units, unit);
671 machine_add_to_gc_queue(machine);
676 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
677 Manager *m = userdata;
684 r = sd_bus_message_read(message, "b", &b);
686 bus_log_parse_error(r);
692 /* systemd finished reloading, let's recheck all our machines */
693 log_debug("System manager has been reloaded, rechecking machines...");
695 HASHMAP_FOREACH(machine, m->machines, i)
696 machine_add_to_gc_queue(machine);
701 int manager_start_scope(
706 const char *description,
707 sd_bus_message *more_properties,
711 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
718 r = sd_bus_message_new_method_call(
721 "org.freedesktop.systemd1",
722 "/org/freedesktop/systemd1",
723 "org.freedesktop.systemd1.Manager",
724 "StartTransientUnit");
728 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
732 r = sd_bus_message_open_container(m, 'a', "(sv)");
736 if (!isempty(slice)) {
737 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
742 if (!isempty(description)) {
743 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
748 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
752 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
756 if (more_properties) {
757 r = sd_bus_message_copy(m, more_properties, true);
762 r = sd_bus_message_close_container(m);
766 r = sd_bus_message_append(m, "a(sa(sv))", 0);
770 r = sd_bus_call(manager->bus, m, 0, error, &reply);
778 r = sd_bus_message_read(reply, "o", &j);
792 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
793 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
799 r = sd_bus_call_method(
801 "org.freedesktop.systemd1",
802 "/org/freedesktop/systemd1",
803 "org.freedesktop.systemd1.Manager",
809 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
810 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
815 sd_bus_error_free(error);
826 r = sd_bus_message_read(reply, "o", &j);
840 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
844 return sd_bus_call_method(
846 "org.freedesktop.systemd1",
847 "/org/freedesktop/systemd1",
848 "org.freedesktop.systemd1.Manager",
852 "ssi", unit, "all", signo);
855 int manager_unit_is_active(Manager *manager, const char *unit) {
856 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
857 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
858 _cleanup_free_ char *path = NULL;
865 path = unit_dbus_path_from_name(unit);
869 r = sd_bus_get_property(
871 "org.freedesktop.systemd1",
873 "org.freedesktop.systemd1.Unit",
879 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
880 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
883 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
884 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
890 r = sd_bus_message_read(reply, "s", &state);
894 return !streq(state, "inactive") && !streq(state, "failed");
897 int manager_job_is_active(Manager *manager, const char *path) {
898 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
899 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
905 r = sd_bus_get_property(
907 "org.freedesktop.systemd1",
909 "org.freedesktop.systemd1.Job",
915 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
916 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
919 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
925 /* We don't actually care about the state really. The fact
926 * that we could read the job state is enough for us */
931 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
932 _cleanup_free_ char *unit = NULL;
940 r = cg_pid_get_unit(pid, &unit);
942 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
944 mm = hashmap_get(m->machine_units, unit);
953 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
959 machine = hashmap_get(m->machines, name);
961 machine = machine_new(m, name);