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