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 match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
346 const char *path, *result, *unit;
347 Manager *m = userdata;
356 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
358 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
362 machine = hashmap_get(m->machine_units, unit);
366 if (streq_ptr(path, machine->scope_job)) {
367 free(machine->scope_job);
368 machine->scope_job = NULL;
370 if (machine->started) {
371 if (streq(result, "done"))
372 machine_send_create_reply(machine, NULL);
374 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
376 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
378 machine_send_create_reply(machine, &error);
381 machine_save(machine);
384 machine_add_to_gc_queue(machine);
388 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
389 _cleanup_free_ char *unit = NULL;
390 Manager *m = userdata;
398 path = sd_bus_message_get_path(message);
402 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) {
414 const char *path, *unit;
415 Manager *m = userdata;
423 r = sd_bus_message_read(message, "so", &unit, &path);
425 log_error("Failed to parse UnitRemoved message: %s", strerror(-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) {
437 Manager *m = userdata;
444 r = sd_bus_message_read(message, "b", &b);
446 log_error("Failed to parse Reloading message: %s", strerror(-r));
453 /* systemd finished reloading, let's recheck all our machines */
454 log_debug("System manager has been reloaded, rechecking machines...");
456 HASHMAP_FOREACH(machine, m->machines, i)
457 machine_add_to_gc_queue(machine);
462 int manager_start_scope(
467 const char *description,
468 sd_bus_message *more_properties,
472 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
479 r = sd_bus_message_new_method_call(
481 "org.freedesktop.systemd1",
482 "/org/freedesktop/systemd1",
483 "org.freedesktop.systemd1.Manager",
484 "StartTransientUnit",
489 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
493 r = sd_bus_message_open_container(m, 'a', "(sv)");
497 if (!isempty(slice)) {
498 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
503 if (!isempty(description)) {
504 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
509 /* cgroup empty notification is not available in containers
510 * currently. To make this less problematic, let's shorten the
511 * stop timeout for machines, so that we don't wait
513 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
517 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
521 if (more_properties) {
522 r = sd_bus_message_copy(m, more_properties, true);
527 r = sd_bus_message_close_container(m);
531 r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
539 r = sd_bus_message_read(reply, "o", &j);
553 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
554 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
560 r = sd_bus_call_method(
562 "org.freedesktop.systemd1",
563 "/org/freedesktop/systemd1",
564 "org.freedesktop.systemd1.Manager",
570 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
571 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
576 sd_bus_error_free(error);
587 r = sd_bus_message_read(reply, "o", &j);
601 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
605 return sd_bus_call_method(
607 "org.freedesktop.systemd1",
608 "/org/freedesktop/systemd1",
609 "org.freedesktop.systemd1.Manager",
613 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
616 int manager_unit_is_active(Manager *manager, const char *unit) {
617 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
618 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
619 _cleanup_free_ char *path = NULL;
626 path = unit_dbus_path_from_name(unit);
630 r = sd_bus_get_property(
632 "org.freedesktop.systemd1",
634 "org.freedesktop.systemd1.Unit",
640 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
641 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
644 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
645 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
651 r = sd_bus_message_read(reply, "s", &state);
655 return !streq(state, "inactive") && !streq(state, "failed");
658 int manager_job_is_active(Manager *manager, const char *path) {
659 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
660 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
666 r = sd_bus_get_property(
668 "org.freedesktop.systemd1",
670 "org.freedesktop.systemd1.Job",
676 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
677 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
680 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
686 /* We don't actually care about the state really. The fact
687 * that we could read the job state is enough for us */