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.systemd1.Manager',"
217 "member='UnitRemoved',"
218 "path='/org/freedesktop/systemd1'",
220 if (dbus_error_is_set(&error)) {
221 log_error("Failed to add match for UnitRemoved: %s", bus_error_message(&error));
222 dbus_error_free(&error);
225 dbus_bus_add_match(m->bus,
227 "sender='org.freedesktop.systemd1',"
228 "interface='org.freedesktop.DBus.Properties',"
229 "member='PropertiesChanged'",
231 if (dbus_error_is_set(&error)) {
232 log_error("Failed to add match for PropertiesChanged: %s", bus_error_message(&error));
233 dbus_error_free(&error);
236 r = bus_method_call_with_reply(
238 "org.freedesktop.systemd1",
239 "/org/freedesktop/systemd1",
240 "org.freedesktop.systemd1.Manager",
246 log_error("Failed to enable subscription: %s", bus_error(&error, r));
247 dbus_error_free(&error);
250 r = dbus_bus_request_name(m->bus, "org.freedesktop.machine1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
251 if (dbus_error_is_set(&error)) {
252 log_error("Failed to register name on bus: %s", bus_error_message(&error));
257 if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
258 log_error("Failed to acquire name.");
263 m->bus_fd = bus_loop_open(m->bus);
269 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
275 dbus_error_free(&error);
280 void manager_gc(Manager *m, bool drop_not_started) {
285 while ((machine = m->machine_gc_queue)) {
286 LIST_REMOVE(Machine, gc_queue, m->machine_gc_queue, machine);
287 machine->in_gc_queue = false;
289 if (machine_check_gc(machine, drop_not_started) == 0) {
290 machine_stop(machine);
291 machine_free(machine);
296 int manager_startup(Manager *m) {
302 assert(m->epoll_fd <= 0);
304 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
308 /* Connect to the bus */
309 r = manager_connect_bus(m);
313 /* Deserialize state */
314 manager_enumerate_machines(m);
316 /* Remove stale objects before we start them */
317 manager_gc(m, false);
319 /* And start everything */
320 HASHMAP_FOREACH(machine, m->machines, i)
321 machine_start(machine);
326 int manager_run(Manager *m) {
330 struct epoll_event event;
335 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
340 n = epoll_wait(m->epoll_fd, &event, 1, -1);
342 if (errno == EINTR || errno == EAGAIN)
345 log_error("epoll() failed: %m");
352 switch (event.data.u32) {
355 bus_loop_dispatch(m->bus_fd);
359 assert_not_reached("Unknown fd");
366 int main(int argc, char *argv[]) {
370 log_set_target(LOG_TARGET_AUTO);
371 log_set_facility(LOG_AUTH);
372 log_parse_environment();
378 log_error("This program takes no arguments.");
383 /* Always create the directories people can create inotify
384 * watches in. Note that some applications might check for the
385 * existence of /run/systemd/seats/ to determine whether
386 * machined is available, so please always make sure this check
388 mkdir_label("/run/systemd/machines", 0755);
396 r = manager_startup(m);
398 log_error("Failed to fully start up daemon: %s", strerror(-r));
402 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
406 "STATUS=Processing requests...");
410 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
414 "STATUS=Shutting down...");
419 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;