]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined.c
util: make machine_name_is_valid() a macro and move it to hostname-util.h
[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"
c3350683 27#include "cgroup-util.h"
c3350683
LP
28#include "bus-util.h"
29#include "bus-error.h"
c34255bd 30#include "label.h"
24882e06
LP
31#include "formats-util.h"
32#include "signal-util.h"
25300b5a 33#include "hostname-util.h"
1ddb263d 34#include "machine-image.h"
ebeccf9e 35#include "machined.h"
1ee306e1
LP
36
37Manager *manager_new(void) {
38 Manager *m;
c3350683 39 int r;
1ee306e1
LP
40
41 m = new0(Manager, 1);
42 if (!m)
43 return NULL;
44
d5099efc
MS
45 m->machines = hashmap_new(&string_hash_ops);
46 m->machine_units = hashmap_new(&string_hash_ops);
47 m->machine_leaders = hashmap_new(NULL);
1ee306e1 48
d3e84ddb 49 if (!m->machines || !m->machine_units || !m->machine_leaders) {
c3350683
LP
50 manager_free(m);
51 return NULL;
52 }
53
afc6adb5 54 r = sd_event_default(&m->event);
a658cafa 55 if (r < 0) {
1ee306e1
LP
56 manager_free(m);
57 return NULL;
58 }
59
cde93897
LP
60 sd_event_set_watchdog(m->event, true);
61
1ee306e1
LP
62 return m;
63}
64
65void manager_free(Manager *m) {
66 Machine *machine;
1ddb263d 67 Image *i;
1ee306e1
LP
68
69 assert(m);
70
71 while ((machine = hashmap_first(m->machines)))
72 machine_free(machine);
73
74 hashmap_free(m->machines);
75 hashmap_free(m->machine_units);
d3e84ddb 76 hashmap_free(m->machine_leaders);
1ee306e1 77
1ddb263d
LP
78 while ((i = hashmap_steal_first(m->image_cache)))
79 image_unref(i);
80
81 hashmap_free(m->image_cache);
82
83 sd_event_source_unref(m->image_cache_defer_event);
84
d04c1fb8
LP
85 bus_verify_polkit_async_registry_free(m->polkit_registry);
86
c3350683
LP
87 sd_bus_unref(m->bus);
88 sd_event_unref(m->event);
89
90 free(m);
91}
92
1ee306e1
LP
93int manager_enumerate_machines(Manager *m) {
94 _cleanup_closedir_ DIR *d = NULL;
95 struct dirent *de;
96 int r = 0;
97
98 assert(m);
99
100 /* Read in machine data stored on disk */
101 d = opendir("/run/systemd/machines");
102 if (!d) {
103 if (errno == ENOENT)
104 return 0;
105
56f64d95 106 log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
1ee306e1
LP
107 return -errno;
108 }
109
110 FOREACH_DIRENT(de, d, return -errno) {
111 struct Machine *machine;
112 int k;
113
114 if (!dirent_is_file(de))
115 continue;
116
b87633c4
LP
117 /* Ignore symlinks that map the unit name to the machine */
118 if (startswith(de->d_name, "unit:"))
119 continue;
120
1ee306e1
LP
121 k = manager_add_machine(m, de->d_name, &machine);
122 if (k < 0) {
da927ba9 123 log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
1ee306e1
LP
124
125 r = k;
126 continue;
127 }
128
129 machine_add_to_gc_queue(machine);
130
131 k = machine_load(machine);
132 if (k < 0)
133 r = k;
134 }
135
136 return r;
137}
138
1ee306e1 139static int manager_connect_bus(Manager *m) {
c3350683 140 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1 141 int r;
1ee306e1
LP
142
143 assert(m);
144 assert(!m->bus);
1ee306e1 145
76b54375 146 r = sd_bus_default_system(&m->bus);
f647962d
MS
147 if (r < 0)
148 return log_error_errno(r, "Failed to connect to system bus: %m");
1ee306e1 149
19befb2d 150 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
f647962d
MS
151 if (r < 0)
152 return log_error_errno(r, "Failed to add manager object vtable: %m");
1ee306e1 153
19befb2d 154 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
155 if (r < 0)
156 return log_error_errno(r, "Failed to add machine object vtable: %m");
c3350683 157
19befb2d 158 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
f647962d
MS
159 if (r < 0)
160 return log_error_errno(r, "Failed to add machine enumerator: %m");
1ee306e1 161
ebeccf9e
LP
162 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
163 if (r < 0)
164 return log_error_errno(r, "Failed to add image object vtable: %m");
165
166 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
167 if (r < 0)
168 return log_error_errno(r, "Failed to add image enumerator: %m");
169
c3350683 170 r = sd_bus_add_match(m->bus,
19befb2d 171 NULL,
c3350683
LP
172 "type='signal',"
173 "sender='org.freedesktop.systemd1',"
174 "interface='org.freedesktop.systemd1.Manager',"
175 "member='JobRemoved',"
176 "path='/org/freedesktop/systemd1'",
177 match_job_removed,
178 m);
f647962d
MS
179 if (r < 0)
180 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
1ee306e1 181
c3350683 182 r = sd_bus_add_match(m->bus,
19befb2d 183 NULL,
c3350683
LP
184 "type='signal',"
185 "sender='org.freedesktop.systemd1',"
186 "interface='org.freedesktop.systemd1.Manager',"
187 "member='UnitRemoved',"
188 "path='/org/freedesktop/systemd1'",
189 match_unit_removed,
190 m);
f647962d
MS
191 if (r < 0)
192 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
943aca8e 193
c3350683 194 r = sd_bus_add_match(m->bus,
19befb2d 195 NULL,
c3350683
LP
196 "type='signal',"
197 "sender='org.freedesktop.systemd1',"
198 "interface='org.freedesktop.DBus.Properties',"
11b90e69
LP
199 "member='PropertiesChanged',"
200 "arg0='org.freedesktop.systemd1.Unit'",
c3350683
LP
201 match_properties_changed,
202 m);
f647962d
MS
203 if (r < 0)
204 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
1ee306e1 205
c3350683 206 r = sd_bus_add_match(m->bus,
19befb2d 207 NULL,
c3350683
LP
208 "type='signal',"
209 "sender='org.freedesktop.systemd1',"
210 "interface='org.freedesktop.systemd1.Manager',"
211 "member='Reloading',"
212 "path='/org/freedesktop/systemd1'",
213 match_reloading,
214 m);
f647962d
MS
215 if (r < 0)
216 return log_error_errno(r, "Failed to add match for Reloading: %m");
6797c324 217
c3350683 218 r = sd_bus_call_method(
1ee306e1
LP
219 m->bus,
220 "org.freedesktop.systemd1",
221 "/org/freedesktop/systemd1",
222 "org.freedesktop.systemd1.Manager",
223 "Subscribe",
1ee306e1 224 &error,
c3350683 225 NULL, NULL);
1ee306e1 226 if (r < 0) {
c3350683
LP
227 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
228 return r;
1ee306e1
LP
229 }
230
5bb658a1 231 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
f647962d
MS
232 if (r < 0)
233 return log_error_errno(r, "Failed to register name: %m");
1ee306e1 234
c3350683 235 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
236 if (r < 0)
237 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1ee306e1 238
1ee306e1 239 return 0;
1ee306e1
LP
240}
241
242void manager_gc(Manager *m, bool drop_not_started) {
243 Machine *machine;
244
245 assert(m);
246
247 while ((machine = m->machine_gc_queue)) {
71fda00f 248 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
1ee306e1
LP
249 machine->in_gc_queue = false;
250
49f3fffd
LP
251 /* First, if we are not closing yet, initiate stopping */
252 if (!machine_check_gc(machine, drop_not_started) &&
253 machine_get_state(machine) != MACHINE_CLOSING)
1ee306e1 254 machine_stop(machine);
49f3fffd
LP
255
256 /* Now, the stop stop probably made this referenced
257 * again, but if it didn't, then it's time to let it
258 * go entirely. */
259 if (!machine_check_gc(machine, drop_not_started)) {
260 machine_finalize(machine);
1ee306e1
LP
261 machine_free(machine);
262 }
263 }
264}
265
266int manager_startup(Manager *m) {
1ee306e1
LP
267 Machine *machine;
268 Iterator i;
c3350683 269 int r;
1ee306e1
LP
270
271 assert(m);
1ee306e1
LP
272
273 /* Connect to the bus */
274 r = manager_connect_bus(m);
275 if (r < 0)
276 return r;
277
278 /* Deserialize state */
279 manager_enumerate_machines(m);
280
281 /* Remove stale objects before we start them */
282 manager_gc(m, false);
283
284 /* And start everything */
285 HASHMAP_FOREACH(machine, m->machines, i)
c3350683 286 machine_start(machine, NULL, NULL);
1ee306e1
LP
287
288 return 0;
289}
290
d9e34bfd
LP
291static bool check_idle(void *userdata) {
292 Manager *m = userdata;
1ee306e1 293
d9e34bfd 294 manager_gc(m, true);
1ee306e1 295
d9e34bfd
LP
296 return hashmap_isempty(m->machines);
297}
1ee306e1 298
d9e34bfd
LP
299int manager_run(Manager *m) {
300 assert(m);
1ee306e1 301
d9e34bfd
LP
302 return bus_event_loop_with_idle(
303 m->event,
304 m->bus,
305 "org.freedesktop.machine1",
306 DEFAULT_EXIT_USEC,
307 check_idle, m);
1ee306e1
LP
308}
309
310int main(int argc, char *argv[]) {
311 Manager *m = NULL;
312 int r;
313
314 log_set_target(LOG_TARGET_AUTO);
315 log_set_facility(LOG_AUTH);
316 log_parse_environment();
317 log_open();
318
319 umask(0022);
320
321 if (argc != 1) {
322 log_error("This program takes no arguments.");
323 r = -EINVAL;
324 goto finish;
325 }
326
327 /* Always create the directories people can create inotify
328 * watches in. Note that some applications might check for the
c3350683
LP
329 * existence of /run/systemd/machines/ to determine whether
330 * machined is available, so please always make sure this
331 * check stays in. */
1ee306e1
LP
332 mkdir_label("/run/systemd/machines", 0755);
333
72c0a2c2 334 assert_se(sigprocmask_many(SIG_BLOCK, NULL, SIGCHLD, -1) >= 0);
0370612e 335
1ee306e1
LP
336 m = manager_new();
337 if (!m) {
338 r = log_oom();
339 goto finish;
340 }
341
342 r = manager_startup(m);
343 if (r < 0) {
da927ba9 344 log_error_errno(r, "Failed to fully start up daemon: %m");
1ee306e1
LP
345 goto finish;
346 }
347
de0671ee 348 log_debug("systemd-machined running as pid "PID_FMT, getpid());
1ee306e1
LP
349
350 sd_notify(false,
351 "READY=1\n"
352 "STATUS=Processing requests...");
353
354 r = manager_run(m);
355
de0671ee 356 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
1ee306e1
LP
357
358finish:
3e044c49 359 manager_free(m);
1ee306e1
LP
360
361 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
362}