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 "time-util.h"
42 static bool valid_machine_name(const char *p) {
45 if (!filename_is_safe(p))
48 if (!ascii_is_valid(p))
59 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
60 _cleanup_free_ char *p = NULL;
61 Manager *m = userdata;
70 r = sd_bus_message_read(message, "s", &name);
72 return sd_bus_reply_method_errno(bus, message, r, NULL);
74 machine = hashmap_get(m->machines, name);
76 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
78 p = machine_bus_path(machine);
80 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
82 return sd_bus_reply_method_return(bus, message, "o", p);
85 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
86 _cleanup_free_ char *p = NULL;
87 Manager *m = userdata;
88 Machine *machine = NULL;
96 r = sd_bus_message_read(message, "u", &pid);
98 return sd_bus_reply_method_errno(bus, message, r, NULL);
100 r = manager_get_machine_by_pid(m, pid, &machine);
102 return sd_bus_reply_method_errno(bus, message, r, NULL);
104 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_MACHINE_FOR_PID, "PID %lu does not belong to any known machine", (unsigned long) pid);
106 p = machine_bus_path(machine);
108 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
110 return sd_bus_reply_method_return(bus, message, "o", p);
113 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata) {
114 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
115 Manager *m = userdata;
124 r = sd_bus_message_new_method_return(bus, message, &reply);
126 return sd_bus_reply_method_errno(bus, message, r, NULL);
128 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
130 return sd_bus_reply_method_errno(bus, message, r, NULL);
132 HASHMAP_FOREACH(machine, m->machines, i) {
133 _cleanup_free_ char *p = NULL;
135 p = machine_bus_path(machine);
137 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
139 r = sd_bus_message_append(reply, "(ssso)",
141 strempty(machine_class_to_string(machine->class)),
145 return sd_bus_reply_method_errno(bus, message, r, NULL);
148 r = sd_bus_message_close_container(reply);
150 return sd_bus_reply_method_errno(bus, message, r, NULL);
152 return sd_bus_send(bus, reply, NULL);
155 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
156 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
157 const char *name, *service, *class, *root_directory;
158 Manager *manager = userdata;
171 r = sd_bus_message_read(message, "s", &name);
173 return sd_bus_reply_method_errno(bus, message, r, NULL);
174 if (!valid_machine_name(name))
175 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
177 r = sd_bus_message_read_array(message, 'y', &v, &n);
179 return sd_bus_reply_method_errno(bus, message, r, NULL);
185 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
187 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
189 return sd_bus_reply_method_errno(bus, message, r, NULL);
192 c = _MACHINE_CLASS_INVALID;
194 c = machine_class_from_string(class);
196 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
200 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
202 if (!isempty(root_directory) && !path_is_absolute(root_directory))
203 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
205 r = sd_bus_message_enter_container(message, 'a', "(sv)");
207 return sd_bus_reply_method_errno(bus, message, r, NULL);
210 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
212 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
214 return sd_bus_reply_method_errno(bus, message, r, NULL);
217 if (hashmap_get(manager->machines, name))
218 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
220 r = manager_add_machine(manager, name, &m);
222 return sd_bus_reply_method_errno(bus, message, r, NULL);
228 if (!isempty(service)) {
229 m->service = strdup(service);
231 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
236 if (!isempty(root_directory)) {
237 m->root_directory = strdup(root_directory);
238 if (!m->root_directory) {
239 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
244 r = machine_start(m, message, &error);
246 r = sd_bus_reply_method_errno(bus, message, r, &error);
250 m->create_message = sd_bus_message_ref(message);
255 machine_add_to_gc_queue(m);
260 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
261 Manager *m = userdata;
270 r = sd_bus_message_read(message, "s", &name);
272 return sd_bus_reply_method_errno(bus, message, r, NULL);
274 machine = hashmap_get(m->machines, name);
276 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
278 r = machine_stop(machine);
280 return sd_bus_reply_method_errno(bus, message, r, NULL);
282 return sd_bus_reply_method_return(bus, message, NULL);
285 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
286 Manager *m = userdata;
298 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
300 return sd_bus_reply_method_errno(bus, message, r, NULL);
305 who = kill_who_from_string(swho);
307 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
310 if (signo <= 0 || signo >= _NSIG)
311 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
313 machine = hashmap_get(m->machines, name);
315 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
317 r = machine_kill(machine, who, signo);
319 return sd_bus_reply_method_errno(bus, message, r, NULL);
321 return sd_bus_reply_method_return(bus, message, NULL);
324 const sd_bus_vtable manager_vtable[] = {
325 SD_BUS_VTABLE_START(0),
326 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, 0),
327 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, 0),
328 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, 0),
329 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
330 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, 0),
331 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, 0),
332 SD_BUS_SIGNAL("MachineNew", "so", 0),
333 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
337 int machine_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
338 Machine *machine = NULL;
339 Manager *m = userdata;
348 HASHMAP_FOREACH(machine, m->machines, i) {
351 p = machine_bus_path(machine);
355 r = strv_push(&l, p);
366 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
367 const char *path, *result, *unit;
368 Manager *m = userdata;
377 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
379 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
383 machine = hashmap_get(m->machine_units, unit);
387 if (streq_ptr(path, machine->scope_job)) {
388 free(machine->scope_job);
389 machine->scope_job = NULL;
391 if (machine->started) {
392 if (streq(result, "done"))
393 machine_send_create_reply(machine, NULL);
395 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
397 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
399 machine_send_create_reply(machine, &error);
402 machine_save(machine);
405 machine_add_to_gc_queue(machine);
409 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
410 _cleanup_free_ char *unit = NULL;
411 Manager *m = userdata;
419 path = sd_bus_message_get_path(message);
423 unit_name_from_dbus_path(path, &unit);
427 machine = hashmap_get(m->machine_units, unit);
429 machine_add_to_gc_queue(machine);
434 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
435 const char *path, *unit;
436 Manager *m = userdata;
444 r = sd_bus_message_read(message, "so", &unit, &path);
446 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
450 machine = hashmap_get(m->machine_units, unit);
452 machine_add_to_gc_queue(machine);
457 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
458 Manager *m = userdata;
463 r = sd_bus_message_read(message, "b", &b);
465 log_error("Failed to parse Reloading message: %s", strerror(-r));
469 /* systemd finished reloading, let's recheck all our machines */
474 log_debug("System manager has been reloaded, rechecking machines...");
476 HASHMAP_FOREACH(machine, m->machines, i)
477 machine_add_to_gc_queue(machine);
483 int manager_start_scope(
488 const char *description,
489 sd_bus_message *more_properties,
493 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
500 r = sd_bus_message_new_method_call(
502 "org.freedesktop.systemd1",
503 "/org/freedesktop/systemd1",
504 "org.freedesktop.systemd1.Manager",
505 "StartTransientUnit",
510 r = sd_bus_message_append(m, "ss", scope, "fail");
514 r = sd_bus_message_open_container(m, 'a', "(sv)");
518 if (!isempty(slice)) {
519 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
524 if (!isempty(description)) {
525 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
530 /* cgroup empty notification is not available in containers
531 * currently. To make this less problematic, let's shorten the
532 * stop timeout for machines, so that we don't wait
534 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
538 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
542 if (more_properties) {
543 r = sd_bus_message_copy(m, more_properties, true);
548 r = sd_bus_message_close_container(m);
552 r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
560 r = sd_bus_message_read(reply, "o", &j);
574 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
575 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
581 r = sd_bus_call_method(
583 "org.freedesktop.systemd1",
584 "/org/freedesktop/systemd1",
585 "org.freedesktop.systemd1.Manager",
591 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
592 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
597 sd_bus_error_free(error);
608 r = sd_bus_message_read(reply, "o", &j);
622 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
623 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
629 r = sd_bus_call_method(
631 "org.freedesktop.systemd1",
632 "/org/freedesktop/systemd1",
633 "org.freedesktop.systemd1.Manager",
637 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
642 int manager_unit_is_active(Manager *manager, const char *unit) {
643 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
644 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
645 _cleanup_free_ char *path = NULL;
652 path = unit_dbus_path_from_name(unit);
656 r = sd_bus_get_property(
658 "org.freedesktop.systemd1",
660 "org.freedesktop.systemd1.Unit",
666 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
667 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
670 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
671 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
677 r = sd_bus_message_read(reply, "s", &state);
681 return !streq(state, "inactive") && !streq(state, "failed");
684 int manager_job_is_active(Manager *manager, const char *path) {
685 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
686 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
692 r = sd_bus_get_property(
694 "org.freedesktop.systemd1",
696 "org.freedesktop.systemd1.Job",
702 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
703 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
706 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
712 /* We don't actually care about the state really. The fact
713 * that we could read the job state is enough for us */