]> git.proxmox.com Git - systemd.git/blame - src/machine/machined.c
Imported Upstream version 229
[systemd.git] / src / machine / machined.c
CommitLineData
14228c0d
MB
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>
14228c0d
MB
21#include <string.h>
22#include <unistd.h>
14228c0d 23
60f067b4 24#include "sd-daemon.h"
db2df898
MP
25
26#include "alloc-util.h"
60f067b4 27#include "bus-error.h"
db2df898
MP
28#include "bus-util.h"
29#include "cgroup-util.h"
30#include "dirent-util.h"
31#include "fd-util.h"
86f210e9 32#include "formats-util.h"
13d276d0 33#include "hostname-util.h"
db2df898 34#include "label.h"
e735f4d4
MP
35#include "machine-image.h"
36#include "machined.h"
db2df898 37#include "signal-util.h"
14228c0d
MB
38
39Manager *manager_new(void) {
40 Manager *m;
60f067b4 41 int r;
14228c0d
MB
42
43 m = new0(Manager, 1);
44 if (!m)
45 return NULL;
46
5eef597e
MP
47 m->machines = hashmap_new(&string_hash_ops);
48 m->machine_units = hashmap_new(&string_hash_ops);
49 m->machine_leaders = hashmap_new(NULL);
14228c0d 50
60f067b4
JS
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) {
14228c0d
MB
58 manager_free(m);
59 return NULL;
60 }
61
60f067b4
JS
62 sd_event_set_watchdog(m->event, true);
63
14228c0d
MB
64 return m;
65}
66
67void manager_free(Manager *m) {
68 Machine *machine;
e735f4d4 69 Image *i;
14228c0d
MB
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);
60f067b4 78 hashmap_free(m->machine_leaders);
14228c0d 79
e735f4d4
MP
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
60f067b4
JS
89 sd_bus_unref(m->bus);
90 sd_event_unref(m->event);
14228c0d
MB
91
92 free(m);
93}
94
13d276d0
MP
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
14228c0d
MB
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
13d276d0
MP
141 r = manager_add_host_machine(m);
142 if (r < 0)
143 return r;
144
14228c0d
MB
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
db2df898 151 return log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
14228c0d
MB
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
60f067b4
JS
161 /* Ignore symlinks that map the unit name to the machine */
162 if (startswith(de->d_name, "unit:"))
163 continue;
164
13d276d0
MP
165 if (!machine_name_is_valid(de->d_name))
166 continue;
167
14228c0d
MB
168 k = manager_add_machine(m, de->d_name, &machine);
169 if (k < 0) {
13d276d0 170 r = log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
14228c0d
MB
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
184static int manager_connect_bus(Manager *m) {
4c89c718 185 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
14228c0d 186 int r;
14228c0d
MB
187
188 assert(m);
189 assert(!m->bus);
14228c0d 190
60f067b4 191 r = sd_bus_default_system(&m->bus);
f47781d8
MP
192 if (r < 0)
193 return log_error_errno(r, "Failed to connect to system bus: %m");
14228c0d 194
60f067b4 195 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
f47781d8
MP
196 if (r < 0)
197 return log_error_errno(r, "Failed to add manager object vtable: %m");
14228c0d 198
60f067b4 199 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
f47781d8
MP
200 if (r < 0)
201 return log_error_errno(r, "Failed to add machine object vtable: %m");
14228c0d 202
60f067b4 203 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
f47781d8
MP
204 if (r < 0)
205 return log_error_errno(r, "Failed to add machine enumerator: %m");
14228c0d 206
e735f4d4
MP
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
60f067b4
JS
215 r = sd_bus_add_match(m->bus,
216 NULL,
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);
f47781d8
MP
224 if (r < 0)
225 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
14228c0d 226
60f067b4
JS
227 r = sd_bus_add_match(m->bus,
228 NULL,
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);
f47781d8
MP
236 if (r < 0)
237 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
60f067b4
JS
238
239 r = sd_bus_add_match(m->bus,
240 NULL,
241 "type='signal',"
242 "sender='org.freedesktop.systemd1',"
243 "interface='org.freedesktop.DBus.Properties',"
e3bff60a
MP
244 "member='PropertiesChanged',"
245 "arg0='org.freedesktop.systemd1.Unit'",
60f067b4
JS
246 match_properties_changed,
247 m);
f47781d8
MP
248 if (r < 0)
249 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
14228c0d 250
60f067b4
JS
251 r = sd_bus_add_match(m->bus,
252 NULL,
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);
f47781d8
MP
260 if (r < 0)
261 return log_error_errno(r, "Failed to add match for Reloading: %m");
14228c0d 262
60f067b4 263 r = sd_bus_call_method(
14228c0d
MB
264 m->bus,
265 "org.freedesktop.systemd1",
266 "/org/freedesktop/systemd1",
267 "org.freedesktop.systemd1.Manager",
268 "Subscribe",
14228c0d 269 &error,
60f067b4 270 NULL, NULL);
14228c0d 271 if (r < 0) {
60f067b4
JS
272 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
273 return r;
14228c0d
MB
274 }
275
60f067b4 276 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
f47781d8
MP
277 if (r < 0)
278 return log_error_errno(r, "Failed to register name: %m");
14228c0d 279
60f067b4 280 r = sd_bus_attach_event(m->bus, m->event, 0);
f47781d8
MP
281 if (r < 0)
282 return log_error_errno(r, "Failed to attach bus to event loop: %m");
14228c0d 283
14228c0d 284 return 0;
14228c0d
MB
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)) {
60f067b4 293 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
14228c0d
MB
294 machine->in_gc_queue = false;
295
13d276d0
MP
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)
14228c0d 299 machine_stop(machine);
13d276d0
MP
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);
14228c0d
MB
306 machine_free(machine);
307 }
308 }
309}
310
311int manager_startup(Manager *m) {
14228c0d
MB
312 Machine *machine;
313 Iterator i;
60f067b4 314 int r;
14228c0d
MB
315
316 assert(m);
14228c0d
MB
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)
60f067b4 331 machine_start(machine, NULL, NULL);
14228c0d
MB
332
333 return 0;
334}
335
60f067b4
JS
336static bool check_idle(void *userdata) {
337 Manager *m = userdata;
14228c0d 338
60f067b4 339 manager_gc(m, true);
14228c0d 340
60f067b4
JS
341 return hashmap_isempty(m->machines);
342}
14228c0d 343
60f067b4
JS
344int manager_run(Manager *m) {
345 assert(m);
14228c0d 346
60f067b4
JS
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);
14228c0d
MB
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
60f067b4
JS
374 * existence of /run/systemd/machines/ to determine whether
375 * machined is available, so please always make sure this
376 * check stays in. */
14228c0d
MB
377 mkdir_label("/run/systemd/machines", 0755);
378
86f210e9 379 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
e3bff60a 380
14228c0d
MB
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) {
f47781d8 389 log_error_errno(r, "Failed to fully start up daemon: %m");
14228c0d
MB
390 goto finish;
391 }
392
60f067b4 393 log_debug("systemd-machined running as pid "PID_FMT, getpid());
14228c0d
MB
394
395 sd_notify(false,
396 "READY=1\n"
397 "STATUS=Processing requests...");
398
399 r = manager_run(m);
400
60f067b4 401 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
14228c0d
MB
402
403finish:
13d276d0 404 manager_free(m);
14228c0d
MB
405
406 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
407}