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"
40 #include "cgroup-util.h"
43 static bool valid_machine_name(const char *p) {
46 if (!filename_is_safe(p))
49 if (!ascii_is_valid(p))
60 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
61 _cleanup_free_ char *p = NULL;
62 Manager *m = userdata;
71 r = sd_bus_message_read(message, "s", &name);
73 return sd_bus_reply_method_errno(bus, message, r, NULL);
75 machine = hashmap_get(m->machines, name);
77 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
79 p = machine_bus_path(machine);
81 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
83 return sd_bus_reply_method_return(bus, message, "o", p);
86 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata) {
87 _cleanup_free_ char *p = NULL;
88 Manager *m = userdata;
89 Machine *machine = NULL;
97 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
99 r = sd_bus_message_read(message, "u", &pid);
101 return sd_bus_reply_method_errno(bus, message, r, NULL);
104 r = sd_bus_get_owner_pid(bus, sd_bus_message_get_sender(message), &pid);
106 return sd_bus_reply_method_errno(bus, message, r, NULL);
109 r = manager_get_machine_by_pid(m, pid, &machine);
111 return sd_bus_reply_method_errno(bus, message, r, NULL);
113 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);
115 p = machine_bus_path(machine);
117 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
119 return sd_bus_reply_method_return(bus, message, "o", p);
122 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata) {
123 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
124 Manager *m = userdata;
133 r = sd_bus_message_new_method_return(bus, message, &reply);
135 return sd_bus_reply_method_errno(bus, message, r, NULL);
137 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
139 return sd_bus_reply_method_errno(bus, message, r, NULL);
141 HASHMAP_FOREACH(machine, m->machines, i) {
142 _cleanup_free_ char *p = NULL;
144 p = machine_bus_path(machine);
146 return sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
148 r = sd_bus_message_append(reply, "(ssso)",
150 strempty(machine_class_to_string(machine->class)),
154 return sd_bus_reply_method_errno(bus, message, r, NULL);
157 r = sd_bus_message_close_container(reply);
159 return sd_bus_reply_method_errno(bus, message, r, NULL);
161 return sd_bus_send(bus, reply, NULL);
164 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
165 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
166 const char *name, *service, *class, *root_directory;
167 Manager *manager = userdata;
180 r = sd_bus_message_read(message, "s", &name);
182 return sd_bus_reply_method_errno(bus, message, r, NULL);
183 if (!valid_machine_name(name))
184 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
186 r = sd_bus_message_read_array(message, 'y', &v, &n);
188 return sd_bus_reply_method_errno(bus, message, r, NULL);
194 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
196 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
198 return sd_bus_reply_method_errno(bus, message, r, NULL);
201 c = _MACHINE_CLASS_INVALID;
203 c = machine_class_from_string(class);
205 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
209 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
211 if (!isempty(root_directory) && !path_is_absolute(root_directory))
212 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
214 r = sd_bus_message_enter_container(message, 'a', "(sv)");
216 return sd_bus_reply_method_errno(bus, message, r, NULL);
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);
223 return sd_bus_reply_method_errno(bus, message, r, NULL);
226 if (hashmap_get(manager->machines, name))
227 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
229 r = manager_add_machine(manager, name, &m);
231 return sd_bus_reply_method_errno(bus, message, r, NULL);
237 if (!isempty(service)) {
238 m->service = strdup(service);
240 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
245 if (!isempty(root_directory)) {
246 m->root_directory = strdup(root_directory);
247 if (!m->root_directory) {
248 r = sd_bus_reply_method_errno(bus, message, -ENOMEM, NULL);
253 r = machine_start(m, message, &error);
255 r = sd_bus_reply_method_errno(bus, message, r, &error);
259 m->create_message = sd_bus_message_ref(message);
264 machine_add_to_gc_queue(m);
269 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
270 Manager *m = userdata;
279 r = sd_bus_message_read(message, "s", &name);
281 return sd_bus_reply_method_errno(bus, message, r, NULL);
283 machine = hashmap_get(m->machines, name);
285 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
287 r = machine_stop(machine);
289 return sd_bus_reply_method_errno(bus, message, r, NULL);
291 return sd_bus_reply_method_return(bus, message, NULL);
294 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata) {
295 Manager *m = userdata;
307 r = sd_bus_message_read(message, "ssi", &name, &swho, &signo);
309 return sd_bus_reply_method_errno(bus, message, r, NULL);
314 who = kill_who_from_string(swho);
316 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid kill parameter '%s'", swho);
319 if (signo <= 0 || signo >= _NSIG)
320 return sd_bus_reply_method_errorf(bus, message, SD_BUS_ERROR_INVALID_ARGS, "Invalid signal %i", signo);
322 machine = hashmap_get(m->machines, name);
324 return sd_bus_reply_method_errorf(bus, message, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
326 r = machine_kill(machine, who, signo);
328 return sd_bus_reply_method_errno(bus, message, r, NULL);
330 return sd_bus_reply_method_return(bus, message, NULL);
333 const sd_bus_vtable manager_vtable[] = {
334 SD_BUS_VTABLE_START(0),
335 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, 0),
336 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, 0),
337 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, 0),
338 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
339 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, 0),
340 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, 0),
341 SD_BUS_SIGNAL("MachineNew", "so", 0),
342 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
346 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
347 const char *path, *result, *unit;
348 Manager *m = userdata;
357 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
359 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
363 machine = hashmap_get(m->machine_units, unit);
367 if (streq_ptr(path, machine->scope_job)) {
368 free(machine->scope_job);
369 machine->scope_job = NULL;
371 if (machine->started) {
372 if (streq(result, "done"))
373 machine_send_create_reply(machine, NULL);
375 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
377 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
379 machine_send_create_reply(machine, &error);
382 machine_save(machine);
385 machine_add_to_gc_queue(machine);
389 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
390 _cleanup_free_ char *unit = NULL;
391 Manager *m = userdata;
399 path = sd_bus_message_get_path(message);
403 unit_name_from_dbus_path(path, &unit);
407 machine = hashmap_get(m->machine_units, unit);
409 machine_add_to_gc_queue(machine);
414 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
415 const char *path, *unit;
416 Manager *m = userdata;
424 r = sd_bus_message_read(message, "so", &unit, &path);
426 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
430 machine = hashmap_get(m->machine_units, unit);
432 machine_add_to_gc_queue(machine);
437 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
438 Manager *m = userdata;
445 r = sd_bus_message_read(message, "b", &b);
447 log_error("Failed to parse Reloading message: %s", strerror(-r));
454 /* systemd finished reloading, let's recheck all our machines */
455 log_debug("System manager has been reloaded, rechecking machines...");
457 HASHMAP_FOREACH(machine, m->machines, i)
458 machine_add_to_gc_queue(machine);
463 int manager_start_scope(
468 const char *description,
469 sd_bus_message *more_properties,
473 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
480 r = sd_bus_message_new_method_call(
482 "org.freedesktop.systemd1",
483 "/org/freedesktop/systemd1",
484 "org.freedesktop.systemd1.Manager",
485 "StartTransientUnit",
490 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
494 r = sd_bus_message_open_container(m, 'a', "(sv)");
498 if (!isempty(slice)) {
499 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
504 if (!isempty(description)) {
505 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
510 /* cgroup empty notification is not available in containers
511 * currently. To make this less problematic, let's shorten the
512 * stop timeout for machines, so that we don't wait
514 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
518 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
522 if (more_properties) {
523 r = sd_bus_message_copy(m, more_properties, true);
528 r = sd_bus_message_close_container(m);
532 r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
540 r = sd_bus_message_read(reply, "o", &j);
554 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
555 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
561 r = sd_bus_call_method(
563 "org.freedesktop.systemd1",
564 "/org/freedesktop/systemd1",
565 "org.freedesktop.systemd1.Manager",
571 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
572 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
577 sd_bus_error_free(error);
588 r = sd_bus_message_read(reply, "o", &j);
602 int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
606 return sd_bus_call_method(
608 "org.freedesktop.systemd1",
609 "/org/freedesktop/systemd1",
610 "org.freedesktop.systemd1.Manager",
614 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
617 int manager_unit_is_active(Manager *manager, const char *unit) {
618 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
619 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
620 _cleanup_free_ char *path = NULL;
627 path = unit_dbus_path_from_name(unit);
631 r = sd_bus_get_property(
633 "org.freedesktop.systemd1",
635 "org.freedesktop.systemd1.Unit",
641 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
642 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
645 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
646 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
652 r = sd_bus_message_read(reply, "s", &state);
656 return !streq(state, "inactive") && !streq(state, "failed");
659 int manager_job_is_active(Manager *manager, const char *path) {
660 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
661 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
667 r = sd_bus_get_property(
669 "org.freedesktop.systemd1",
671 "org.freedesktop.systemd1.Job",
677 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
678 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
681 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
687 /* We don't actually care about the state really. The fact
688 * that we could read the job state is enough for us */
693 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
694 _cleanup_free_ char *unit = NULL;
702 r = cg_pid_get_unit(pid, &unit);
704 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
706 mm = hashmap_get(m->machine_units, unit);
715 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
721 machine = hashmap_get(m->machines, name);
723 machine = machine_new(m, name);