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