]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined.c
machined: make "machinectl copy-to" and "machinectl copy-from" server side operations
[thirdparty/systemd.git] / src / machine / machined.c
CommitLineData
1ee306e1
LP
1/*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2
3/***
4 This file is part of systemd.
5
6 Copyright 2013 Lennart Poettering
7
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.
12
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.
17
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/>.
20***/
21
22#include <errno.h>
23#include <pwd.h>
24#include <fcntl.h>
25#include <string.h>
26#include <unistd.h>
27#include <sys/epoll.h>
28
c3350683 29#include "sd-daemon.h"
1ee306e1
LP
30#include "strv.h"
31#include "conf-parser.h"
c3350683 32#include "cgroup-util.h"
1ee306e1 33#include "mkdir.h"
c3350683
LP
34#include "bus-util.h"
35#include "bus-error.h"
c34255bd 36#include "label.h"
1ddb263d 37#include "machine-image.h"
ebeccf9e 38#include "machined.h"
1ee306e1
LP
39
40Manager *manager_new(void) {
41 Manager *m;
c3350683 42 int r;
1ee306e1
LP
43
44 m = new0(Manager, 1);
45 if (!m)
46 return NULL;
47
d5099efc
MS
48 m->machines = hashmap_new(&string_hash_ops);
49 m->machine_units = hashmap_new(&string_hash_ops);
50 m->machine_leaders = hashmap_new(NULL);
1ee306e1 51
d3e84ddb 52 if (!m->machines || !m->machine_units || !m->machine_leaders) {
c3350683
LP
53 manager_free(m);
54 return NULL;
55 }
56
afc6adb5 57 r = sd_event_default(&m->event);
a658cafa 58 if (r < 0) {
1ee306e1
LP
59 manager_free(m);
60 return NULL;
61 }
62
cde93897
LP
63 sd_event_set_watchdog(m->event, true);
64
1ee306e1
LP
65 return m;
66}
67
68void manager_free(Manager *m) {
69 Machine *machine;
1ddb263d 70 Image *i;
1ee306e1
LP
71
72 assert(m);
73
74 while ((machine = hashmap_first(m->machines)))
75 machine_free(machine);
76
77 hashmap_free(m->machines);
78 hashmap_free(m->machine_units);
d3e84ddb 79 hashmap_free(m->machine_leaders);
1ee306e1 80
1ddb263d
LP
81 while ((i = hashmap_steal_first(m->image_cache)))
82 image_unref(i);
83
84 hashmap_free(m->image_cache);
85
86 sd_event_source_unref(m->image_cache_defer_event);
87
d04c1fb8
LP
88 bus_verify_polkit_async_registry_free(m->polkit_registry);
89
c3350683
LP
90 sd_bus_unref(m->bus);
91 sd_event_unref(m->event);
92
93 free(m);
94}
95
1ee306e1
LP
96int manager_enumerate_machines(Manager *m) {
97 _cleanup_closedir_ DIR *d = NULL;
98 struct dirent *de;
99 int r = 0;
100
101 assert(m);
102
103 /* Read in machine data stored on disk */
104 d = opendir("/run/systemd/machines");
105 if (!d) {
106 if (errno == ENOENT)
107 return 0;
108
56f64d95 109 log_error_errno(errno, "Failed to open /run/systemd/machines: %m");
1ee306e1
LP
110 return -errno;
111 }
112
113 FOREACH_DIRENT(de, d, return -errno) {
114 struct Machine *machine;
115 int k;
116
117 if (!dirent_is_file(de))
118 continue;
119
b87633c4
LP
120 /* Ignore symlinks that map the unit name to the machine */
121 if (startswith(de->d_name, "unit:"))
122 continue;
123
1ee306e1
LP
124 k = manager_add_machine(m, de->d_name, &machine);
125 if (k < 0) {
da927ba9 126 log_error_errno(k, "Failed to add machine by file name %s: %m", de->d_name);
1ee306e1
LP
127
128 r = k;
129 continue;
130 }
131
132 machine_add_to_gc_queue(machine);
133
134 k = machine_load(machine);
135 if (k < 0)
136 r = k;
137 }
138
139 return r;
140}
141
1ee306e1 142static int manager_connect_bus(Manager *m) {
c3350683 143 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1ee306e1 144 int r;
1ee306e1
LP
145
146 assert(m);
147 assert(!m->bus);
1ee306e1 148
76b54375 149 r = sd_bus_default_system(&m->bus);
f647962d
MS
150 if (r < 0)
151 return log_error_errno(r, "Failed to connect to system bus: %m");
1ee306e1 152
19befb2d 153 r = sd_bus_add_object_vtable(m->bus, NULL, "/org/freedesktop/machine1", "org.freedesktop.machine1.Manager", manager_vtable, m);
f647962d
MS
154 if (r < 0)
155 return log_error_errno(r, "Failed to add manager object vtable: %m");
1ee306e1 156
19befb2d 157 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/machine", "org.freedesktop.machine1.Machine", machine_vtable, machine_object_find, m);
f647962d
MS
158 if (r < 0)
159 return log_error_errno(r, "Failed to add machine object vtable: %m");
c3350683 160
19befb2d 161 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/machine", machine_node_enumerator, m);
f647962d
MS
162 if (r < 0)
163 return log_error_errno(r, "Failed to add machine enumerator: %m");
1ee306e1 164
ebeccf9e
LP
165 r = sd_bus_add_fallback_vtable(m->bus, NULL, "/org/freedesktop/machine1/image", "org.freedesktop.machine1.Image", image_vtable, image_object_find, m);
166 if (r < 0)
167 return log_error_errno(r, "Failed to add image object vtable: %m");
168
169 r = sd_bus_add_node_enumerator(m->bus, NULL, "/org/freedesktop/machine1/image", image_node_enumerator, m);
170 if (r < 0)
171 return log_error_errno(r, "Failed to add image enumerator: %m");
172
c3350683 173 r = sd_bus_add_match(m->bus,
19befb2d 174 NULL,
c3350683
LP
175 "type='signal',"
176 "sender='org.freedesktop.systemd1',"
177 "interface='org.freedesktop.systemd1.Manager',"
178 "member='JobRemoved',"
179 "path='/org/freedesktop/systemd1'",
180 match_job_removed,
181 m);
f647962d
MS
182 if (r < 0)
183 return log_error_errno(r, "Failed to add match for JobRemoved: %m");
1ee306e1 184
c3350683 185 r = sd_bus_add_match(m->bus,
19befb2d 186 NULL,
c3350683
LP
187 "type='signal',"
188 "sender='org.freedesktop.systemd1',"
189 "interface='org.freedesktop.systemd1.Manager',"
190 "member='UnitRemoved',"
191 "path='/org/freedesktop/systemd1'",
192 match_unit_removed,
193 m);
f647962d
MS
194 if (r < 0)
195 return log_error_errno(r, "Failed to add match for UnitRemoved: %m");
943aca8e 196
c3350683 197 r = sd_bus_add_match(m->bus,
19befb2d 198 NULL,
c3350683
LP
199 "type='signal',"
200 "sender='org.freedesktop.systemd1',"
201 "interface='org.freedesktop.DBus.Properties',"
202 "member='PropertiesChanged'",
203 match_properties_changed,
204 m);
f647962d
MS
205 if (r < 0)
206 return log_error_errno(r, "Failed to add match for PropertiesChanged: %m");
1ee306e1 207
c3350683 208 r = sd_bus_add_match(m->bus,
19befb2d 209 NULL,
c3350683
LP
210 "type='signal',"
211 "sender='org.freedesktop.systemd1',"
212 "interface='org.freedesktop.systemd1.Manager',"
213 "member='Reloading',"
214 "path='/org/freedesktop/systemd1'",
215 match_reloading,
216 m);
f647962d
MS
217 if (r < 0)
218 return log_error_errno(r, "Failed to add match for Reloading: %m");
6797c324 219
c3350683 220 r = sd_bus_call_method(
1ee306e1
LP
221 m->bus,
222 "org.freedesktop.systemd1",
223 "/org/freedesktop/systemd1",
224 "org.freedesktop.systemd1.Manager",
225 "Subscribe",
1ee306e1 226 &error,
c3350683 227 NULL, NULL);
1ee306e1 228 if (r < 0) {
c3350683
LP
229 log_error("Failed to enable subscription: %s", bus_error_message(&error, r));
230 return r;
1ee306e1
LP
231 }
232
5bb658a1 233 r = sd_bus_request_name(m->bus, "org.freedesktop.machine1", 0);
f647962d
MS
234 if (r < 0)
235 return log_error_errno(r, "Failed to register name: %m");
1ee306e1 236
c3350683 237 r = sd_bus_attach_event(m->bus, m->event, 0);
f647962d
MS
238 if (r < 0)
239 return log_error_errno(r, "Failed to attach bus to event loop: %m");
1ee306e1 240
1ee306e1 241 return 0;
1ee306e1
LP
242}
243
244void manager_gc(Manager *m, bool drop_not_started) {
245 Machine *machine;
246
247 assert(m);
248
249 while ((machine = m->machine_gc_queue)) {
71fda00f 250 LIST_REMOVE(gc_queue, m->machine_gc_queue, machine);
1ee306e1
LP
251 machine->in_gc_queue = false;
252
a658cafa 253 if (!machine_check_gc(machine, drop_not_started)) {
1ee306e1
LP
254 machine_stop(machine);
255 machine_free(machine);
256 }
257 }
258}
259
260int manager_startup(Manager *m) {
1ee306e1
LP
261 Machine *machine;
262 Iterator i;
c3350683 263 int r;
1ee306e1
LP
264
265 assert(m);
1ee306e1
LP
266
267 /* Connect to the bus */
268 r = manager_connect_bus(m);
269 if (r < 0)
270 return r;
271
272 /* Deserialize state */
273 manager_enumerate_machines(m);
274
275 /* Remove stale objects before we start them */
276 manager_gc(m, false);
277
278 /* And start everything */
279 HASHMAP_FOREACH(machine, m->machines, i)
c3350683 280 machine_start(machine, NULL, NULL);
1ee306e1
LP
281
282 return 0;
283}
284
d9e34bfd
LP
285static bool check_idle(void *userdata) {
286 Manager *m = userdata;
1ee306e1 287
d9e34bfd 288 manager_gc(m, true);
1ee306e1 289
d9e34bfd
LP
290 return hashmap_isempty(m->machines);
291}
1ee306e1 292
d9e34bfd
LP
293int manager_run(Manager *m) {
294 assert(m);
1ee306e1 295
d9e34bfd
LP
296 return bus_event_loop_with_idle(
297 m->event,
298 m->bus,
299 "org.freedesktop.machine1",
300 DEFAULT_EXIT_USEC,
301 check_idle, m);
1ee306e1
LP
302}
303
304int main(int argc, char *argv[]) {
305 Manager *m = NULL;
306 int r;
307
308 log_set_target(LOG_TARGET_AUTO);
309 log_set_facility(LOG_AUTH);
310 log_parse_environment();
311 log_open();
312
313 umask(0022);
314
315 if (argc != 1) {
316 log_error("This program takes no arguments.");
317 r = -EINVAL;
318 goto finish;
319 }
320
321 /* Always create the directories people can create inotify
322 * watches in. Note that some applications might check for the
c3350683
LP
323 * existence of /run/systemd/machines/ to determine whether
324 * machined is available, so please always make sure this
325 * check stays in. */
1ee306e1
LP
326 mkdir_label("/run/systemd/machines", 0755);
327
0370612e
LP
328 assert_se(sigprocmask_many(SIG_BLOCK, SIGCHLD, -1) >= 0);
329
1ee306e1
LP
330 m = manager_new();
331 if (!m) {
332 r = log_oom();
333 goto finish;
334 }
335
336 r = manager_startup(m);
337 if (r < 0) {
da927ba9 338 log_error_errno(r, "Failed to fully start up daemon: %m");
1ee306e1
LP
339 goto finish;
340 }
341
de0671ee 342 log_debug("systemd-machined running as pid "PID_FMT, getpid());
1ee306e1
LP
343
344 sd_notify(false,
345 "READY=1\n"
346 "STATUS=Processing requests...");
347
348 r = manager_run(m);
349
de0671ee 350 log_debug("systemd-machined stopped as pid "PID_FMT, getpid());
1ee306e1
LP
351
352finish:
1ee306e1
LP
353 if (m)
354 manager_free(m);
355
356 return r < 0 ? EXIT_FAILURE : EXIT_SUCCESS;
357}