]> git.proxmox.com Git - systemd.git/blame - src/machine/machined.c
Imported Upstream version 217
[systemd.git] / src / machine / machined.c
CommitLineData
14228c0d
MB
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
60f067b4 29#include "sd-daemon.h"
14228c0d 30
14228c0d
MB
31#include "strv.h"
32#include "conf-parser.h"
60f067b4 33#include "cgroup-util.h"
14228c0d 34#include "mkdir.h"
60f067b4
JS
35#include "bus-util.h"
36#include "bus-error.h"
37#include "machined.h"
5eef597e 38#include "label.h"
14228c0d
MB
39
40Manager *manager_new(void) {
41 Manager *m;
60f067b4 42 int r;
14228c0d
MB
43
44 m = new0(Manager, 1);
45 if (!m)
46 return NULL;
47
5eef597e
MP
48 m->machines = hashmap_new(&string_hash_ops);
49 m->machine_units = hashmap_new(&string_hash_ops);
50 m->machine_leaders = hashmap_new(NULL);
14228c0d 51
60f067b4
JS
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) {
14228c0d
MB
59 manager_free(m);
60 return NULL;
61 }
62
60f067b4
JS
63 sd_event_set_watchdog(m->event, true);
64
14228c0d
MB
65 return m;
66}
67
68void 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);
60f067b4 78 hashmap_free(m->machine_leaders);
14228c0d 79
60f067b4
JS
80 sd_bus_unref(m->bus);
81 sd_event_unref(m->event);
14228c0d
MB
82
83 free(m);
84}
85
86int 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
60f067b4
JS
110 /* Ignore symlinks that map the unit name to the machine */
111 if (startswith(de->d_name, "unit:"))
112 continue;
113
14228c0d
MB
114 k = manager_add_machine(m, de->d_name, &machine);
115 if (k < 0) {
116 log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
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
132static int manager_connect_bus(Manager *m) {
60f067b4 133 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
14228c0d 134 int r;
14228c0d
MB
135
136 assert(m);
137 assert(!m->bus);
14228c0d 138
60f067b4
JS
139 r = sd_bus_default_system(&m->bus);
140 if (r < 0) {
141 log_error("Failed to connect to system bus: %s", strerror(-r));
142 return r;
143 }
14228c0d 144
60f067b4
JS
145 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
146 if (r < 0) {
147 log_error("Failed to add manager object vtable: %s", strerror(-r));
148 return r;
14228c0d
MB
149 }
150
60f067b4
JS
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 log_error("Failed to add machine object vtable: %s", strerror(-r));
154 return r;
14228c0d
MB
155 }
156
60f067b4
JS
157 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
158 if (r < 0) {
159 log_error("Failed to add machine enumerator: %s", strerror(-r));
160 return r;
14228c0d
MB
161 }
162
60f067b4
JS
163 r = sd_bus_add_match(m->bus,
164 NULL,
165 "type='signal',"
166 "sender='org.freedesktop.systemd1',"
167 "interface='org.freedesktop.systemd1.Manager',"
168 "member='JobRemoved',"
169 "path='/org/freedesktop/systemd1'",
170 match_job_removed,
171 m);
172 if (r < 0) {
173 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
174 return r;
14228c0d
MB
175 }
176
60f067b4
JS
177 r = sd_bus_add_match(m->bus,
178 NULL,
179 "type='signal',"
180 "sender='org.freedesktop.systemd1',"
181 "interface='org.freedesktop.systemd1.Manager',"
182 "member='UnitRemoved',"
183 "path='/org/freedesktop/systemd1'",
184 match_unit_removed,
185 m);
186 if (r < 0) {
187 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
188 return r;
189 }
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 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
201 return r;
14228c0d
MB
202 }
203
60f067b4
JS
204 r = sd_bus_add_match(m->bus,
205 NULL,
206 "type='signal',"
207 "sender='org.freedesktop.systemd1',"
208 "interface='org.freedesktop.systemd1.Manager',"
209 "member='Reloading',"
210 "path='/org/freedesktop/systemd1'",
211 match_reloading,
212 m);
213 if (r < 0) {
214 log_error("Failed to add match for Reloading: %s", strerror(-r));
215 return r;
14228c0d
MB
216 }
217
60f067b4 218 r = sd_bus_call_method(
14228c0d
MB
219 m->bus,
220 "org.freedesktop.systemd1",
221 "/org/freedesktop/systemd1",
222 "org.freedesktop.systemd1.Manager",
223 "Subscribe",
14228c0d 224 &error,
60f067b4 225 NULL, NULL);
14228c0d 226 if (r < 0) {
60f067b4
JS
227 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
228 return r;
14228c0d
MB
229 }
230
60f067b4
JS
231 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
232 if (r < 0) {
233 log_error("Failed to register name: %s", strerror(-r));
234 return r;
14228c0d
MB
235 }
236
60f067b4
JS
237 r = sd_bus_attach_event(m->bus, m->event, 0);
238 if (r < 0) {
239 log_error("Failed to attach bus to event loop: %s", strerror(-r));
240 return r;
14228c0d
MB
241 }
242
14228c0d 243 return 0;
14228c0d
MB
244}
245
246void manager_gc(Manager *m, bool drop_not_started) {
247 Machine *machine;
248
249 assert(m);
250
251 while ((machine = m->machine_gc_queue)) {
60f067b4 252 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
14228c0d
MB
253 machine->in_gc_queue = false;
254
60f067b4 255 if (!machine_check_gc(machine, drop_not_started)) {
14228c0d
MB
256 machine_stop(machine);
257 machine_free(machine);
258 }
259 }
260}
261
262int manager_startup(Manager *m) {
14228c0d
MB
263 Machine *machine;
264 Iterator i;
60f067b4 265 int r;
14228c0d
MB
266
267 assert(m);
14228c0d
MB
268
269 /* Connect to the bus */
270 r = manager_connect_bus(m);
271 if (r < 0)
272 return r;
273
274 /* Deserialize state */
275 manager_enumerate_machines(m);
276
277 /* Remove stale objects before we start them */
278 manager_gc(m, false);
279
280 /* And start everything */
281 HASHMAP_FOREACH(machine, m->machines, i)
60f067b4 282 machine_start(machine, NULL, NULL);
14228c0d
MB
283
284 return 0;
285}
286
60f067b4
JS
287static bool check_idle(void *userdata) {
288 Manager *m = userdata;
14228c0d 289
60f067b4 290 manager_gc(m, true);
14228c0d 291
60f067b4
JS
292 return hashmap_isempty(m->machines);
293}
14228c0d 294
60f067b4
JS
295int manager_run(Manager *m) {
296 assert(m);
14228c0d 297
60f067b4
JS
298 return bus_event_loop_with_idle(
299 m->event,
300 m->bus,
301 "org.freedesktop.machine1",
302 DEFAULT_EXIT_USEC,
303 check_idle, m);
14228c0d
MB
304}
305
306int main(int argc, char *argv[]) {
307 Manager *m = NULL;
308 int r;
309
310 log_set_target(LOG_TARGET_AUTO);
311 log_set_facility(LOG_AUTH);
312 log_parse_environment();
313 log_open();
314
315 umask(0022);
316
317 if (argc != 1) {
318 log_error("This program takes no arguments.");
319 r = -EINVAL;
320 goto finish;
321 }
322
323 /* Always create the directories people can create inotify
324 * watches in. Note that some applications might check for the
60f067b4
JS
325 * existence of /run/systemd/machines/ to determine whether
326 * machined is available, so please always make sure this
327 * check stays in. */
14228c0d
MB
328 mkdir_label("/run/systemd/machines", 0755);
329
330 m = manager_new();
331 if (!m) {
332 r = log_oom();
333 goto finish;
334 }
335
336 r = manager_startup(m);
337 if (r < 0) {
338 log_error("Failed to fully start up daemon: %s", strerror(-r));
339 goto finish;
340 }
341
60f067b4 342 log_debug("systemd-machined running as pid "PID_FMT, getpid());
14228c0d
MB
343
344 sd_notify(false,
345 "READY=1\n"
346 "STATUS=Processing requests...");
347
348 r = manager_run(m);
349
60f067b4 350 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
14228c0d
MB
351
352finish:
14228c0d
MB
353 if (m)
354 manager_free(m);
355
356 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
357}