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