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