1 /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
4 This file is part of systemd.
6 Copyright 2013 Lennart Poettering
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.
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.
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/>.
27 #include <sys/epoll.h>
29 #include "sd-daemon.h"
32 #include "conf-parser.h"
33 #include "cgroup-util.h"
36 #include "bus-error.h"
39 Manager *manager_new(void) {
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);
51 if (!m->machines || !m->machine_units || !m->machine_leaders) {
56 r = sd_event_new(&m->event);
65 void manager_free(Manager *m) {
70 while ((machine = hashmap_first(m->machines)))
71 machine_free(machine);
73 hashmap_free(m->machines);
74 hashmap_free(m->machine_units);
75 hashmap_free(m->machine_leaders);
78 sd_event_unref(m->event);
83 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
89 machine = hashmap_get(m->machines, name);
91 machine = machine_new(m, name);
102 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
103 _cleanup_free_ char *unit = NULL;
111 r = cg_pid_get_unit(pid, &unit);
113 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
115 mm = hashmap_get(m->machine_units, unit);
124 int manager_enumerate_machines(Manager *m) {
125 _cleanup_closedir_ DIR *d = NULL;
131 /* Read in machine data stored on disk */
132 d = opendir("/run/systemd/machines");
137 log_error("Failed to open /run/systemd/machines: %m");
141 FOREACH_DIRENT(de, d, return -errno) {
142 struct Machine *machine;
145 if (!dirent_is_file(de))
148 k = manager_add_machine(m, de->d_name, &machine);
150 log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
156 machine_add_to_gc_queue(machine);
158 k = machine_load(machine);
166 static int manager_connect_bus(Manager *m) {
167 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
173 r = sd_bus_open_system(&m->bus);
175 log_error("Failed to connect to system bus: %s", strerror(-r));
179 r = sd_bus_add_object_vtable(m->bus, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
181 log_error("Failed to add manager object vtable: %s", strerror(-r));
185 r = sd_bus_add_fallback_vtable(m->bus, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
187 log_error("Failed to add machine object vtable: %s", strerror(-r));
191 r = sd_bus_add_node_enumerator(m->bus, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
193 log_error("Failed to add machine enumerator: %s", strerror(-r));
197 r = sd_bus_add_match(m->bus,
199 "sender='org.freedesktop.systemd1',"
200 "interface='org.freedesktop.systemd1.Manager',"
201 "member='JobRemoved',"
202 "path='/org/freedesktop/systemd1'",
206 log_error("Failed to add match for JobRemoved: %s", strerror(-r));
210 r = sd_bus_add_match(m->bus,
212 "sender='org.freedesktop.systemd1',"
213 "interface='org.freedesktop.systemd1.Manager',"
214 "member='UnitRemoved',"
215 "path='/org/freedesktop/systemd1'",
219 log_error("Failed to add match for UnitRemoved: %s", strerror(-r));
223 r = sd_bus_add_match(m->bus,
225 "sender='org.freedesktop.systemd1',"
226 "interface='org.freedesktop.DBus.Properties',"
227 "member='PropertiesChanged'",
228 match_properties_changed,
231 log_error("Failed to add match for PropertiesChanged: %s", strerror(-r));
235 r = sd_bus_add_match(m->bus,
237 "sender='org.freedesktop.systemd1',"
238 "interface='org.freedesktop.systemd1.Manager',"
239 "member='Reloading',"
240 "path='/org/freedesktop/systemd1'",
244 log_error("Failed to add match for Reloading: %s", strerror(-r));
248 r = sd_bus_call_method(
250 "org.freedesktop.systemd1",
251 "/org/freedesktop/systemd1",
252 "org.freedesktop.systemd1.Manager",
257 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
261 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", SD_BUS_NAME_DO_NOT_QUEUE);
263 log_error("Failed to register name: %s", strerror(-r));
267 if (r != SD_BUS_NAME_PRIMARY_OWNER) {
268 log_error("Failed to acquire name.");
272 r = sd_bus_attach_event(m->bus, m->event, 0);
274 log_error("Failed to attach bus to event loop: %s", strerror(-r));
281 void manager_gc(Manager *m, bool drop_not_started) {
286 while ((machine = m->machine_gc_queue)) {
287 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
288 machine->in_gc_queue = false;
290 if (!machine_check_gc(machine, drop_not_started)) {
291 machine_stop(machine);
292 machine_free(machine);
297 int manager_startup(Manager *m) {
304 /* Connect to the bus */
305 r = manager_connect_bus(m);
309 /* Deserialize state */
310 manager_enumerate_machines(m);
312 /* Remove stale objects before we start them */
313 manager_gc(m, false);
315 /* And start everything */
316 HASHMAP_FOREACH(machine, m->machines, i)
317 machine_start(machine, NULL, NULL);
322 int manager_run(Manager *m) {
328 r = sd_event_get_state(m->event);
331 if (r == SD_EVENT_FINISHED)
336 r = sd_event_run(m->event, (uint64_t) -1);
344 int main(int argc, char *argv[]) {
348 log_set_target(LOG_TARGET_AUTO);
349 log_set_facility(LOG_AUTH);
350 log_parse_environment();
356 log_error("This program takes no arguments.");
361 /* Always create the directories people can create inotify
362 * watches in. Note that some applications might check for the
363 * existence of /run/systemd/machines/ to determine whether
364 * machined is available, so please always make sure this
366 mkdir_label("/run/systemd/machines", 0755);
374 r = manager_startup(m);
376 log_error("Failed to fully start up daemon: %s", strerror(-r));
380 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
384 "STATUS=Processing requests...");
388 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
392 "STATUS=Shutting down...");
397 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;