chiark / gitweb /
machine: move symbols referenced by shared code from main to shared file
[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_new(&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_open_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_DO_NOT_QUEUE);
221         if (r < 0) {
222                 log_error("Failed to register name: %s", strerror(-r));
223                 return r;
224         }
225
226         if (r != SD_BUS_NAME_PRIMARY_OWNER)  {
227                 log_error("Failed to acquire name.");
228                 return -EEXIST;
229         }
230
231         r = sd_bus_attach_event(m->bus, m->event, 0);
232         if (r < 0) {
233                 log_error("Failed to attach bus to event loop: %s", strerror(-r));
234                 return r;
235         }
236
237         return 0;
238 }
239
240 void manager_gc(Manager *m, bool drop_not_started) {
241         Machine *machine;
242
243         assert(m);
244
245         while ((machine = m->machine_gc_queue)) {
246                 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
247                 machine->in_gc_queue = false;
248
249                 if (!machine_check_gc(machine, drop_not_started)) {
250                         machine_stop(machine);
251                         machine_free(machine);
252                 }
253         }
254 }
255
256 int manager_startup(Manager *m) {
257         Machine *machine;
258         Iterator i;
259         int r;
260
261         assert(m);
262
263         /* Connect to the bus */
264         r = manager_connect_bus(m);
265         if (r < 0)
266                 return r;
267
268         /* Deserialize state */
269         manager_enumerate_machines(m);
270
271         /* Remove stale objects before we start them */
272         manager_gc(m, false);
273
274         /* And start everything */
275         HASHMAP_FOREACH(machine, m->machines, i)
276                 machine_start(machine, NULL, NULL);
277
278         return 0;
279 }
280
281 int manager_run(Manager *m) {
282         int r;
283
284         assert(m);
285
286         for (;;) {
287                 r = sd_event_get_state(m->event);
288                 if (r < 0)
289                         return r;
290                 if (r == SD_EVENT_FINISHED)
291                         return 0;
292
293                 manager_gc(m, true);
294
295                 r = sd_event_run(m->event, (uint64_t) -1);
296                 if (r < 0)
297                         return r;
298         }
299
300         return 0;
301 }
302
303 int main(int argc, char *argv[]) {
304         Manager *m = NULL;
305         int r;
306
307         log_set_target(LOG_TARGET_AUTO);
308         log_set_facility(LOG_AUTH);
309         log_parse_environment();
310         log_open();
311
312         umask(0022);
313
314         if (argc != 1) {
315                 log_error("This program takes no arguments.");
316                 r = -EINVAL;
317                 goto finish;
318         }
319
320         /* Always create the directories people can create inotify
321          * watches in. Note that some applications might check for the
322          * existence of /run/systemd/machines/ to determine whether
323          * machined is available, so please always make sure this
324          * check stays in. */
325         mkdir_label("/run/systemd/machines", 0755);
326
327         m = manager_new();
328         if (!m) {
329                 r = log_oom();
330                 goto finish;
331         }
332
333         r = manager_startup(m);
334         if (r < 0) {
335                 log_error("Failed to fully start up daemon: %s", strerror(-r));
336                 goto finish;
337         }
338
339         log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
340
341         sd_notify(false,
342                   "READY=1\n"
343                   "STATUS=Processing requests...");
344
345         r = manager_run(m);
346
347         log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
348
349 finish:
350         sd_notify(false,
351                   "STATUS=Shutting down...");
352
353         if (m)
354                 manager_free(m);
355
356         return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
357 }