1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 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/>.
27 #include <sys/epoll.h>
29 #include "sd-daemon.h"
32 #include "conf-parser.h"
33 #include "cgroup-util.h"
36 #include "bus-error.h"
39 Manager *manager_new(void) {
47 m->machines = hashmap_new(string_hash_func, string_compare_func);
48 m->machine_units = hashmap_new(string_hash_func, string_compare_func);
49 m->machine_leaders = hashmap_new(trivial_hash_func, trivial_compare_func);
51 if (!m->machines || !m->machine_units || !m->machine_leaders) {
56 r = sd_event_default(&m->event);
62 sd_event_set_watchdog(m->event, true);
67 void manager_free(Manager *m) {
72 while ((machine = hashmap_first(m->machines)))
73 machine_free(machine);
75 hashmap_free(m->machines);
76 hashmap_free(m->machine_units);
77 hashmap_free(m->machine_leaders);
80 sd_event_unref(m->event);
85 int manager_enumerate_machines(Manager *m) {
86 _cleanup_closedir_ DIR *d = NULL;
92 /* Read in machine data stored on disk */
93 d = opendir("/run/systemd/machines");
98 log_error("Failed to open /run/systemd/machines: %m");
102 FOREACH_DIRENT(de, d, return -errno) {
103 struct Machine *machine;
106 if (!dirent_is_file(de))
109 k = manager_add_machine(m, de->d_name, &machine);
111 log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
117 machine_add_to_gc_queue(machine);
119 k = machine_load(machine);
127 static int manager_connect_bus(Manager *m) {
128 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
134 r = sd_bus_default_system(&m->bus);
136 log_error("Failed to connect to system bus: %s", strerror(-r));
140 r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
142 log_error("Failed to add manager object vtable: %s", strerror(-r));
146 r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
148 log_error("Failed to add machine object vtable: %s", strerror(-r));
152 r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
154 log_error("Failed to add machine enumerator: %s", strerror(-r));
158 r = sd_bus_add_match(m->bus,
160 "sender='org.freedesktop.systemd1',"
161 "interface='org.freedesktop.systemd1.Manager',"
162 "member='JobRemoved',"
163 "path='/org/freedesktop/systemd1'",
167 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
171 r = sd_bus_add_match(m->bus,
173 "sender='org.freedesktop.systemd1',"
174 "interface='org.freedesktop.systemd1.Manager',"
175 "member='UnitRemoved',"
176 "path='/org/freedesktop/systemd1'",
180 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
184 r = sd_bus_add_match(m->bus,
186 "sender='org.freedesktop.systemd1',"
187 "interface='org.freedesktop.DBus.Properties',"
188 "member='PropertiesChanged'",
189 match_properties_changed,
192 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
196 r = sd_bus_add_match(m->bus,
198 "sender='org.freedesktop.systemd1',"
199 "interface='org.freedesktop.systemd1.Manager',"
200 "member='Reloading',"
201 "path='/org/freedesktop/systemd1'",
205 log_error("Failed to add match for Reloading: %s", strerror(-r));
209 r = sd_bus_call_method(
211 "org.freedesktop.systemd1",
212 "/org/freedesktop/systemd1",
213 "org.freedesktop.systemd1.Manager",
218 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
222 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
224 log_error("Failed to register name: %s", strerror(-r));
228 r = sd_bus_attach_event(m->bus, m->event, 0);
230 log_error("Failed to attach bus to event loop: %s", strerror(-r));
237 void manager_gc(Manager *m, bool drop_not_started) {
242 while ((machine = m->machine_gc_queue)) {
243 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
244 machine->in_gc_queue = false;
246 if (!machine_check_gc(machine, drop_not_started)) {
247 machine_stop(machine);
248 machine_free(machine);
253 int manager_startup(Manager *m) {
260 /* Connect to the bus */
261 r = manager_connect_bus(m);
265 /* Deserialize state */
266 manager_enumerate_machines(m);
268 /* Remove stale objects before we start them */
269 manager_gc(m, false);
271 /* And start everything */
272 HASHMAP_FOREACH(machine, m->machines, i)
273 machine_start(machine, NULL, NULL);
278 static bool check_idle(void *userdata) {
279 Manager *m = userdata;
283 return hashmap_isempty(m->machines);
286 int manager_run(Manager *m) {
289 return bus_event_loop_with_idle(
292 "org.freedesktop.machine1",
297 int main(int argc, char *argv[]) {
301 log_set_target(LOG_TARGET_AUTO);
302 log_set_facility(LOG_AUTH);
303 log_parse_environment();
309 log_error("This program takes no arguments.");
314 /* Always create the directories people can create inotify
315 * watches in. Note that some applications might check for the
316 * existence of /run/systemd/machines/ to determine whether
317 * machined is available, so please always make sure this
319 mkdir_label("/run/systemd/machines", 0755);
327 r = manager_startup(m);
329 log_error("Failed to fully start up daemon: %s", strerror(-r));
333 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
337 "STATUS=Processing requests...");
341 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
345 "STATUS=Shutting down...");
350 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;