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);
226 m->registered = true;
228 if (!isempty(service)) {
229 m->service = strdup(service);
236 if (!isempty(root_directory)) {
237 m->root_directory = strdup(root_directory);
238 if (!m->root_directory) {
249 machine_add_to_gc_queue(m);
253 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
254 Manager *manager = userdata;
258 r = method_create_or_register_machine(manager, message, &m, error);
262 r = sd_bus_message_enter_container(message, 'a', "(sv)");
266 r = machine_start(m, message, error);
270 m->create_message = sd_bus_message_ref(message);
274 machine_add_to_gc_queue(m);
278 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
279 Manager *manager = userdata;
280 _cleanup_free_ char *p = NULL;
284 r = method_create_or_register_machine(manager, message, &m, error);
288 r = cg_pid_get_unit(m->leader, &m->unit);
290 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
294 r = machine_start(m, NULL, error);
298 p = machine_bus_path(m);
304 return sd_bus_reply_method_return(message, "o", p);
307 machine_add_to_gc_queue(m);
311 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
312 Manager *m = userdata;
321 r = sd_bus_message_read(message, "s", &name);
323 return sd_bus_error_set_errno(error, r);
325 machine = hashmap_get(m->machines, name);
327 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
329 return bus_machine_method_terminate(bus, message, machine, error);
332 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
333 Manager *m = userdata;
342 r = sd_bus_message_read(message, "s", &name);
344 return sd_bus_error_set_errno(error, r);
346 machine = hashmap_get(m->machines, name);
348 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
350 return bus_machine_method_kill(bus, message, machine, error);
353 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
354 Manager *m = userdata;
363 r = sd_bus_message_read(message, "s", &name);
365 return sd_bus_error_set_errno(error, r);
367 machine = hashmap_get(m->machines, name);
369 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
371 return bus_machine_method_get_addresses(bus, message, machine, error);
374 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
375 Manager *m = userdata;
384 r = sd_bus_message_read(message, "s", &name);
386 return sd_bus_error_set_errno(error, r);
388 machine = hashmap_get(m->machines, name);
390 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
392 return bus_machine_method_get_os_release(bus, message, machine, error);
395 const sd_bus_vtable manager_vtable[] = {
396 SD_BUS_VTABLE_START(0),
397 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
398 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
399 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
400 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
401 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
402 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
403 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
404 SD_BUS_METHOD("GetMachineAddresses", "s", "a(yay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
405 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
406 SD_BUS_SIGNAL("MachineNew", "so", 0),
407 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
411 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
412 const char *path, *result, *unit;
413 Manager *m = userdata;
422 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
424 bus_log_parse_error(r);
428 machine = hashmap_get(m->machine_units, unit);
432 if (streq_ptr(path, machine->scope_job)) {
433 free(machine->scope_job);
434 machine->scope_job = NULL;
436 if (machine->started) {
437 if (streq(result, "done"))
438 machine_send_create_reply(machine, NULL);
440 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
442 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
444 machine_send_create_reply(machine, &e);
447 machine_save(machine);
450 machine_add_to_gc_queue(machine);
454 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
455 _cleanup_free_ char *unit = NULL;
456 Manager *m = userdata;
465 path = sd_bus_message_get_path(message);
469 r = unit_name_from_dbus_path(path, &unit);
473 machine = hashmap_get(m->machine_units, unit);
475 machine_add_to_gc_queue(machine);
480 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
481 const char *path, *unit;
482 Manager *m = userdata;
490 r = sd_bus_message_read(message, "so", &unit, &path);
492 bus_log_parse_error(r);
496 machine = hashmap_get(m->machine_units, unit);
498 machine_add_to_gc_queue(machine);
503 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
504 Manager *m = userdata;
511 r = sd_bus_message_read(message, "b", &b);
513 bus_log_parse_error(r);
519 /* systemd finished reloading, let's recheck all our machines */
520 log_debug("System manager has been reloaded, rechecking machines...");
522 HASHMAP_FOREACH(machine, m->machines, i)
523 machine_add_to_gc_queue(machine);
528 int manager_start_scope(
533 const char *description,
534 sd_bus_message *more_properties,
538 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
545 r = sd_bus_message_new_method_call(
548 "org.freedesktop.systemd1",
549 "/org/freedesktop/systemd1",
550 "org.freedesktop.systemd1.Manager",
551 "StartTransientUnit");
555 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
559 r = sd_bus_message_open_container(m, 'a', "(sv)");
563 if (!isempty(slice)) {
564 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
569 if (!isempty(description)) {
570 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
575 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
579 if (more_properties) {
580 r = sd_bus_message_copy(m, more_properties, true);
585 r = sd_bus_message_close_container(m);
589 r = sd_bus_message_append(m, "a(sa(sv))", 0);
593 r = sd_bus_call(manager->bus, m, 0, error, &reply);
601 r = sd_bus_message_read(reply, "o", &j);
615 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
616 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
622 r = sd_bus_call_method(
624 "org.freedesktop.systemd1",
625 "/org/freedesktop/systemd1",
626 "org.freedesktop.systemd1.Manager",
632 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
633 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
638 sd_bus_error_free(error);
649 r = sd_bus_message_read(reply, "o", &j);
663 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
667 return sd_bus_call_method(
669 "org.freedesktop.systemd1",
670 "/org/freedesktop/systemd1",
671 "org.freedesktop.systemd1.Manager",
675 "ssi", unit, "all", signo);
678 int manager_unit_is_active(Manager *manager, const char *unit) {
679 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
680 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
681 _cleanup_free_ char *path = NULL;
688 path = unit_dbus_path_from_name(unit);
692 r = sd_bus_get_property(
694 "org.freedesktop.systemd1",
696 "org.freedesktop.systemd1.Unit",
702 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
703 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
706 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
707 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
713 r = sd_bus_message_read(reply, "s", &state);
717 return !streq(state, "inactive") && !streq(state, "failed");
720 int manager_job_is_active(Manager *manager, const char *path) {
721 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
722 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
728 r = sd_bus_get_property(
730 "org.freedesktop.systemd1",
732 "org.freedesktop.systemd1.Job",
738 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
739 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
742 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
748 /* We don't actually care about the state really. The fact
749 * that we could read the job state is enough for us */
754 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
755 _cleanup_free_ char *unit = NULL;
763 r = cg_pid_get_unit(pid, &unit);
765 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
767 mm = hashmap_get(m->machine_units, unit);
776 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
782 machine = hashmap_get(m->machines, name);
784 machine = machine_new(m, name);