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 _cleanup_strv_free_ char **l = NULL;
339 Machine *machine = NULL;
340 Manager *m = userdata;
348 HASHMAP_FOREACH(machine, m->machines, i) {
351 p = machine_bus_path(machine);
355 r = strv_push(&l, p);
368 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
369 const char *path, *result, *unit;
370 Manager *m = userdata;
379 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
381 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
385 machine = hashmap_get(m->machine_units, unit);
389 if (streq_ptr(path, machine->scope_job)) {
390 free(machine->scope_job);
391 machine->scope_job = NULL;
393 if (machine->started) {
394 if (streq(result, "done"))
395 machine_send_create_reply(machine, NULL);
397 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
399 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
401 machine_send_create_reply(machine, &error);
404 machine_save(machine);
407 machine_add_to_gc_queue(machine);
411 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
412 _cleanup_free_ char *unit = NULL;
413 Manager *m = userdata;
421 path = sd_bus_message_get_path(message);
425 unit_name_from_dbus_path(path, &unit);
429 machine = hashmap_get(m->machine_units, unit);
431 machine_add_to_gc_queue(machine);
436 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
437 const char *path, *unit;
438 Manager *m = userdata;
446 r = sd_bus_message_read(message, "so", &unit, &path);
448 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
452 machine = hashmap_get(m->machine_units, unit);
454 machine_add_to_gc_queue(machine);
459 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
460 Manager *m = userdata;
467 r = sd_bus_message_read(message, "b", &b);
469 log_error("Failed to parse Reloading message: %s", strerror(-r));
476 /* systemd finished reloading, let's recheck all our machines */
477 log_debug("System manager has been reloaded, rechecking machines...");
479 HASHMAP_FOREACH(machine, m->machines, i)
480 machine_add_to_gc_queue(machine);
485 int manager_start_scope(
490 const char *description,
491 sd_bus_message *more_properties,
495 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
502 r = sd_bus_message_new_method_call(
504 "org.freedesktop.systemd1",
505 "/org/freedesktop/systemd1",
506 "org.freedesktop.systemd1.Manager",
507 "StartTransientUnit",
512 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
516 r = sd_bus_message_open_container(m, 'a', "(sv)");
520 if (!isempty(slice)) {
521 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
526 if (!isempty(description)) {
527 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
532 /* cgroup empty notification is not available in containers
533 * currently. To make this less problematic, let's shorten the
534 * stop timeout for machines, so that we don't wait
536 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
540 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
544 if (more_properties) {
545 r = sd_bus_message_copy(m, more_properties, true);
550 r = sd_bus_message_close_container(m);
554 r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
562 r = sd_bus_message_read(reply, "o", &j);
576 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
577 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
583 r = sd_bus_call_method(
585 "org.freedesktop.systemd1",
586 "/org/freedesktop/systemd1",
587 "org.freedesktop.systemd1.Manager",
593 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
594 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
599 sd_bus_error_free(error);
610 r = sd_bus_message_read(reply, "o", &j);
624 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
628 return sd_bus_call_method(
630 "org.freedesktop.systemd1",
631 "/org/freedesktop/systemd1",
632 "org.freedesktop.systemd1.Manager",
636 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
639 int manager_unit_is_active(Manager *manager, const char *unit) {
640 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
641 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
642 _cleanup_free_ char *path = NULL;
649 path = unit_dbus_path_from_name(unit);
653 r = sd_bus_get_property(
655 "org.freedesktop.systemd1",
657 "org.freedesktop.systemd1.Unit",
663 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
664 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
667 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
668 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
674 r = sd_bus_message_read(reply, "s", &state);
678 return !streq(state, "inactive") && !streq(state, "failed");
681 int manager_job_is_active(Manager *manager, const char *path) {
682 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
683 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
689 r = sd_bus_get_property(
691 "org.freedesktop.systemd1",
693 "org.freedesktop.systemd1.Job",
699 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
700 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
703 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
709 /* We don't actually care about the state really. The fact
710 * that we could read the job state is enough for us */