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