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 r = machine_start(m, NULL, error);
297 p = machine_bus_path(m);
303 return sd_bus_reply_method_return(message, "o", p);
306 machine_add_to_gc_queue(m);
310 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
311 Manager *m = userdata;
320 r = sd_bus_message_read(message, "s", &name);
322 return sd_bus_error_set_errno(error, r);
324 machine = hashmap_get(m->machines, name);
326 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
328 return bus_machine_method_terminate(bus, message, machine, error);
331 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
332 Manager *m = userdata;
341 r = sd_bus_message_read(message, "s", &name);
343 return sd_bus_error_set_errno(error, r);
345 machine = hashmap_get(m->machines, name);
347 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
349 return bus_machine_method_kill(bus, message, machine, error);
352 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
353 Manager *m = userdata;
362 r = sd_bus_message_read(message, "s", &name);
364 return sd_bus_error_set_errno(error, r);
366 machine = hashmap_get(m->machines, name);
368 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
370 return bus_machine_method_get_addresses(bus, message, machine, error);
373 const sd_bus_vtable manager_vtable[] = {
374 SD_BUS_VTABLE_START(0),
375 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
376 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
377 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
378 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
379 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
380 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
381 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
382 SD_BUS_METHOD("GetMachineAddresses", "s", "a(yay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
383 SD_BUS_SIGNAL("MachineNew", "so", 0),
384 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
388 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
389 const char *path, *result, *unit;
390 Manager *m = userdata;
399 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
401 bus_log_parse_error(r);
405 machine = hashmap_get(m->machine_units, unit);
409 if (streq_ptr(path, machine->scope_job)) {
410 free(machine->scope_job);
411 machine->scope_job = NULL;
413 if (machine->started) {
414 if (streq(result, "done"))
415 machine_send_create_reply(machine, NULL);
417 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
419 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
421 machine_send_create_reply(machine, &e);
424 machine_save(machine);
427 machine_add_to_gc_queue(machine);
431 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
432 _cleanup_free_ char *unit = NULL;
433 Manager *m = userdata;
442 path = sd_bus_message_get_path(message);
446 r = unit_name_from_dbus_path(path, &unit);
450 machine = hashmap_get(m->machine_units, unit);
452 machine_add_to_gc_queue(machine);
457 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
458 const char *path, *unit;
459 Manager *m = userdata;
467 r = sd_bus_message_read(message, "so", &unit, &path);
469 bus_log_parse_error(r);
473 machine = hashmap_get(m->machine_units, unit);
475 machine_add_to_gc_queue(machine);
480 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
481 Manager *m = userdata;
488 r = sd_bus_message_read(message, "b", &b);
490 bus_log_parse_error(r);
496 /* systemd finished reloading, let's recheck all our machines */
497 log_debug("System manager has been reloaded, rechecking machines...");
499 HASHMAP_FOREACH(machine, m->machines, i)
500 machine_add_to_gc_queue(machine);
505 int manager_start_scope(
510 const char *description,
511 sd_bus_message *more_properties,
515 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
522 r = sd_bus_message_new_method_call(
525 "org.freedesktop.systemd1",
526 "/org/freedesktop/systemd1",
527 "org.freedesktop.systemd1.Manager",
528 "StartTransientUnit");
532 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
536 r = sd_bus_message_open_container(m, 'a', "(sv)");
540 if (!isempty(slice)) {
541 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
546 if (!isempty(description)) {
547 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
552 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
556 if (more_properties) {
557 r = sd_bus_message_copy(m, more_properties, true);
562 r = sd_bus_message_close_container(m);
566 r = sd_bus_message_append(m, "a(sa(sv))", 0);
570 r = sd_bus_call(manager->bus, m, 0, error, &reply);
578 r = sd_bus_message_read(reply, "o", &j);
592 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
593 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
599 r = sd_bus_call_method(
601 "org.freedesktop.systemd1",
602 "/org/freedesktop/systemd1",
603 "org.freedesktop.systemd1.Manager",
609 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
610 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
615 sd_bus_error_free(error);
626 r = sd_bus_message_read(reply, "o", &j);
640 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
644 return sd_bus_call_method(
646 "org.freedesktop.systemd1",
647 "/org/freedesktop/systemd1",
648 "org.freedesktop.systemd1.Manager",
652 "ssi", unit, "all", signo);
655 int manager_unit_is_active(Manager *manager, const char *unit) {
656 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
657 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
658 _cleanup_free_ char *path = NULL;
665 path = unit_dbus_path_from_name(unit);
669 r = sd_bus_get_property(
671 "org.freedesktop.systemd1",
673 "org.freedesktop.systemd1.Unit",
679 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
680 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
683 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
684 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
690 r = sd_bus_message_read(reply, "s", &state);
694 return !streq(state, "inactive") && !streq(state, "failed");
697 int manager_job_is_active(Manager *manager, const char *path) {
698 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
699 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
705 r = sd_bus_get_property(
707 "org.freedesktop.systemd1",
709 "org.freedesktop.systemd1.Job",
715 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
716 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
719 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
725 /* We don't actually care about the state really. The fact
726 * that we could read the job state is enough for us */
731 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
732 _cleanup_free_ char *unit = NULL;
740 r = cg_pid_get_unit(pid, &unit);
742 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
744 mm = hashmap_get(m->machine_units, unit);
753 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
759 machine = hashmap_get(m->machines, name);
761 machine = machine_new(m, name);