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