]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined.c
label: don't try to create labelled directories more than once
[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
d5099efc
MS
47 m->machines = hashmap_new(&string_hash_ops);
48 m->machine_units = hashmap_new(&string_hash_ops);
49 m->machine_leaders = hashmap_new(NULL);
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
19befb2d 144 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
c3350683
LP
145 if (r < 0) {
146 log_error("Failed to add manager object vtable: %s", strerror(-r));
147 return r;
1ee306e1
LP
148 }
149
19befb2d 150 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
c3350683
LP
151 if (r < 0) {
152 log_error("Failed to add machine object vtable: %s", strerror(-r));
153 return r;
154 }
155
19befb2d 156 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
c3350683
LP
157 if (r < 0) {
158 log_error("Failed to add machine enumerator: %s", strerror(-r));
159 return r;
1ee306e1
LP
160 }
161
c3350683 162 r = sd_bus_add_match(m->bus,
19befb2d 163 NULL,
c3350683
LP
164 "type='signal',"
165 "sender='org.freedesktop.systemd1',"
166 "interface='org.freedesktop.systemd1.Manager',"
167 "member='JobRemoved',"
168 "path='/org/freedesktop/systemd1'",
169 match_job_removed,
170 m);
171 if (r < 0) {
172 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
173 return r;
1ee306e1
LP
174 }
175
c3350683 176 r = sd_bus_add_match(m->bus,
19befb2d 177 NULL,
c3350683
LP
178 "type='signal',"
179 "sender='org.freedesktop.systemd1',"
180 "interface='org.freedesktop.systemd1.Manager',"
181 "member='UnitRemoved',"
182 "path='/org/freedesktop/systemd1'",
183 match_unit_removed,
184 m);
185 if (r < 0) {
186 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
187 return r;
943aca8e
LP
188 }
189
c3350683 190 r = sd_bus_add_match(m->bus,
19befb2d 191 NULL,
c3350683
LP
192 "type='signal',"
193 "sender='org.freedesktop.systemd1',"
194 "interface='org.freedesktop.DBus.Properties',"
195 "member='PropertiesChanged'",
196 match_properties_changed,
197 m);
198 if (r < 0) {
199 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
200 return r;
1ee306e1
LP
201 }
202
c3350683 203 r = sd_bus_add_match(m->bus,
19befb2d 204 NULL,
c3350683
LP
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 log_error("Failed to add match for Reloading: %s", strerror(-r));
214 return r;
6797c324
LP
215 }
216
c3350683 217 r = sd_bus_call_method(
1ee306e1
LP
218 m->bus,
219 "org.freedesktop.systemd1",
220 "/org/freedesktop/systemd1",
221 "org.freedesktop.systemd1.Manager",
222 "Subscribe",
1ee306e1 223 &error,
c3350683 224 NULL, NULL);
1ee306e1 225 if (r < 0) {
c3350683
LP
226 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
227 return r;
1ee306e1
LP
228 }
229
5bb658a1 230 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
c3350683
LP
231 if (r < 0) {
232 log_error("Failed to register name: %s", strerror(-r));
233 return r;
1ee306e1
LP
234 }
235
c3350683
LP
236 r = sd_bus_attach_event(m->bus, m->event, 0);
237 if (r < 0) {
238 log_error("Failed to attach bus to event loop: %s", strerror(-r));
239 return r;
1ee306e1
LP
240 }
241
1ee306e1 242 return 0;
1ee306e1
LP
243}
244
245void manager_gc(Manager *m, bool drop_not_started) {
246 Machine *machine;
247
248 assert(m);
249
250 while ((machine = m->machine_gc_queue)) {
71fda00f 251 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
1ee306e1
LP
252 machine->in_gc_queue = false;
253
a658cafa 254 if (!machine_check_gc(machine, drop_not_started)) {
1ee306e1
LP
255 machine_stop(machine);
256 machine_free(machine);
257 }
258 }
259}
260
261int manager_startup(Manager *m) {
1ee306e1
LP
262 Machine *machine;
263 Iterator i;
c3350683 264 int r;
1ee306e1
LP
265
266 assert(m);
1ee306e1
LP
267
268 /* Connect to the bus */
269 r = manager_connect_bus(m);
270 if (r < 0)
271 return r;
272
273 /* Deserialize state */
274 manager_enumerate_machines(m);
275
276 /* Remove stale objects before we start them */
277 manager_gc(m, false);
278
279 /* And start everything */
280 HASHMAP_FOREACH(machine, m->machines, i)
c3350683 281 machine_start(machine, NULL, NULL);
1ee306e1
LP
282
283 return 0;
284}
285
d9e34bfd
LP
286static bool check_idle(void *userdata) {
287 Manager *m = userdata;
1ee306e1 288
d9e34bfd 289 manager_gc(m, true);
1ee306e1 290
d9e34bfd
LP
291 return hashmap_isempty(m->machines);
292}
1ee306e1 293
d9e34bfd
LP
294int manager_run(Manager *m) {
295 assert(m);
1ee306e1 296
d9e34bfd
LP
297 return bus_event_loop_with_idle(
298 m->event,
299 m->bus,
300 "org.freedesktop.machine1",
301 DEFAULT_EXIT_USEC,
302 check_idle, m);
1ee306e1
LP
303}
304
305int main(int argc, char *argv[]) {
306 Manager *m = NULL;
307 int r;
308
309 log_set_target(LOG_TARGET_AUTO);
310 log_set_facility(LOG_AUTH);
311 log_parse_environment();
312 log_open();
313
314 umask(0022);
315
316 if (argc != 1) {
317 log_error("This program takes no arguments.");
318 r = -EINVAL;
319 goto finish;
320 }
321
322 /* Always create the directories people can create inotify
323 * watches in. Note that some applications might check for the
c3350683
LP
324 * existence of /run/systemd/machines/ to determine whether
325 * machined is available, so please always make sure this
326 * check stays in. */
1ee306e1
LP
327 mkdir_label("/run/systemd/machines", 0755);
328
329 m = manager_new();
330 if (!m) {
331 r = log_oom();
332 goto finish;
333 }
334
335 r = manager_startup(m);
336 if (r < 0) {
337 log_error("Failed to fully start up daemon: %s", strerror(-r));
338 goto finish;
339 }
340
de0671ee 341 log_debug("systemd-machined running as pid "PID_FMT, getpid());
1ee306e1
LP
342
343 sd_notify(false,
344 "READY=1\n"
345 "STATUS=Processing requests...");
346
347 r = manager_run(m);
348
de0671ee 349 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
1ee306e1
LP
350
351finish:
1ee306e1
LP
352 if (m)
353 manager_free(m);
354
355 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
356}