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 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
110 r = manager_get_machine_by_pid(m, pid, &machine);
114 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid);
116 p = machine_bus_path(machine);
120 return sd_bus_reply_method_return(message, "o", p);
123 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
124 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
125 Manager *m = userdata;
134 r = sd_bus_message_new_method_return(message, &reply);
136 return sd_bus_error_set_errno(error, r);
138 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
140 return sd_bus_error_set_errno(error, r);
142 HASHMAP_FOREACH(machine, m->machines, i) {
143 _cleanup_free_ char *p = NULL;
145 p = machine_bus_path(machine);
149 r = sd_bus_message_append(reply, "(ssso)",
151 strempty(machine_class_to_string(machine->class)),
155 return sd_bus_error_set_errno(error, r);
158 r = sd_bus_message_close_container(reply);
160 return sd_bus_error_set_errno(error, r);
162 return sd_bus_send(bus, reply, NULL);
165 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
166 const char *name, *service, *class, *root_directory;
167 Manager *manager = userdata;
180 r = sd_bus_message_read(message, "s", &name);
183 if (!valid_machine_name(name))
184 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
186 r = sd_bus_message_read_array(message, 'y', &v, &n);
194 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
196 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
201 c = _MACHINE_CLASS_INVALID;
203 c = machine_class_from_string(class);
205 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
209 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
211 if (!isempty(root_directory) && !path_is_absolute(root_directory))
212 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
214 r = sd_bus_message_enter_container(message, 'a', "(sv)");
219 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
221 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
226 if (hashmap_get(manager->machines, name))
227 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
229 r = manager_add_machine(manager, name, &m);
237 if (!isempty(service)) {
238 m->service = strdup(service);
245 if (!isempty(root_directory)) {
246 m->root_directory = strdup(root_directory);
247 if (!m->root_directory) {
253 r = machine_start(m, message, error);
257 m->create_message = sd_bus_message_ref(message);
262 machine_add_to_gc_queue(m);
267 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
268 Manager *m = userdata;
277 r = sd_bus_message_read(message, "s", &name);
279 return sd_bus_error_set_errno(error, r);
281 machine = hashmap_get(m->machines, name);
283 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
285 r = machine_stop(machine);
287 return sd_bus_error_set_errno(error, r);
289 return sd_bus_reply_method_return(message, NULL);
292 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
293 Manager *m = userdata;
305 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
307 return sd_bus_error_set_errno(error, r);
312 who = kill_who_from_string(swho);
314 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
317 if (signo <= 0 || signo >= _NSIG)
318 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
320 machine = hashmap_get(m->machines, name);
322 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
324 r = machine_kill(machine, who, signo);
326 return sd_bus_error_set_errno(error, r);
328 return sd_bus_reply_method_return(message, NULL);
331 const sd_bus_vtable manager_vtable[] = {
332 SD_BUS_VTABLE_START(0),
333 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, 0),
334 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, 0),
335 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, 0),
336 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
337 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, 0),
338 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, 0),
339 SD_BUS_SIGNAL("MachineNew", "so", 0),
340 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
344 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
345 const char *path, *result, *unit;
346 Manager *m = userdata;
355 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
357 bus_log_parse_error(r);
361 machine = hashmap_get(m->machine_units, unit);
365 if (streq_ptr(path, machine->scope_job)) {
366 free(machine->scope_job);
367 machine->scope_job = NULL;
369 if (machine->started) {
370 if (streq(result, "done"))
371 machine_send_create_reply(machine, NULL);
373 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
375 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
377 machine_send_create_reply(machine, &e);
380 machine_save(machine);
383 machine_add_to_gc_queue(machine);
387 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
388 _cleanup_free_ char *unit = NULL;
389 Manager *m = userdata;
398 path = sd_bus_message_get_path(message);
402 r = unit_name_from_dbus_path(path, &unit);
406 machine = hashmap_get(m->machine_units, unit);
408 machine_add_to_gc_queue(machine);
413 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
414 const char *path, *unit;
415 Manager *m = userdata;
423 r = sd_bus_message_read(message, "so", &unit, &path);
425 bus_log_parse_error(r);
429 machine = hashmap_get(m->machine_units, unit);
431 machine_add_to_gc_queue(machine);
436 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
437 Manager *m = userdata;
444 r = sd_bus_message_read(message, "b", &b);
446 bus_log_parse_error(r);
452 /* systemd finished reloading, let's recheck all our machines */
453 log_debug("System manager has been reloaded, rechecking machines...");
455 HASHMAP_FOREACH(machine, m->machines, i)
456 machine_add_to_gc_queue(machine);
461 int manager_start_scope(
466 const char *description,
467 sd_bus_message *more_properties,
471 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
478 r = sd_bus_message_new_method_call(
480 "org.freedesktop.systemd1",
481 "/org/freedesktop/systemd1",
482 "org.freedesktop.systemd1.Manager",
483 "StartTransientUnit",
488 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
492 r = sd_bus_message_open_container(m, 'a', "(sv)");
496 if (!isempty(slice)) {
497 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
502 if (!isempty(description)) {
503 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
508 /* cgroup empty notification is not available in containers
509 * currently. To make this less problematic, let's shorten the
510 * stop timeout for machines, so that we don't wait
512 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
516 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
520 if (more_properties) {
521 r = sd_bus_message_copy(m, more_properties, true);
526 r = sd_bus_message_close_container(m);
530 r = sd_bus_message_append(m, "a(sa(sv))", 0);
534 r = sd_bus_call(manager->bus, m, 0, error, &reply);
542 r = sd_bus_message_read(reply, "o", &j);
556 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
557 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
563 r = sd_bus_call_method(
565 "org.freedesktop.systemd1",
566 "/org/freedesktop/systemd1",
567 "org.freedesktop.systemd1.Manager",
573 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
574 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
579 sd_bus_error_free(error);
590 r = sd_bus_message_read(reply, "o", &j);
604 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
608 return sd_bus_call_method(
610 "org.freedesktop.systemd1",
611 "/org/freedesktop/systemd1",
612 "org.freedesktop.systemd1.Manager",
616 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
619 int manager_unit_is_active(Manager *manager, const char *unit) {
620 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
621 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
622 _cleanup_free_ char *path = NULL;
629 path = unit_dbus_path_from_name(unit);
633 r = sd_bus_get_property(
635 "org.freedesktop.systemd1",
637 "org.freedesktop.systemd1.Unit",
643 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
644 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
647 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
648 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
654 r = sd_bus_message_read(reply, "s", &state);
658 return !streq(state, "inactive") && !streq(state, "failed");
661 int manager_job_is_active(Manager *manager, const char *path) {
662 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
663 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
669 r = sd_bus_get_property(
671 "org.freedesktop.systemd1",
673 "org.freedesktop.systemd1.Job",
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, SD_BUS_ERROR_UNKNOWN_OBJECT))
689 /* We don't actually care about the state really. The fact
690 * that we could read the job state is enough for us */
695 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
696 _cleanup_free_ char *unit = NULL;
704 r = cg_pid_get_unit(pid, &unit);
706 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
708 mm = hashmap_get(m->machine_units, unit);
717 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
723 machine = hashmap_get(m->machines, name);
725 machine = machine_new(m, name);