]>
git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined.c
99301408d340a92119e97a29871310cf2f2b859c
1 /* SPDX-License-Identifier: LGPL-2.1-or-later */
9 #include "alloc-util.h"
10 #include "bus-error.h"
11 #include "bus-locator.h"
12 #include "bus-log-control-api.h"
13 #include "bus-polkit.h"
14 #include "cgroup-util.h"
15 #include "common-signal.h"
16 #include "daemon-util.h"
17 #include "dirent-util.h"
18 #include "discover-image.h"
20 #include "format-util.h"
21 #include "hostname-util.h"
22 #include "machined-varlink.h"
24 #include "main-func.h"
25 #include "mkdir-label.h"
26 #include "process-util.h"
27 #include "service-util.h"
28 #include "signal-util.h"
31 static Manager
* manager_unref(Manager
*m
);
32 DEFINE_TRIVIAL_CLEANUP_FUNC(Manager
*, manager_unref
);
34 DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(machine_hash_ops
, char, string_hash_func
, string_compare_func
, Machine
, machine_free
);
36 static int manager_new(Manager
**ret
) {
37 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
46 m
->machines
= hashmap_new(&machine_hash_ops
);
47 m
->machine_units
= hashmap_new(&string_hash_ops
);
48 m
->machine_leaders
= hashmap_new(NULL
);
50 if (!m
->machines
|| !m
->machine_units
|| !m
->machine_leaders
)
53 r
= sd_event_default(&m
->event
);
57 r
= sd_event_add_signal(m
->event
, NULL
, SIGINT
, NULL
, NULL
);
61 r
= sd_event_add_signal(m
->event
, NULL
, SIGTERM
, NULL
, NULL
);
65 r
= sd_event_add_signal(m
->event
, NULL
, SIGRTMIN
+18, sigrtmin18_handler
, NULL
);
69 r
= sd_event_add_memory_pressure(m
->event
, NULL
, NULL
, NULL
);
71 log_full_errno(ERRNO_IS_NOT_SUPPORTED(r
) || ERRNO_IS_PRIVILEGE(r
) || r
== -EHOSTDOWN
? LOG_DEBUG
: LOG_NOTICE
, r
,
72 "Unable to create memory pressure event source, ignoring: %m");
74 (void) sd_event_set_watchdog(m
->event
, true);
80 static Manager
* manager_unref(Manager
*m
) {
85 operation_free(m
->operations
);
87 assert(m
->n_operations
== 0);
89 hashmap_free(m
->machines
); /* This will free all machines, so that the machine_units/machine_leaders is empty */
90 hashmap_free(m
->machine_units
);
91 hashmap_free(m
->machine_leaders
);
92 hashmap_free(m
->image_cache
);
94 sd_event_source_unref(m
->image_cache_defer_event
);
96 sd_event_source_unref(m
->nscd_cache_flush_event
);
99 hashmap_free(m
->polkit_registry
);
101 manager_varlink_done(m
);
103 sd_bus_flush_close_unref(m
->bus
);
104 sd_event_unref(m
->event
);
109 static int manager_add_host_machine(Manager
*m
) {
110 _cleanup_(pidref_done
) PidRef pidref
= PIDREF_NULL
;
111 _cleanup_free_
char *rd
= NULL
, *unit
= NULL
;
119 r
= sd_id128_get_machine(&mid
);
121 return log_error_errno(r
, "Failed to get machine ID: %m");
127 unit
= strdup(SPECIAL_ROOT_SLICE
);
131 r
= pidref_set_pid(&pidref
, 1);
133 return log_error_errno(r
, "Failed to open reference to PID 1: %m");
135 r
= machine_new(m
, MACHINE_HOST
, ".host", &t
);
137 return log_error_errno(r
, "Failed to create machine: %m");
139 t
->leader
= TAKE_PIDREF(pidref
);
142 t
->root_directory
= TAKE_PTR(rd
);
143 t
->unit
= TAKE_PTR(unit
);
145 dual_timestamp_from_boottime(&t
->timestamp
, 0);
152 static int manager_enumerate_machines(Manager
*m
) {
153 _cleanup_closedir_
DIR *d
= NULL
;
158 r
= manager_add_host_machine(m
);
162 /* Read in machine data stored on disk */
163 d
= opendir("/run/systemd/machines");
168 return log_error_errno(errno
, "Failed to open /run/systemd/machines: %m");
171 FOREACH_DIRENT(de
, d
, return -errno
) {
172 struct Machine
*machine
;
175 if (!dirent_is_file(de
))
178 /* Ignore symlinks that map the unit name to the machine */
179 if (startswith(de
->d_name
, "unit:"))
182 if (!hostname_is_valid(de
->d_name
, 0))
185 k
= manager_add_machine(m
, de
->d_name
, &machine
);
187 r
= log_error_errno(k
, "Failed to add machine by file name %s: %m", de
->d_name
);
191 machine_add_to_gc_queue(machine
);
193 k
= machine_load(machine
);
201 static int manager_connect_bus(Manager
*m
) {
207 r
= sd_bus_default_system(&m
->bus
);
209 return log_error_errno(r
, "Failed to connect to system bus: %m");
211 r
= bus_add_implementation(m
->bus
, &manager_object
, m
);
215 r
= bus_match_signal_async(m
->bus
, NULL
, bus_systemd_mgr
, "JobRemoved", match_job_removed
, NULL
, m
);
217 return log_error_errno(r
, "Failed to add match for JobRemoved: %m");
219 r
= bus_match_signal_async(m
->bus
, NULL
, bus_systemd_mgr
, "UnitRemoved", match_unit_removed
, NULL
, m
);
221 return log_error_errno(r
, "Failed to request match for UnitRemoved: %m");
223 r
= sd_bus_match_signal_async(
226 "org.freedesktop.systemd1",
228 "org.freedesktop.DBus.Properties",
230 match_properties_changed
, NULL
, m
);
232 return log_error_errno(r
, "Failed to request match for PropertiesChanged: %m");
234 r
= bus_match_signal_async(m
->bus
, NULL
, bus_systemd_mgr
, "Reloading", match_reloading
, NULL
, m
);
236 return log_error_errno(r
, "Failed to request match for Reloading: %m");
238 r
= bus_call_method_async(m
->bus
, NULL
, bus_systemd_mgr
, "Subscribe", NULL
, NULL
, NULL
);
240 return log_error_errno(r
, "Failed to enable subscription: %m");
242 r
= bus_log_control_api_register(m
->bus
);
246 r
= sd_bus_request_name_async(m
->bus
, NULL
, "org.freedesktop.machine1", 0, NULL
, NULL
);
248 return log_error_errno(r
, "Failed to request name: %m");
250 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
252 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
257 static void manager_gc(Manager
*m
, bool drop_not_started
) {
262 while ((machine
= LIST_POP(gc_queue
, m
->machine_gc_queue
))) {
263 machine
->in_gc_queue
= false;
265 /* First, if we are not closing yet, initiate stopping */
266 if (machine_may_gc(machine
, drop_not_started
) &&
267 machine_get_state(machine
) != MACHINE_CLOSING
)
268 machine_stop(machine
);
270 /* Now, the stop probably made this referenced
271 * again, but if it didn't, then it's time to let it
273 if (machine_may_gc(machine
, drop_not_started
)) {
274 machine_finalize(machine
);
275 machine_free(machine
);
280 static int manager_startup(Manager
*m
) {
286 /* Connect to the bus */
287 r
= manager_connect_bus(m
);
291 /* Set up Varlink service */
292 r
= manager_varlink_init(m
);
296 /* Deserialize state */
297 manager_enumerate_machines(m
);
299 /* Remove stale objects before we start them */
300 manager_gc(m
, false);
302 /* And start everything */
303 HASHMAP_FOREACH(machine
, m
->machines
)
304 machine_start(machine
, NULL
, NULL
);
309 static bool check_idle(void *userdata
) {
310 Manager
*m
= userdata
;
315 if (varlink_server_current_connections(m
->varlink_server
) > 0)
320 return hashmap_isempty(m
->machines
);
323 static int run(int argc
, char *argv
[]) {
324 _cleanup_(manager_unrefp
) Manager
*m
= NULL
;
327 log_set_facility(LOG_AUTH
);
330 r
= service_parse_argv("systemd-machined.service",
331 "Manage registrations of local VMs and containers.",
332 BUS_IMPLEMENTATIONS(&manager_object
,
333 &log_control_object
),
340 /* Always create the directories people can create inotify watches in. Note that some applications might check
341 * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
342 * make sure this check stays in. */
343 (void) mkdir_label("/run/systemd/machines", 0755);
345 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGCHLD
, SIGTERM
, SIGINT
, SIGRTMIN
+18) >= 0);
349 return log_error_errno(r
, "Failed to allocate manager object: %m");
351 r
= manager_startup(m
);
353 return log_error_errno(r
, "Failed to fully start up daemon: %m");
355 r
= sd_notify(false, NOTIFY_READY
);
357 log_warning_errno(r
, "Failed to send readiness notification, ignoring: %m");
359 r
= bus_event_loop_with_idle(
362 "org.freedesktop.machine1",
366 return log_error_errno(r
, "Failed to run main loop: %m");
371 DEFINE_MAIN_FUNCTION(run
);