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 <systemd/sd-daemon.h>
32 #include "dbus-common.h"
33 #include "dbus-loop.h"
35 #include "conf-parser.h"
38 Manager *manager_new(void) {
48 m->machines = hashmap_new(string_hash_func, string_compare_func);
49 m->machine_units = hashmap_new(string_hash_func, string_compare_func);
51 if (!m->machines || !m->machine_units) {
59 void manager_free(Manager *m) {
64 while ((machine = hashmap_first(m->machines)))
65 machine_free(machine);
67 hashmap_free(m->machines);
68 hashmap_free(m->machine_units);
71 dbus_connection_flush(m->bus);
72 dbus_connection_close(m->bus);
73 dbus_connection_unref(m->bus);
77 close_nointr_nofail(m->bus_fd);
80 close_nointr_nofail(m->epoll_fd);
85 int manager_enumerate_machines(Manager *m) {
86 _cleanup_closedir_ DIR *d = NULL;
92 /* Read in machine data stored on disk */
93 d = opendir("/run/systemd/machines");
98 log_error("Failed to open /run/systemd/machines: %m");
102 FOREACH_DIRENT(de, d, return -errno) {
103 struct Machine *machine;
106 if (!dirent_is_file(de))
109 k = manager_add_machine(m, de->d_name, &machine);
111 log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
117 machine_add_to_gc_queue(machine);
119 k = machine_load(machine);
127 static int manager_connect_bus(Manager *m) {
130 struct epoll_event ev = {
137 assert(m->bus_fd < 0);
139 dbus_error_init(&error);
141 m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
143 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
148 if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/machine1", &bus_manager_vtable, m) ||
149 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/machine1/machine", &bus_machine_vtable, m) ||
150 !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
155 dbus_bus_add_match(m->bus,
157 "sender='org.freedesktop.systemd1',"
158 "interface='org.freedesktop.systemd1.Manager',"
159 "member='JobRemoved',"
160 "path='/org/freedesktop/systemd1'",
162 if (dbus_error_is_set(&error)) {
163 log_error("Failed to add match for JobRemoved: %s", bus_error_message(&error));
164 dbus_error_free(&error);
167 dbus_bus_add_match(m->bus,
169 "sender='org.freedesktop.systemd1',"
170 "interface='org.freedesktop.systemd1.Manager',"
171 "member='UnitRemoved',"
172 "path='/org/freedesktop/systemd1'",
174 if (dbus_error_is_set(&error)) {
175 log_error("Failed to add match for UnitRemoved: %s", bus_error_message(&error));
176 dbus_error_free(&error);
179 dbus_bus_add_match(m->bus,
181 "sender='org.freedesktop.systemd1',"
182 "interface='org.freedesktop.DBus.Properties',"
183 "member='PropertiesChanged'",
185 if (dbus_error_is_set(&error)) {
186 log_error("Failed to add match for PropertiesChanged: %s", bus_error_message(&error));
187 dbus_error_free(&error);
190 dbus_bus_add_match(m->bus,
192 "sender='org.freedesktop.systemd1',"
193 "interface='org.freedesktop.systemd1.Manager',"
194 "member='Reloading',"
195 "path='/org/freedesktop/systemd1'",
197 if (dbus_error_is_set(&error)) {
198 log_error("Failed to add match for Reloading: %s", bus_error_message(&error));
199 dbus_error_free(&error);
202 r = bus_method_call_with_reply(
204 "org.freedesktop.systemd1",
205 "/org/freedesktop/systemd1",
206 "org.freedesktop.systemd1.Manager",
212 log_error("Failed to enable subscription: %s", bus_error(&error, r));
213 dbus_error_free(&error);
216 r = dbus_bus_request_name(m->bus, "org.freedesktop.machine1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
217 if (dbus_error_is_set(&error)) {
218 log_error("Failed to register name on bus: %s", bus_error_message(&error));
223 if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
224 log_error("Failed to acquire name.");
229 m->bus_fd = bus_loop_open(m->bus);
235 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
241 dbus_error_free(&error);
246 void manager_gc(Manager *m, bool drop_not_started) {
251 while ((machine = m->machine_gc_queue)) {
252 LIST_REMOVE(Machine, gc_queue, m->machine_gc_queue, machine);
253 machine->in_gc_queue = false;
255 if (machine_check_gc(machine, drop_not_started) == 0) {
256 machine_stop(machine);
257 machine_free(machine);
262 int manager_startup(Manager *m) {
268 assert(m->epoll_fd <= 0);
270 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
274 /* Connect to the bus */
275 r = manager_connect_bus(m);
279 /* Deserialize state */
280 manager_enumerate_machines(m);
282 /* Remove stale objects before we start them */
283 manager_gc(m, false);
285 /* And start everything */
286 HASHMAP_FOREACH(machine, m->machines, i)
287 machine_start(machine, NULL);
292 int manager_run(Manager *m) {
296 struct epoll_event event;
301 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
306 n = epoll_wait(m->epoll_fd, &event, 1, -1);
308 if (errno == EINTR || errno == EAGAIN)
311 log_error("epoll() failed: %m");
318 switch (event.data.u32) {
321 bus_loop_dispatch(m->bus_fd);
325 assert_not_reached("Unknown fd");
332 int main(int argc, char *argv[]) {
336 log_set_target(LOG_TARGET_AUTO);
337 log_set_facility(LOG_AUTH);
338 log_parse_environment();
344 log_error("This program takes no arguments.");
349 /* Always create the directories people can create inotify
350 * watches in. Note that some applications might check for the
351 * existence of /run/systemd/seats/ to determine whether
352 * machined is available, so please always make sure this check
354 mkdir_label("/run/systemd/machines", 0755);
362 r = manager_startup(m);
364 log_error("Failed to fully start up daemon: %s", strerror(-r));
368 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
372 "STATUS=Processing requests...");
376 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
380 "STATUS=Shutting down...");
385 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;