chiark / gitweb /
core: always create /dev/kdbus/ns (and make it private 0700) after setting up the...
[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 <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
39 Manager *manager_new(void) {
40         Manager *m;
41         int r;
42
43         m = new0(Manager, 1);
44         if (!m)
45                 return NULL;
46
47         m->machines = hashmap_new(string_hash_func, string_compare_func);
48         m->machine_units = hashmap_new(string_hash_func, string_compare_func);
49         m->machine_leaders = hashmap_new(trivial_hash_func, trivial_compare_func);
50
51         if (!m->machines || !m->machine_units || !m->machine_leaders) {
52                 manager_free(m);
53                 return NULL;
54         }
55
56         r = sd_event_default(&m->event);
57         if (r < 0) {
58                 manager_free(m);
59                 return NULL;
60         }
61
62         sd_event_set_watchdog(m->event, true);
63
64         return m;
65 }
66
67 void 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);
77         hashmap_free(m->machine_leaders);
78
79         sd_bus_unref(m->bus);
80         sd_event_unref(m->event);
81
82         free(m);
83 }
84
85 int 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
109                 k = manager_add_machine(m, de->d_name, &machine);
110                 if (k < 0) {
111                         log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
112
113                         r = k;
114                         continue;
115                 }
116
117                 machine_add_to_gc_queue(machine);
118
119                 k = machine_load(machine);
120                 if (k < 0)
121                         r = k;
122         }
123
124         return r;
125 }
126
127 static int manager_connect_bus(Manager *m) {
128         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
129         int r;
130
131         assert(m);
132         assert(!m->bus);
133
134         r = sd_bus_default_system(&m->bus);
135         if (r < 0) {
136                 log_error("Failed to connect to system bus: %s", strerror(-r));
137                 return r;
138         }
139
140         r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
141         if (r < 0) {
142                 log_error("Failed to add manager object vtable: %s", strerror(-r));
143                 return r;
144         }
145
146         r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
147         if (r < 0) {
148                 log_error("Failed to add machine object vtable: %s", strerror(-r));
149                 return r;
150         }
151
152         r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
153         if (r < 0) {
154                 log_error("Failed to add machine enumerator: %s", strerror(-r));
155                 return r;
156         }
157
158         r = sd_bus_add_match(m->bus,
159                              "type='signal',"
160                              "sender='org.freedesktop.systemd1',"
161                              "interface='org.freedesktop.systemd1.Manager',"
162                              "member='JobRemoved',"
163                              "path='/org/freedesktop/systemd1'",
164                              match_job_removed,
165                              m);
166         if (r < 0) {
167                 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
168                 return r;
169         }
170
171         r = sd_bus_add_match(m->bus,
172                              "type='signal',"
173                              "sender='org.freedesktop.systemd1',"
174                              "interface='org.freedesktop.systemd1.Manager',"
175                              "member='UnitRemoved',"
176                              "path='/org/freedesktop/systemd1'",
177                              match_unit_removed,
178                              m);
179         if (r < 0) {
180                 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
181                 return r;
182         }
183
184         r = sd_bus_add_match(m->bus,
185                              "type='signal',"
186                              "sender='org.freedesktop.systemd1',"
187                              "interface='org.freedesktop.DBus.Properties',"
188                              "member='PropertiesChanged'",
189                              match_properties_changed,
190                              m);
191         if (r < 0) {
192                 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
193                 return r;
194         }
195
196         r = sd_bus_add_match(m->bus,
197                              "type='signal',"
198                              "sender='org.freedesktop.systemd1',"
199                              "interface='org.freedesktop.systemd1.Manager',"
200                              "member='Reloading',"
201                              "path='/org/freedesktop/systemd1'",
202                              match_reloading,
203                              m);
204         if (r < 0) {
205                 log_error("Failed to add match for Reloading: %s", strerror(-r));
206                 return r;
207         }
208
209         r = sd_bus_call_method(
210                         m->bus,
211                         "org.freedesktop.systemd1",
212                         "/org/freedesktop/systemd1",
213                         "org.freedesktop.systemd1.Manager",
214                         "Subscribe",
215                         &error,
216                         NULL, NULL);
217         if (r < 0) {
218                 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
219                 return r;
220         }
221
222         r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
223         if (r < 0) {
224                 log_error("Failed to register name: %s", strerror(-r));
225                 return r;
226         }
227
228         r = sd_bus_attach_event(m->bus, m->event, 0);
229         if (r < 0) {
230                 log_error("Failed to attach bus to event loop: %s", strerror(-r));
231                 return r;
232         }
233
234         return 0;
235 }
236
237 void manager_gc(Manager *m, bool drop_not_started) {
238         Machine *machine;
239
240         assert(m);
241
242         while ((machine = m->machine_gc_queue)) {
243                 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
244                 machine->in_gc_queue = false;
245
246                 if (!machine_check_gc(machine, drop_not_started)) {
247                         machine_stop(machine);
248                         machine_free(machine);
249                 }
250         }
251 }
252
253 int manager_startup(Manager *m) {
254         Machine *machine;
255         Iterator i;
256         int r;
257
258         assert(m);
259
260         /* Connect to the bus */
261         r = manager_connect_bus(m);
262         if (r < 0)
263                 return r;
264
265         /* Deserialize state */
266         manager_enumerate_machines(m);
267
268         /* Remove stale objects before we start them */
269         manager_gc(m, false);
270
271         /* And start everything */
272         HASHMAP_FOREACH(machine, m->machines, i)
273                 machine_start(machine, NULL, NULL);
274
275         return 0;
276 }
277
278 int manager_run(Manager *m) {
279         int r;
280
281         assert(m);
282
283         for (;;) {
284                 r = sd_event_get_state(m->event);
285                 if (r < 0)
286                         return r;
287                 if (r == SD_EVENT_FINISHED)
288                         return 0;
289
290                 manager_gc(m, true);
291
292                 r = sd_event_run(m->event, (uint64_t) -1);
293                 if (r < 0)
294                         return r;
295         }
296
297         return 0;
298 }
299
300 int main(int argc, char *argv[]) {
301         Manager *m = NULL;
302         int r;
303
304         log_set_target(LOG_TARGET_AUTO);
305         log_set_facility(LOG_AUTH);
306         log_parse_environment();
307         log_open();
308
309         umask(0022);
310
311         if (argc != 1) {
312                 log_error("This program takes no arguments.");
313                 r = -EINVAL;
314                 goto finish;
315         }
316
317         /* Always create the directories people can create inotify
318          * watches in. Note that some applications might check for the
319          * existence of /run/systemd/machines/ to determine whether
320          * machined is available, so please always make sure this
321          * check stays in. */
322         mkdir_label("/run/systemd/machines", 0755);
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("Failed to fully start up daemon: %s", strerror(-r));
333                 goto finish;
334         }
335
336         log_debug("systemd-machined running as pid %lu", (unsigned long) 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 %lu", (unsigned long) getpid());
345
346 finish:
347         sd_notify(false,
348                   "STATUS=Shutting down...");
349
350         if (m)
351                 manager_free(m);
352
353         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
354 }