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"
31 #include "conf-parser.h"
32 #include "cgroup-util.h"
35 #include "bus-error.h"
37 #include "machine-image.h"
40 Manager *manager_new(void) {
48 m->machines = hashmap_new(&string_hash_ops);
49 m->machine_units = hashmap_new(&string_hash_ops);
50 m->machine_leaders = hashmap_new(NULL);
52 if (!m->machines || !m->machine_units || !m->machine_leaders) {
57 r = sd_event_default(&m->event);
63 sd_event_set_watchdog(m->event, true);
68 void manager_free(Manager *m) {
74 while ((machine = hashmap_first(m->machines)))
75 machine_free(machine);
77 hashmap_free(m->machines);
78 hashmap_free(m->machine_units);
79 hashmap_free(m->machine_leaders);
81 while ((i = hashmap_steal_first(m->image_cache)))
84 hashmap_free(m->image_cache);
86 sd_event_source_unref(m->image_cache_defer_event);
88 bus_verify_polkit_async_registry_free(m->polkit_registry);
91 sd_event_unref(m->event);
96 int manager_enumerate_machines(Manager *m) {
97 _cleanup_closedir_ DIR *d = NULL;
103 /* Read in machine data stored on disk */
104 d = opendir("/run/systemd/machines");
109 log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
113 FOREACH_DIRENT(de, d, return -errno) {
114 struct Machine *machine;
117 if (!dirent_is_file(de))
120 /* Ignore symlinks that map the unit name to the machine */
121 if (startswith(de->d_name, "unit:"))
124 k = manager_add_machine(m, de->d_name, &machine);
126 log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
132 machine_add_to_gc_queue(machine);
134 k = machine_load(machine);
142 static int manager_connect_bus(Manager *m) {
143 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
149 r = sd_bus_default_system(&m->bus);
151 return log_error_errno(r, "Failed to connect to system bus: %m");
153 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
155 return log_error_errno(r, "Failed to add manager object vtable: %m");
157 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
159 return log_error_errno(r, "Failed to add machine object vtable: %m");
161 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
163 return log_error_errno(r, "Failed to add machine enumerator: %m");
165 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
167 return log_error_errno(r, "Failed to add image object vtable: %m");
169 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
171 return log_error_errno(r, "Failed to add image enumerator: %m");
173 r = sd_bus_add_match(m->bus,
176 "sender='org.freedesktop.systemd1',"
177 "interface='org.freedesktop.systemd1.Manager',"
178 "member='JobRemoved',"
179 "path='/org/freedesktop/systemd1'",
183 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
185 r = sd_bus_add_match(m->bus,
188 "sender='org.freedesktop.systemd1',"
189 "interface='org.freedesktop.systemd1.Manager',"
190 "member='UnitRemoved',"
191 "path='/org/freedesktop/systemd1'",
195 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
197 r = sd_bus_add_match(m->bus,
200 "sender='org.freedesktop.systemd1',"
201 "interface='org.freedesktop.DBus.Properties',"
202 "member='PropertiesChanged'",
203 match_properties_changed,
206 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
208 r = sd_bus_add_match(m->bus,
211 "sender='org.freedesktop.systemd1',"
212 "interface='org.freedesktop.systemd1.Manager',"
213 "member='Reloading',"
214 "path='/org/freedesktop/systemd1'",
218 return log_error_errno(r, "Failed to add match for Reloading: %m");
220 r = sd_bus_call_method(
222 "org.freedesktop.systemd1",
223 "/org/freedesktop/systemd1",
224 "org.freedesktop.systemd1.Manager",
229 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
233 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
235 return log_error_errno(r, "Failed to register name: %m");
237 r = sd_bus_attach_event(m->bus, m->event, 0);
239 return log_error_errno(r, "Failed to attach bus to event loop: %m");
244 void manager_gc(Manager *m, bool drop_not_started) {
249 while ((machine = m->machine_gc_queue)) {
250 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
251 machine->in_gc_queue = false;
253 if (!machine_check_gc(machine, drop_not_started)) {
254 machine_stop(machine);
255 machine_free(machine);
260 int manager_startup(Manager *m) {
267 /* Connect to the bus */
268 r = manager_connect_bus(m);
272 /* Deserialize state */
273 manager_enumerate_machines(m);
275 /* Remove stale objects before we start them */
276 manager_gc(m, false);
278 /* And start everything */
279 HASHMAP_FOREACH(machine, m->machines, i)
280 machine_start(machine, NULL, NULL);
285 static bool check_idle(void *userdata) {
286 Manager *m = userdata;
290 return hashmap_isempty(m->machines);
293 int manager_run(Manager *m) {
296 return bus_event_loop_with_idle(
299 "org.freedesktop.machine1",
304 int main(int argc, char *argv[]) {
308 log_set_target(LOG_TARGET_AUTO);
309 log_set_facility(LOG_AUTH);
310 log_parse_environment();
316 log_error("This program takes no arguments.");
321 /* Always create the directories people can create inotify
322 * watches in. Note that some applications might check for the
323 * existence of /run/systemd/machines/ to determine whether
324 * machined is available, so please always make sure this
326 mkdir_label("/run/systemd/machines", 0755);
334 r = manager_startup(m);
336 log_error_errno(r, "Failed to fully start up daemon: %m");
340 log_debug("systemd-machined running as pid "PID_FMT, getpid());
344 "STATUS=Processing requests...");
348 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
354 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;