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