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/>.
26 #include "sd-daemon.h"
27 #include "cgroup-util.h"
29 #include "bus-error.h"
31 #include "formats-util.h"
32 #include "signal-util.h"
33 #include "machine-image.h"
36 Manager
*manager_new(void) {
44 m
->machines
= hashmap_new(&string_hash_ops
);
45 m
->machine_units
= hashmap_new(&string_hash_ops
);
46 m
->machine_leaders
= hashmap_new(NULL
);
48 if (!m
->machines
|| !m
->machine_units
|| !m
->machine_leaders
) {
53 r
= sd_event_default(&m
->event
);
59 sd_event_set_watchdog(m
->event
, true);
64 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
);
77 while ((i
= hashmap_steal_first(m
->image_cache
)))
80 hashmap_free(m
->image_cache
);
82 sd_event_source_unref(m
->image_cache_defer_event
);
84 bus_verify_polkit_async_registry_free(m
->polkit_registry
);
87 sd_event_unref(m
->event
);
92 int manager_enumerate_machines(Manager
*m
) {
93 _cleanup_closedir_
DIR *d
= NULL
;
99 /* Read in machine data stored on disk */
100 d
= opendir("/run/systemd/machines");
105 log_error_errno(errno
, "Failed to open /run/systemd/machines: %m");
109 FOREACH_DIRENT(de
, d
, return -errno
) {
110 struct Machine
*machine
;
113 if (!dirent_is_file(de
))
116 /* Ignore symlinks that map the unit name to the machine */
117 if (startswith(de
->d_name
, "unit:"))
120 k
= manager_add_machine(m
, de
->d_name
, &machine
);
122 log_error_errno(k
, "Failed to add machine by file name %s: %m", de
->d_name
);
128 machine_add_to_gc_queue(machine
);
130 k
= machine_load(machine
);
138 static int manager_connect_bus(Manager
*m
) {
139 _cleanup_bus_error_free_ sd_bus_error error
= SD_BUS_ERROR_NULL
;
145 r
= sd_bus_default_system(&m
->bus
);
147 return log_error_errno(r
, "Failed to connect to system bus: %m");
149 r
= sd_bus_add_object_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable
, m
);
151 return log_error_errno(r
, "Failed to add manager object vtable: %m");
153 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable
, machine_object_find
, m
);
155 return log_error_errno(r
, "Failed to add machine object vtable: %m");
157 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/machine", machine_node_enumerator
, m
);
159 return log_error_errno(r
, "Failed to add machine enumerator: %m");
161 r
= sd_bus_add_fallback_vtable(m
->bus
, NULL
, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable
, image_object_find
, m
);
163 return log_error_errno(r
, "Failed to add image object vtable: %m");
165 r
= sd_bus_add_node_enumerator(m
->bus
, NULL
, "/org/freedesktop/machine1/image", image_node_enumerator
, m
);
167 return log_error_errno(r
, "Failed to add image enumerator: %m");
169 r
= sd_bus_add_match(m
->bus
,
172 "sender='org.freedesktop.systemd1',"
173 "interface='org.freedesktop.systemd1.Manager',"
174 "member='JobRemoved',"
175 "path='/org/freedesktop/systemd1'",
179 return log_error_errno(r
, "Failed to add match for JobRemoved: %m");
181 r
= sd_bus_add_match(m
->bus
,
184 "sender='org.freedesktop.systemd1',"
185 "interface='org.freedesktop.systemd1.Manager',"
186 "member='UnitRemoved',"
187 "path='/org/freedesktop/systemd1'",
191 return log_error_errno(r
, "Failed to add match for UnitRemoved: %m");
193 r
= sd_bus_add_match(m
->bus
,
196 "sender='org.freedesktop.systemd1',"
197 "interface='org.freedesktop.DBus.Properties',"
198 "member='PropertiesChanged',"
199 "arg0='org.freedesktop.systemd1.Unit'",
200 match_properties_changed
,
203 return log_error_errno(r
, "Failed to add match for PropertiesChanged: %m");
205 r
= sd_bus_add_match(m
->bus
,
208 "sender='org.freedesktop.systemd1',"
209 "interface='org.freedesktop.systemd1.Manager',"
210 "member='Reloading',"
211 "path='/org/freedesktop/systemd1'",
215 return log_error_errno(r
, "Failed to add match for Reloading: %m");
217 r
= sd_bus_call_method(
219 "org.freedesktop.systemd1",
220 "/org/freedesktop/systemd1",
221 "org.freedesktop.systemd1.Manager",
226 log_error("Failed to enable subscription: %s", bus_error_message(&error
, r
));
230 r
= sd_bus_request_name(m
->bus
, "org.freedesktop.machine1", 0);
232 return log_error_errno(r
, "Failed to register name: %m");
234 r
= sd_bus_attach_event(m
->bus
, m
->event
, 0);
236 return log_error_errno(r
, "Failed to attach bus to event loop: %m");
241 void manager_gc(Manager
*m
, bool drop_not_started
) {
246 while ((machine
= m
->machine_gc_queue
)) {
247 LIST_REMOVE(gc_queue
, m
->machine_gc_queue
, machine
);
248 machine
->in_gc_queue
= false;
250 /* First, if we are not closing yet, initiate stopping */
251 if (!machine_check_gc(machine
, drop_not_started
) &&
252 machine_get_state(machine
) != MACHINE_CLOSING
)
253 machine_stop(machine
);
255 /* Now, the stop stop probably made this referenced
256 * again, but if it didn't, then it's time to let it
258 if (!machine_check_gc(machine
, drop_not_started
)) {
259 machine_finalize(machine
);
260 machine_free(machine
);
265 int manager_startup(Manager
*m
) {
272 /* Connect to the bus */
273 r
= manager_connect_bus(m
);
277 /* Deserialize state */
278 manager_enumerate_machines(m
);
280 /* Remove stale objects before we start them */
281 manager_gc(m
, false);
283 /* And start everything */
284 HASHMAP_FOREACH(machine
, m
->machines
, i
)
285 machine_start(machine
, NULL
, NULL
);
290 static bool check_idle(void *userdata
) {
291 Manager
*m
= userdata
;
295 return hashmap_isempty(m
->machines
);
298 int manager_run(Manager
*m
) {
301 return bus_event_loop_with_idle(
304 "org.freedesktop.machine1",
309 int main(int argc
, char *argv
[]) {
313 log_set_target(LOG_TARGET_AUTO
);
314 log_set_facility(LOG_AUTH
);
315 log_parse_environment();
321 log_error("This program takes no arguments.");
326 /* Always create the directories people can create inotify
327 * watches in. Note that some applications might check for the
328 * existence of /run/systemd/machines/ to determine whether
329 * machined is available, so please always make sure this
331 mkdir_label("/run/systemd/machines", 0755);
333 assert_se(sigprocmask_many(SIG_BLOCK
, NULL
, SIGCHLD
, -1) >= 0);
341 r
= manager_startup(m
);
343 log_error_errno(r
, "Failed to fully start up daemon: %m");
347 log_debug("systemd-machined running as pid "PID_FMT
, getpid());
351 "STATUS=Processing requests...");
355 log_debug("systemd-machined stopped as pid "PID_FMT
, getpid());
360 return r
< 0 ? EXIT_FAILURE
: EXIT_SUCCESS
;