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-errors.h"
40 #include "time-util.h"
41 #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_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
71 _cleanup_free_ char *p = NULL;
72 Manager *m = userdata;
73 Machine *machine = NULL;
81 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
83 r = sd_bus_message_read(message, "u", &pid);
88 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
90 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
94 r = sd_bus_creds_get_pid(creds, &pid);
99 r = manager_get_machine_by_pid(m, pid, &machine);
103 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
105 p = machine_bus_path(machine);
109 return sd_bus_reply_method_return(message, "o", p);
112 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
113 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
114 Manager *m = userdata;
123 r = sd_bus_message_new_method_return(message, &reply);
125 return sd_bus_error_set_errno(error, r);
127 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
129 return sd_bus_error_set_errno(error, r);
131 HASHMAP_FOREACH(machine, m->machines, i) {
132 _cleanup_free_ char *p = NULL;
134 p = machine_bus_path(machine);
138 r = sd_bus_message_append(reply, "(ssso)",
140 strempty(machine_class_to_string(machine->class)),
144 return sd_bus_error_set_errno(error, r);
147 r = sd_bus_message_close_container(reply);
149 return sd_bus_error_set_errno(error, r);
151 return sd_bus_send(bus, reply, NULL);
154 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) {
155 const char *name, *service, *class, *root_directory;
168 r = sd_bus_message_read(message, "s", &name);
171 if (!machine_name_is_valid(name))
172 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
174 r = sd_bus_message_read_array(message, 'y', &v, &n);
182 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
184 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
189 c = _MACHINE_CLASS_INVALID;
191 c = machine_class_from_string(class);
193 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
197 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
199 if (!isempty(root_directory) && !path_is_absolute(root_directory))
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
203 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
205 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
209 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
211 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
216 if (hashmap_get(manager->machines, name))
217 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
219 r = manager_add_machine(manager, name, &m);
227 if (!isempty(service)) {
228 m->service = strdup(service);
235 if (!isempty(root_directory)) {
236 m->root_directory = strdup(root_directory);
237 if (!m->root_directory) {
248 machine_add_to_gc_queue(m);
252 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
253 Manager *manager = userdata;
257 r = method_create_or_register_machine(manager, message, &m, error);
261 r = sd_bus_message_enter_container(message, 'a', "(sv)");
265 r = machine_start(m, message, error);
269 m->create_message = sd_bus_message_ref(message);
273 machine_add_to_gc_queue(m);
277 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
278 Manager *manager = userdata;
279 _cleanup_free_ char *p = NULL;
283 r = method_create_or_register_machine(manager, message, &m, error);
287 r = cg_pid_get_unit(m->leader, &m->unit);
289 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
293 m->registered = true;
295 r = machine_start(m, NULL, error);
299 p = machine_bus_path(m);
305 return sd_bus_reply_method_return(message, "o", p);
308 machine_add_to_gc_queue(m);
312 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
313 Manager *m = userdata;
322 r = sd_bus_message_read(message, "s", &name);
324 return sd_bus_error_set_errno(error, r);
326 machine = hashmap_get(m->machines, name);
328 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
330 return bus_machine_method_terminate(bus, message, machine, error);
333 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
334 Manager *m = userdata;
343 r = sd_bus_message_read(message, "s", &name);
345 return sd_bus_error_set_errno(error, r);
347 machine = hashmap_get(m->machines, name);
349 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
351 return bus_machine_method_kill(bus, message, machine, error);
354 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
355 Manager *m = userdata;
364 r = sd_bus_message_read(message, "s", &name);
366 return sd_bus_error_set_errno(error, r);
368 machine = hashmap_get(m->machines, name);
370 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
372 return bus_machine_method_get_addresses(bus, message, machine, error);
375 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
376 Manager *m = userdata;
385 r = sd_bus_message_read(message, "s", &name);
387 return sd_bus_error_set_errno(error, r);
389 machine = hashmap_get(m->machines, name);
391 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
393 return bus_machine_method_get_os_release(bus, message, machine, error);
396 const sd_bus_vtable manager_vtable[] = {
397 SD_BUS_VTABLE_START(0),
398 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
399 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
400 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
401 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
402 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
403 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
404 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
405 SD_BUS_METHOD("GetMachineAddresses", "s", "a(yay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
406 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
407 SD_BUS_SIGNAL("MachineNew", "so", 0),
408 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
412 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
413 const char *path, *result, *unit;
414 Manager *m = userdata;
423 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
425 bus_log_parse_error(r);
429 machine = hashmap_get(m->machine_units, unit);
433 if (streq_ptr(path, machine->scope_job)) {
434 free(machine->scope_job);
435 machine->scope_job = NULL;
437 if (machine->started) {
438 if (streq(result, "done"))
439 machine_send_create_reply(machine, NULL);
441 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
443 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
445 machine_send_create_reply(machine, &e);
448 machine_save(machine);
451 machine_add_to_gc_queue(machine);
455 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
456 _cleanup_free_ char *unit = NULL;
457 Manager *m = userdata;
466 path = sd_bus_message_get_path(message);
470 r = unit_name_from_dbus_path(path, &unit);
474 machine = hashmap_get(m->machine_units, unit);
476 machine_add_to_gc_queue(machine);
481 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
482 const char *path, *unit;
483 Manager *m = userdata;
491 r = sd_bus_message_read(message, "so", &unit, &path);
493 bus_log_parse_error(r);
497 machine = hashmap_get(m->machine_units, unit);
499 machine_add_to_gc_queue(machine);
504 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
505 Manager *m = userdata;
512 r = sd_bus_message_read(message, "b", &b);
514 bus_log_parse_error(r);
520 /* systemd finished reloading, let's recheck all our machines */
521 log_debug("System manager has been reloaded, rechecking machines...");
523 HASHMAP_FOREACH(machine, m->machines, i)
524 machine_add_to_gc_queue(machine);
529 int manager_start_scope(
534 const char *description,
535 sd_bus_message *more_properties,
539 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
546 r = sd_bus_message_new_method_call(
549 "org.freedesktop.systemd1",
550 "/org/freedesktop/systemd1",
551 "org.freedesktop.systemd1.Manager",
552 "StartTransientUnit");
556 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
560 r = sd_bus_message_open_container(m, 'a', "(sv)");
564 if (!isempty(slice)) {
565 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
570 if (!isempty(description)) {
571 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
576 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
580 if (more_properties) {
581 r = sd_bus_message_copy(m, more_properties, true);
586 r = sd_bus_message_close_container(m);
590 r = sd_bus_message_append(m, "a(sa(sv))", 0);
594 r = sd_bus_call(manager->bus, m, 0, error, &reply);
602 r = sd_bus_message_read(reply, "o", &j);
616 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
617 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
623 r = sd_bus_call_method(
625 "org.freedesktop.systemd1",
626 "/org/freedesktop/systemd1",
627 "org.freedesktop.systemd1.Manager",
633 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
634 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
639 sd_bus_error_free(error);
650 r = sd_bus_message_read(reply, "o", &j);
664 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
668 return sd_bus_call_method(
670 "org.freedesktop.systemd1",
671 "/org/freedesktop/systemd1",
672 "org.freedesktop.systemd1.Manager",
676 "ssi", unit, "all", signo);
679 int manager_unit_is_active(Manager *manager, const char *unit) {
680 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
681 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
682 _cleanup_free_ char *path = NULL;
689 path = unit_dbus_path_from_name(unit);
693 r = sd_bus_get_property(
695 "org.freedesktop.systemd1",
697 "org.freedesktop.systemd1.Unit",
703 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
704 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
707 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
708 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
714 r = sd_bus_message_read(reply, "s", &state);
718 return !streq(state, "inactive") && !streq(state, "failed");
721 int manager_job_is_active(Manager *manager, const char *path) {
722 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
723 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
729 r = sd_bus_get_property(
731 "org.freedesktop.systemd1",
733 "org.freedesktop.systemd1.Job",
739 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
740 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
743 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
749 /* We don't actually care about the state really. The fact
750 * that we could read the job state is enough for us */
755 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
756 _cleanup_free_ char *unit = NULL;
764 r = cg_pid_get_unit(pid, &unit);
766 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
768 mm = hashmap_get(m->machine_units, unit);
777 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
783 machine = hashmap_get(m->machines, name);
785 machine = machine_new(m, name);