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 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
98 r = sd_bus_message_read(message, "u", &pid);
100 return sd_bus_reply_method_errno(bus, message, r, NULL);
103 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
105 return sd_bus_reply_method_errno(bus, message, r, NULL);
108 r = manager_get_machine_by_pid(m, pid, &machine);
110 return sd_bus_reply_method_errno(bus, message, r, NULL);
112 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);
114 p = machine_bus_path(machine);
116 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
118 return sd_bus_reply_method_return(bus, message, "o", p);
121 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata) {
122 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
123 Manager *m = userdata;
132 r = sd_bus_message_new_method_return(bus, message, &reply);
134 return sd_bus_reply_method_errno(bus, message, r, NULL);
136 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
138 return sd_bus_reply_method_errno(bus, message, r, NULL);
140 HASHMAP_FOREACH(machine, m->machines, i) {
141 _cleanup_free_ char *p = NULL;
143 p = machine_bus_path(machine);
145 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
147 r = sd_bus_message_append(reply, "(ssso)",
149 strempty(machine_class_to_string(machine->class)),
153 return sd_bus_reply_method_errno(bus, message, r, NULL);
156 r = sd_bus_message_close_container(reply);
158 return sd_bus_reply_method_errno(bus, message, r, NULL);
160 return sd_bus_send(bus, reply, NULL);
163 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
164 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
165 const char *name, *service, *class, *root_directory;
166 Manager *manager = userdata;
179 r = sd_bus_message_read(message, "s", &name);
181 return sd_bus_reply_method_errno(bus, message, r, NULL);
182 if (!valid_machine_name(name))
183 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
185 r = sd_bus_message_read_array(message, 'y', &v, &n);
187 return sd_bus_reply_method_errno(bus, message, r, NULL);
193 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
195 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
197 return sd_bus_reply_method_errno(bus, message, r, NULL);
200 c = _MACHINE_CLASS_INVALID;
202 c = machine_class_from_string(class);
204 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
208 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
210 if (!isempty(root_directory) && !path_is_absolute(root_directory))
211 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
213 r = sd_bus_message_enter_container(message, 'a', "(sv)");
215 return sd_bus_reply_method_errno(bus, message, r, NULL);
218 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
220 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), (pid_t*) &leader);
222 return sd_bus_reply_method_errno(bus, message, r, NULL);
225 if (hashmap_get(manager->machines, name))
226 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
228 r = manager_add_machine(manager, name, &m);
230 return sd_bus_reply_method_errno(bus, message, r, NULL);
236 if (!isempty(service)) {
237 m->service = strdup(service);
239 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
244 if (!isempty(root_directory)) {
245 m->root_directory = strdup(root_directory);
246 if (!m->root_directory) {
247 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
252 r = machine_start(m, message, &error);
254 r = sd_bus_reply_method_errno(bus, message, r, &error);
258 m->create_message = sd_bus_message_ref(message);
263 machine_add_to_gc_queue(m);
268 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
269 Manager *m = userdata;
278 r = sd_bus_message_read(message, "s", &name);
280 return sd_bus_reply_method_errno(bus, message, r, NULL);
282 machine = hashmap_get(m->machines, name);
284 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
286 r = machine_stop(machine);
288 return sd_bus_reply_method_errno(bus, message, r, NULL);
290 return sd_bus_reply_method_return(bus, message, NULL);
293 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
294 Manager *m = userdata;
306 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
308 return sd_bus_reply_method_errno(bus, message, r, NULL);
313 who = kill_who_from_string(swho);
315 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
318 if (signo <= 0 || signo >= _NSIG)
319 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
321 machine = hashmap_get(m->machines, name);
323 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
325 r = machine_kill(machine, who, signo);
327 return sd_bus_reply_method_errno(bus, message, r, NULL);
329 return sd_bus_reply_method_return(bus, message, NULL);
332 const sd_bus_vtable manager_vtable[] = {
333 SD_BUS_VTABLE_START(0),
334 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, 0),
335 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, 0),
336 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, 0),
337 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
338 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, 0),
339 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, 0),
340 SD_BUS_SIGNAL("MachineNew", "so", 0),
341 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
345 int machine_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
346 _cleanup_strv_free_ char **l = NULL;
347 Machine *machine = NULL;
348 Manager *m = userdata;
356 HASHMAP_FOREACH(machine, m->machines, i) {
359 p = machine_bus_path(machine);
363 r = strv_push(&l, p);
376 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
377 const char *path, *result, *unit;
378 Manager *m = userdata;
387 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
389 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
393 machine = hashmap_get(m->machine_units, unit);
397 if (streq_ptr(path, machine->scope_job)) {
398 free(machine->scope_job);
399 machine->scope_job = NULL;
401 if (machine->started) {
402 if (streq(result, "done"))
403 machine_send_create_reply(machine, NULL);
405 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
407 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
409 machine_send_create_reply(machine, &error);
412 machine_save(machine);
415 machine_add_to_gc_queue(machine);
419 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
420 _cleanup_free_ char *unit = NULL;
421 Manager *m = userdata;
429 path = sd_bus_message_get_path(message);
433 unit_name_from_dbus_path(path, &unit);
437 machine = hashmap_get(m->machine_units, unit);
439 machine_add_to_gc_queue(machine);
444 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
445 const char *path, *unit;
446 Manager *m = userdata;
454 r = sd_bus_message_read(message, "so", &unit, &path);
456 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
460 machine = hashmap_get(m->machine_units, unit);
462 machine_add_to_gc_queue(machine);
467 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
468 Manager *m = userdata;
475 r = sd_bus_message_read(message, "b", &b);
477 log_error("Failed to parse Reloading message: %s", strerror(-r));
484 /* systemd finished reloading, let's recheck all our machines */
485 log_debug("System manager has been reloaded, rechecking machines...");
487 HASHMAP_FOREACH(machine, m->machines, i)
488 machine_add_to_gc_queue(machine);
493 int manager_start_scope(
498 const char *description,
499 sd_bus_message *more_properties,
503 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
510 r = sd_bus_message_new_method_call(
512 "org.freedesktop.systemd1",
513 "/org/freedesktop/systemd1",
514 "org.freedesktop.systemd1.Manager",
515 "StartTransientUnit",
520 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
524 r = sd_bus_message_open_container(m, 'a', "(sv)");
528 if (!isempty(slice)) {
529 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
534 if (!isempty(description)) {
535 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
540 /* cgroup empty notification is not available in containers
541 * currently. To make this less problematic, let's shorten the
542 * stop timeout for machines, so that we don't wait
544 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
548 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
552 if (more_properties) {
553 r = sd_bus_message_copy(m, more_properties, true);
558 r = sd_bus_message_close_container(m);
562 r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
570 r = sd_bus_message_read(reply, "o", &j);
584 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
585 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
591 r = sd_bus_call_method(
593 "org.freedesktop.systemd1",
594 "/org/freedesktop/systemd1",
595 "org.freedesktop.systemd1.Manager",
601 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
602 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
607 sd_bus_error_free(error);
618 r = sd_bus_message_read(reply, "o", &j);
632 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
636 return sd_bus_call_method(
638 "org.freedesktop.systemd1",
639 "/org/freedesktop/systemd1",
640 "org.freedesktop.systemd1.Manager",
644 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
647 int manager_unit_is_active(Manager *manager, const char *unit) {
648 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
649 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
650 _cleanup_free_ char *path = NULL;
657 path = unit_dbus_path_from_name(unit);
661 r = sd_bus_get_property(
663 "org.freedesktop.systemd1",
665 "org.freedesktop.systemd1.Unit",
671 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
672 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
675 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
676 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
682 r = sd_bus_message_read(reply, "s", &state);
686 return !streq(state, "inactive") && !streq(state, "failed");
689 int manager_job_is_active(Manager *manager, const char *path) {
690 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
691 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
697 r = sd_bus_get_property(
699 "org.freedesktop.systemd1",
701 "org.freedesktop.systemd1.Job",
707 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
708 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
711 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
717 /* We don't actually care about the state really. The fact
718 * that we could read the job state is enough for us */