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 const sd_bus_vtable manager_vtable[] = {
375 SD_BUS_VTABLE_START(0),
376 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
377 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
378 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
379 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
380 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
381 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
382 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
383 SD_BUS_METHOD("GetMachineAddresses", "s", "a(yay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
384 SD_BUS_SIGNAL("MachineNew", "so", 0),
385 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
389 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
390 const char *path, *result, *unit;
391 Manager *m = userdata;
400 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
402 bus_log_parse_error(r);
406 machine = hashmap_get(m->machine_units, unit);
410 if (streq_ptr(path, machine->scope_job)) {
411 free(machine->scope_job);
412 machine->scope_job = NULL;
414 if (machine->started) {
415 if (streq(result, "done"))
416 machine_send_create_reply(machine, NULL);
418 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
420 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
422 machine_send_create_reply(machine, &e);
425 machine_save(machine);
428 machine_add_to_gc_queue(machine);
432 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
433 _cleanup_free_ char *unit = NULL;
434 Manager *m = userdata;
443 path = sd_bus_message_get_path(message);
447 r = unit_name_from_dbus_path(path, &unit);
451 machine = hashmap_get(m->machine_units, unit);
453 machine_add_to_gc_queue(machine);
458 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
459 const char *path, *unit;
460 Manager *m = userdata;
468 r = sd_bus_message_read(message, "so", &unit, &path);
470 bus_log_parse_error(r);
474 machine = hashmap_get(m->machine_units, unit);
476 machine_add_to_gc_queue(machine);
481 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
482 Manager *m = userdata;
489 r = sd_bus_message_read(message, "b", &b);
491 bus_log_parse_error(r);
497 /* systemd finished reloading, let's recheck all our machines */
498 log_debug("System manager has been reloaded, rechecking machines...");
500 HASHMAP_FOREACH(machine, m->machines, i)
501 machine_add_to_gc_queue(machine);
506 int manager_start_scope(
511 const char *description,
512 sd_bus_message *more_properties,
516 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
523 r = sd_bus_message_new_method_call(
526 "org.freedesktop.systemd1",
527 "/org/freedesktop/systemd1",
528 "org.freedesktop.systemd1.Manager",
529 "StartTransientUnit");
533 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
537 r = sd_bus_message_open_container(m, 'a', "(sv)");
541 if (!isempty(slice)) {
542 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
547 if (!isempty(description)) {
548 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
553 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
557 if (more_properties) {
558 r = sd_bus_message_copy(m, more_properties, true);
563 r = sd_bus_message_close_container(m);
567 r = sd_bus_message_append(m, "a(sa(sv))", 0);
571 r = sd_bus_call(manager->bus, m, 0, error, &reply);
579 r = sd_bus_message_read(reply, "o", &j);
593 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
594 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
600 r = sd_bus_call_method(
602 "org.freedesktop.systemd1",
603 "/org/freedesktop/systemd1",
604 "org.freedesktop.systemd1.Manager",
610 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
611 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
616 sd_bus_error_free(error);
627 r = sd_bus_message_read(reply, "o", &j);
641 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
645 return sd_bus_call_method(
647 "org.freedesktop.systemd1",
648 "/org/freedesktop/systemd1",
649 "org.freedesktop.systemd1.Manager",
653 "ssi", unit, "all", signo);
656 int manager_unit_is_active(Manager *manager, const char *unit) {
657 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
658 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
659 _cleanup_free_ char *path = NULL;
666 path = unit_dbus_path_from_name(unit);
670 r = sd_bus_get_property(
672 "org.freedesktop.systemd1",
674 "org.freedesktop.systemd1.Unit",
680 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
681 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
684 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
685 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
691 r = sd_bus_message_read(reply, "s", &state);
695 return !streq(state, "inactive") && !streq(state, "failed");
698 int manager_job_is_active(Manager *manager, const char *path) {
699 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
700 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
706 r = sd_bus_get_property(
708 "org.freedesktop.systemd1",
710 "org.freedesktop.systemd1.Job",
716 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
717 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
720 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
726 /* We don't actually care about the state really. The fact
727 * that we could read the job state is enough for us */
732 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
733 _cleanup_free_ char *unit = NULL;
741 r = cg_pid_get_unit(pid, &unit);
743 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
745 mm = hashmap_get(m->machine_units, unit);
754 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
760 machine = hashmap_get(m->machines, name);
762 machine = machine_new(m, name);