chiark / gitweb /
bus: make sd_bus_request_name() and sd_bus_release_name() behave more like other...
[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         return m;
63 }
64
65 void manager_free(Manager *m) {
66         Machine *machine;
67
68         assert(m);
69
70         while ((machine = hashmap_first(m->machines)))
71                 machine_free(machine);
72
73         hashmap_free(m->machines);
74         hashmap_free(m->machine_units);
75         hashmap_free(m->machine_leaders);
76
77         sd_bus_unref(m->bus);
78         sd_event_unref(m->event);
79
80         free(m);
81 }
82
83 int manager_enumerate_machines(Manager *m) {
84         _cleanup_closedir_ DIR *d = NULL;
85         struct dirent *de;
86         int r = 0;
87
88         assert(m);
89
90         /* Read in machine data stored on disk */
91         d = opendir("/run/systemd/machines");
92         if (!d) {
93                 if (errno == ENOENT)
94                         return 0;
95
96                 log_error("Failed to open /run/systemd/machines: %m");
97                 return -errno;
98         }
99
100         FOREACH_DIRENT(de, d, return -errno) {
101                 struct Machine *machine;
102                 int k;
103
104                 if (!dirent_is_file(de))
105                         continue;
106
107                 k = manager_add_machine(m, de->d_name, &machine);
108                 if (k < 0) {
109                         log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
110
111                         r = k;
112                         continue;
113                 }
114
115                 machine_add_to_gc_queue(machine);
116
117                 k = machine_load(machine);
118                 if (k < 0)
119                         r = k;
120         }
121
122         return r;
123 }
124
125 static int manager_connect_bus(Manager *m) {
126         _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
127         int r;
128
129         assert(m);
130         assert(!m->bus);
131
132         r = sd_bus_default_system(&m->bus);
133         if (r < 0) {
134                 log_error("Failed to connect to system bus: %s", strerror(-r));
135                 return r;
136         }
137
138         r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
139         if (r < 0) {
140                 log_error("Failed to add manager object vtable: %s", strerror(-r));
141                 return r;
142         }
143
144         r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
145         if (r < 0) {
146                 log_error("Failed to add machine object vtable: %s", strerror(-r));
147                 return r;
148         }
149
150         r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
151         if (r < 0) {
152                 log_error("Failed to add machine enumerator: %s", strerror(-r));
153                 return r;
154         }
155
156         r = sd_bus_add_match(m->bus,
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                 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
166                 return r;
167         }
168
169         r = sd_bus_add_match(m->bus,
170                              "type='signal',"
171                              "sender='org.freedesktop.systemd1',"
172                              "interface='org.freedesktop.systemd1.Manager',"
173                              "member='UnitRemoved',"
174                              "path='/org/freedesktop/systemd1'",
175                              match_unit_removed,
176                              m);
177         if (r < 0) {
178                 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
179                 return r;
180         }
181
182         r = sd_bus_add_match(m->bus,
183                              "type='signal',"
184                              "sender='org.freedesktop.systemd1',"
185                              "interface='org.freedesktop.DBus.Properties',"
186                              "member='PropertiesChanged'",
187                              match_properties_changed,
188                              m);
189         if (r < 0) {
190                 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
191                 return r;
192         }
193
194         r = sd_bus_add_match(m->bus,
195                              "type='signal',"
196                              "sender='org.freedesktop.systemd1',"
197                              "interface='org.freedesktop.systemd1.Manager',"
198                              "member='Reloading',"
199                              "path='/org/freedesktop/systemd1'",
200                              match_reloading,
201                              m);
202         if (r < 0) {
203                 log_error("Failed to add match for Reloading: %s", strerror(-r));
204                 return r;
205         }
206
207         r = sd_bus_call_method(
208                         m->bus,
209                         "org.freedesktop.systemd1",
210                         "/org/freedesktop/systemd1",
211                         "org.freedesktop.systemd1.Manager",
212                         "Subscribe",
213                         &error,
214                         NULL, NULL);
215         if (r < 0) {
216                 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
217                 return r;
218         }
219
220         r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", SD_BUS_NAME_REPLACE_EXISTING|SD_BUS_NAME_DO_NOT_QUEUE);
221         if (r < 0) {
222                 log_error("Failed to register name: %s", strerror(-r));
223                 return r;
224         }
225
226         r = sd_bus_attach_event(m->bus, m->event, 0);
227         if (r < 0) {
228                 log_error("Failed to attach bus to event loop: %s", strerror(-r));
229                 return r;
230         }
231
232         return 0;
233 }
234
235 void manager_gc(Manager *m, bool drop_not_started) {
236         Machine *machine;
237
238         assert(m);
239
240         while ((machine = m->machine_gc_queue)) {
241                 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
242                 machine->in_gc_queue = false;
243
244                 if (!machine_check_gc(machine, drop_not_started)) {
245                         machine_stop(machine);
246                         machine_free(machine);
247                 }
248         }
249 }
250
251 int manager_startup(Manager *m) {
252         Machine *machine;
253         Iterator i;
254         int r;
255
256         assert(m);
257
258         /* Connect to the bus */
259         r = manager_connect_bus(m);
260         if (r < 0)
261                 return r;
262
263         /* Deserialize state */
264         manager_enumerate_machines(m);
265
266         /* Remove stale objects before we start them */
267         manager_gc(m, false);
268
269         /* And start everything */
270         HASHMAP_FOREACH(machine, m->machines, i)
271                 machine_start(machine, NULL, NULL);
272
273         return 0;
274 }
275
276 int manager_run(Manager *m) {
277         int r;
278
279         assert(m);
280
281         for (;;) {
282                 r = sd_event_get_state(m->event);
283                 if (r < 0)
284                         return r;
285                 if (r == SD_EVENT_FINISHED)
286                         return 0;
287
288                 manager_gc(m, true);
289
290                 r = sd_event_run(m->event, (uint64_t) -1);
291                 if (r < 0)
292                         return r;
293         }
294
295         return 0;
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         m = manager_new();
323         if (!m) {
324                 r = log_oom();
325                 goto finish;
326         }
327
328         r = manager_startup(m);
329         if (r < 0) {
330                 log_error("Failed to fully start up daemon: %s", strerror(-r));
331                 goto finish;
332         }
333
334         log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
335
336         sd_notify(false,
337                   "READY=1\n"
338                   "STATUS=Processing requests...");
339
340         r = manager_run(m);
341
342         log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
343
344 finish:
345         sd_notify(false,
346                   "STATUS=Shutting down...");
347
348         if (m)
349                 manager_free(m);
350
351         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
352 }