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