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"
37 #include "cgroup-util.h"
39 Manager *manager_new(void) {
49 m->machines = hashmap_new(string_hash_func, string_compare_func);
50 m->machine_units = hashmap_new(string_hash_func, string_compare_func);
52 if (!m->machines || !m->machine_units) {
60 void manager_free(Manager *m) {
65 while ((machine = hashmap_first(m->machines)))
66 machine_free(machine);
68 hashmap_free(m->machines);
69 hashmap_free(m->machine_units);
72 dbus_connection_flush(m->bus);
73 dbus_connection_close(m->bus);
74 dbus_connection_unref(m->bus);
78 close_nointr_nofail(m->bus_fd);
81 close_nointr_nofail(m->epoll_fd);
86 int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
92 machine = hashmap_get(m->machines, name);
100 machine = machine_new(m, name);
110 int manager_enumerate_machines(Manager *m) {
111 _cleanup_closedir_ DIR *d = NULL;
117 /* Read in machine data stored on disk */
118 d = opendir("/run/systemd/machines");
123 log_error("Failed to open /run/systemd/machines: %m");
127 FOREACH_DIRENT(de, d, return -errno) {
128 struct Machine *machine;
131 if (!dirent_is_file(de))
134 k = manager_add_machine(m, de->d_name, &machine);
136 log_error("Failed to add machine by file name %s: %s", de->d_name, strerror(-k));
142 machine_add_to_gc_queue(machine);
144 k = machine_load(machine);
152 int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
153 _cleanup_free_ char *unit = NULL;
161 r = cg_pid_get_unit(pid, &unit);
165 mm = hashmap_get(m->machine_units, unit);
173 static int manager_connect_bus(Manager *m) {
176 struct epoll_event ev = {
183 assert(m->bus_fd < 0);
185 dbus_error_init(&error);
187 m->bus = dbus_bus_get_private(DBUS_BUS_SYSTEM, &error);
189 log_error("Failed to get system D-Bus connection: %s", bus_error_message(&error));
194 if (!dbus_connection_register_object_path(m->bus, "/org/freedesktop/machine1", &bus_manager_vtable, m) ||
195 !dbus_connection_register_fallback(m->bus, "/org/freedesktop/machine1/machine", &bus_machine_vtable, m) ||
196 !dbus_connection_add_filter(m->bus, bus_message_filter, m, NULL)) {
201 dbus_bus_add_match(m->bus,
203 "sender='org.freedesktop.systemd1',"
204 "interface='org.freedesktop.systemd1.Manager',"
205 "member='JobRemoved',"
206 "path='/org/freedesktop/systemd1'",
208 if (dbus_error_is_set(&error)) {
209 log_error("Failed to add match for JobRemoved: %s", bus_error_message(&error));
210 dbus_error_free(&error);
213 dbus_bus_add_match(m->bus,
215 "sender='org.freedesktop.systemd1',"
216 "interface='org.freedesktop.DBus.Properties',"
217 "member='PropertiesChanged'",
219 if (dbus_error_is_set(&error)) {
220 log_error("Failed to add match for PropertiesChanged: %s", bus_error_message(&error));
221 dbus_error_free(&error);
224 r = bus_method_call_with_reply(
226 "org.freedesktop.systemd1",
227 "/org/freedesktop/systemd1",
228 "org.freedesktop.systemd1.Manager",
234 log_error("Failed to enable subscription: %s", bus_error(&error, r));
235 dbus_error_free(&error);
238 r = dbus_bus_request_name(m->bus, "org.freedesktop.machine1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
239 if (dbus_error_is_set(&error)) {
240 log_error("Failed to register name on bus: %s", bus_error_message(&error));
245 if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
246 log_error("Failed to acquire name.");
251 m->bus_fd = bus_loop_open(m->bus);
257 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
263 dbus_error_free(&error);
268 void manager_gc(Manager *m, bool drop_not_started) {
273 while ((machine = m->machine_gc_queue)) {
274 LIST_REMOVE(Machine, gc_queue, m->machine_gc_queue, machine);
275 machine->in_gc_queue = false;
277 if (machine_check_gc(machine, drop_not_started) == 0) {
278 machine_stop(machine);
279 machine_free(machine);
284 int manager_startup(Manager *m) {
290 assert(m->epoll_fd <= 0);
292 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
296 /* Connect to the bus */
297 r = manager_connect_bus(m);
301 /* Deserialize state */
302 manager_enumerate_machines(m);
304 /* Remove stale objects before we start them */
305 manager_gc(m, false);
307 /* And start everything */
308 HASHMAP_FOREACH(machine, m->machines, i)
309 machine_start(machine);
314 int manager_run(Manager *m) {
318 struct epoll_event event;
323 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
328 n = epoll_wait(m->epoll_fd, &event, 1, -1);
330 if (errno == EINTR || errno == EAGAIN)
333 log_error("epoll() failed: %m");
340 switch (event.data.u32) {
343 bus_loop_dispatch(m->bus_fd);
347 assert_not_reached("Unknown fd");
354 int main(int argc, char *argv[]) {
358 log_set_target(LOG_TARGET_AUTO);
359 log_set_facility(LOG_AUTH);
360 log_parse_environment();
366 log_error("This program takes no arguments.");
371 /* Always create the directories people can create inotify
372 * watches in. Note that some applications might check for the
373 * existence of /run/systemd/seats/ to determine whether
374 * machined is available, so please always make sure this check
376 mkdir_label("/run/systemd/machines", 0755);
384 r = manager_startup(m);
386 log_error("Failed to fully start up daemon: %s", strerror(-r));
390 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
394 "STATUS=Processing requests...");
398 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
402 "STATUS=Shutting down...");
407 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;