]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined.c
1 /* SPDX-License-Identifier: LGPL-2.1+ */
3 This file is part of systemd.
5 Copyright 2013 Lennart Poettering
12 #include "sd-daemon.h"
14 #include "alloc-util.h"
15 #include "bus-error.h"
17 #include "cgroup-util.h"
18 #include "dirent-util.h"
20 #include "format-util.h"
21 #include "hostname-util.h"
23 #include "machine-image.h"
25 #include "process-util.h"
26 #include "signal-util.h"
29 static Manager
* manager_unref(Manager
*m
);
30 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager
*, manager_unref
);
32 static int manager_new(Manager
**ret
) {
33 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
42 m
->machines
= hashmap_new(&string_hash_ops
);
43 m
->machine_units
= hashmap_new(&string_hash_ops
);
44 m
->machine_leaders
= hashmap_new(NULL
);
46 if (!m
->machines
|| !m
->machine_units
|| !m
->machine_leaders
)
49 r
= sd_event_default(&m
->event
);
53 r
= sd_event_add_signal(m
->event
, NULL
, SIGINT
, NULL
, NULL
);
57 r
= sd_event_add_signal(m
->event
, NULL
, SIGTERM
, NULL
, NULL
);
61 (void) sd_event_set_watchdog(m
->event
, true);
67 static Manager
* manager_unref(Manager
*m
) {
74 operation_free(m
->operations
);
76 assert(m
->n_operations
== 0);
78 while ((machine
= hashmap_first(m
->machines
)))
79 machine_free(machine
);
81 hashmap_free(m
->machines
);
82 hashmap_free(m
->machine_units
);
83 hashmap_free(m
->machine_leaders
);
85 hashmap_free_with_destructor(m
->image_cache
, image_unref
);
87 sd_event_source_unref(m
->image_cache_defer_event
);
89 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
92 sd_event_unref(m
->event
);
97 static int manager_add_host_machine(Manager
*m
) {
98 _cleanup_free_
char *rd
= NULL
, *unit
= NULL
;
106 r
= sd_id128_get_machine(&mid
);
108 return log_error_errno(r
, "Failed to get machine ID: %m");
114 unit
= strdup(SPECIAL_ROOT_SLICE
);
118 t
= machine_new(m
, MACHINE_HOST
, ".host");
125 t
->root_directory
= TAKE_PTR(rd
);
126 t
->unit
= TAKE_PTR(unit
);
128 dual_timestamp_from_boottime_or_monotonic(&t
->timestamp
, 0);
135 static int manager_enumerate_machines(Manager
*m
) {
136 _cleanup_closedir_
DIR *d
= NULL
;
142 r
= manager_add_host_machine(m
);
146 /* Read in machine data stored on disk */
147 d
= opendir("/run/systemd/machines");
152 return log_error_errno(errno
, "Failed to open /run/systemd/machines: %m");
155 FOREACH_DIRENT(de
, d
, return -errno
) {
156 struct Machine
*machine
;
159 if (!dirent_is_file(de
))
162 /* Ignore symlinks that map the unit name to the machine */
163 if (startswith(de
->d_name
, "unit:"))
166 if (!machine_name_is_valid(de
->d_name
))
169 k
= manager_add_machine(m
, de
->d_name
, &machine
);
171 r
= log_error_errno(k
, "Failed to add machine by file name %s: %m", de
->d_name
);
175 machine_add_to_gc_queue(machine
);
177 k
= machine_load(machine
);
185 static int manager_connect_bus(Manager
*m
) {
191 r
= sd_bus_default_system(&m
->bus
);
193 return log_error_errno(r
, "Failed to connect to system bus: %m");
195 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable
, m
);
197 return log_error_errno(r
, "Failed to add manager object vtable: %m");
199 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable
, machine_object_find
, m
);
201 return log_error_errno(r
, "Failed to add machine object vtable: %m");
203 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", machine_node_enumerator
, m
);
205 return log_error_errno(r
, "Failed to add machine enumerator: %m");
207 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable
, image_object_find
, m
);
209 return log_error_errno(r
, "Failed to add image object vtable: %m");
211 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/image", image_node_enumerator
, m
);
213 return log_error_errno(r
, "Failed to add image enumerator: %m");
215 r
= sd_bus_match_signal_async(
218 "org.freedesktop.systemd1",
219 "/org/freedesktop/systemd1",
220 "org.freedesktop.systemd1.Manager",
222 match_job_removed
, NULL
, m
);
224 return log_error_errno(r
, "Failed to add match for JobRemoved: %m");
226 r
= sd_bus_match_signal_async(
229 "org.freedesktop.systemd1",
230 "/org/freedesktop/systemd1",
231 "org.freedesktop.systemd1.Manager",
233 match_unit_removed
, NULL
, m
);
235 return log_error_errno(r
, "Failed to request match for UnitRemoved: %m");
237 r
= sd_bus_match_signal_async(
240 "org.freedesktop.systemd1",
242 "org.freedesktop.DBus.Properties",
244 match_properties_changed
, NULL
, m
);
246 return log_error_errno(r
, "Failed to request match for PropertiesChanged: %m");
248 r
= sd_bus_match_signal_async(
251 "org.freedesktop.systemd1",
252 "/org/freedesktop/systemd1",
253 "org.freedesktop.systemd1.Manager",
255 match_reloading
, NULL
, m
);
257 return log_error_errno(r
, "Failed to request match for Reloading: %m");
259 r
= sd_bus_call_method_async(
262 "org.freedesktop.systemd1",
263 "/org/freedesktop/systemd1",
264 "org.freedesktop.systemd1.Manager",
269 return log_error_errno(r
, "Failed to enable subscription: %m");
271 r
= sd_bus_request_name_async(m
->bus
, NULL
, "org.freedesktop.machine1", 0, NULL
, NULL
);
273 return log_error_errno(r
, "Failed to request name: %m");
275 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
277 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
282 static void manager_gc(Manager
*m
, bool drop_not_started
) {
287 while ((machine
= m
->machine_gc_queue
)) {
288 LIST_REMOVE(gc_queue
, m
->machine_gc_queue
, machine
);
289 machine
->in_gc_queue
= false;
291 /* First, if we are not closing yet, initiate stopping */
292 if (machine_may_gc(machine
, drop_not_started
) &&
293 machine_get_state(machine
) != MACHINE_CLOSING
)
294 machine_stop(machine
);
296 /* Now, the stop probably made this referenced
297 * again, but if it didn't, then it's time to let it
299 if (machine_may_gc(machine
, drop_not_started
)) {
300 machine_finalize(machine
);
301 machine_free(machine
);
306 static int manager_startup(Manager
*m
) {
313 /* Connect to the bus */
314 r
= manager_connect_bus(m
);
318 /* Deserialize state */
319 manager_enumerate_machines(m
);
321 /* Remove stale objects before we start them */
322 manager_gc(m
, false);
324 /* And start everything */
325 HASHMAP_FOREACH(machine
, m
->machines
, i
)
326 machine_start(machine
, NULL
, NULL
);
331 static bool check_idle(void *userdata
) {
332 Manager
*m
= userdata
;
339 return hashmap_isempty(m
->machines
);
342 static int manager_run(Manager
*m
) {
345 return bus_event_loop_with_idle(
348 "org.freedesktop.machine1",
353 int main(int argc
, char *argv
[]) {
354 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
357 log_set_target(LOG_TARGET_AUTO
);
358 log_set_facility(LOG_AUTH
);
359 log_parse_environment();
365 log_error("This program takes no arguments.");
370 /* Always create the directories people can create inotify watches in. Note that some applications might check
371 * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
372 * make sure this check stays in. */
373 (void) mkdir_label("/run/systemd/machines", 0755);
375 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGCHLD
, SIGTERM
, SIGINT
, -1) >= 0);
379 log_error_errno(r
, "Failed to allocate manager object: %m");
383 r
= manager_startup(m
);
385 log_error_errno(r
, "Failed to fully start up daemon: %m");
389 log_debug("systemd-machined running as pid "PID_FMT
, getpid_cached());
391 (void) sd_notify(false,
393 "STATUS=Processing requests...");
397 log_debug("systemd-machined stopped as pid "PID_FMT
, getpid_cached());
399 (void) sd_notify(false,
401 "STATUS=Shutting down...");
404 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;