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 "formats-util.h"
32 #include "signal-util.h"
33 #include "hostname-util.h"
34 #include "machine-image.h"
37 Manager
*manager_new(void) {
45 m
->machines
= hashmap_new(&string_hash_ops
);
46 m
->machine_units
= hashmap_new(&string_hash_ops
);
47 m
->machine_leaders
= hashmap_new(NULL
);
49 if (!m
->machines
|| !m
->machine_units
|| !m
->machine_leaders
) {
54 r
= sd_event_default(&m
->event
);
60 sd_event_set_watchdog(m
->event
, true);
65 void manager_free(Manager
*m
) {
71 while ((machine
= hashmap_first(m
->machines
)))
72 machine_free(machine
);
74 hashmap_free(m
->machines
);
75 hashmap_free(m
->machine_units
);
76 hashmap_free(m
->machine_leaders
);
78 while ((i
= hashmap_steal_first(m
->image_cache
)))
81 hashmap_free(m
->image_cache
);
83 sd_event_source_unref(m
->image_cache_defer_event
);
85 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
88 sd_event_unref(m
->event
);
93 static int manager_add_host_machine(Manager
*m
) {
94 _cleanup_free_
char *rd
= NULL
, *unit
= NULL
;
102 r
= sd_id128_get_machine(&mid
);
104 return log_error_errno(r
, "Failed to get machine ID: %m");
110 unit
= strdup("-.slice");
114 t
= machine_new(m
, MACHINE_HOST
, ".host");
121 t
->root_directory
= rd
;
125 dual_timestamp_from_boottime_or_monotonic(&t
->timestamp
, 0);
132 int manager_enumerate_machines(Manager
*m
) {
133 _cleanup_closedir_
DIR *d
= NULL
;
139 r
= manager_add_host_machine(m
);
143 /* Read in machine data stored on disk */
144 d
= opendir("/run/systemd/machines");
149 log_error_errno(errno
, "Failed to open /run/systemd/machines: %m");
153 FOREACH_DIRENT(de
, d
, return -errno
) {
154 struct Machine
*machine
;
157 if (!dirent_is_file(de
))
160 /* Ignore symlinks that map the unit name to the machine */
161 if (startswith(de
->d_name
, "unit:"))
164 if (!machine_name_is_valid(de
->d_name
))
167 k
= manager_add_machine(m
, de
->d_name
, &machine
);
169 r
= log_error_errno(k
, "Failed to add machine by file name %s: %m", de
->d_name
);
173 machine_add_to_gc_queue(machine
);
175 k
= machine_load(machine
);
183 static int manager_connect_bus(Manager
*m
) {
184 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
190 r
= sd_bus_default_system(&m
->bus
);
192 return log_error_errno(r
, "Failed to connect to system bus: %m");
194 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable
, m
);
196 return log_error_errno(r
, "Failed to add manager object vtable: %m");
198 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable
, machine_object_find
, m
);
200 return log_error_errno(r
, "Failed to add machine object vtable: %m");
202 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", machine_node_enumerator
, m
);
204 return log_error_errno(r
, "Failed to add machine enumerator: %m");
206 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable
, image_object_find
, m
);
208 return log_error_errno(r
, "Failed to add image object vtable: %m");
210 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/image", image_node_enumerator
, m
);
212 return log_error_errno(r
, "Failed to add image enumerator: %m");
214 r
= sd_bus_add_match(m
->bus
,
217 "sender='org.freedesktop.systemd1',"
218 "interface='org.freedesktop.systemd1.Manager',"
219 "member='JobRemoved',"
220 "path='/org/freedesktop/systemd1'",
224 return log_error_errno(r
, "Failed to add match for JobRemoved: %m");
226 r
= sd_bus_add_match(m
->bus
,
229 "sender='org.freedesktop.systemd1',"
230 "interface='org.freedesktop.systemd1.Manager',"
231 "member='UnitRemoved',"
232 "path='/org/freedesktop/systemd1'",
236 return log_error_errno(r
, "Failed to add match for UnitRemoved: %m");
238 r
= sd_bus_add_match(m
->bus
,
241 "sender='org.freedesktop.systemd1',"
242 "interface='org.freedesktop.DBus.Properties',"
243 "member='PropertiesChanged',"
244 "arg0='org.freedesktop.systemd1.Unit'",
245 match_properties_changed
,
248 return log_error_errno(r
, "Failed to add match for PropertiesChanged: %m");
250 r
= sd_bus_add_match(m
->bus
,
253 "sender='org.freedesktop.systemd1',"
254 "interface='org.freedesktop.systemd1.Manager',"
255 "member='Reloading',"
256 "path='/org/freedesktop/systemd1'",
260 return log_error_errno(r
, "Failed to add match for Reloading: %m");
262 r
= sd_bus_call_method(
264 "org.freedesktop.systemd1",
265 "/org/freedesktop/systemd1",
266 "org.freedesktop.systemd1.Manager",
271 log_error("Failed to enable subscription: %s", bus_error_message(&error
, r
));
275 r
= sd_bus_request_name(m
->bus
, "org.freedesktop.machine1", 0);
277 return log_error_errno(r
, "Failed to register name: %m");
279 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
281 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
286 void manager_gc(Manager
*m
, bool drop_not_started
) {
291 while ((machine
= m
->machine_gc_queue
)) {
292 LIST_REMOVE(gc_queue
, m
->machine_gc_queue
, machine
);
293 machine
->in_gc_queue
= false;
295 /* First, if we are not closing yet, initiate stopping */
296 if (!machine_check_gc(machine
, drop_not_started
) &&
297 machine_get_state(machine
) != MACHINE_CLOSING
)
298 machine_stop(machine
);
300 /* Now, the stop stop probably made this referenced
301 * again, but if it didn't, then it's time to let it
303 if (!machine_check_gc(machine
, drop_not_started
)) {
304 machine_finalize(machine
);
305 machine_free(machine
);
310 int manager_startup(Manager
*m
) {
317 /* Connect to the bus */
318 r
= manager_connect_bus(m
);
322 /* Deserialize state */
323 manager_enumerate_machines(m
);
325 /* Remove stale objects before we start them */
326 manager_gc(m
, false);
328 /* And start everything */
329 HASHMAP_FOREACH(machine
, m
->machines
, i
)
330 machine_start(machine
, NULL
, NULL
);
335 static bool check_idle(void *userdata
) {
336 Manager
*m
= userdata
;
340 return hashmap_isempty(m
->machines
);
343 int manager_run(Manager
*m
) {
346 return bus_event_loop_with_idle(
349 "org.freedesktop.machine1",
354 int main(int argc
, char *argv
[]) {
358 log_set_target(LOG_TARGET_AUTO
);
359 log_set_facility(LOG_AUTH
);
360 log_parse_environment();
366 log_error("This program takes no arguments.");
371 /* Always create the directories people can create inotify
372 * watches in. Note that some applications might check for the
373 * existence of /run/systemd/machines/ to determine whether
374 * machined is available, so please always make sure this
376 mkdir_label("/run/systemd/machines", 0755);
378 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGCHLD
, -1) >= 0);
386 r
= manager_startup(m
);
388 log_error_errno(r
, "Failed to fully start up daemon: %m");
392 log_debug("systemd-machined running as pid "PID_FMT
, getpid());
396 "STATUS=Processing requests...");
400 log_debug("systemd-machined stopped as pid "PID_FMT
, getpid());
405 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;