Line data Source code
1 : /*-*- Mode: C; c-basic-offset: 8; indent-tabs-mode: nil -*-*/
2 :
3 : /***
4 : This file is part of systemd.
5 :
6 : Copyright 2011 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 <string.h>
24 : #include <unistd.h>
25 :
26 : #include "sd-id128.h"
27 : #include "strv.h"
28 : #include "path-util.h"
29 : #include "unit-name.h"
30 : #include "bus-util.h"
31 : #include "bus-common-errors.h"
32 : #include "cgroup-util.h"
33 : #include "btrfs-util.h"
34 : #include "formats-util.h"
35 : #include "process-util.h"
36 : #include "machine-image.h"
37 : #include "machine-pool.h"
38 : #include "image-dbus.h"
39 : #include "machined.h"
40 : #include "machine-dbus.h"
41 :
42 0 : static int property_get_pool_path(
43 : sd_bus *bus,
44 : const char *path,
45 : const char *interface,
46 : const char *property,
47 : sd_bus_message *reply,
48 : void *userdata,
49 : sd_bus_error *error) {
50 :
51 0 : assert(bus);
52 0 : assert(reply);
53 :
54 0 : return sd_bus_message_append(reply, "s", "/var/lib/machines");
55 : }
56 :
57 0 : static int property_get_pool_usage(
58 : sd_bus *bus,
59 : const char *path,
60 : const char *interface,
61 : const char *property,
62 : sd_bus_message *reply,
63 : void *userdata,
64 : sd_bus_error *error) {
65 :
66 0 : _cleanup_close_ int fd = -1;
67 0 : uint64_t usage = (uint64_t) -1;
68 : struct stat st;
69 :
70 0 : assert(bus);
71 0 : assert(reply);
72 :
73 : /* We try to read the quota info from /var/lib/machines, as
74 : * well as the usage of the loopback file
75 : * /var/lib/machines.raw, and pick the larger value. */
76 :
77 0 : fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
78 0 : if (fd >= 0) {
79 : BtrfsQuotaInfo q;
80 :
81 0 : if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
82 0 : usage = q.referenced;
83 : }
84 :
85 0 : if (stat("/var/lib/machines.raw", &st) >= 0) {
86 0 : if (usage == (uint64_t) -1 || st.st_blocks * 512ULL > usage)
87 0 : usage = st.st_blocks * 512ULL;
88 : }
89 :
90 0 : return sd_bus_message_append(reply, "t", usage);
91 : }
92 :
93 0 : static int property_get_pool_limit(
94 : sd_bus *bus,
95 : const char *path,
96 : const char *interface,
97 : const char *property,
98 : sd_bus_message *reply,
99 : void *userdata,
100 : sd_bus_error *error) {
101 :
102 0 : _cleanup_close_ int fd = -1;
103 0 : uint64_t size = (uint64_t) -1;
104 : struct stat st;
105 :
106 0 : assert(bus);
107 0 : assert(reply);
108 :
109 : /* We try to read the quota limit from /var/lib/machines, as
110 : * well as the size of the loopback file
111 : * /var/lib/machines.raw, and pick the smaller value. */
112 :
113 0 : fd = open("/var/lib/machines", O_RDONLY|O_CLOEXEC|O_DIRECTORY);
114 0 : if (fd >= 0) {
115 : BtrfsQuotaInfo q;
116 :
117 0 : if (btrfs_subvol_get_quota_fd(fd, &q) >= 0)
118 0 : size = q.referenced_max;
119 : }
120 :
121 0 : if (stat("/var/lib/machines.raw", &st) >= 0) {
122 0 : if (size == (uint64_t) -1 || (uint64_t) st.st_size < size)
123 0 : size = st.st_size;
124 : }
125 :
126 0 : return sd_bus_message_append(reply, "t", size);
127 : }
128 :
129 0 : static int method_get_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
130 0 : _cleanup_free_ char *p = NULL;
131 0 : Manager *m = userdata;
132 : Machine *machine;
133 : const char *name;
134 : int r;
135 :
136 0 : assert(message);
137 0 : assert(m);
138 :
139 0 : r = sd_bus_message_read(message, "s", &name);
140 0 : if (r < 0)
141 0 : return r;
142 :
143 0 : machine = hashmap_get(m->machines, name);
144 0 : if (!machine)
145 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
146 :
147 0 : p = machine_bus_path(machine);
148 0 : if (!p)
149 0 : return -ENOMEM;
150 :
151 0 : return sd_bus_reply_method_return(message, "o", p);
152 : }
153 :
154 0 : static int method_get_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
155 0 : _cleanup_free_ char *p = NULL;
156 0 : Manager *m = userdata;
157 : const char *name;
158 : int r;
159 :
160 0 : assert(message);
161 0 : assert(m);
162 :
163 0 : r = sd_bus_message_read(message, "s", &name);
164 0 : if (r < 0)
165 0 : return r;
166 :
167 0 : r = image_find(name, NULL);
168 0 : if (r == 0)
169 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
170 0 : if (r < 0)
171 0 : return r;
172 :
173 0 : p = image_bus_path(name);
174 0 : if (!p)
175 0 : return -ENOMEM;
176 :
177 0 : return sd_bus_reply_method_return(message, "o", p);
178 : }
179 :
180 0 : static int method_get_machine_by_pid(sd_bus_message *message, void *userdata, sd_bus_error *error) {
181 0 : _cleanup_free_ char *p = NULL;
182 0 : Manager *m = userdata;
183 0 : Machine *machine = NULL;
184 : pid_t pid;
185 : int r;
186 :
187 0 : assert(message);
188 0 : assert(m);
189 :
190 : assert_cc(sizeof(pid_t) == sizeof(uint32_t));
191 :
192 0 : r = sd_bus_message_read(message, "u", &pid);
193 0 : if (r < 0)
194 0 : return r;
195 :
196 0 : if (pid == 0) {
197 0 : _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
198 :
199 0 : r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
200 0 : if (r < 0)
201 0 : return r;
202 :
203 0 : r = sd_bus_creds_get_pid(creds, &pid);
204 0 : if (r < 0)
205 0 : return r;
206 : }
207 :
208 0 : r = manager_get_machine_by_pid(m, pid, &machine);
209 0 : if (r < 0)
210 0 : return r;
211 0 : if (!machine)
212 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
213 :
214 0 : p = machine_bus_path(machine);
215 0 : if (!p)
216 0 : return -ENOMEM;
217 :
218 0 : return sd_bus_reply_method_return(message, "o", p);
219 : }
220 :
221 0 : static int method_list_machines(sd_bus_message *message, void *userdata, sd_bus_error *error) {
222 0 : _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
223 0 : Manager *m = userdata;
224 : Machine *machine;
225 : Iterator i;
226 : int r;
227 :
228 0 : assert(message);
229 0 : assert(m);
230 :
231 0 : r = sd_bus_message_new_method_return(message, &reply);
232 0 : if (r < 0)
233 0 : return sd_bus_error_set_errno(error, r);
234 :
235 0 : r = sd_bus_message_open_container(reply, 'a', "(ssso)");
236 0 : if (r < 0)
237 0 : return sd_bus_error_set_errno(error, r);
238 :
239 0 : HASHMAP_FOREACH(machine, m->machines, i) {
240 0 : _cleanup_free_ char *p = NULL;
241 :
242 0 : p = machine_bus_path(machine);
243 0 : if (!p)
244 0 : return -ENOMEM;
245 :
246 0 : r = sd_bus_message_append(reply, "(ssso)",
247 0 : machine->name,
248 0 : strempty(machine_class_to_string(machine->class)),
249 0 : machine->service,
250 : p);
251 0 : if (r < 0)
252 0 : return sd_bus_error_set_errno(error, r);
253 : }
254 :
255 0 : r = sd_bus_message_close_container(reply);
256 0 : if (r < 0)
257 0 : return sd_bus_error_set_errno(error, r);
258 :
259 0 : return sd_bus_send(NULL, reply, NULL);
260 : }
261 :
262 0 : static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
263 : const char *name, *service, *class, *root_directory;
264 0 : const int32_t *netif = NULL;
265 : MachineClass c;
266 : uint32_t leader;
267 : sd_id128_t id;
268 : const void *v;
269 : Machine *m;
270 0 : size_t n, n_netif = 0;
271 : int r;
272 :
273 0 : assert(manager);
274 0 : assert(message);
275 0 : assert(_m);
276 :
277 0 : r = sd_bus_message_read(message, "s", &name);
278 0 : if (r < 0)
279 0 : return r;
280 0 : if (!machine_name_is_valid(name))
281 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
282 :
283 0 : r = sd_bus_message_read_array(message, 'y', &v, &n);
284 0 : if (r < 0)
285 0 : return r;
286 0 : if (n == 0)
287 0 : id = SD_ID128_NULL;
288 0 : else if (n == 16)
289 0 : memcpy(&id, v, n);
290 : else
291 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
292 :
293 0 : r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
294 0 : if (r < 0)
295 0 : return r;
296 :
297 0 : if (read_network) {
298 : size_t i;
299 :
300 0 : r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
301 0 : if (r < 0)
302 0 : return r;
303 :
304 0 : n_netif /= sizeof(int32_t);
305 :
306 0 : for (i = 0; i < n_netif; i++) {
307 0 : if (netif[i] <= 0)
308 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
309 : }
310 : }
311 :
312 0 : if (isempty(class))
313 0 : c = _MACHINE_CLASS_INVALID;
314 : else {
315 0 : c = machine_class_from_string(class);
316 0 : if (c < 0)
317 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
318 : }
319 :
320 0 : if (leader == 1)
321 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
322 :
323 0 : if (!isempty(root_directory) && !path_is_absolute(root_directory))
324 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
325 :
326 0 : if (leader == 0) {
327 0 : _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
328 :
329 0 : r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
330 0 : if (r < 0)
331 0 : return r;
332 :
333 : assert_cc(sizeof(uint32_t) == sizeof(pid_t));
334 :
335 0 : r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
336 0 : if (r < 0)
337 0 : return r;
338 : }
339 :
340 0 : if (hashmap_get(manager->machines, name))
341 0 : return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
342 :
343 0 : r = manager_add_machine(manager, name, &m);
344 0 : if (r < 0)
345 0 : return r;
346 :
347 0 : m->leader = leader;
348 0 : m->class = c;
349 0 : m->id = id;
350 :
351 0 : if (!isempty(service)) {
352 0 : m->service = strdup(service);
353 0 : if (!m->service) {
354 0 : r = -ENOMEM;
355 0 : goto fail;
356 : }
357 : }
358 :
359 0 : if (!isempty(root_directory)) {
360 0 : m->root_directory = strdup(root_directory);
361 0 : if (!m->root_directory) {
362 0 : r = -ENOMEM;
363 0 : goto fail;
364 : }
365 : }
366 :
367 0 : if (n_netif > 0) {
368 : assert_cc(sizeof(int32_t) == sizeof(int));
369 0 : m->netif = memdup(netif, sizeof(int32_t) * n_netif);
370 0 : if (!m->netif) {
371 0 : r = -ENOMEM;
372 0 : goto fail;
373 : }
374 :
375 0 : m->n_netif = n_netif;
376 : }
377 :
378 0 : *_m = m;
379 :
380 0 : return 1;
381 :
382 : fail:
383 0 : machine_add_to_gc_queue(m);
384 0 : return r;
385 : }
386 :
387 0 : static int method_create_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
388 0 : Manager *manager = userdata;
389 0 : Machine *m = NULL;
390 : int r;
391 :
392 0 : assert(message);
393 0 : assert(manager);
394 :
395 0 : r = method_create_or_register_machine(manager, message, read_network, &m, error);
396 0 : if (r < 0)
397 0 : return r;
398 :
399 0 : r = sd_bus_message_enter_container(message, 'a', "(sv)");
400 0 : if (r < 0)
401 0 : goto fail;
402 :
403 0 : r = machine_start(m, message, error);
404 0 : if (r < 0)
405 0 : goto fail;
406 :
407 0 : m->create_message = sd_bus_message_ref(message);
408 0 : return 1;
409 :
410 : fail:
411 0 : machine_add_to_gc_queue(m);
412 0 : return r;
413 : }
414 :
415 0 : static int method_create_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
416 0 : return method_create_machine_internal(message, true, userdata, error);
417 : }
418 :
419 0 : static int method_create_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
420 0 : return method_create_machine_internal(message, false, userdata, error);
421 : }
422 :
423 0 : static int method_register_machine_internal(sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
424 0 : Manager *manager = userdata;
425 0 : _cleanup_free_ char *p = NULL;
426 0 : Machine *m = NULL;
427 : int r;
428 :
429 0 : assert(message);
430 0 : assert(manager);
431 :
432 0 : r = method_create_or_register_machine(manager, message, read_network, &m, error);
433 0 : if (r < 0)
434 0 : return r;
435 :
436 0 : r = cg_pid_get_unit(m->leader, &m->unit);
437 0 : if (r < 0) {
438 0 : r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
439 0 : goto fail;
440 : }
441 :
442 0 : r = machine_start(m, NULL, error);
443 0 : if (r < 0)
444 0 : goto fail;
445 :
446 0 : p = machine_bus_path(m);
447 0 : if (!p) {
448 0 : r = -ENOMEM;
449 0 : goto fail;
450 : }
451 :
452 0 : return sd_bus_reply_method_return(message, "o", p);
453 :
454 : fail:
455 0 : machine_add_to_gc_queue(m);
456 0 : return r;
457 : }
458 :
459 0 : static int method_register_machine_with_network(sd_bus_message *message, void *userdata, sd_bus_error *error) {
460 0 : return method_register_machine_internal(message, true, userdata, error);
461 : }
462 :
463 0 : static int method_register_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
464 0 : return method_register_machine_internal(message, false, userdata, error);
465 : }
466 :
467 0 : static int method_terminate_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 0 : Manager *m = userdata;
469 : Machine *machine;
470 : const char *name;
471 : int r;
472 :
473 0 : assert(message);
474 0 : assert(m);
475 :
476 0 : r = sd_bus_message_read(message, "s", &name);
477 0 : if (r < 0)
478 0 : return sd_bus_error_set_errno(error, r);
479 :
480 0 : machine = hashmap_get(m->machines, name);
481 0 : if (!machine)
482 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
483 :
484 0 : return bus_machine_method_terminate(message, machine, error);
485 : }
486 :
487 0 : static int method_kill_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
488 0 : Manager *m = userdata;
489 : Machine *machine;
490 : const char *name;
491 : int r;
492 :
493 0 : assert(message);
494 0 : assert(m);
495 :
496 0 : r = sd_bus_message_read(message, "s", &name);
497 0 : if (r < 0)
498 0 : return sd_bus_error_set_errno(error, r);
499 :
500 0 : machine = hashmap_get(m->machines, name);
501 0 : if (!machine)
502 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
503 :
504 0 : return bus_machine_method_kill(message, machine, error);
505 : }
506 :
507 0 : static int method_get_machine_addresses(sd_bus_message *message, void *userdata, sd_bus_error *error) {
508 0 : Manager *m = userdata;
509 : Machine *machine;
510 : const char *name;
511 : int r;
512 :
513 0 : assert(message);
514 0 : assert(m);
515 :
516 0 : r = sd_bus_message_read(message, "s", &name);
517 0 : if (r < 0)
518 0 : return sd_bus_error_set_errno(error, r);
519 :
520 0 : machine = hashmap_get(m->machines, name);
521 0 : if (!machine)
522 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
523 :
524 0 : return bus_machine_method_get_addresses(message, machine, error);
525 : }
526 :
527 0 : static int method_get_machine_os_release(sd_bus_message *message, void *userdata, sd_bus_error *error) {
528 0 : Manager *m = userdata;
529 : Machine *machine;
530 : const char *name;
531 : int r;
532 :
533 0 : assert(message);
534 0 : assert(m);
535 :
536 0 : r = sd_bus_message_read(message, "s", &name);
537 0 : if (r < 0)
538 0 : return sd_bus_error_set_errno(error, r);
539 :
540 0 : machine = hashmap_get(m->machines, name);
541 0 : if (!machine)
542 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
543 :
544 0 : return bus_machine_method_get_os_release(message, machine, error);
545 : }
546 :
547 0 : static int method_list_images(sd_bus_message *message, void *userdata, sd_bus_error *error) {
548 0 : _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
549 0 : _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
550 0 : Manager *m = userdata;
551 : Image *image;
552 : Iterator i;
553 : int r;
554 :
555 0 : assert(message);
556 0 : assert(m);
557 :
558 0 : images = hashmap_new(&string_hash_ops);
559 0 : if (!images)
560 0 : return -ENOMEM;
561 :
562 0 : r = image_discover(images);
563 0 : if (r < 0)
564 0 : return r;
565 :
566 0 : r = sd_bus_message_new_method_return(message, &reply);
567 0 : if (r < 0)
568 0 : return r;
569 :
570 0 : r = sd_bus_message_open_container(reply, 'a', "(ssbttto)");
571 0 : if (r < 0)
572 0 : return r;
573 :
574 0 : HASHMAP_FOREACH(image, images, i) {
575 0 : _cleanup_free_ char *p = NULL;
576 :
577 0 : p = image_bus_path(image->name);
578 0 : if (!p)
579 0 : return -ENOMEM;
580 :
581 0 : r = sd_bus_message_append(reply, "(ssbttto)",
582 0 : image->name,
583 0 : image_type_to_string(image->type),
584 0 : image->read_only,
585 0 : image->crtime,
586 0 : image->mtime,
587 0 : image->usage,
588 : p);
589 0 : if (r < 0)
590 0 : return r;
591 : }
592 :
593 0 : r = sd_bus_message_close_container(reply);
594 0 : if (r < 0)
595 0 : return r;
596 :
597 0 : return sd_bus_send(NULL, reply, NULL);
598 : }
599 :
600 0 : static int method_open_machine_pty(sd_bus_message *message, void *userdata, sd_bus_error *error) {
601 0 : Manager *m = userdata;
602 : Machine *machine;
603 : const char *name;
604 : int r;
605 :
606 0 : assert(message);
607 0 : assert(m);
608 :
609 0 : r = sd_bus_message_read(message, "s", &name);
610 0 : if (r < 0)
611 0 : return sd_bus_error_set_errno(error, r);
612 :
613 0 : machine = hashmap_get(m->machines, name);
614 0 : if (!machine)
615 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
616 :
617 0 : return bus_machine_method_open_pty(message, machine, error);
618 : }
619 :
620 0 : static int method_open_machine_login(sd_bus_message *message, void *userdata, sd_bus_error *error) {
621 0 : Manager *m = userdata;
622 : Machine *machine;
623 : const char *name;
624 : int r;
625 :
626 0 : assert(message);
627 0 : assert(m);
628 :
629 0 : r = sd_bus_message_read(message, "s", &name);
630 0 : if (r < 0)
631 0 : return r;
632 :
633 0 : machine = hashmap_get(m->machines, name);
634 0 : if (!machine)
635 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
636 :
637 0 : return bus_machine_method_open_login(message, machine, error);
638 : }
639 :
640 0 : static int method_bind_mount_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
641 0 : Manager *m = userdata;
642 : Machine *machine;
643 : const char *name;
644 : int r;
645 :
646 0 : assert(message);
647 0 : assert(m);
648 :
649 0 : r = sd_bus_message_read(message, "s", &name);
650 0 : if (r < 0)
651 0 : return r;
652 :
653 0 : machine = hashmap_get(m->machines, name);
654 0 : if (!machine)
655 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
656 :
657 0 : return bus_machine_method_bind_mount(message, machine, error);
658 : }
659 :
660 0 : static int method_copy_machine(sd_bus_message *message, void *userdata, sd_bus_error *error) {
661 0 : Manager *m = userdata;
662 : Machine *machine;
663 : const char *name;
664 : int r;
665 :
666 0 : assert(message);
667 0 : assert(m);
668 :
669 0 : r = sd_bus_message_read(message, "s", &name);
670 0 : if (r < 0)
671 0 : return r;
672 :
673 0 : machine = hashmap_get(m->machines, name);
674 0 : if (!machine)
675 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
676 :
677 0 : return bus_machine_method_copy(message, machine, error);
678 : }
679 :
680 0 : static int method_remove_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
681 0 : _cleanup_(image_unrefp) Image* i = NULL;
682 : const char *name;
683 : int r;
684 :
685 0 : assert(message);
686 :
687 0 : r = sd_bus_message_read(message, "s", &name);
688 0 : if (r < 0)
689 0 : return r;
690 :
691 0 : if (!image_name_is_valid(name))
692 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
693 :
694 0 : r = image_find(name, &i);
695 0 : if (r < 0)
696 0 : return r;
697 0 : if (r == 0)
698 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
699 :
700 0 : i->userdata = userdata;
701 0 : return bus_image_method_remove(message, i, error);
702 : }
703 :
704 0 : static int method_rename_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
705 0 : _cleanup_(image_unrefp) Image* i = NULL;
706 : const char *old_name;
707 : int r;
708 :
709 0 : assert(message);
710 :
711 0 : r = sd_bus_message_read(message, "s", &old_name);
712 0 : if (r < 0)
713 0 : return r;
714 :
715 0 : if (!image_name_is_valid(old_name))
716 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
717 :
718 0 : r = image_find(old_name, &i);
719 0 : if (r < 0)
720 0 : return r;
721 0 : if (r == 0)
722 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
723 :
724 0 : i->userdata = userdata;
725 0 : return bus_image_method_rename(message, i, error);
726 : }
727 :
728 0 : static int method_clone_image(sd_bus_message *message, void *userdata, sd_bus_error *error) {
729 0 : _cleanup_(image_unrefp) Image *i = NULL;
730 : const char *old_name;
731 : int r;
732 :
733 0 : assert(message);
734 :
735 0 : r = sd_bus_message_read(message, "s", &old_name);
736 0 : if (r < 0)
737 0 : return r;
738 :
739 0 : if (!image_name_is_valid(old_name))
740 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", old_name);
741 :
742 0 : r = image_find(old_name, &i);
743 0 : if (r < 0)
744 0 : return r;
745 0 : if (r == 0)
746 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", old_name);
747 :
748 0 : i->userdata = userdata;
749 0 : return bus_image_method_clone(message, i, error);
750 : }
751 :
752 0 : static int method_mark_image_read_only(sd_bus_message *message, void *userdata, sd_bus_error *error) {
753 0 : _cleanup_(image_unrefp) Image *i = NULL;
754 : const char *name;
755 : int r;
756 :
757 0 : assert(message);
758 :
759 0 : r = sd_bus_message_read(message, "s", &name);
760 0 : if (r < 0)
761 0 : return r;
762 :
763 0 : if (!image_name_is_valid(name))
764 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
765 :
766 0 : r = image_find(name, &i);
767 0 : if (r < 0)
768 0 : return r;
769 0 : if (r == 0)
770 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
771 :
772 0 : i->userdata = userdata;
773 0 : return bus_image_method_mark_read_only(message, i, error);
774 : }
775 :
776 0 : static int method_set_pool_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
777 0 : Manager *m = userdata;
778 : uint64_t limit;
779 : int r;
780 :
781 0 : assert(message);
782 :
783 0 : r = sd_bus_message_read(message, "t", &limit);
784 0 : if (r < 0)
785 0 : return r;
786 :
787 0 : r = bus_verify_polkit_async(
788 : message,
789 : CAP_SYS_ADMIN,
790 : "org.freedesktop.machine1.manage-machines",
791 : false,
792 : UID_INVALID,
793 : &m->polkit_registry,
794 : error);
795 0 : if (r < 0)
796 0 : return r;
797 0 : if (r == 0)
798 0 : return 1; /* Will call us back */
799 :
800 : /* Set up the machine directory if necessary */
801 0 : r = setup_machine_directory(limit, error);
802 0 : if (r < 0)
803 0 : return r;
804 :
805 0 : r = btrfs_resize_loopback("/var/lib/machines", limit, false);
806 0 : if (r == -ENOTTY)
807 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
808 0 : if (r < 0 && r != -ENODEV) /* ignore ENODEV, as that's what is returned if the file system is not on loopback */
809 0 : return sd_bus_error_set_errnof(error, r, "Failed to adjust loopback limit: %m");
810 :
811 0 : r = btrfs_quota_limit("/var/lib/machines", limit);
812 0 : if (r == -ENOTTY)
813 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_NOT_SUPPORTED, "Quota is only supported on btrfs.");
814 0 : if (r < 0)
815 0 : return sd_bus_error_set_errnof(error, r, "Failed to adjust quota limit: %m");
816 :
817 0 : return sd_bus_reply_method_return(message, NULL);
818 : }
819 :
820 0 : static int method_set_image_limit(sd_bus_message *message, void *userdata, sd_bus_error *error) {
821 0 : _cleanup_(image_unrefp) Image *i = NULL;
822 : const char *name;
823 : int r;
824 :
825 0 : assert(message);
826 :
827 0 : r = sd_bus_message_read(message, "s", &name);
828 0 : if (r < 0)
829 0 : return r;
830 :
831 0 : if (!image_name_is_valid(name))
832 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Image name '%s' is invalid.", name);
833 :
834 0 : r = image_find(name, &i);
835 0 : if (r < 0)
836 0 : return r;
837 0 : if (r == 0)
838 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
839 :
840 0 : i->userdata = userdata;
841 0 : return bus_image_method_set_limit(message, i, error);
842 : }
843 :
844 0 : static int method_map_from_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
845 0 : _cleanup_fclose_ FILE *f = NULL;
846 0 : Manager *m = userdata;
847 : const char *name, *p;
848 : Machine *machine;
849 : uint32_t uid;
850 : int r;
851 :
852 0 : r = sd_bus_message_read(message, "su", &name, &uid);
853 0 : if (r < 0)
854 0 : return r;
855 :
856 0 : if (UID_IS_INVALID(uid))
857 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
858 :
859 0 : machine = hashmap_get(m->machines, name);
860 0 : if (!machine)
861 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
862 :
863 0 : p = procfs_file_alloca(machine->leader, "uid_map");
864 0 : f = fopen(p, "re");
865 0 : if (!f)
866 0 : return -errno;
867 :
868 : for (;;) {
869 : uid_t uid_base, uid_shift, uid_range, converted;
870 : int k;
871 :
872 0 : errno = 0;
873 0 : k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
874 0 : if (k < 0 && feof(f))
875 0 : break;
876 0 : if (k != 3) {
877 0 : if (ferror(f) && errno != 0)
878 0 : return -errno;
879 :
880 0 : return -EIO;
881 : }
882 :
883 0 : if (uid < uid_base || uid >= uid_base + uid_range)
884 0 : continue;
885 :
886 0 : converted = uid - uid_base + uid_shift;
887 0 : if (UID_IS_INVALID(converted))
888 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
889 :
890 0 : return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
891 0 : }
892 :
893 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "Machine '%s' has no matching user mappings.", name);
894 : }
895 :
896 0 : static int method_map_to_machine_user(sd_bus_message *message, void *userdata, sd_bus_error *error) {
897 0 : Manager *m = userdata;
898 : Machine *machine;
899 : uid_t uid;
900 : Iterator i;
901 : int r;
902 :
903 0 : r = sd_bus_message_read(message, "u", &uid);
904 0 : if (r < 0)
905 0 : return r;
906 0 : if (UID_IS_INVALID(uid))
907 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
908 0 : if (uid < 0x10000)
909 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "User " UID_FMT " belongs to host UID range", uid);
910 :
911 0 : HASHMAP_FOREACH(machine, m->machines, i) {
912 0 : _cleanup_fclose_ FILE *f = NULL;
913 0 : char p[strlen("/proc//uid_map") + DECIMAL_STR_MAX(pid_t) + 1];
914 :
915 0 : xsprintf(p, "/proc/" UID_FMT "/uid_map", machine->leader);
916 0 : f = fopen(p, "re");
917 0 : if (!f) {
918 0 : log_warning_errno(errno, "Failed top open %s, ignoring,", p);
919 0 : continue;
920 : }
921 :
922 : for (;;) {
923 0 : _cleanup_free_ char *o = NULL;
924 : uid_t uid_base, uid_shift, uid_range, converted;
925 : int k;
926 :
927 0 : errno = 0;
928 0 : k = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT, &uid_base, &uid_shift, &uid_range);
929 0 : if (k < 0 && feof(f))
930 0 : break;
931 0 : if (k != 3) {
932 0 : if (ferror(f) && errno != 0)
933 0 : return -errno;
934 :
935 0 : return -EIO;
936 : }
937 :
938 0 : if (uid < uid_shift || uid >= uid_shift + uid_range)
939 0 : continue;
940 :
941 0 : converted = (uid - uid_shift + uid_base);
942 0 : if (UID_IS_INVALID(converted))
943 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid user ID " UID_FMT, uid);
944 :
945 0 : o = machine_bus_path(machine);
946 0 : if (!o)
947 0 : return -ENOMEM;
948 :
949 0 : return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
950 0 : }
951 : }
952 :
953 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_USER_MAPPING, "No matching user mapping for " UID_FMT ".", uid);
954 : }
955 :
956 0 : static int method_map_from_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
957 0 : _cleanup_fclose_ FILE *f = NULL;
958 0 : Manager *m = groupdata;
959 : const char *name, *p;
960 : Machine *machine;
961 : uint32_t gid;
962 : int r;
963 :
964 0 : r = sd_bus_message_read(message, "su", &name, &gid);
965 0 : if (r < 0)
966 0 : return r;
967 :
968 0 : if (GID_IS_INVALID(gid))
969 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
970 :
971 0 : machine = hashmap_get(m->machines, name);
972 0 : if (!machine)
973 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
974 :
975 0 : p = procfs_file_alloca(machine->leader, "gid_map");
976 0 : f = fopen(p, "re");
977 0 : if (!f)
978 0 : return -errno;
979 :
980 : for (;;) {
981 : gid_t gid_base, gid_shift, gid_range, converted;
982 : int k;
983 :
984 0 : errno = 0;
985 0 : k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
986 0 : if (k < 0 && feof(f))
987 0 : break;
988 0 : if (k != 3) {
989 0 : if (ferror(f) && errno != 0)
990 0 : return -errno;
991 :
992 0 : return -EIO;
993 : }
994 :
995 0 : if (gid < gid_base || gid >= gid_base + gid_range)
996 0 : continue;
997 :
998 0 : converted = gid - gid_base + gid_shift;
999 0 : if (GID_IS_INVALID(converted))
1000 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1001 :
1002 0 : return sd_bus_reply_method_return(message, "u", (uint32_t) converted);
1003 0 : }
1004 :
1005 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Machine '%s' has no matching group mappings.", name);
1006 : }
1007 :
1008 0 : static int method_map_to_machine_group(sd_bus_message *message, void *groupdata, sd_bus_error *error) {
1009 0 : Manager *m = groupdata;
1010 : Machine *machine;
1011 : gid_t gid;
1012 : Iterator i;
1013 : int r;
1014 :
1015 0 : r = sd_bus_message_read(message, "u", &gid);
1016 0 : if (r < 0)
1017 0 : return r;
1018 0 : if (GID_IS_INVALID(gid))
1019 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1020 0 : if (gid < 0x10000)
1021 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "Group " GID_FMT " belongs to host GID range", gid);
1022 :
1023 0 : HASHMAP_FOREACH(machine, m->machines, i) {
1024 0 : _cleanup_fclose_ FILE *f = NULL;
1025 0 : char p[strlen("/proc//gid_map") + DECIMAL_STR_MAX(pid_t) + 1];
1026 :
1027 0 : xsprintf(p, "/proc/" GID_FMT "/gid_map", machine->leader);
1028 0 : f = fopen(p, "re");
1029 0 : if (!f) {
1030 0 : log_warning_errno(errno, "Failed top open %s, ignoring,", p);
1031 0 : continue;
1032 : }
1033 :
1034 : for (;;) {
1035 0 : _cleanup_free_ char *o = NULL;
1036 : gid_t gid_base, gid_shift, gid_range, converted;
1037 : int k;
1038 :
1039 0 : errno = 0;
1040 0 : k = fscanf(f, GID_FMT " " GID_FMT " " GID_FMT, &gid_base, &gid_shift, &gid_range);
1041 0 : if (k < 0 && feof(f))
1042 0 : break;
1043 0 : if (k != 3) {
1044 0 : if (ferror(f) && errno != 0)
1045 0 : return -errno;
1046 :
1047 0 : return -EIO;
1048 : }
1049 :
1050 0 : if (gid < gid_shift || gid >= gid_shift + gid_range)
1051 0 : continue;
1052 :
1053 0 : converted = (gid - gid_shift + gid_base);
1054 0 : if (GID_IS_INVALID(converted))
1055 0 : return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid group ID " GID_FMT, gid);
1056 :
1057 0 : o = machine_bus_path(machine);
1058 0 : if (!o)
1059 0 : return -ENOMEM;
1060 :
1061 0 : return sd_bus_reply_method_return(message, "sou", machine->name, o, (uint32_t) converted);
1062 0 : }
1063 : }
1064 :
1065 0 : return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_GROUP_MAPPING, "No matching group mapping for " GID_FMT ".", gid);
1066 : }
1067 :
1068 : const sd_bus_vtable manager_vtable[] = {
1069 : SD_BUS_VTABLE_START(0),
1070 : SD_BUS_PROPERTY("PoolPath", "s", property_get_pool_path, 0, 0),
1071 : SD_BUS_PROPERTY("PoolUsage", "t", property_get_pool_usage, 0, 0),
1072 : SD_BUS_PROPERTY("PoolLimit", "t", property_get_pool_limit, 0, 0),
1073 : SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1074 : SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
1075 : SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
1076 : SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
1077 : SD_BUS_METHOD("ListImages", NULL, "a(ssbttto)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
1078 : SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
1079 : SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
1080 : SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
1081 : SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
1082 : SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1083 : SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1084 : SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
1085 : SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
1086 : SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
1087 : SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, SD_BUS_VTABLE_UNPRIVILEGED),
1088 : SD_BUS_METHOD("BindMountMachine", "sssbb", NULL, method_bind_mount_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1089 : SD_BUS_METHOD("CopyFromMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1090 : SD_BUS_METHOD("CopyToMachine", "sss", NULL, method_copy_machine, SD_BUS_VTABLE_UNPRIVILEGED),
1091 : SD_BUS_METHOD("RemoveImage", "s", NULL, method_remove_image, SD_BUS_VTABLE_UNPRIVILEGED),
1092 : SD_BUS_METHOD("RenameImage", "ss", NULL, method_rename_image, SD_BUS_VTABLE_UNPRIVILEGED),
1093 : SD_BUS_METHOD("CloneImage", "ssb", NULL, method_clone_image, SD_BUS_VTABLE_UNPRIVILEGED),
1094 : SD_BUS_METHOD("MarkImageReadOnly", "sb", NULL, method_mark_image_read_only, SD_BUS_VTABLE_UNPRIVILEGED),
1095 : SD_BUS_METHOD("SetPoolLimit", "t", NULL, method_set_pool_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1096 : SD_BUS_METHOD("SetImageLimit", "st", NULL, method_set_image_limit, SD_BUS_VTABLE_UNPRIVILEGED),
1097 : SD_BUS_METHOD("MapFromMachineUser", "su", "u", method_map_from_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1098 : SD_BUS_METHOD("MapToMachineUser", "u", "sou", method_map_to_machine_user, SD_BUS_VTABLE_UNPRIVILEGED),
1099 : SD_BUS_METHOD("MapFromMachineGroup", "su", "u", method_map_from_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1100 : SD_BUS_METHOD("MapToMachineGroup", "u", "sou", method_map_to_machine_group, SD_BUS_VTABLE_UNPRIVILEGED),
1101 : SD_BUS_SIGNAL("MachineNew", "so", 0),
1102 : SD_BUS_SIGNAL("MachineRemoved", "so", 0),
1103 : SD_BUS_VTABLE_END
1104 : };
1105 :
1106 0 : int match_job_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1107 : const char *path, *result, *unit;
1108 0 : Manager *m = userdata;
1109 : Machine *machine;
1110 : uint32_t id;
1111 : int r;
1112 :
1113 0 : assert(message);
1114 0 : assert(m);
1115 :
1116 0 : r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
1117 0 : if (r < 0) {
1118 0 : bus_log_parse_error(r);
1119 0 : return r;
1120 : }
1121 :
1122 0 : machine = hashmap_get(m->machine_units, unit);
1123 0 : if (!machine)
1124 0 : return 0;
1125 :
1126 0 : if (streq_ptr(path, machine->scope_job)) {
1127 0 : free(machine->scope_job);
1128 0 : machine->scope_job = NULL;
1129 :
1130 0 : if (machine->started) {
1131 0 : if (streq(result, "done"))
1132 0 : machine_send_create_reply(machine, NULL);
1133 : else {
1134 0 : _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
1135 :
1136 0 : sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
1137 :
1138 0 : machine_send_create_reply(machine, &e);
1139 : }
1140 : } else
1141 0 : machine_save(machine);
1142 : }
1143 :
1144 0 : machine_add_to_gc_queue(machine);
1145 0 : return 0;
1146 : }
1147 :
1148 0 : int match_properties_changed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1149 0 : _cleanup_free_ char *unit = NULL;
1150 : const char *path, *interface;
1151 0 : Manager *m = userdata;
1152 : Machine *machine;
1153 : int r;
1154 :
1155 0 : assert(message);
1156 0 : assert(m);
1157 :
1158 0 : path = sd_bus_message_get_path(message);
1159 0 : if (!path)
1160 0 : return 0;
1161 :
1162 0 : r = unit_name_from_dbus_path(path, &unit);
1163 0 : if (r == -EINVAL) /* not for a unit */
1164 0 : return 0;
1165 0 : if (r < 0){
1166 0 : log_oom();
1167 0 : return 0;
1168 : }
1169 :
1170 0 : machine = hashmap_get(m->machine_units, unit);
1171 0 : if (!machine)
1172 0 : return 0;
1173 :
1174 0 : r = sd_bus_message_read(message, "s", &interface);
1175 0 : if (r < 0) {
1176 0 : bus_log_parse_error(r);
1177 0 : return 0;
1178 : }
1179 :
1180 0 : if (streq(interface, "org.freedesktop.systemd1.Unit")) {
1181 : struct properties {
1182 : char *active_state;
1183 : char *sub_state;
1184 0 : } properties = {};
1185 :
1186 0 : const struct bus_properties_map map[] = {
1187 : { "ActiveState", "s", NULL, offsetof(struct properties, active_state) },
1188 : { "SubState", "s", NULL, offsetof(struct properties, sub_state) },
1189 : {}
1190 : };
1191 :
1192 0 : r = bus_message_map_properties_changed(message, map, &properties);
1193 0 : if (r < 0)
1194 0 : bus_log_parse_error(r);
1195 0 : else if (streq_ptr(properties.active_state, "inactive") ||
1196 0 : streq_ptr(properties.active_state, "failed") ||
1197 0 : streq_ptr(properties.sub_state, "auto-restart"))
1198 0 : machine_release_unit(machine);
1199 :
1200 0 : free(properties.active_state);
1201 0 : free(properties.sub_state);
1202 : }
1203 :
1204 0 : machine_add_to_gc_queue(machine);
1205 0 : return 0;
1206 : }
1207 :
1208 0 : int match_unit_removed(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1209 : const char *path, *unit;
1210 0 : Manager *m = userdata;
1211 : Machine *machine;
1212 : int r;
1213 :
1214 0 : assert(message);
1215 0 : assert(m);
1216 :
1217 0 : r = sd_bus_message_read(message, "so", &unit, &path);
1218 0 : if (r < 0) {
1219 0 : bus_log_parse_error(r);
1220 0 : return 0;
1221 : }
1222 :
1223 0 : machine = hashmap_get(m->machine_units, unit);
1224 0 : if (!machine)
1225 0 : return 0;
1226 :
1227 0 : machine_release_unit(machine);
1228 0 : machine_add_to_gc_queue(machine);
1229 :
1230 0 : return 0;
1231 : }
1232 :
1233 0 : int match_reloading(sd_bus_message *message, void *userdata, sd_bus_error *error) {
1234 0 : Manager *m = userdata;
1235 : Machine *machine;
1236 : Iterator i;
1237 : int b, r;
1238 :
1239 0 : assert(message);
1240 0 : assert(m);
1241 :
1242 0 : r = sd_bus_message_read(message, "b", &b);
1243 0 : if (r < 0) {
1244 0 : bus_log_parse_error(r);
1245 0 : return r;
1246 : }
1247 0 : if (b)
1248 0 : return 0;
1249 :
1250 : /* systemd finished reloading, let's recheck all our machines */
1251 0 : log_debug("System manager has been reloaded, rechecking machines...");
1252 :
1253 0 : HASHMAP_FOREACH(machine, m->machines, i)
1254 0 : machine_add_to_gc_queue(machine);
1255 :
1256 0 : return 0;
1257 : }
1258 :
1259 0 : int manager_start_scope(
1260 : Manager *manager,
1261 : const char *scope,
1262 : pid_t pid,
1263 : const char *slice,
1264 : const char *description,
1265 : sd_bus_message *more_properties,
1266 : sd_bus_error *error,
1267 : char **job) {
1268 :
1269 0 : _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
1270 : int r;
1271 :
1272 0 : assert(manager);
1273 0 : assert(scope);
1274 0 : assert(pid > 1);
1275 :
1276 0 : r = sd_bus_message_new_method_call(
1277 : manager->bus,
1278 : &m,
1279 : "org.freedesktop.systemd1",
1280 : "/org/freedesktop/systemd1",
1281 : "org.freedesktop.systemd1.Manager",
1282 : "StartTransientUnit");
1283 0 : if (r < 0)
1284 0 : return r;
1285 :
1286 0 : r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
1287 0 : if (r < 0)
1288 0 : return r;
1289 :
1290 0 : r = sd_bus_message_open_container(m, 'a', "(sv)");
1291 0 : if (r < 0)
1292 0 : return r;
1293 :
1294 0 : if (!isempty(slice)) {
1295 0 : r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
1296 0 : if (r < 0)
1297 0 : return r;
1298 : }
1299 :
1300 0 : if (!isempty(description)) {
1301 0 : r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
1302 0 : if (r < 0)
1303 0 : return r;
1304 : }
1305 :
1306 0 : r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
1307 0 : if (r < 0)
1308 0 : return r;
1309 :
1310 0 : r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
1311 0 : if (r < 0)
1312 0 : return r;
1313 :
1314 0 : if (more_properties) {
1315 0 : r = sd_bus_message_copy(m, more_properties, true);
1316 0 : if (r < 0)
1317 0 : return r;
1318 : }
1319 :
1320 0 : r = sd_bus_message_close_container(m);
1321 0 : if (r < 0)
1322 0 : return r;
1323 :
1324 0 : r = sd_bus_message_append(m, "a(sa(sv))", 0);
1325 0 : if (r < 0)
1326 0 : return r;
1327 :
1328 0 : r = sd_bus_call(manager->bus, m, 0, error, &reply);
1329 0 : if (r < 0)
1330 0 : return r;
1331 :
1332 0 : if (job) {
1333 : const char *j;
1334 : char *copy;
1335 :
1336 0 : r = sd_bus_message_read(reply, "o", &j);
1337 0 : if (r < 0)
1338 0 : return r;
1339 :
1340 0 : copy = strdup(j);
1341 0 : if (!copy)
1342 0 : return -ENOMEM;
1343 :
1344 0 : *job = copy;
1345 : }
1346 :
1347 0 : return 1;
1348 : }
1349 :
1350 0 : int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
1351 0 : _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1352 : int r;
1353 :
1354 0 : assert(manager);
1355 0 : assert(unit);
1356 :
1357 0 : r = sd_bus_call_method(
1358 : manager->bus,
1359 : "org.freedesktop.systemd1",
1360 : "/org/freedesktop/systemd1",
1361 : "org.freedesktop.systemd1.Manager",
1362 : "StopUnit",
1363 : error,
1364 : &reply,
1365 : "ss", unit, "fail");
1366 0 : if (r < 0) {
1367 0 : if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
1368 0 : sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
1369 :
1370 0 : if (job)
1371 0 : *job = NULL;
1372 :
1373 0 : sd_bus_error_free(error);
1374 0 : return 0;
1375 : }
1376 :
1377 0 : return r;
1378 : }
1379 :
1380 0 : if (job) {
1381 : const char *j;
1382 : char *copy;
1383 :
1384 0 : r = sd_bus_message_read(reply, "o", &j);
1385 0 : if (r < 0)
1386 0 : return r;
1387 :
1388 0 : copy = strdup(j);
1389 0 : if (!copy)
1390 0 : return -ENOMEM;
1391 :
1392 0 : *job = copy;
1393 : }
1394 :
1395 0 : return 1;
1396 : }
1397 :
1398 0 : int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1399 0 : assert(manager);
1400 0 : assert(unit);
1401 :
1402 0 : return sd_bus_call_method(
1403 : manager->bus,
1404 : "org.freedesktop.systemd1",
1405 : "/org/freedesktop/systemd1",
1406 : "org.freedesktop.systemd1.Manager",
1407 : "KillUnit",
1408 : error,
1409 : NULL,
1410 : "ssi", unit, "all", signo);
1411 : }
1412 :
1413 0 : int manager_unit_is_active(Manager *manager, const char *unit) {
1414 0 : _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1415 0 : _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1416 0 : _cleanup_free_ char *path = NULL;
1417 : const char *state;
1418 : int r;
1419 :
1420 0 : assert(manager);
1421 0 : assert(unit);
1422 :
1423 0 : path = unit_dbus_path_from_name(unit);
1424 0 : if (!path)
1425 0 : return -ENOMEM;
1426 :
1427 0 : r = sd_bus_get_property(
1428 : manager->bus,
1429 : "org.freedesktop.systemd1",
1430 : path,
1431 : "org.freedesktop.systemd1.Unit",
1432 : "ActiveState",
1433 : &error,
1434 : &reply,
1435 : "s");
1436 0 : if (r < 0) {
1437 0 : if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1438 0 : sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1439 0 : return true;
1440 :
1441 0 : if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
1442 0 : sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
1443 0 : return false;
1444 :
1445 0 : return r;
1446 : }
1447 :
1448 0 : r = sd_bus_message_read(reply, "s", &state);
1449 0 : if (r < 0)
1450 0 : return -EINVAL;
1451 :
1452 0 : return !STR_IN_SET(state, "inactive", "failed");
1453 : }
1454 :
1455 0 : int manager_job_is_active(Manager *manager, const char *path) {
1456 0 : _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
1457 0 : _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1458 : int r;
1459 :
1460 0 : assert(manager);
1461 0 : assert(path);
1462 :
1463 0 : r = sd_bus_get_property(
1464 : manager->bus,
1465 : "org.freedesktop.systemd1",
1466 : path,
1467 : "org.freedesktop.systemd1.Job",
1468 : "State",
1469 : &error,
1470 : &reply,
1471 : "s");
1472 0 : if (r < 0) {
1473 0 : if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
1474 0 : sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
1475 0 : return true;
1476 :
1477 0 : if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
1478 0 : return false;
1479 :
1480 0 : return r;
1481 : }
1482 :
1483 : /* We don't actually care about the state really. The fact
1484 : * that we could read the job state is enough for us */
1485 :
1486 0 : return true;
1487 : }
1488 :
1489 0 : int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
1490 0 : _cleanup_free_ char *unit = NULL;
1491 : Machine *mm;
1492 : int r;
1493 :
1494 0 : assert(m);
1495 0 : assert(pid >= 1);
1496 0 : assert(machine);
1497 :
1498 0 : r = cg_pid_get_unit(pid, &unit);
1499 0 : if (r < 0)
1500 0 : mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
1501 : else
1502 0 : mm = hashmap_get(m->machine_units, unit);
1503 :
1504 0 : if (!mm)
1505 0 : return 0;
1506 :
1507 0 : *machine = mm;
1508 0 : return 1;
1509 : }
1510 :
1511 0 : int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
1512 : Machine *machine;
1513 :
1514 0 : assert(m);
1515 0 : assert(name);
1516 :
1517 0 : machine = hashmap_get(m->machines, name);
1518 0 : if (!machine) {
1519 0 : machine = machine_new(m, name);
1520 0 : if (!machine)
1521 0 : return -ENOMEM;
1522 : }
1523 :
1524 0 : if (_machine)
1525 0 : *_machine = machine;
1526 :
1527 0 : return 0;
1528 : }
|