]> git.ipfire.org Git - thirdparty/systemd.git/blob - src/machine/machined.c
Merge pull request #1681 from ssahani/journal
[thirdparty/systemd.git] / src / machine / machined.c
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>
23 #include <string.h>
24 #include <unistd.h>
25
26 #include "sd-daemon.h"
27
28 #include "bus-error.h"
29 #include "bus-util.h"
30 #include "cgroup-util.h"
31 #include "fd-util.h"
32 #include "formats-util.h"
33 #include "hostname-util.h"
34 #include "label.h"
35 #include "machine-image.h"
36 #include "machined.h"
37 #include "signal-util.h"
38
39 Manager *manager_new(void) {
40 Manager *m;
41 int r;
42
43 m = new0(Manager, 1);
44 if (!m)
45 return NULL;
46
47 m->machines = hashmap_new(&string_hash_ops);
48 m->machine_units = hashmap_new(&string_hash_ops);
49 m->machine_leaders = hashmap_new(NULL);
50
51 if (!m->machines || !m->machine_units || !m->machine_leaders) {
52 manager_free(m);
53 return NULL;
54 }
55
56 r = sd_event_default(&m->event);
57 if (r < 0) {
58 manager_free(m);
59 return NULL;
60 }
61
62 sd_event_set_watchdog(m->event, true);
63
64 return m;
65 }
66
67 void manager_free(Manager *m) {
68 Machine *machine;
69 Image *i;
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);
78 hashmap_free(m->machine_leaders);
79
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
87 bus_verify_polkit_async_registry_free(m->polkit_registry);
88
89 sd_bus_unref(m->bus);
90 sd_event_unref(m->event);
91
92 free(m);
93 }
94
95 static 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
134 int manager_enumerate_machines(Manager *m) {
135 _cleanup_closedir_ DIR *d = NULL;
136 struct dirent *de;
137 int r = 0;
138
139 assert(m);
140
141 r = manager_add_host_machine(m);
142 if (r < 0)
143 return r;
144
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
151 log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
152 return -errno;
153 }
154
155 FOREACH_DIRENT(de, d, return -errno) {
156 struct Machine *machine;
157 int k;
158
159 if (!dirent_is_file(de))
160 continue;
161
162 /* Ignore symlinks that map the unit name to the machine */
163 if (startswith(de->d_name, "unit:"))
164 continue;
165
166 if (!machine_name_is_valid(de->d_name))
167 continue;
168
169 k = manager_add_machine(m, de->d_name, &machine);
170 if (k < 0) {
171 r = log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
172 continue;
173 }
174
175 machine_add_to_gc_queue(machine);
176
177 k = machine_load(machine);
178 if (k < 0)
179 r = k;
180 }
181
182 return r;
183 }
184
185 static int manager_connect_bus(Manager *m) {
186 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
187 int r;
188
189 assert(m);
190 assert(!m->bus);
191
192 r = sd_bus_default_system(&m->bus);
193 if (r < 0)
194 return log_error_errno(r, "Failed to connect to system bus: %m");
195
196 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
197 if (r < 0)
198 return log_error_errno(r, "Failed to add manager object vtable: %m");
199
200 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
201 if (r < 0)
202 return log_error_errno(r, "Failed to add machine object vtable: %m");
203
204 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
205 if (r < 0)
206 return log_error_errno(r, "Failed to add machine enumerator: %m");
207
208 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
209 if (r < 0)
210 return log_error_errno(r, "Failed to add image object vtable: %m");
211
212 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
213 if (r < 0)
214 return log_error_errno(r, "Failed to add image enumerator: %m");
215
216 r = sd_bus_add_match(m->bus,
217 NULL,
218 "type='signal',"
219 "sender='org.freedesktop.systemd1',"
220 "interface='org.freedesktop.systemd1.Manager',"
221 "member='JobRemoved',"
222 "path='/org/freedesktop/systemd1'",
223 match_job_removed,
224 m);
225 if (r < 0)
226 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
227
228 r = sd_bus_add_match(m->bus,
229 NULL,
230 "type='signal',"
231 "sender='org.freedesktop.systemd1',"
232 "interface='org.freedesktop.systemd1.Manager',"
233 "member='UnitRemoved',"
234 "path='/org/freedesktop/systemd1'",
235 match_unit_removed,
236 m);
237 if (r < 0)
238 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
239
240 r = sd_bus_add_match(m->bus,
241 NULL,
242 "type='signal',"
243 "sender='org.freedesktop.systemd1',"
244 "interface='org.freedesktop.DBus.Properties',"
245 "member='PropertiesChanged',"
246 "arg0='org.freedesktop.systemd1.Unit'",
247 match_properties_changed,
248 m);
249 if (r < 0)
250 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
251
252 r = sd_bus_add_match(m->bus,
253 NULL,
254 "type='signal',"
255 "sender='org.freedesktop.systemd1',"
256 "interface='org.freedesktop.systemd1.Manager',"
257 "member='Reloading',"
258 "path='/org/freedesktop/systemd1'",
259 match_reloading,
260 m);
261 if (r < 0)
262 return log_error_errno(r, "Failed to add match for Reloading: %m");
263
264 r = sd_bus_call_method(
265 m->bus,
266 "org.freedesktop.systemd1",
267 "/org/freedesktop/systemd1",
268 "org.freedesktop.systemd1.Manager",
269 "Subscribe",
270 &error,
271 NULL, NULL);
272 if (r < 0) {
273 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
274 return r;
275 }
276
277 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
278 if (r < 0)
279 return log_error_errno(r, "Failed to register name: %m");
280
281 r = sd_bus_attach_event(m->bus, m->event, 0);
282 if (r < 0)
283 return log_error_errno(r, "Failed to attach bus to event loop: %m");
284
285 return 0;
286 }
287
288 void manager_gc(Manager *m, bool drop_not_started) {
289 Machine *machine;
290
291 assert(m);
292
293 while ((machine = m->machine_gc_queue)) {
294 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
295 machine->in_gc_queue = false;
296
297 /* First, if we are not closing yet, initiate stopping */
298 if (!machine_check_gc(machine, drop_not_started) &&
299 machine_get_state(machine) != MACHINE_CLOSING)
300 machine_stop(machine);
301
302 /* Now, the stop stop probably made this referenced
303 * again, but if it didn't, then it's time to let it
304 * go entirely. */
305 if (!machine_check_gc(machine, drop_not_started)) {
306 machine_finalize(machine);
307 machine_free(machine);
308 }
309 }
310 }
311
312 int manager_startup(Manager *m) {
313 Machine *machine;
314 Iterator i;
315 int r;
316
317 assert(m);
318
319 /* Connect to the bus */
320 r = manager_connect_bus(m);
321 if (r < 0)
322 return r;
323
324 /* Deserialize state */
325 manager_enumerate_machines(m);
326
327 /* Remove stale objects before we start them */
328 manager_gc(m, false);
329
330 /* And start everything */
331 HASHMAP_FOREACH(machine, m->machines, i)
332 machine_start(machine, NULL, NULL);
333
334 return 0;
335 }
336
337 static bool check_idle(void *userdata) {
338 Manager *m = userdata;
339
340 manager_gc(m, true);
341
342 return hashmap_isempty(m->machines);
343 }
344
345 int manager_run(Manager *m) {
346 assert(m);
347
348 return bus_event_loop_with_idle(
349 m->event,
350 m->bus,
351 "org.freedesktop.machine1",
352 DEFAULT_EXIT_USEC,
353 check_idle, m);
354 }
355
356 int main(int argc, char *argv[]) {
357 Manager *m = NULL;
358 int r;
359
360 log_set_target(LOG_TARGET_AUTO);
361 log_set_facility(LOG_AUTH);
362 log_parse_environment();
363 log_open();
364
365 umask(0022);
366
367 if (argc != 1) {
368 log_error("This program takes no arguments.");
369 r = -EINVAL;
370 goto finish;
371 }
372
373 /* Always create the directories people can create inotify
374 * watches in. Note that some applications might check for the
375 * existence of /run/systemd/machines/ to determine whether
376 * machined is available, so please always make sure this
377 * check stays in. */
378 mkdir_label("/run/systemd/machines", 0755);
379
380 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
381
382 m = manager_new();
383 if (!m) {
384 r = log_oom();
385 goto finish;
386 }
387
388 r = manager_startup(m);
389 if (r < 0) {
390 log_error_errno(r, "Failed to fully start up daemon: %m");
391 goto finish;
392 }
393
394 log_debug("systemd-machined running as pid "PID_FMT, getpid());
395
396 sd_notify(false,
397 "READY=1\n"
398 "STATUS=Processing requests...");
399
400 r = manager_run(m);
401
402 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
403
404 finish:
405 manager_free(m);
406
407 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
408 }