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