]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined.c
Merge pull request #11077 from yuwata/udev-issue-better-fix
[thirdparty/systemd.git] / src / machine / machined.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
1ee306e1
LP
2
3#include <errno.h>
1ee306e1
LP
4#include <string.h>
5#include <unistd.h>
1ee306e1 6
c3350683 7#include "sd-daemon.h"
3ffd4af2 8
b5efdb8a 9#include "alloc-util.h"
c3350683 10#include "bus-error.h"
3ffd4af2
LP
11#include "bus-util.h"
12#include "cgroup-util.h"
a0956174 13#include "dirent-util.h"
3ffd4af2 14#include "fd-util.h"
f97b34a6 15#include "format-util.h"
25300b5a 16#include "hostname-util.h"
3ffd4af2 17#include "label.h"
1ddb263d 18#include "machine-image.h"
ebeccf9e 19#include "machined.h"
5e332028 20#include "main-func.h"
df0ff127 21#include "process-util.h"
3ffd4af2 22#include "signal-util.h"
e5af6e0e 23#include "special.h"
1ee306e1 24
730fa7ce
LP
25static Manager* manager_unref(Manager *m);
26DEFINE_TRIVIAL_CLEANUP_FUNC(Manager*, manager_unref);
27
5be61bea 28DEFINE_PRIVATE_HASH_OPS_WITH_VALUE_DESTRUCTOR(machine_hash_ops, char, string_hash_func, string_compare_func, Machine, machine_free);
bb1a05d6 29
730fa7ce
LP
30static int manager_new(Manager **ret) {
31 _cleanup_(manager_unrefp) Manager *m = NULL;
c3350683 32 int r;
1ee306e1 33
730fa7ce
LP
34 assert(ret);
35
1ee306e1
LP
36 m = new0(Manager, 1);
37 if (!m)
730fa7ce 38 return -ENOMEM;
1ee306e1 39
5be61bea 40 m->machines = hashmap_new(&machine_hash_ops);
d5099efc 41 m->machine_units = hashmap_new(&string_hash_ops);
5be61bea 42 m->machine_leaders = hashmap_new(NULL);
1ee306e1 43
730fa7ce
LP
44 if (!m->machines || !m->machine_units || !m->machine_leaders)
45 return -ENOMEM;
c3350683 46
afc6adb5 47 r = sd_event_default(&m->event);
730fa7ce
LP
48 if (r < 0)
49 return r;
50
51 r = sd_event_add_signal(m->event, NULL, SIGINT, NULL, NULL);
52 if (r < 0)
53 return r;
54
55 r = sd_event_add_signal(m->event, NULL, SIGTERM, NULL, NULL);
56 if (r < 0)
57 return r;
1ee306e1 58
730fa7ce 59 (void) sd_event_set_watchdog(m->event, true);
cde93897 60
730fa7ce
LP
61 *ret = TAKE_PTR(m);
62 return 0;
1ee306e1
LP
63}
64
730fa7ce 65static Manager* manager_unref(Manager *m) {
c8f05436
LP
66 if (!m)
67 return NULL;
1ee306e1 68
56599585
LP
69 while (m->operations)
70 operation_free(m->operations);
71
72 assert(m->n_operations == 0);
73
5be61bea 74 hashmap_free(m->machines); /* This will free all machines, so that the machine_units/machine_leaders is empty */
1ee306e1 75 hashmap_free(m->machine_units);
d3e84ddb 76 hashmap_free(m->machine_leaders);
b07ec5a1 77 hashmap_free(m->image_cache);
1ddb263d
LP
78
79 sd_event_source_unref(m->image_cache_defer_event);
9fdcbae5 80 sd_event_source_unref(m->nscd_cache_flush_event);
1ddb263d 81
d04c1fb8
LP
82 bus_verify_polkit_async_registry_free(m->polkit_registry);
83
c3350683
LP
84 sd_bus_unref(m->bus);
85 sd_event_unref(m->event);
86
730fa7ce 87 return mfree(m);
c3350683
LP
88}
89
fbe55073
LP
90static int manager_add_host_machine(Manager *m) {
91 _cleanup_free_ char *rd = NULL, *unit = NULL;
92 sd_id128_t mid;
93 Machine *t;
94 int r;
95
96 if (m->host_machine)
97 return 0;
98
99 r = sd_id128_get_machine(&mid);
100 if (r < 0)
101 return log_error_errno(r, "Failed to get machine ID: %m");
102
103 rd = strdup("/");
104 if (!rd)
105 return log_oom();
106
e5af6e0e 107 unit = strdup(SPECIAL_ROOT_SLICE);
fbe55073
LP
108 if (!unit)
109 return log_oom();
110
111 t = machine_new(m, MACHINE_HOST, ".host");
112 if (!t)
113 return log_oom();
114
115 t->leader = 1;
116 t->id = mid;
117
1cc6c93a
YW
118 t->root_directory = TAKE_PTR(rd);
119 t->unit = TAKE_PTR(unit);
fbe55073
LP
120
121 dual_timestamp_from_boottime_or_monotonic(&t->timestamp, 0);
122
123 m->host_machine = t;
124
125 return 0;
126}
127
730fa7ce 128static int manager_enumerate_machines(Manager *m) {
1ee306e1
LP
129 _cleanup_closedir_ DIR *d = NULL;
130 struct dirent *de;
131 int r = 0;
132
133 assert(m);
134
fbe55073
LP
135 r = manager_add_host_machine(m);
136 if (r < 0)
137 return r;
138
1ee306e1
LP
139 /* Read in machine data stored on disk */
140 d = opendir("/run/systemd/machines");
141 if (!d) {
142 if (errno == ENOENT)
143 return 0;
144
e1427b13 145 return log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
1ee306e1
LP
146 }
147
148 FOREACH_DIRENT(de, d, return -errno) {
149 struct Machine *machine;
150 int k;
151
152 if (!dirent_is_file(de))
153 continue;
154
b87633c4
LP
155 /* Ignore symlinks that map the unit name to the machine */
156 if (startswith(de->d_name, "unit:"))
157 continue;
158
b9a8d250
LP
159 if (!machine_name_is_valid(de->d_name))
160 continue;
161
1ee306e1
LP
162 k = manager_add_machine(m, de->d_name, &machine);
163 if (k < 0) {
fbe55073 164 r = log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
1ee306e1
LP
165 continue;
166 }
167
168 machine_add_to_gc_queue(machine);
169
170 k = machine_load(machine);
171 if (k < 0)
172 r = k;
173 }
174
175 return r;
176}
177
1ee306e1 178static int manager_connect_bus(Manager *m) {
1ee306e1 179 int r;
1ee306e1
LP
180
181 assert(m);
182 assert(!m->bus);
1ee306e1 183
76b54375 184 r = sd_bus_default_system(&m->bus);
f647962d
MS
185 if (r < 0)
186 return log_error_errno(r, "Failed to connect to system bus: %m");
1ee306e1 187
19befb2d 188 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
f647962d
MS
189 if (r < 0)
190 return log_error_errno(r, "Failed to add manager object vtable: %m");
1ee306e1 191
19befb2d 192 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
f647962d
MS
193 if (r < 0)
194 return log_error_errno(r, "Failed to add machine object vtable: %m");
c3350683 195
19befb2d 196 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
f647962d
MS
197 if (r < 0)
198 return log_error_errno(r, "Failed to add machine enumerator: %m");
1ee306e1 199
ebeccf9e
LP
200 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
201 if (r < 0)
202 return log_error_errno(r, "Failed to add image object vtable: %m");
203
204 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
205 if (r < 0)
206 return log_error_errno(r, "Failed to add image enumerator: %m");
207
75152a4d
LP
208 r = sd_bus_match_signal_async(
209 m->bus,
210 NULL,
211 "org.freedesktop.systemd1",
212 "/org/freedesktop/systemd1",
213 "org.freedesktop.systemd1.Manager",
214 "JobRemoved",
215 match_job_removed, NULL, m);
f647962d
MS
216 if (r < 0)
217 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
1ee306e1 218
75152a4d
LP
219 r = sd_bus_match_signal_async(
220 m->bus,
221 NULL,
222 "org.freedesktop.systemd1",
223 "/org/freedesktop/systemd1",
224 "org.freedesktop.systemd1.Manager",
225 "UnitRemoved",
226 match_unit_removed, NULL, m);
f647962d 227 if (r < 0)
75152a4d
LP
228 return log_error_errno(r, "Failed to request match for UnitRemoved: %m");
229
230 r = sd_bus_match_signal_async(
231 m->bus,
232 NULL,
233 "org.freedesktop.systemd1",
234 NULL,
235 "org.freedesktop.DBus.Properties",
236 "PropertiesChanged",
237 match_properties_changed, NULL, m);
f647962d 238 if (r < 0)
75152a4d
LP
239 return log_error_errno(r, "Failed to request match for PropertiesChanged: %m");
240
241 r = sd_bus_match_signal_async(
242 m->bus,
243 NULL,
244 "org.freedesktop.systemd1",
245 "/org/freedesktop/systemd1",
246 "org.freedesktop.systemd1.Manager",
247 "Reloading",
248 match_reloading, NULL, m);
f647962d 249 if (r < 0)
75152a4d 250 return log_error_errno(r, "Failed to request match for Reloading: %m");
6797c324 251
31b2cd5d 252 r = sd_bus_call_method_async(
1ee306e1 253 m->bus,
31b2cd5d 254 NULL,
1ee306e1
LP
255 "org.freedesktop.systemd1",
256 "/org/freedesktop/systemd1",
257 "org.freedesktop.systemd1.Manager",
258 "Subscribe",
31b2cd5d
LP
259 NULL, NULL,
260 NULL);
261 if (r < 0)
262 return log_error_errno(r, "Failed to enable subscription: %m");
1ee306e1 263
0c0b9306 264 r = sd_bus_request_name_async(m->bus, NULL, "org.freedesktop.machine1", 0, NULL, NULL);
f647962d 265 if (r < 0)
0c0b9306 266 return log_error_errno(r, "Failed to request name: %m");
1ee306e1 267
c3350683 268 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
269 if (r < 0)
270 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1ee306e1 271
1ee306e1 272 return 0;
1ee306e1
LP
273}
274
730fa7ce 275static void manager_gc(Manager *m, bool drop_not_started) {
1ee306e1
LP
276 Machine *machine;
277
278 assert(m);
279
280 while ((machine = m->machine_gc_queue)) {
71fda00f 281 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
1ee306e1
LP
282 machine->in_gc_queue = false;
283
49f3fffd 284 /* First, if we are not closing yet, initiate stopping */
554ce41f 285 if (machine_may_gc(machine, drop_not_started) &&
49f3fffd 286 machine_get_state(machine) != MACHINE_CLOSING)
1ee306e1 287 machine_stop(machine);
49f3fffd 288
61233823 289 /* Now, the stop probably made this referenced
49f3fffd
LP
290 * again, but if it didn't, then it's time to let it
291 * go entirely. */
554ce41f 292 if (machine_may_gc(machine, drop_not_started)) {
49f3fffd 293 machine_finalize(machine);
1ee306e1
LP
294 machine_free(machine);
295 }
296 }
297}
298
730fa7ce 299static int manager_startup(Manager *m) {
1ee306e1
LP
300 Machine *machine;
301 Iterator i;
c3350683 302 int r;
1ee306e1
LP
303
304 assert(m);
1ee306e1
LP
305
306 /* Connect to the bus */
307 r = manager_connect_bus(m);
308 if (r < 0)
309 return r;
310
311 /* Deserialize state */
312 manager_enumerate_machines(m);
313
314 /* Remove stale objects before we start them */
315 manager_gc(m, false);
316
317 /* And start everything */
318 HASHMAP_FOREACH(machine, m->machines, i)
c3350683 319 machine_start(machine, NULL, NULL);
1ee306e1
LP
320
321 return 0;
322}
323
d9e34bfd
LP
324static bool check_idle(void *userdata) {
325 Manager *m = userdata;
1ee306e1 326
56599585
LP
327 if (m->operations)
328 return false;
329
d9e34bfd 330 manager_gc(m, true);
1ee306e1 331
d9e34bfd
LP
332 return hashmap_isempty(m->machines);
333}
1ee306e1 334
730fa7ce 335static int manager_run(Manager *m) {
d9e34bfd 336 assert(m);
1ee306e1 337
d9e34bfd
LP
338 return bus_event_loop_with_idle(
339 m->event,
340 m->bus,
341 "org.freedesktop.machine1",
342 DEFAULT_EXIT_USEC,
343 check_idle, m);
1ee306e1
LP
344}
345
9b58b5ad 346static int run(int argc, char *argv[]) {
730fa7ce 347 _cleanup_(manager_unrefp) Manager *m = NULL;
1ee306e1
LP
348 int r;
349
1ee306e1 350 log_set_facility(LOG_AUTH);
6bf3c61c 351 log_setup_service();
1ee306e1
LP
352
353 umask(0022);
354
355 if (argc != 1) {
356 log_error("This program takes no arguments.");
9b58b5ad 357 return -EINVAL;
1ee306e1
LP
358 }
359
730fa7ce
LP
360 /* Always create the directories people can create inotify watches in. Note that some applications might check
361 * for the existence of /run/systemd/machines/ to determine whether machined is available, so please always
362 * make sure this check stays in. */
363 (void) mkdir_label("/run/systemd/machines", 0755);
1ee306e1 364
730fa7ce 365 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, SIGTERM, SIGINT, -1) >= 0);
0370612e 366
730fa7ce 367 r = manager_new(&m);
9b58b5ad
ZJS
368 if (r < 0)
369 return log_error_errno(r, "Failed to allocate manager object: %m");
1ee306e1
LP
370
371 r = manager_startup(m);
9b58b5ad
ZJS
372 if (r < 0)
373 return log_error_errno(r, "Failed to fully start up daemon: %m");
1ee306e1 374
df0ff127 375 log_debug("systemd-machined running as pid "PID_FMT, getpid_cached());
c8f05436
LP
376 (void) sd_notify(false,
377 "READY=1\n"
378 "STATUS=Processing requests...");
1ee306e1
LP
379
380 r = manager_run(m);
381
df0ff127 382 log_debug("systemd-machined stopped as pid "PID_FMT, getpid_cached());
c8f05436
LP
383 (void) sd_notify(false,
384 "STOPPING=1\n"
385 "STATUS=Shutting down...");
386
9b58b5ad 387 return r;
1ee306e1 388}
9b58b5ad
ZJS
389
390DEFINE_MAIN_FUNCTION(run);