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 dbus_bus_add_match(m->bus,
238 "sender='org.freedesktop.systemd1',"
239 "interface='org.freedesktop.systemd1.Manager',"
240 "member='Reloading',"
241 "path='/org/freedesktop/systemd1'",
243 if (dbus_error_is_set(&error)) {
244 log_error("Failed to add match for Reloading: %s", bus_error_message(&error));
245 dbus_error_free(&error);
248 r = bus_method_call_with_reply(
250 "org.freedesktop.systemd1",
251 "/org/freedesktop/systemd1",
252 "org.freedesktop.systemd1.Manager",
258 log_error("Failed to enable subscription: %s", bus_error(&error, r));
259 dbus_error_free(&error);
262 r = dbus_bus_request_name(m->bus, "org.freedesktop.machine1", DBUS_NAME_FLAG_DO_NOT_QUEUE, &error);
263 if (dbus_error_is_set(&error)) {
264 log_error("Failed to register name on bus: %s", bus_error_message(&error));
269 if (r != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER) {
270 log_error("Failed to acquire name.");
275 m->bus_fd = bus_loop_open(m->bus);
281 if (epoll_ctl(m->epoll_fd, EPOLL_CTL_ADD, m->bus_fd, &ev) < 0)
287 dbus_error_free(&error);
292 void manager_gc(Manager *m, bool drop_not_started) {
297 while ((machine = m->machine_gc_queue)) {
298 LIST_REMOVE(Machine, gc_queue, m->machine_gc_queue, machine);
299 machine->in_gc_queue = false;
301 if (machine_check_gc(machine, drop_not_started) == 0) {
302 machine_stop(machine);
303 machine_free(machine);
308 int manager_startup(Manager *m) {
314 assert(m->epoll_fd <= 0);
316 m->epoll_fd = epoll_create1(EPOLL_CLOEXEC);
320 /* Connect to the bus */
321 r = manager_connect_bus(m);
325 /* Deserialize state */
326 manager_enumerate_machines(m);
328 /* Remove stale objects before we start them */
329 manager_gc(m, false);
331 /* And start everything */
332 HASHMAP_FOREACH(machine, m->machines, i)
333 machine_start(machine, NULL);
338 int manager_run(Manager *m) {
342 struct epoll_event event;
347 if (dbus_connection_dispatch(m->bus) != DBUS_DISPATCH_COMPLETE)
352 n = epoll_wait(m->epoll_fd, &event, 1, -1);
354 if (errno == EINTR || errno == EAGAIN)
357 log_error("epoll() failed: %m");
364 switch (event.data.u32) {
367 bus_loop_dispatch(m->bus_fd);
371 assert_not_reached("Unknown fd");
378 int main(int argc, char *argv[]) {
382 log_set_target(LOG_TARGET_AUTO);
383 log_set_facility(LOG_AUTH);
384 log_parse_environment();
390 log_error("This program takes no arguments.");
395 /* Always create the directories people can create inotify
396 * watches in. Note that some applications might check for the
397 * existence of /run/systemd/seats/ to determine whether
398 * machined is available, so please always make sure this check
400 mkdir_label("/run/systemd/machines", 0755);
408 r = manager_startup(m);
410 log_error("Failed to fully start up daemon: %s", strerror(-r));
414 log_debug("systemd-machined running as pid %lu", (unsigned long) getpid());
418 "STATUS=Processing requests...");
422 log_debug("systemd-machined stopped as pid %lu", (unsigned long) getpid());
426 "STATUS=Shutting down...");
431 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;