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", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_DO_NOT_QUEUE);
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 int manager_run(Manager *m) {
284 r = sd_event_get_state(m->event);
287 if (r == SD_EVENT_FINISHED)
292 r = sd_event_run(m->event, (uint64_t) -1);
300 int main(int argc, char *argv[]) {
304 log_set_target(LOG_TARGET_AUTO);
305 log_set_facility(LOG_AUTH);
306 log_parse_environment();
312 log_error("This program takes no arguments.");
317 /* Always create the directories people can create inotify
318 * watches in. Note that some applications might check for the
319 * existence of /run/systemd/machines/ to determine whether
320 * machined is available, so please always make sure this
322 mkdir_label("/run/systemd/machines", 0755);
330 r = manager_startup(m);
332 log_error("Failed to fully start up daemon: %s", strerror(-r));
336 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
340 "STATUS=Processing requests...");
344 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
348 "STATUS=Shutting down...");
353 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;