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_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) {
173 const char *name, *service, *class, *root_directory;
186 r = sd_bus_message_read(message, "s", &name);
189 if (!valid_machine_name(name))
190 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
192 r = sd_bus_message_read_array(message, 'y', &v, &n);
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
202 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
207 c = _MACHINE_CLASS_INVALID;
209 c = machine_class_from_string(class);
211 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
215 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
217 if (!isempty(root_directory) && !path_is_absolute(root_directory))
218 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
221 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
223 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
227 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
229 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
234 if (hashmap_get(manager->machines, name))
235 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
237 r = manager_add_machine(manager, name, &m);
245 if (!isempty(service)) {
246 m->service = strdup(service);
253 if (!isempty(root_directory)) {
254 m->root_directory = strdup(root_directory);
255 if (!m->root_directory) {
266 machine_add_to_gc_queue(m);
270 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
271 Manager *manager = userdata;
275 r = method_create_or_register_machine(manager, message, &m, error);
279 r = sd_bus_message_enter_container(message, 'a', "(sv)");
283 r = machine_start(m, message, error);
287 m->create_message = sd_bus_message_ref(message);
291 machine_add_to_gc_queue(m);
295 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
296 Manager *manager = userdata;
297 _cleanup_free_ char *p = NULL;
301 r = method_create_or_register_machine(manager, message, &m, error);
305 r = cg_pid_get_unit(m->leader, &m->unit);
307 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
311 r = machine_start(m, NULL, error);
315 p = machine_bus_path(m);
321 return sd_bus_reply_method_return(message, "o", p);
324 machine_add_to_gc_queue(m);
328 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
329 Manager *m = userdata;
338 r = sd_bus_message_read(message, "s", &name);
340 return sd_bus_error_set_errno(error, r);
342 machine = hashmap_get(m->machines, name);
344 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
346 r = machine_stop(machine);
348 return sd_bus_error_set_errno(error, r);
350 return sd_bus_reply_method_return(message, NULL);
353 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
354 Manager *m = userdata;
366 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
368 return sd_bus_error_set_errno(error, r);
373 who = kill_who_from_string(swho);
375 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
378 if (signo <= 0 || signo >= _NSIG)
379 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
381 machine = hashmap_get(m->machines, name);
383 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
385 r = machine_kill(machine, who, signo);
387 return sd_bus_error_set_errno(error, r);
389 return sd_bus_reply_method_return(message, NULL);
392 const sd_bus_vtable manager_vtable[] = {
393 SD_BUS_VTABLE_START(0),
394 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
395 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
396 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
397 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
398 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
399 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
400 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
401 SD_BUS_SIGNAL("MachineNew", "so", 0),
402 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
406 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
407 const char *path, *result, *unit;
408 Manager *m = userdata;
417 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
419 bus_log_parse_error(r);
423 machine = hashmap_get(m->machine_units, unit);
427 if (streq_ptr(path, machine->scope_job)) {
428 free(machine->scope_job);
429 machine->scope_job = NULL;
431 if (machine->started) {
432 if (streq(result, "done"))
433 machine_send_create_reply(machine, NULL);
435 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
437 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
439 machine_send_create_reply(machine, &e);
442 machine_save(machine);
445 machine_add_to_gc_queue(machine);
449 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
450 _cleanup_free_ char *unit = NULL;
451 Manager *m = userdata;
460 path = sd_bus_message_get_path(message);
464 r = unit_name_from_dbus_path(path, &unit);
468 machine = hashmap_get(m->machine_units, unit);
470 machine_add_to_gc_queue(machine);
475 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
476 const char *path, *unit;
477 Manager *m = userdata;
485 r = sd_bus_message_read(message, "so", &unit, &path);
487 bus_log_parse_error(r);
491 machine = hashmap_get(m->machine_units, unit);
493 machine_add_to_gc_queue(machine);
498 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
499 Manager *m = userdata;
506 r = sd_bus_message_read(message, "b", &b);
508 bus_log_parse_error(r);
514 /* systemd finished reloading, let's recheck all our machines */
515 log_debug("System manager has been reloaded, rechecking machines...");
517 HASHMAP_FOREACH(machine, m->machines, i)
518 machine_add_to_gc_queue(machine);
523 int manager_start_scope(
528 const char *description,
529 sd_bus_message *more_properties,
533 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
540 r = sd_bus_message_new_method_call(
543 "org.freedesktop.systemd1",
544 "/org/freedesktop/systemd1",
545 "org.freedesktop.systemd1.Manager",
546 "StartTransientUnit");
550 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
554 r = sd_bus_message_open_container(m, 'a', "(sv)");
558 if (!isempty(slice)) {
559 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
564 if (!isempty(description)) {
565 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
570 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
574 if (more_properties) {
575 r = sd_bus_message_copy(m, more_properties, true);
580 r = sd_bus_message_close_container(m);
584 r = sd_bus_message_append(m, "a(sa(sv))", 0);
588 r = sd_bus_call(manager->bus, m, 0, error, &reply);
596 r = sd_bus_message_read(reply, "o", &j);
610 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
611 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
617 r = sd_bus_call_method(
619 "org.freedesktop.systemd1",
620 "/org/freedesktop/systemd1",
621 "org.freedesktop.systemd1.Manager",
627 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
628 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
633 sd_bus_error_free(error);
644 r = sd_bus_message_read(reply, "o", &j);
658 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
662 return sd_bus_call_method(
664 "org.freedesktop.systemd1",
665 "/org/freedesktop/systemd1",
666 "org.freedesktop.systemd1.Manager",
670 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
673 int manager_unit_is_active(Manager *manager, const char *unit) {
674 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
675 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
676 _cleanup_free_ char *path = NULL;
683 path = unit_dbus_path_from_name(unit);
687 r = sd_bus_get_property(
689 "org.freedesktop.systemd1",
691 "org.freedesktop.systemd1.Unit",
697 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
698 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
701 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
702 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
708 r = sd_bus_message_read(reply, "s", &state);
712 return !streq(state, "inactive") && !streq(state, "failed");
715 int manager_job_is_active(Manager *manager, const char *path) {
716 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
717 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
723 r = sd_bus_get_property(
725 "org.freedesktop.systemd1",
727 "org.freedesktop.systemd1.Job",
733 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
734 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
737 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
743 /* We don't actually care about the state really. The fact
744 * that we could read the job state is enough for us */
749 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
750 _cleanup_free_ char *unit = NULL;
758 r = cg_pid_get_unit(pid, &unit);
760 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
762 mm = hashmap_get(m->machine_units, unit);
771 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
777 machine = hashmap_get(m->machines, name);
779 machine = machine_new(m, name);