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 const sd_bus_vtable manager_vtable[] = {
519 SD_BUS_VTABLE_START(0),
520 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
521 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
522 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
523 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
524 SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
525 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
526 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
527 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
528 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
529 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
530 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
531 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
532 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
533 SD_BUS_SIGNAL("MachineNew", "so", 0),
534 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
538 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
539 const char *path, *result, *unit;
540 Manager *m = userdata;
549 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
551 bus_log_parse_error(r);
555 machine = hashmap_get(m->machine_units, unit);
559 if (streq_ptr(path, machine->scope_job)) {
560 free(machine->scope_job);
561 machine->scope_job = NULL;
563 if (machine->started) {
564 if (streq(result, "done"))
565 machine_send_create_reply(machine, NULL);
567 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
569 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
571 machine_send_create_reply(machine, &e);
574 machine_save(machine);
577 machine_add_to_gc_queue(machine);
581 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
582 _cleanup_free_ char *unit = NULL;
583 Manager *m = userdata;
592 path = sd_bus_message_get_path(message);
596 r = unit_name_from_dbus_path(path, &unit);
600 machine = hashmap_get(m->machine_units, unit);
602 machine_add_to_gc_queue(machine);
607 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
608 const char *path, *unit;
609 Manager *m = userdata;
617 r = sd_bus_message_read(message, "so", &unit, &path);
619 bus_log_parse_error(r);
623 machine = hashmap_get(m->machine_units, unit);
625 machine_add_to_gc_queue(machine);
630 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
631 Manager *m = userdata;
638 r = sd_bus_message_read(message, "b", &b);
640 bus_log_parse_error(r);
646 /* systemd finished reloading, let's recheck all our machines */
647 log_debug("System manager has been reloaded, rechecking machines...");
649 HASHMAP_FOREACH(machine, m->machines, i)
650 machine_add_to_gc_queue(machine);
655 int manager_start_scope(
660 const char *description,
661 sd_bus_message *more_properties,
665 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
672 r = sd_bus_message_new_method_call(
675 "org.freedesktop.systemd1",
676 "/org/freedesktop/systemd1",
677 "org.freedesktop.systemd1.Manager",
678 "StartTransientUnit");
682 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
686 r = sd_bus_message_open_container(m, 'a', "(sv)");
690 if (!isempty(slice)) {
691 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
696 if (!isempty(description)) {
697 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
702 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
706 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
710 if (more_properties) {
711 r = sd_bus_message_copy(m, more_properties, true);
716 r = sd_bus_message_close_container(m);
720 r = sd_bus_message_append(m, "a(sa(sv))", 0);
724 r = sd_bus_call(manager->bus, m, 0, error, &reply);
732 r = sd_bus_message_read(reply, "o", &j);
746 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
747 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
753 r = sd_bus_call_method(
755 "org.freedesktop.systemd1",
756 "/org/freedesktop/systemd1",
757 "org.freedesktop.systemd1.Manager",
763 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
764 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
769 sd_bus_error_free(error);
780 r = sd_bus_message_read(reply, "o", &j);
794 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
798 return sd_bus_call_method(
800 "org.freedesktop.systemd1",
801 "/org/freedesktop/systemd1",
802 "org.freedesktop.systemd1.Manager",
806 "ssi", unit, "all", signo);
809 int manager_unit_is_active(Manager *manager, const char *unit) {
810 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
811 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
812 _cleanup_free_ char *path = NULL;
819 path = unit_dbus_path_from_name(unit);
823 r = sd_bus_get_property(
825 "org.freedesktop.systemd1",
827 "org.freedesktop.systemd1.Unit",
833 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
834 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
837 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
838 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
844 r = sd_bus_message_read(reply, "s", &state);
848 return !streq(state, "inactive") && !streq(state, "failed");
851 int manager_job_is_active(Manager *manager, const char *path) {
852 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
853 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
859 r = sd_bus_get_property(
861 "org.freedesktop.systemd1",
863 "org.freedesktop.systemd1.Job",
869 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
870 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
873 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
879 /* We don't actually care about the state really. The fact
880 * that we could read the job state is enough for us */
885 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
886 _cleanup_free_ char *unit = NULL;
894 r = cg_pid_get_unit(pid, &unit);
896 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
898 mm = hashmap_get(m->machine_units, unit);
907 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
913 machine = hashmap_get(m->machines, name);
915 machine = machine_new(m, name);