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