]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined.c
machined: simplifications
[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);
49
a658cafa 50 if (!m->machines || !m->machine_units) {
c3350683
LP
51 manager_free(m);
52 return NULL;
53 }
54
a658cafa
LP
55 r = sd_event_new(&m->event);
56 if (r < 0) {
1ee306e1
LP
57 manager_free(m);
58 return NULL;
59 }
60
61 return m;
62}
63
64void manager_free(Manager *m) {
65 Machine *machine;
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
c3350683
LP
75 sd_bus_unref(m->bus);
76 sd_event_unref(m->event);
77
78 free(m);
79}
80
81int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
82 Machine *machine;
83
84 assert(m);
85 assert(name);
86
87 machine = hashmap_get(m->machines, name);
88 if (!machine) {
89 machine = machine_new(m, name);
90 if (!machine)
91 return -ENOMEM;
1ee306e1
LP
92 }
93
c3350683
LP
94 if (_machine)
95 *_machine = machine;
96
97 return 0;
98}
99
100int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
101 _cleanup_free_ char *unit = NULL;
102 Machine *mm;
103 int r;
1ee306e1 104
c3350683
LP
105 assert(m);
106 assert(pid >= 1);
107 assert(machine);
1ee306e1 108
c3350683
LP
109 r = cg_pid_get_unit(pid, &unit);
110 if (r < 0)
111 return r;
112
113 mm = hashmap_get(m->machine_units, unit);
114 if (!mm)
115 return 0;
116
117 *machine = mm;
118 return 1;
1ee306e1
LP
119}
120
1ee306e1
LP
121int manager_enumerate_machines(Manager *m) {
122 _cleanup_closedir_ DIR *d = NULL;
123 struct dirent *de;
124 int r = 0;
125
126 assert(m);
127
128 /* Read in machine data stored on disk */
129 d = opendir("/run/systemd/machines");
130 if (!d) {
131 if (errno == ENOENT)
132 return 0;
133
134 log_error("Failed to open /run/systemd/machines: %m");
135 return -errno;
136 }
137
138 FOREACH_DIRENT(de, d, return -errno) {
139 struct Machine *machine;
140 int k;
141
142 if (!dirent_is_file(de))
143 continue;
144
145 k = manager_add_machine(m, de->d_name, &machine);
146 if (k < 0) {
147 log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
148
149 r = k;
150 continue;
151 }
152
153 machine_add_to_gc_queue(machine);
154
155 k = machine_load(machine);
156 if (k < 0)
157 r = k;
158 }
159
160 return r;
161}
162
1ee306e1 163static int manager_connect_bus(Manager *m) {
c3350683 164 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1 165 int r;
1ee306e1
LP
166
167 assert(m);
168 assert(!m->bus);
1ee306e1 169
c3350683
LP
170 r = sd_bus_open_system(&m->bus);
171 if (r < 0) {
172 log_error("Failed to connect to system bus: %s", strerror(-r));
173 return r;
174 }
1ee306e1 175
c3350683
LP
176 r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
177 if (r < 0) {
178 log_error("Failed to add manager object vtable: %s", strerror(-r));
179 return r;
1ee306e1
LP
180 }
181
c3350683
LP
182 r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
183 if (r < 0) {
184 log_error("Failed to add machine object vtable: %s", strerror(-r));
185 return r;
186 }
187
188 r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
189 if (r < 0) {
190 log_error("Failed to add machine enumerator: %s", strerror(-r));
191 return r;
1ee306e1
LP
192 }
193
c3350683
LP
194 r = sd_bus_add_match(m->bus,
195 "type='signal',"
196 "sender='org.freedesktop.systemd1',"
197 "interface='org.freedesktop.systemd1.Manager',"
198 "member='JobRemoved',"
199 "path='/org/freedesktop/systemd1'",
200 match_job_removed,
201 m);
202 if (r < 0) {
203 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
204 return r;
1ee306e1
LP
205 }
206
c3350683
LP
207 r = sd_bus_add_match(m->bus,
208 "type='signal',"
209 "sender='org.freedesktop.systemd1',"
210 "interface='org.freedesktop.systemd1.Manager',"
211 "member='UnitRemoved',"
212 "path='/org/freedesktop/systemd1'",
213 match_unit_removed,
214 m);
215 if (r < 0) {
216 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
217 return r;
943aca8e
LP
218 }
219
c3350683
LP
220 r = sd_bus_add_match(m->bus,
221 "type='signal',"
222 "sender='org.freedesktop.systemd1',"
223 "interface='org.freedesktop.DBus.Properties',"
224 "member='PropertiesChanged'",
225 match_properties_changed,
226 m);
227 if (r < 0) {
228 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
229 return r;
1ee306e1
LP
230 }
231
c3350683
LP
232 r = sd_bus_add_match(m->bus,
233 "type='signal',"
234 "sender='org.freedesktop.systemd1',"
235 "interface='org.freedesktop.systemd1.Manager',"
236 "member='Reloading',"
237 "path='/org/freedesktop/systemd1'",
238 match_reloading,
239 m);
240 if (r < 0) {
241 log_error("Failed to add match for Reloading: %s", strerror(-r));
242 return r;
6797c324
LP
243 }
244
c3350683 245 r = sd_bus_call_method(
1ee306e1
LP
246 m->bus,
247 "org.freedesktop.systemd1",
248 "/org/freedesktop/systemd1",
249 "org.freedesktop.systemd1.Manager",
250 "Subscribe",
1ee306e1 251 &error,
c3350683 252 NULL, NULL);
1ee306e1 253 if (r < 0) {
c3350683
LP
254 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
255 return r;
1ee306e1
LP
256 }
257
c3350683
LP
258 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", SD_BUS_NAME_DO_NOT_QUEUE);
259 if (r < 0) {
260 log_error("Failed to register name: %s", strerror(-r));
261 return r;
1ee306e1
LP
262 }
263
c3350683 264 if (r != SD_BUS_NAME_PRIMARY_OWNER) {
1ee306e1 265 log_error("Failed to acquire name.");
c3350683 266 return -EEXIST;
1ee306e1
LP
267 }
268
c3350683
LP
269 r = sd_bus_attach_event(m->bus, m->event, 0);
270 if (r < 0) {
271 log_error("Failed to attach bus to event loop: %s", strerror(-r));
272 return r;
1ee306e1
LP
273 }
274
1ee306e1 275 return 0;
1ee306e1
LP
276}
277
278void manager_gc(Manager *m, bool drop_not_started) {
279 Machine *machine;
280
281 assert(m);
282
283 while ((machine = m->machine_gc_queue)) {
71fda00f 284 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
1ee306e1
LP
285 machine->in_gc_queue = false;
286
a658cafa 287 if (!machine_check_gc(machine, drop_not_started)) {
1ee306e1
LP
288 machine_stop(machine);
289 machine_free(machine);
290 }
291 }
292}
293
294int manager_startup(Manager *m) {
1ee306e1
LP
295 Machine *machine;
296 Iterator i;
c3350683 297 int r;
1ee306e1
LP
298
299 assert(m);
1ee306e1
LP
300
301 /* Connect to the bus */
302 r = manager_connect_bus(m);
303 if (r < 0)
304 return r;
305
306 /* Deserialize state */
307 manager_enumerate_machines(m);
308
309 /* Remove stale objects before we start them */
310 manager_gc(m, false);
311
312 /* And start everything */
313 HASHMAP_FOREACH(machine, m->machines, i)
c3350683 314 machine_start(machine, NULL, NULL);
1ee306e1
LP
315
316 return 0;
317}
318
319int manager_run(Manager *m) {
c3350683
LP
320 int r;
321
1ee306e1
LP
322 assert(m);
323
324 for (;;) {
c3350683
LP
325 r = sd_event_get_state(m->event);
326 if (r < 0)
327 return r;
328 if (r == SD_EVENT_FINISHED)
329 return 0;
1ee306e1
LP
330
331 manager_gc(m, true);
332
c3350683
LP
333 r = sd_event_run(m->event, (uint64_t) -1);
334 if (r < 0)
335 return r;
1ee306e1
LP
336 }
337
338 return 0;
339}
340
341int main(int argc, char *argv[]) {
342 Manager *m = NULL;
343 int r;
344
345 log_set_target(LOG_TARGET_AUTO);
346 log_set_facility(LOG_AUTH);
347 log_parse_environment();
348 log_open();
349
350 umask(0022);
351
352 if (argc != 1) {
353 log_error("This program takes no arguments.");
354 r = -EINVAL;
355 goto finish;
356 }
357
358 /* Always create the directories people can create inotify
359 * watches in. Note that some applications might check for the
c3350683
LP
360 * existence of /run/systemd/machines/ to determine whether
361 * machined is available, so please always make sure this
362 * check stays in. */
1ee306e1
LP
363 mkdir_label("/run/systemd/machines", 0755);
364
365 m = manager_new();
366 if (!m) {
367 r = log_oom();
368 goto finish;
369 }
370
371 r = manager_startup(m);
372 if (r < 0) {
373 log_error("Failed to fully start up daemon: %s", strerror(-r));
374 goto finish;
375 }
376
377 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
378
379 sd_notify(false,
380 "READY=1\n"
381 "STATUS=Processing requests...");
382
383 r = manager_run(m);
384
385 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
386
387finish:
388 sd_notify(false,
389 "STATUS=Shutting down...");
390
391 if (m)
392 manager_free(m);
393
394 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
395}