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/>.
28 #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 bool valid_machine_name(const char *p) {
47 if (!filename_is_safe(p))
50 if (!ascii_is_valid(p))
61 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
62 _cleanup_free_ char *p = NULL;
63 Manager *m = userdata;
72 r = sd_bus_message_read(message, "s", &name);
76 machine = hashmap_get(m->machines, name);
78 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
80 p = machine_bus_path(machine);
84 return sd_bus_reply_method_return(message, "o", p);
87 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
88 _cleanup_free_ char *p = NULL;
89 Manager *m = userdata;
90 Machine *machine = NULL;
98 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
100 r = sd_bus_message_read(message, "u", &pid);
105 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
107 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
111 r = sd_bus_creds_get_pid(creds, &pid);
116 r = manager_get_machine_by_pid(m, pid, &machine);
120 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid);
122 p = machine_bus_path(machine);
126 return sd_bus_reply_method_return(message, "o", p);
129 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
130 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
131 Manager *m = userdata;
140 r = sd_bus_message_new_method_return(message, &reply);
142 return sd_bus_error_set_errno(error, r);
144 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
146 return sd_bus_error_set_errno(error, r);
148 HASHMAP_FOREACH(machine, m->machines, i) {
149 _cleanup_free_ char *p = NULL;
151 p = machine_bus_path(machine);
155 r = sd_bus_message_append(reply, "(ssso)",
157 strempty(machine_class_to_string(machine->class)),
161 return sd_bus_error_set_errno(error, r);
164 r = sd_bus_message_close_container(reply);
166 return sd_bus_error_set_errno(error, r);
168 return sd_bus_send(bus, reply, NULL);
171 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
172 const char *name, *service, *class, *root_directory;
173 Manager *manager = userdata;
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");
220 r = sd_bus_message_enter_container(message, 'a', "(sv)");
225 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
227 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
231 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
233 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
238 if (hashmap_get(manager->machines, name))
239 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
241 r = manager_add_machine(manager, name, &m);
249 if (!isempty(service)) {
250 m->service = strdup(service);
257 if (!isempty(root_directory)) {
258 m->root_directory = strdup(root_directory);
259 if (!m->root_directory) {
265 r = machine_start(m, message, error);
269 m->create_message = sd_bus_message_ref(message);
274 machine_add_to_gc_queue(m);
279 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
280 Manager *m = userdata;
289 r = sd_bus_message_read(message, "s", &name);
291 return sd_bus_error_set_errno(error, r);
293 machine = hashmap_get(m->machines, name);
295 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
297 r = machine_stop(machine);
299 return sd_bus_error_set_errno(error, r);
301 return sd_bus_reply_method_return(message, NULL);
304 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
305 Manager *m = userdata;
317 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
319 return sd_bus_error_set_errno(error, r);
324 who = kill_who_from_string(swho);
326 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
329 if (signo <= 0 || signo >= _NSIG)
330 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
332 machine = hashmap_get(m->machines, name);
334 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
336 r = machine_kill(machine, who, signo);
338 return sd_bus_error_set_errno(error, r);
340 return sd_bus_reply_method_return(message, NULL);
343 const sd_bus_vtable manager_vtable[] = {
344 SD_BUS_VTABLE_START(0),
345 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, 0),
346 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, 0),
347 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, 0),
348 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
349 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, 0),
350 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, 0),
351 SD_BUS_SIGNAL("MachineNew", "so", 0),
352 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
356 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
357 const char *path, *result, *unit;
358 Manager *m = userdata;
367 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
369 bus_log_parse_error(r);
373 machine = hashmap_get(m->machine_units, unit);
377 if (streq_ptr(path, machine->scope_job)) {
378 free(machine->scope_job);
379 machine->scope_job = NULL;
381 if (machine->started) {
382 if (streq(result, "done"))
383 machine_send_create_reply(machine, NULL);
385 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
387 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
389 machine_send_create_reply(machine, &e);
392 machine_save(machine);
395 machine_add_to_gc_queue(machine);
399 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
400 _cleanup_free_ char *unit = NULL;
401 Manager *m = userdata;
410 path = sd_bus_message_get_path(message);
414 r = unit_name_from_dbus_path(path, &unit);
418 machine = hashmap_get(m->machine_units, unit);
420 machine_add_to_gc_queue(machine);
425 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
426 const char *path, *unit;
427 Manager *m = userdata;
435 r = sd_bus_message_read(message, "so", &unit, &path);
437 bus_log_parse_error(r);
441 machine = hashmap_get(m->machine_units, unit);
443 machine_add_to_gc_queue(machine);
448 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
449 Manager *m = userdata;
456 r = sd_bus_message_read(message, "b", &b);
458 bus_log_parse_error(r);
464 /* systemd finished reloading, let's recheck all our machines */
465 log_debug("System manager has been reloaded, rechecking machines...");
467 HASHMAP_FOREACH(machine, m->machines, i)
468 machine_add_to_gc_queue(machine);
473 int manager_start_scope(
478 const char *description,
479 sd_bus_message *more_properties,
483 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
490 r = sd_bus_message_new_method_call(
492 "org.freedesktop.systemd1",
493 "/org/freedesktop/systemd1",
494 "org.freedesktop.systemd1.Manager",
495 "StartTransientUnit",
500 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
504 r = sd_bus_message_open_container(m, 'a', "(sv)");
508 if (!isempty(slice)) {
509 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
514 if (!isempty(description)) {
515 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
520 /* cgroup empty notification is not available in containers
521 * currently. To make this less problematic, let's shorten the
522 * stop timeout for machines, so that we don't wait
524 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
528 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
532 if (more_properties) {
533 r = sd_bus_message_copy(m, more_properties, true);
538 r = sd_bus_message_close_container(m);
542 r = sd_bus_message_append(m, "a(sa(sv))", 0);
546 r = sd_bus_call(manager->bus, m, 0, error, &reply);
554 r = sd_bus_message_read(reply, "o", &j);
568 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
569 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
575 r = sd_bus_call_method(
577 "org.freedesktop.systemd1",
578 "/org/freedesktop/systemd1",
579 "org.freedesktop.systemd1.Manager",
585 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
586 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
591 sd_bus_error_free(error);
602 r = sd_bus_message_read(reply, "o", &j);
616 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
620 return sd_bus_call_method(
622 "org.freedesktop.systemd1",
623 "/org/freedesktop/systemd1",
624 "org.freedesktop.systemd1.Manager",
628 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
631 int manager_unit_is_active(Manager *manager, const char *unit) {
632 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
633 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
634 _cleanup_free_ char *path = NULL;
641 path = unit_dbus_path_from_name(unit);
645 r = sd_bus_get_property(
647 "org.freedesktop.systemd1",
649 "org.freedesktop.systemd1.Unit",
655 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
656 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
659 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
660 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
666 r = sd_bus_message_read(reply, "s", &state);
670 return !streq(state, "inactive") && !streq(state, "failed");
673 int manager_job_is_active(Manager *manager, const char *path) {
674 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
675 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
681 r = sd_bus_get_property(
683 "org.freedesktop.systemd1",
685 "org.freedesktop.systemd1.Job",
691 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
692 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
695 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
701 /* We don't actually care about the state really. The fact
702 * that we could read the job state is enough for us */
707 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
708 _cleanup_free_ char *unit = NULL;
716 r = cg_pid_get_unit(pid, &unit);
718 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
720 mm = hashmap_get(m->machine_units, unit);
729 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
735 machine = hashmap_get(m->machines, name);
737 machine = machine_new(m, name);