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"
33 #include "path-util.h"
35 #include "fileio-label.h"
38 #include "unit-name.h"
40 #include "bus-errors.h"
41 #include "time-util.h"
42 #include "cgroup-util.h"
45 static bool valid_machine_name(const char *p) {
48 if (!filename_is_safe(p))
51 if (!ascii_is_valid(p))
62 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
63 _cleanup_free_ char *p = NULL;
64 Manager *m = userdata;
73 r = sd_bus_message_read(message, "s", &name);
77 machine = hashmap_get(m->machines, name);
79 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
81 p = machine_bus_path(machine);
85 return sd_bus_reply_method_return(message, "o", p);
88 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
89 _cleanup_free_ char *p = NULL;
90 Manager *m = userdata;
91 Machine *machine = NULL;
99 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
101 r = sd_bus_message_read(message, "u", &pid);
106 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
108 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
112 r = sd_bus_creds_get_pid(creds, &pid);
117 r = manager_get_machine_by_pid(m, pid, &machine);
121 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid);
123 p = machine_bus_path(machine);
127 return sd_bus_reply_method_return(message, "o", p);
130 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
131 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
132 Manager *m = userdata;
141 r = sd_bus_message_new_method_return(message, &reply);
143 return sd_bus_error_set_errno(error, r);
145 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
147 return sd_bus_error_set_errno(error, r);
149 HASHMAP_FOREACH(machine, m->machines, i) {
150 _cleanup_free_ char *p = NULL;
152 p = machine_bus_path(machine);
156 r = sd_bus_message_append(reply, "(ssso)",
158 strempty(machine_class_to_string(machine->class)),
162 return sd_bus_error_set_errno(error, r);
165 r = sd_bus_message_close_container(reply);
167 return sd_bus_error_set_errno(error, r);
169 return sd_bus_send(bus, reply, NULL);
172 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
173 const char *name, *service, *class, *root_directory;
174 Manager *manager = userdata;
187 r = sd_bus_message_read(message, "s", &name);
190 if (!valid_machine_name(name))
191 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
193 r = sd_bus_message_read_array(message, 'y', &v, &n);
201 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
203 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
208 c = _MACHINE_CLASS_INVALID;
210 c = machine_class_from_string(class);
212 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
216 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
218 if (!isempty(root_directory) && !path_is_absolute(root_directory))
219 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
221 r = sd_bus_message_enter_container(message, 'a', "(sv)");
226 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
228 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
232 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
234 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
239 if (hashmap_get(manager->machines, name))
240 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
242 r = manager_add_machine(manager, name, &m);
250 if (!isempty(service)) {
251 m->service = strdup(service);
258 if (!isempty(root_directory)) {
259 m->root_directory = strdup(root_directory);
260 if (!m->root_directory) {
266 r = machine_start(m, message, error);
270 m->create_message = sd_bus_message_ref(message);
275 machine_add_to_gc_queue(m);
280 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
281 Manager *m = userdata;
290 r = sd_bus_message_read(message, "s", &name);
292 return sd_bus_error_set_errno(error, r);
294 machine = hashmap_get(m->machines, name);
296 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
298 r = machine_stop(machine);
300 return sd_bus_error_set_errno(error, r);
302 return sd_bus_reply_method_return(message, NULL);
305 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
306 Manager *m = userdata;
318 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
320 return sd_bus_error_set_errno(error, r);
325 who = kill_who_from_string(swho);
327 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
330 if (signo <= 0 || signo >= _NSIG)
331 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
333 machine = hashmap_get(m->machines, name);
335 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
337 r = machine_kill(machine, who, signo);
339 return sd_bus_error_set_errno(error, r);
341 return sd_bus_reply_method_return(message, NULL);
344 const sd_bus_vtable manager_vtable[] = {
345 SD_BUS_VTABLE_START(0),
346 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
347 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
348 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
349 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
350 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
351 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
352 SD_BUS_SIGNAL("MachineNew", "so", 0),
353 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
357 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
358 const char *path, *result, *unit;
359 Manager *m = userdata;
368 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
370 bus_log_parse_error(r);
374 machine = hashmap_get(m->machine_units, unit);
378 if (streq_ptr(path, machine->scope_job)) {
379 free(machine->scope_job);
380 machine->scope_job = NULL;
382 if (machine->started) {
383 if (streq(result, "done"))
384 machine_send_create_reply(machine, NULL);
386 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
388 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
390 machine_send_create_reply(machine, &e);
393 machine_save(machine);
396 machine_add_to_gc_queue(machine);
400 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
401 _cleanup_free_ char *unit = NULL;
402 Manager *m = userdata;
411 path = sd_bus_message_get_path(message);
415 r = unit_name_from_dbus_path(path, &unit);
419 machine = hashmap_get(m->machine_units, unit);
421 machine_add_to_gc_queue(machine);
426 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
427 const char *path, *unit;
428 Manager *m = userdata;
436 r = sd_bus_message_read(message, "so", &unit, &path);
438 bus_log_parse_error(r);
442 machine = hashmap_get(m->machine_units, unit);
444 machine_add_to_gc_queue(machine);
449 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
450 Manager *m = userdata;
457 r = sd_bus_message_read(message, "b", &b);
459 bus_log_parse_error(r);
465 /* systemd finished reloading, let's recheck all our machines */
466 log_debug("System manager has been reloaded, rechecking machines...");
468 HASHMAP_FOREACH(machine, m->machines, i)
469 machine_add_to_gc_queue(machine);
474 int manager_start_scope(
479 const char *description,
480 sd_bus_message *more_properties,
484 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
491 r = sd_bus_message_new_method_call(
493 "org.freedesktop.systemd1",
494 "/org/freedesktop/systemd1",
495 "org.freedesktop.systemd1.Manager",
496 "StartTransientUnit",
501 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
505 r = sd_bus_message_open_container(m, 'a', "(sv)");
509 if (!isempty(slice)) {
510 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
515 if (!isempty(description)) {
516 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
521 /* cgroup empty notification is not available in containers
522 * currently. To make this less problematic, let's shorten the
523 * stop timeout for machines, so that we don't wait
525 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
529 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
533 if (more_properties) {
534 r = sd_bus_message_copy(m, more_properties, true);
539 r = sd_bus_message_close_container(m);
543 r = sd_bus_message_append(m, "a(sa(sv))", 0);
547 r = sd_bus_call(manager->bus, m, 0, error, &reply);
555 r = sd_bus_message_read(reply, "o", &j);
569 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
570 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
576 r = sd_bus_call_method(
578 "org.freedesktop.systemd1",
579 "/org/freedesktop/systemd1",
580 "org.freedesktop.systemd1.Manager",
586 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
587 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
592 sd_bus_error_free(error);
603 r = sd_bus_message_read(reply, "o", &j);
617 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
621 return sd_bus_call_method(
623 "org.freedesktop.systemd1",
624 "/org/freedesktop/systemd1",
625 "org.freedesktop.systemd1.Manager",
629 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
632 int manager_unit_is_active(Manager *manager, const char *unit) {
633 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
634 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
635 _cleanup_free_ char *path = NULL;
642 path = unit_dbus_path_from_name(unit);
646 r = sd_bus_get_property(
648 "org.freedesktop.systemd1",
650 "org.freedesktop.systemd1.Unit",
656 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
657 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
660 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
661 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
667 r = sd_bus_message_read(reply, "s", &state);
671 return !streq(state, "inactive") && !streq(state, "failed");
674 int manager_job_is_active(Manager *manager, const char *path) {
675 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
676 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
682 r = sd_bus_get_property(
684 "org.freedesktop.systemd1",
686 "org.freedesktop.systemd1.Job",
692 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
693 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
696 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
702 /* We don't actually care about the state really. The fact
703 * that we could read the job state is enough for us */
708 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
709 _cleanup_free_ char *unit = NULL;
717 r = cg_pid_get_unit(pid, &unit);
719 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
721 mm = hashmap_get(m->machine_units, unit);
730 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
736 machine = hashmap_get(m->machines, name);
738 machine = machine_new(m, name);