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/>.
26 #include "sd-daemon.h"
27 #include "cgroup-util.h"
29 #include "bus-error.h"
31 #include "machine-image.h"
33 #include "formats-util.h"
35 Manager
*manager_new(void) {
43 m
->machines
= hashmap_new(&string_hash_ops
);
44 m
->machine_units
= hashmap_new(&string_hash_ops
);
45 m
->machine_leaders
= hashmap_new(NULL
);
47 if (!m
->machines
|| !m
->machine_units
|| !m
->machine_leaders
) {
52 r
= sd_event_default(&m
->event
);
58 sd_event_set_watchdog(m
->event
, true);
63 void manager_free(Manager
*m
) {
69 while ((machine
= hashmap_first(m
->machines
)))
70 machine_free(machine
);
72 hashmap_free(m
->machines
);
73 hashmap_free(m
->machine_units
);
74 hashmap_free(m
->machine_leaders
);
76 while ((i
= hashmap_steal_first(m
->image_cache
)))
79 hashmap_free(m
->image_cache
);
81 sd_event_source_unref(m
->image_cache_defer_event
);
83 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
86 sd_event_unref(m
->event
);
91 int manager_enumerate_machines(Manager
*m
) {
92 _cleanup_closedir_
DIR *d
= NULL
;
98 /* Read in machine data stored on disk */
99 d
= opendir("/run/systemd/machines");
104 log_error_errno(errno
, "Failed to open /run/systemd/machines: %m");
108 FOREACH_DIRENT(de
, d
, return -errno
) {
109 struct Machine
*machine
;
112 if (!dirent_is_file(de
))
115 /* Ignore symlinks that map the unit name to the machine */
116 if (startswith(de
->d_name
, "unit:"))
119 k
= manager_add_machine(m
, de
->d_name
, &machine
);
121 log_error_errno(k
, "Failed to add machine by file name %s: %m", de
->d_name
);
127 machine_add_to_gc_queue(machine
);
129 k
= machine_load(machine
);
137 static int manager_connect_bus(Manager
*m
) {
138 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
144 r
= sd_bus_default_system(&m
->bus
);
146 return log_error_errno(r
, "Failed to connect to system bus: %m");
148 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable
, m
);
150 return log_error_errno(r
, "Failed to add manager object vtable: %m");
152 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable
, machine_object_find
, m
);
154 return log_error_errno(r
, "Failed to add machine object vtable: %m");
156 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", machine_node_enumerator
, m
);
158 return log_error_errno(r
, "Failed to add machine enumerator: %m");
160 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable
, image_object_find
, m
);
162 return log_error_errno(r
, "Failed to add image object vtable: %m");
164 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/image", image_node_enumerator
, m
);
166 return log_error_errno(r
, "Failed to add image enumerator: %m");
168 r
= sd_bus_add_match(m
->bus
,
171 "sender='org.freedesktop.systemd1',"
172 "interface='org.freedesktop.systemd1.Manager',"
173 "member='JobRemoved',"
174 "path='/org/freedesktop/systemd1'",
178 return log_error_errno(r
, "Failed to add match for JobRemoved: %m");
180 r
= sd_bus_add_match(m
->bus
,
183 "sender='org.freedesktop.systemd1',"
184 "interface='org.freedesktop.systemd1.Manager',"
185 "member='UnitRemoved',"
186 "path='/org/freedesktop/systemd1'",
190 return log_error_errno(r
, "Failed to add match for UnitRemoved: %m");
192 r
= sd_bus_add_match(m
->bus
,
195 "sender='org.freedesktop.systemd1',"
196 "interface='org.freedesktop.DBus.Properties',"
197 "member='PropertiesChanged'",
198 match_properties_changed
,
201 return log_error_errno(r
, "Failed to add match for PropertiesChanged: %m");
203 r
= sd_bus_add_match(m
->bus
,
206 "sender='org.freedesktop.systemd1',"
207 "interface='org.freedesktop.systemd1.Manager',"
208 "member='Reloading',"
209 "path='/org/freedesktop/systemd1'",
213 return log_error_errno(r
, "Failed to add match for Reloading: %m");
215 r
= sd_bus_call_method(
217 "org.freedesktop.systemd1",
218 "/org/freedesktop/systemd1",
219 "org.freedesktop.systemd1.Manager",
224 log_error("Failed to enable subscription: %s", bus_error_message(&error
, r
));
228 r
= sd_bus_request_name(m
->bus
, "org.freedesktop.machine1", 0);
230 return log_error_errno(r
, "Failed to register name: %m");
232 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
234 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
239 void manager_gc(Manager
*m
, bool drop_not_started
) {
244 while ((machine
= m
->machine_gc_queue
)) {
245 LIST_REMOVE(gc_queue
, m
->machine_gc_queue
, machine
);
246 machine
->in_gc_queue
= false;
248 if (!machine_check_gc(machine
, drop_not_started
)) {
249 machine_stop(machine
);
250 machine_free(machine
);
255 int manager_startup(Manager
*m
) {
262 /* Connect to the bus */
263 r
= manager_connect_bus(m
);
267 /* Deserialize state */
268 manager_enumerate_machines(m
);
270 /* Remove stale objects before we start them */
271 manager_gc(m
, false);
273 /* And start everything */
274 HASHMAP_FOREACH(machine
, m
->machines
, i
)
275 machine_start(machine
, NULL
, NULL
);
280 static bool check_idle(void *userdata
) {
281 Manager
*m
= userdata
;
285 return hashmap_isempty(m
->machines
);
288 int manager_run(Manager
*m
) {
291 return bus_event_loop_with_idle(
294 "org.freedesktop.machine1",
299 int main(int argc
, char *argv
[]) {
303 log_set_target(LOG_TARGET_AUTO
);
304 log_set_facility(LOG_AUTH
);
305 log_parse_environment();
311 log_error("This program takes no arguments.");
316 /* Always create the directories people can create inotify
317 * watches in. Note that some applications might check for the
318 * existence of /run/systemd/machines/ to determine whether
319 * machined is available, so please always make sure this
321 mkdir_label("/run/systemd/machines", 0755);
323 assert_se(sigprocmask_many(SIG_BLOCK
, SIGCHLD
, -1) >= 0);
331 r
= manager_startup(m
);
333 log_error_errno(r
, "Failed to fully start up daemon: %m");
337 log_debug("systemd-machined running as pid "PID_FMT
, getpid());
341 "STATUS=Processing requests...");
345 log_debug("systemd-machined stopped as pid "PID_FMT
, getpid());
351 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;