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"
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) {
73 while ((machine = hashmap_first(m->machines)))
74 machine_free(machine);
76 hashmap_free(m->machines);
77 hashmap_free(m->machine_units);
78 hashmap_free(m->machine_leaders);
81 sd_event_unref(m->event);
86 int manager_enumerate_machines(Manager *m) {
87 _cleanup_closedir_ DIR *d = NULL;
93 /* Read in machine data stored on disk */
94 d = opendir("/run/systemd/machines");
99 log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
103 FOREACH_DIRENT(de, d, return -errno) {
104 struct Machine *machine;
107 if (!dirent_is_file(de))
110 /* Ignore symlinks that map the unit name to the machine */
111 if (startswith(de->d_name, "unit:"))
114 k = manager_add_machine(m, de->d_name, &machine);
116 log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
122 machine_add_to_gc_queue(machine);
124 k = machine_load(machine);
132 static int manager_connect_bus(Manager *m) {
133 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
139 r = sd_bus_default_system(&m->bus);
141 return log_error_errno(r, "Failed to connect to system bus: %m");
143 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
145 return log_error_errno(r, "Failed to add manager object vtable: %m");
147 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
149 return log_error_errno(r, "Failed to add machine object vtable: %m");
151 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
153 return log_error_errno(r, "Failed to add machine enumerator: %m");
155 r = sd_bus_add_match(m->bus,
158 "sender='org.freedesktop.systemd1',"
159 "interface='org.freedesktop.systemd1.Manager',"
160 "member='JobRemoved',"
161 "path='/org/freedesktop/systemd1'",
165 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
167 r = sd_bus_add_match(m->bus,
170 "sender='org.freedesktop.systemd1',"
171 "interface='org.freedesktop.systemd1.Manager',"
172 "member='UnitRemoved',"
173 "path='/org/freedesktop/systemd1'",
177 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
179 r = sd_bus_add_match(m->bus,
182 "sender='org.freedesktop.systemd1',"
183 "interface='org.freedesktop.DBus.Properties',"
184 "member='PropertiesChanged'",
185 match_properties_changed,
188 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
190 r = sd_bus_add_match(m->bus,
193 "sender='org.freedesktop.systemd1',"
194 "interface='org.freedesktop.systemd1.Manager',"
195 "member='Reloading',"
196 "path='/org/freedesktop/systemd1'",
200 return log_error_errno(r, "Failed to add match for Reloading: %m");
202 r = sd_bus_call_method(
204 "org.freedesktop.systemd1",
205 "/org/freedesktop/systemd1",
206 "org.freedesktop.systemd1.Manager",
211 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
215 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
217 return log_error_errno(r, "Failed to register name: %m");
219 r = sd_bus_attach_event(m->bus, m->event, 0);
221 return log_error_errno(r, "Failed to attach bus to event loop: %m");
226 void manager_gc(Manager *m, bool drop_not_started) {
231 while ((machine = m->machine_gc_queue)) {
232 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
233 machine->in_gc_queue = false;
235 if (!machine_check_gc(machine, drop_not_started)) {
236 machine_stop(machine);
237 machine_free(machine);
242 int manager_startup(Manager *m) {
249 /* Connect to the bus */
250 r = manager_connect_bus(m);
254 /* Deserialize state */
255 manager_enumerate_machines(m);
257 /* Remove stale objects before we start them */
258 manager_gc(m, false);
260 /* And start everything */
261 HASHMAP_FOREACH(machine, m->machines, i)
262 machine_start(machine, NULL, NULL);
267 static bool check_idle(void *userdata) {
268 Manager *m = userdata;
272 return hashmap_isempty(m->machines);
275 int manager_run(Manager *m) {
278 return bus_event_loop_with_idle(
281 "org.freedesktop.machine1",
286 int main(int argc, char *argv[]) {
290 log_set_target(LOG_TARGET_AUTO);
291 log_set_facility(LOG_AUTH);
292 log_parse_environment();
298 log_error("This program takes no arguments.");
303 /* Always create the directories people can create inotify
304 * watches in. Note that some applications might check for the
305 * existence of /run/systemd/machines/ to determine whether
306 * machined is available, so please always make sure this
308 mkdir_label("/run/systemd/machines", 0755);
316 r = manager_startup(m);
318 log_error_errno(r, "Failed to fully start up daemon: %m");
322 log_debug("systemd-machined running as pid "PID_FMT, getpid());
326 "STATUS=Processing requests...");
330 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
336 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;