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