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"
39 Manager *manager_new(void) {
47 m->machines = hashmap_new(&string_hash_ops);
48 m->machine_units = hashmap_new(&string_hash_ops);
49 m->machine_leaders = hashmap_new(NULL);
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_errno(errno, "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 /* Ignore symlinks that map the unit name to the machine */
110 if (startswith(de->d_name, "unit:"))
113 k = manager_add_machine(m, de->d_name, &machine);
115 log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
121 machine_add_to_gc_queue(machine);
123 k = machine_load(machine);
131 static int manager_connect_bus(Manager *m) {
132 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
138 r = sd_bus_default_system(&m->bus);
140 return log_error_errno(r, "Failed to connect to system bus: %m");
142 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
144 return log_error_errno(r, "Failed to add manager object vtable: %m");
146 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
148 return log_error_errno(r, "Failed to add machine object vtable: %m");
150 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
152 return log_error_errno(r, "Failed to add machine enumerator: %m");
154 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
156 return log_error_errno(r, "Failed to add image object vtable: %m");
158 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
160 return log_error_errno(r, "Failed to add image enumerator: %m");
162 r = sd_bus_add_match(m->bus,
165 "sender='org.freedesktop.systemd1',"
166 "interface='org.freedesktop.systemd1.Manager',"
167 "member='JobRemoved',"
168 "path='/org/freedesktop/systemd1'",
172 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
174 r = sd_bus_add_match(m->bus,
177 "sender='org.freedesktop.systemd1',"
178 "interface='org.freedesktop.systemd1.Manager',"
179 "member='UnitRemoved',"
180 "path='/org/freedesktop/systemd1'",
184 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
186 r = sd_bus_add_match(m->bus,
189 "sender='org.freedesktop.systemd1',"
190 "interface='org.freedesktop.DBus.Properties',"
191 "member='PropertiesChanged'",
192 match_properties_changed,
195 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
197 r = sd_bus_add_match(m->bus,
200 "sender='org.freedesktop.systemd1',"
201 "interface='org.freedesktop.systemd1.Manager',"
202 "member='Reloading',"
203 "path='/org/freedesktop/systemd1'",
207 return log_error_errno(r, "Failed to add match for Reloading: %m");
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 return log_error_errno(r, "Failed to register name: %m");
226 r = sd_bus_attach_event(m->bus, m->event, 0);
228 return log_error_errno(r, "Failed to attach bus to event loop: %m");
233 void manager_gc(Manager *m, bool drop_not_started) {
238 while ((machine = m->machine_gc_queue)) {
239 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
240 machine->in_gc_queue = false;
242 if (!machine_check_gc(machine, drop_not_started)) {
243 machine_stop(machine);
244 machine_free(machine);
249 int manager_startup(Manager *m) {
256 /* Connect to the bus */
257 r = manager_connect_bus(m);
261 /* Deserialize state */
262 manager_enumerate_machines(m);
264 /* Remove stale objects before we start them */
265 manager_gc(m, false);
267 /* And start everything */
268 HASHMAP_FOREACH(machine, m->machines, i)
269 machine_start(machine, NULL, NULL);
274 static bool check_idle(void *userdata) {
275 Manager *m = userdata;
279 return hashmap_isempty(m->machines);
282 int manager_run(Manager *m) {
285 return bus_event_loop_with_idle(
288 "org.freedesktop.machine1",
293 int main(int argc, char *argv[]) {
297 log_set_target(LOG_TARGET_AUTO);
298 log_set_facility(LOG_AUTH);
299 log_parse_environment();
305 log_error("This program takes no arguments.");
310 /* Always create the directories people can create inotify
311 * watches in. Note that some applications might check for the
312 * existence of /run/systemd/machines/ to determine whether
313 * machined is available, so please always make sure this
315 mkdir_label("/run/systemd/machines", 0755);
323 r = manager_startup(m);
325 log_error_errno(r, "Failed to fully start up daemon: %m");
329 log_debug("systemd-machined running as pid "PID_FMT, getpid());
333 "STATUS=Processing requests...");
337 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
343 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;