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/>.
26 #include <sys/capability.h>
29 #include "sd-messages.h"
32 #include "path-util.h"
34 #include "fileio-label.h"
37 #include "unit-name.h"
39 #include "bus-errors.h"
40 #include "time-util.h"
41 #include "cgroup-util.h"
44 static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
45 _cleanup_free_ char *p = NULL;
46 Manager *m = userdata;
55 r = sd_bus_message_read(message, "s", &name);
59 machine = hashmap_get(m->machines, name);
61 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
63 p = machine_bus_path(machine);
67 return sd_bus_reply_method_return(message, "o", p);
70 static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
71 _cleanup_free_ char *p = NULL;
72 Manager *m = userdata;
73 Machine *machine = NULL;
81 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
83 r = sd_bus_message_read(message, "u", &pid);
88 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
90 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
94 r = sd_bus_creds_get_pid(creds, &pid);
99 r = manager_get_machine_by_pid(m, pid, &machine);
103 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
105 p = machine_bus_path(machine);
109 return sd_bus_reply_method_return(message, "o", p);
112 static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
113 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
114 Manager *m = userdata;
123 r = sd_bus_message_new_method_return(message, &reply);
125 return sd_bus_error_set_errno(error, r);
127 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
129 return sd_bus_error_set_errno(error, r);
131 HASHMAP_FOREACH(machine, m->machines, i) {
132 _cleanup_free_ char *p = NULL;
134 p = machine_bus_path(machine);
138 r = sd_bus_message_append(reply, "(ssso)",
140 strempty(machine_class_to_string(machine->class)),
144 return sd_bus_error_set_errno(error, r);
147 r = sd_bus_message_close_container(reply);
149 return sd_bus_error_set_errno(error, r);
151 return sd_bus_send(bus, reply, NULL);
154 static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
155 const char *name, *service, *class, *root_directory;
156 const int32_t *netif = NULL;
162 size_t n, n_netif = 0;
169 r = sd_bus_message_read(message, "s", &name);
172 if (!machine_name_is_valid(name))
173 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
175 r = sd_bus_message_read_array(message, 'y', &v, &n);
183 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
185 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
192 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
196 n_netif /= sizeof(int32_t);
198 for (i = 0; i < n_netif; i++) {
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
205 c = _MACHINE_CLASS_INVALID;
207 c = machine_class_from_string(class);
209 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
213 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
215 if (!isempty(root_directory) && !path_is_absolute(root_directory))
216 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
219 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
221 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
225 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
227 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
232 if (hashmap_get(manager->machines, name))
233 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
235 r = manager_add_machine(manager, name, &m);
243 if (!isempty(service)) {
244 m->service = strdup(service);
251 if (!isempty(root_directory)) {
252 m->root_directory = strdup(root_directory);
253 if (!m->root_directory) {
260 assert_cc(sizeof(int32_t) == sizeof(int));
261 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
267 m->n_netif = n_netif;
275 machine_add_to_gc_queue(m);
279 static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
280 Manager *manager = userdata;
284 r = method_create_or_register_machine(manager, message, read_network, &m, error);
288 r = sd_bus_message_enter_container(message, 'a', "(sv)");
292 r = machine_start(m, message, error);
296 m->create_message = sd_bus_message_ref(message);
300 machine_add_to_gc_queue(m);
304 static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
305 return method_create_machine_internal(bus, message, true, userdata, error);
308 static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
309 return method_create_machine_internal(bus, message, false, userdata, error);
312 static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
313 Manager *manager = userdata;
314 _cleanup_free_ char *p = NULL;
318 r = method_create_or_register_machine(manager, message, read_network, &m, error);
322 r = cg_pid_get_unit(m->leader, &m->unit);
324 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
328 m->registered = true;
330 r = machine_start(m, NULL, error);
334 p = machine_bus_path(m);
340 return sd_bus_reply_method_return(message, "o", p);
343 machine_add_to_gc_queue(m);
347 static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
348 return method_register_machine_internal(bus, message, true, userdata, error);
351 static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
352 return method_register_machine_internal(bus, message, false, userdata, error);
355 static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
356 Manager *m = userdata;
365 r = sd_bus_message_read(message, "s", &name);
367 return sd_bus_error_set_errno(error, r);
369 machine = hashmap_get(m->machines, name);
371 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
373 return bus_machine_method_terminate(bus, message, machine, error);
376 static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
377 Manager *m = userdata;
386 r = sd_bus_message_read(message, "s", &name);
388 return sd_bus_error_set_errno(error, r);
390 machine = hashmap_get(m->machines, name);
392 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
394 return bus_machine_method_kill(bus, message, machine, error);
397 static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
398 Manager *m = userdata;
407 r = sd_bus_message_read(message, "s", &name);
409 return sd_bus_error_set_errno(error, r);
411 machine = hashmap_get(m->machines, name);
413 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
415 return bus_machine_method_get_addresses(bus, message, machine, error);
418 static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
419 Manager *m = userdata;
428 r = sd_bus_message_read(message, "s", &name);
430 return sd_bus_error_set_errno(error, r);
432 machine = hashmap_get(m->machines, name);
434 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
436 return bus_machine_method_get_os_release(bus, message, machine, error);
439 const sd_bus_vtable manager_vtable[] = {
440 SD_BUS_VTABLE_START(0),
441 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
442 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
443 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
444 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
445 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
446 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
447 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
448 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
449 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
450 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
451 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
452 SD_BUS_SIGNAL("MachineNew", "so", 0),
453 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
457 int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
458 const char *path, *result, *unit;
459 Manager *m = userdata;
468 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
470 bus_log_parse_error(r);
474 machine = hashmap_get(m->machine_units, unit);
478 if (streq_ptr(path, machine->scope_job)) {
479 free(machine->scope_job);
480 machine->scope_job = NULL;
482 if (machine->started) {
483 if (streq(result, "done"))
484 machine_send_create_reply(machine, NULL);
486 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
488 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
490 machine_send_create_reply(machine, &e);
493 machine_save(machine);
496 machine_add_to_gc_queue(machine);
500 int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
501 _cleanup_free_ char *unit = NULL;
502 Manager *m = userdata;
511 path = sd_bus_message_get_path(message);
515 r = unit_name_from_dbus_path(path, &unit);
519 machine = hashmap_get(m->machine_units, unit);
521 machine_add_to_gc_queue(machine);
526 int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
527 const char *path, *unit;
528 Manager *m = userdata;
536 r = sd_bus_message_read(message, "so", &unit, &path);
538 bus_log_parse_error(r);
542 machine = hashmap_get(m->machine_units, unit);
544 machine_add_to_gc_queue(machine);
549 int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
550 Manager *m = userdata;
557 r = sd_bus_message_read(message, "b", &b);
559 bus_log_parse_error(r);
565 /* systemd finished reloading, let's recheck all our machines */
566 log_debug("System manager has been reloaded, rechecking machines...");
568 HASHMAP_FOREACH(machine, m->machines, i)
569 machine_add_to_gc_queue(machine);
574 int manager_start_scope(
579 const char *description,
580 sd_bus_message *more_properties,
584 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
591 r = sd_bus_message_new_method_call(
594 "org.freedesktop.systemd1",
595 "/org/freedesktop/systemd1",
596 "org.freedesktop.systemd1.Manager",
597 "StartTransientUnit");
601 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
605 r = sd_bus_message_open_container(m, 'a', "(sv)");
609 if (!isempty(slice)) {
610 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
615 if (!isempty(description)) {
616 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
621 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
625 if (more_properties) {
626 r = sd_bus_message_copy(m, more_properties, true);
631 r = sd_bus_message_close_container(m);
635 r = sd_bus_message_append(m, "a(sa(sv))", 0);
639 r = sd_bus_call(manager->bus, m, 0, error, &reply);
647 r = sd_bus_message_read(reply, "o", &j);
661 int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
662 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
668 r = sd_bus_call_method(
670 "org.freedesktop.systemd1",
671 "/org/freedesktop/systemd1",
672 "org.freedesktop.systemd1.Manager",
678 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
679 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
684 sd_bus_error_free(error);
695 r = sd_bus_message_read(reply, "o", &j);
709 int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
713 return sd_bus_call_method(
715 "org.freedesktop.systemd1",
716 "/org/freedesktop/systemd1",
717 "org.freedesktop.systemd1.Manager",
721 "ssi", unit, "all", signo);
724 int manager_unit_is_active(Manager *manager, const char *unit) {
725 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
726 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
727 _cleanup_free_ char *path = NULL;
734 path = unit_dbus_path_from_name(unit);
738 r = sd_bus_get_property(
740 "org.freedesktop.systemd1",
742 "org.freedesktop.systemd1.Unit",
748 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
749 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
752 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
753 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
759 r = sd_bus_message_read(reply, "s", &state);
763 return !streq(state, "inactive") && !streq(state, "failed");
766 int manager_job_is_active(Manager *manager, const char *path) {
767 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
768 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
774 r = sd_bus_get_property(
776 "org.freedesktop.systemd1",
778 "org.freedesktop.systemd1.Job",
784 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
785 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
788 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
794 /* We don't actually care about the state really. The fact
795 * that we could read the job state is enough for us */
800 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
801 _cleanup_free_ char *unit = NULL;
809 r = cg_pid_get_unit(pid, &unit);
811 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
813 mm = hashmap_get(m->machine_units, unit);
822 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
828 machine = hashmap_get(m->machines, name);
830 machine = machine_new(m, name);