]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
sd-bus: teach x-container-unix: bus protoocol to connect to the namespace of a PID...
[thirdparty/systemd.git] / src / machine / machined-dbus.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 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#include <pwd.h>
adacb957 26#include <sys/capability.h>
1ee306e1 27
c3350683
LP
28#include "sd-id128.h"
29#include "sd-messages.h"
1ee306e1
LP
30#include "strv.h"
31#include "mkdir.h"
32#include "path-util.h"
33#include "special.h"
1ee306e1
LP
34#include "fileio-label.h"
35#include "label.h"
36#include "utf8.h"
37#include "unit-name.h"
c3350683 38#include "bus-util.h"
96aad8d1 39#include "bus-common-errors.h"
c3350683 40#include "time-util.h"
23c80348 41#include "cgroup-util.h"
cd61c3bf 42#include "image.h"
c3350683 43#include "machined.h"
1ee306e1 44
ebcf1f97 45static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
46 _cleanup_free_ char *p = NULL;
47 Manager *m = userdata;
48 Machine *machine;
49 const char *name;
50 int r;
51
52 assert(bus);
53 assert(message);
54 assert(m);
55
56 r = sd_bus_message_read(message, "s", &name);
57 if (r < 0)
ebcf1f97 58 return r;
c3350683
LP
59
60 machine = hashmap_get(m->machines, name);
61 if (!machine)
ebcf1f97 62 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
63
64 p = machine_bus_path(machine);
65 if (!p)
ebcf1f97 66 return -ENOMEM;
c3350683 67
df2d202e 68 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
69}
70
c2ce6a3d
LP
71static int method_get_image(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
72 _cleanup_free_ char *p = NULL;
73 Manager *m = userdata;
74 const char *name;
75 int r;
76
77 assert(bus);
78 assert(message);
79 assert(m);
80
81 r = sd_bus_message_read(message, "s", &name);
82 if (r < 0)
83 return r;
84
85 r = image_find(name, NULL);
86 if (r == 0)
87 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_IMAGE, "No image '%s' known", name);
88 if (r < 0)
89 return r;
90
91 p = image_bus_path(name);
92 if (!p)
93 return -ENOMEM;
94
95 return sd_bus_reply_method_return(message, "o", p);
96}
97
ebcf1f97 98static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
99 _cleanup_free_ char *p = NULL;
100 Manager *m = userdata;
101 Machine *machine = NULL;
4e724d9c 102 pid_t pid;
c3350683
LP
103 int r;
104
105 assert(bus);
106 assert(message);
107 assert(m);
108
4e724d9c
LP
109 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
110
c3350683
LP
111 r = sd_bus_message_read(message, "u", &pid);
112 if (r < 0)
ebcf1f97 113 return r;
c3350683 114
4e724d9c 115 if (pid == 0) {
5b12334d
LP
116 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
117
118 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
119 if (r < 0)
120 return r;
121
122 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 123 if (r < 0)
ebcf1f97 124 return r;
4e724d9c
LP
125 }
126
c3350683
LP
127 r = manager_get_machine_by_pid(m, pid, &machine);
128 if (r < 0)
ebcf1f97 129 return r;
c3350683 130 if (!machine)
de0671ee 131 return sd_bus_error_setf(error, BUS_ERROR_NO_MACHINE_FOR_PID, "PID "PID_FMT" does not belong to any known machine", pid);
c3350683
LP
132
133 p = machine_bus_path(machine);
134 if (!p)
ebcf1f97 135 return -ENOMEM;
c3350683 136
df2d202e 137 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
138}
139
ebcf1f97 140static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
141 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
142 Manager *m = userdata;
143 Machine *machine;
144 Iterator i;
145 int r;
146
147 assert(bus);
148 assert(message);
149 assert(m);
150
df2d202e 151 r = sd_bus_message_new_method_return(message, &reply);
c3350683 152 if (r < 0)
ebcf1f97 153 return sd_bus_error_set_errno(error, r);
c3350683
LP
154
155 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
156 if (r < 0)
ebcf1f97 157 return sd_bus_error_set_errno(error, r);
c3350683
LP
158
159 HASHMAP_FOREACH(machine, m->machines, i) {
160 _cleanup_free_ char *p = NULL;
161
162 p = machine_bus_path(machine);
163 if (!p)
ebcf1f97 164 return -ENOMEM;
c3350683
LP
165
166 r = sd_bus_message_append(reply, "(ssso)",
167 machine->name,
168 strempty(machine_class_to_string(machine->class)),
169 machine->service,
170 p);
171 if (r < 0)
ebcf1f97 172 return sd_bus_error_set_errno(error, r);
c3350683 173 }
1ee306e1 174
c3350683
LP
175 r = sd_bus_message_close_container(reply);
176 if (r < 0)
ebcf1f97 177 return sd_bus_error_set_errno(error, r);
c3350683
LP
178
179 return sd_bus_send(bus, reply, NULL);
180}
181
9b5ed6fe 182static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 183 const char *name, *service, *class, *root_directory;
9b5ed6fe 184 const int32_t *netif = NULL;
1ee306e1
LP
185 MachineClass c;
186 uint32_t leader;
187 sd_id128_t id;
c3350683 188 const void *v;
1ee306e1 189 Machine *m;
9b5ed6fe 190 size_t n, n_netif = 0;
c3350683 191 int r;
1ee306e1 192
c3350683 193 assert(manager);
89f7c846
LP
194 assert(message);
195 assert(_m);
1ee306e1 196
c3350683
LP
197 r = sd_bus_message_read(message, "s", &name);
198 if (r < 0)
ebcf1f97 199 return r;
7f0d207d 200 if (!machine_name_is_valid(name))
ebcf1f97 201 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 202
c3350683
LP
203 r = sd_bus_message_read_array(message, 'y', &v, &n);
204 if (r < 0)
ebcf1f97 205 return r;
1ee306e1
LP
206 if (n == 0)
207 id = SD_ID128_NULL;
208 else if (n == 16)
209 memcpy(&id, v, n);
210 else
ebcf1f97 211 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 212
c3350683
LP
213 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
214 if (r < 0)
ebcf1f97 215 return r;
1ee306e1 216
9b5ed6fe
LP
217 if (read_network) {
218 size_t i;
219
220 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
221 if (r < 0)
222 return r;
223
224 n_netif /= sizeof(int32_t);
225
226 for (i = 0; i < n_netif; i++) {
227 if (netif[i] <= 0)
228 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
229 }
230 }
231
1ee306e1
LP
232 if (isempty(class))
233 c = _MACHINE_CLASS_INVALID;
234 else {
235 c = machine_class_from_string(class);
236 if (c < 0)
ebcf1f97 237 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
238 }
239
c3350683 240 if (leader == 1)
ebcf1f97 241 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 242
c3350683 243 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 244 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 245
c3350683 246 if (leader == 0) {
5b12334d
LP
247 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
248
249 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
250 if (r < 0)
251 return r;
252
c3350683 253 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 254
5b12334d 255 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 256 if (r < 0)
ebcf1f97 257 return r;
c3350683 258 }
554604b3 259
1ee306e1 260 if (hashmap_get(manager->machines, name))
ebcf1f97 261 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
262
263 r = manager_add_machine(manager, name, &m);
264 if (r < 0)
ebcf1f97 265 return r;
1ee306e1
LP
266
267 m->leader = leader;
268 m->class = c;
269 m->id = id;
270
271 if (!isempty(service)) {
272 m->service = strdup(service);
273 if (!m->service) {
ebcf1f97 274 r = -ENOMEM;
1ee306e1
LP
275 goto fail;
276 }
277 }
278
279 if (!isempty(root_directory)) {
280 m->root_directory = strdup(root_directory);
281 if (!m->root_directory) {
ebcf1f97 282 r = -ENOMEM;
1ee306e1
LP
283 goto fail;
284 }
285 }
286
9b5ed6fe
LP
287 if (n_netif > 0) {
288 assert_cc(sizeof(int32_t) == sizeof(int));
289 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
290 if (!m->netif) {
291 r = -ENOMEM;
292 goto fail;
293 }
294
295 m->n_netif = n_netif;
296 }
297
89f7c846
LP
298 *_m = m;
299
300 return 1;
301
302fail:
303 machine_add_to_gc_queue(m);
304 return r;
305}
306
9b5ed6fe 307static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
308 Manager *manager = userdata;
309 Machine *m = NULL;
310 int r;
311
9b5ed6fe 312 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
313 if (r < 0)
314 return r;
315
316 r = sd_bus_message_enter_container(message, 'a', "(sv)");
317 if (r < 0)
318 goto fail;
319
ebcf1f97
LP
320 r = machine_start(m, message, error);
321 if (r < 0)
1ee306e1
LP
322 goto fail;
323
c3350683 324 m->create_message = sd_bus_message_ref(message);
c3350683 325 return 1;
1ee306e1
LP
326
327fail:
a3e7f417 328 machine_add_to_gc_queue(m);
89f7c846
LP
329 return r;
330}
1ee306e1 331
9b5ed6fe
LP
332static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
333 return method_create_machine_internal(bus, message, true, userdata, error);
334}
335
336static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
337 return method_create_machine_internal(bus, message, false, userdata, error);
338}
339
340static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
341 Manager *manager = userdata;
342 _cleanup_free_ char *p = NULL;
343 Machine *m = NULL;
344 int r;
345
9b5ed6fe 346 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
347 if (r < 0)
348 return r;
349
350 r = cg_pid_get_unit(m->leader, &m->unit);
351 if (r < 0) {
352 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
353 goto fail;
354 }
355
8d90c8a8
LP
356 m->registered = true;
357
89f7c846
LP
358 r = machine_start(m, NULL, error);
359 if (r < 0)
360 goto fail;
361
362 p = machine_bus_path(m);
363 if (!p) {
364 r = -ENOMEM;
365 goto fail;
366 }
367
368 return sd_bus_reply_method_return(message, "o", p);
369
370fail:
371 machine_add_to_gc_queue(m);
1ee306e1
LP
372 return r;
373}
374
9b5ed6fe
LP
375static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
376 return method_register_machine_internal(bus, message, true, userdata, error);
377}
378
379static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
380 return method_register_machine_internal(bus, message, false, userdata, error);
381}
382
ebcf1f97 383static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 384 Manager *m = userdata;
c3350683
LP
385 Machine *machine;
386 const char *name;
1ee306e1
LP
387 int r;
388
c3350683 389 assert(bus);
1ee306e1
LP
390 assert(message);
391 assert(m);
392
c3350683
LP
393 r = sd_bus_message_read(message, "s", &name);
394 if (r < 0)
ebcf1f97 395 return sd_bus_error_set_errno(error, r);
1ee306e1 396
c3350683
LP
397 machine = hashmap_get(m->machines, name);
398 if (!machine)
ebcf1f97 399 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 400
878cd7e9 401 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 402}
1ee306e1 403
ebcf1f97 404static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
405 Manager *m = userdata;
406 Machine *machine;
407 const char *name;
c3350683 408 int r;
1ee306e1 409
c3350683
LP
410 assert(bus);
411 assert(message);
412 assert(m);
1ee306e1 413
878cd7e9 414 r = sd_bus_message_read(message, "s", &name);
c3350683 415 if (r < 0)
ebcf1f97 416 return sd_bus_error_set_errno(error, r);
1ee306e1 417
c3350683
LP
418 machine = hashmap_get(m->machines, name);
419 if (!machine)
ebcf1f97 420 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 421
878cd7e9
LP
422 return bus_machine_method_kill(bus, message, machine, error);
423}
424
425static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
426 Manager *m = userdata;
427 Machine *machine;
428 const char *name;
429 int r;
430
431 assert(bus);
432 assert(message);
433 assert(m);
434
435 r = sd_bus_message_read(message, "s", &name);
c3350683 436 if (r < 0)
ebcf1f97 437 return sd_bus_error_set_errno(error, r);
1ee306e1 438
878cd7e9
LP
439 machine = hashmap_get(m->machines, name);
440 if (!machine)
441 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
442
443 return bus_machine_method_get_addresses(bus, message, machine, error);
c3350683 444}
1ee306e1 445
717603e3
LP
446static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
447 Manager *m = userdata;
448 Machine *machine;
449 const char *name;
450 int r;
451
452 assert(bus);
453 assert(message);
454 assert(m);
455
456 r = sd_bus_message_read(message, "s", &name);
457 if (r < 0)
458 return sd_bus_error_set_errno(error, r);
459
460 machine = hashmap_get(m->machines, name);
461 if (!machine)
462 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
463
464 return bus_machine_method_get_os_release(bus, message, machine, error);
465}
466
cd61c3bf
LP
467static int method_list_images(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
468 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
469 _cleanup_(image_hashmap_freep) Hashmap *images = NULL;
470 Manager *m = userdata;
471 Image *image;
472 Iterator i;
473 int r;
474
475 assert(bus);
476 assert(message);
477 assert(m);
478
479 images = hashmap_new(&string_hash_ops);
480 if (!images)
481 return -ENOMEM;
482
483 r = image_discover(images);
484 if (r < 0)
485 return r;
486
487 r = sd_bus_message_new_method_return(message, &reply);
488 if (r < 0)
489 return r;
490
491 r = sd_bus_message_open_container(reply, 'a', "(ssbo)");
492 if (r < 0)
493 return r;
494
495 HASHMAP_FOREACH(image, images, i) {
496 _cleanup_free_ char *p = NULL;
497
498 p = image_bus_path(image->name);
499 if (!p)
500 return -ENOMEM;
501
502 r = sd_bus_message_append(reply, "(ssbo)",
503 image->name,
504 image_type_to_string(image->type),
505 image->read_only,
506 p);
507 if (r < 0)
508 return r;
509 }
510
511 r = sd_bus_message_close_container(reply);
512 if (r < 0)
513 return r;
514
515 return sd_bus_send(bus, reply, NULL);
516}
517
40205d70
LP
518static int method_open_machine_pty(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
519 Manager *m = userdata;
520 Machine *machine;
521 const char *name;
522 int r;
523
524 assert(bus);
525 assert(message);
526 assert(m);
527
528 r = sd_bus_message_read(message, "s", &name);
529 if (r < 0)
530 return sd_bus_error_set_errno(error, r);
531
532 machine = hashmap_get(m->machines, name);
533 if (!machine)
534 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
535
536 return bus_machine_method_open_pty(bus, message, machine, error);
537}
538
c3350683
LP
539const sd_bus_vtable manager_vtable[] = {
540 SD_BUS_VTABLE_START(0),
adacb957 541 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 542 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
543 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
544 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
cd61c3bf 545 SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 546 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 547 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 548 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 549 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
550 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
551 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
3a6fb33c 552 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 553 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 554 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
c3350683
LP
555 SD_BUS_SIGNAL("MachineNew", "so", 0),
556 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
557 SD_BUS_VTABLE_END
558};
1ee306e1 559
ebcf1f97 560int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 561 const char *path, *result, *unit;
1ee306e1 562 Manager *m = userdata;
c3350683
LP
563 Machine *machine;
564 uint32_t id;
565 int r;
1ee306e1 566
c3350683 567 assert(bus);
1ee306e1 568 assert(message);
c3350683 569 assert(m);
1ee306e1 570
c3350683
LP
571 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
572 if (r < 0) {
ebcf1f97
LP
573 bus_log_parse_error(r);
574 return r;
c3350683 575 }
6797c324 576
c3350683
LP
577 machine = hashmap_get(m->machine_units, unit);
578 if (!machine)
579 return 0;
6797c324 580
c3350683
LP
581 if (streq_ptr(path, machine->scope_job)) {
582 free(machine->scope_job);
583 machine->scope_job = NULL;
6797c324 584
c3350683
LP
585 if (machine->started) {
586 if (streq(result, "done"))
587 machine_send_create_reply(machine, NULL);
588 else {
ebcf1f97 589 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 590
ebcf1f97 591 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 592
ebcf1f97 593 machine_send_create_reply(machine, &e);
c3350683
LP
594 }
595 } else
596 machine_save(machine);
1ee306e1
LP
597 }
598
c3350683
LP
599 machine_add_to_gc_queue(machine);
600 return 0;
1ee306e1
LP
601}
602
ebcf1f97 603int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
604 _cleanup_free_ char *unit = NULL;
605 Manager *m = userdata;
606 Machine *machine;
607 const char *path;
ebcf1f97 608 int r;
554604b3 609
c3350683
LP
610 assert(bus);
611 assert(message);
612 assert(m);
554604b3 613
c3350683
LP
614 path = sd_bus_message_get_path(message);
615 if (!path)
554604b3 616 return 0;
554604b3 617
ebcf1f97
LP
618 r = unit_name_from_dbus_path(path, &unit);
619 if (r < 0)
620 return r;
554604b3 621
c3350683
LP
622 machine = hashmap_get(m->machine_units, unit);
623 if (machine)
624 machine_add_to_gc_queue(machine);
554604b3 625
c3350683
LP
626 return 0;
627}
554604b3 628
ebcf1f97 629int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
630 const char *path, *unit;
631 Manager *m = userdata;
632 Machine *machine;
633 int r;
554604b3 634
c3350683
LP
635 assert(bus);
636 assert(message);
637 assert(m);
554604b3 638
c3350683
LP
639 r = sd_bus_message_read(message, "so", &unit, &path);
640 if (r < 0) {
ebcf1f97
LP
641 bus_log_parse_error(r);
642 return r;
554604b3
LP
643 }
644
c3350683
LP
645 machine = hashmap_get(m->machine_units, unit);
646 if (machine)
647 machine_add_to_gc_queue(machine);
554604b3 648
c3350683
LP
649 return 0;
650}
554604b3 651
ebcf1f97 652int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 653 Manager *m = userdata;
a658cafa
LP
654 Machine *machine;
655 Iterator i;
c3350683 656 int b, r;
554604b3 657
c3350683 658 assert(bus);
554604b3 659
c3350683
LP
660 r = sd_bus_message_read(message, "b", &b);
661 if (r < 0) {
ebcf1f97
LP
662 bus_log_parse_error(r);
663 return r;
554604b3 664 }
a658cafa
LP
665 if (b)
666 return 0;
554604b3 667
a658cafa
LP
668 /* systemd finished reloading, let's recheck all our machines */
669 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 670
a658cafa
LP
671 HASHMAP_FOREACH(machine, m->machines, i)
672 machine_add_to_gc_queue(machine);
554604b3
LP
673
674 return 0;
675}
676
1ee306e1
LP
677int manager_start_scope(
678 Manager *manager,
679 const char *scope,
680 pid_t pid,
681 const char *slice,
682 const char *description,
c3350683
LP
683 sd_bus_message *more_properties,
684 sd_bus_error *error,
1ee306e1
LP
685 char **job) {
686
c3350683 687 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 688 int r;
1ee306e1
LP
689
690 assert(manager);
691 assert(scope);
692 assert(pid > 1);
693
c3350683
LP
694 r = sd_bus_message_new_method_call(
695 manager->bus,
151b9b96 696 &m,
1ee306e1
LP
697 "org.freedesktop.systemd1",
698 "/org/freedesktop/systemd1",
699 "org.freedesktop.systemd1.Manager",
151b9b96 700 "StartTransientUnit");
c3350683
LP
701 if (r < 0)
702 return r;
1ee306e1 703
a658cafa 704 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
705 if (r < 0)
706 return r;
1ee306e1 707
c3350683
LP
708 r = sd_bus_message_open_container(m, 'a', "(sv)");
709 if (r < 0)
710 return r;
1ee306e1
LP
711
712 if (!isempty(slice)) {
c3350683
LP
713 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
714 if (r < 0)
715 return r;
1ee306e1
LP
716 }
717
718 if (!isempty(description)) {
c3350683
LP
719 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
720 if (r < 0)
721 return r;
1ee306e1
LP
722 }
723
c3350683
LP
724 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
725 if (r < 0)
726 return r;
554604b3 727
a931ad47
LP
728 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
729 if (r < 0)
730 return r;
731
554604b3 732 if (more_properties) {
c3350683 733 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
734 if (r < 0)
735 return r;
736 }
737
c3350683
LP
738 r = sd_bus_message_close_container(m);
739 if (r < 0)
740 return r;
1ee306e1 741
86b8d289
LP
742 r = sd_bus_message_append(m, "a(sa(sv))", 0);
743 if (r < 0)
744 return r;
745
c49b30a2 746 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
747 if (r < 0)
748 return r;
1ee306e1
LP
749
750 if (job) {
751 const char *j;
752 char *copy;
753
c3350683
LP
754 r = sd_bus_message_read(reply, "o", &j);
755 if (r < 0)
756 return r;
1ee306e1
LP
757
758 copy = strdup(j);
759 if (!copy)
760 return -ENOMEM;
761
762 *job = copy;
763 }
764
c3350683 765 return 1;
1ee306e1
LP
766}
767
c3350683
LP
768int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
769 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
770 int r;
771
772 assert(manager);
773 assert(unit);
774
c3350683 775 r = sd_bus_call_method(
1ee306e1
LP
776 manager->bus,
777 "org.freedesktop.systemd1",
778 "/org/freedesktop/systemd1",
779 "org.freedesktop.systemd1.Manager",
780 "StopUnit",
1ee306e1 781 error,
c3350683
LP
782 &reply,
783 "ss", unit, "fail");
1ee306e1 784 if (r < 0) {
c3350683
LP
785 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
786 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
787
788 if (job)
789 *job = NULL;
790
c3350683 791 sd_bus_error_free(error);
6797c324
LP
792 return 0;
793 }
794
1ee306e1
LP
795 return r;
796 }
797
798 if (job) {
799 const char *j;
800 char *copy;
801
c3350683
LP
802 r = sd_bus_message_read(reply, "o", &j);
803 if (r < 0)
804 return r;
1ee306e1
LP
805
806 copy = strdup(j);
807 if (!copy)
808 return -ENOMEM;
809
810 *job = copy;
811 }
812
6797c324 813 return 1;
1ee306e1
LP
814}
815
de58a50e 816int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
817 assert(manager);
818 assert(unit);
819
a658cafa 820 return sd_bus_call_method(
1ee306e1
LP
821 manager->bus,
822 "org.freedesktop.systemd1",
823 "/org/freedesktop/systemd1",
824 "org.freedesktop.systemd1.Manager",
825 "KillUnit",
1ee306e1 826 error,
a658cafa 827 NULL,
de58a50e 828 "ssi", unit, "all", signo);
1ee306e1
LP
829}
830
831int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
832 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
833 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 834 _cleanup_free_ char *path = NULL;
1ee306e1 835 const char *state;
1ee306e1
LP
836 int r;
837
838 assert(manager);
839 assert(unit);
840
1ee306e1
LP
841 path = unit_dbus_path_from_name(unit);
842 if (!path)
843 return -ENOMEM;
844
c3350683 845 r = sd_bus_get_property(
1ee306e1
LP
846 manager->bus,
847 "org.freedesktop.systemd1",
848 path,
c3350683
LP
849 "org.freedesktop.systemd1.Unit",
850 "ActiveState",
1ee306e1 851 &error,
c3350683
LP
852 &reply,
853 "s");
1ee306e1 854 if (r < 0) {
c3350683
LP
855 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
856 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 857 return true;
6797c324 858
c3350683
LP
859 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
860 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 861 return false;
6797c324 862
1ee306e1
LP
863 return r;
864 }
865
c3350683
LP
866 r = sd_bus_message_read(reply, "s", &state);
867 if (r < 0)
1ee306e1 868 return -EINVAL;
1ee306e1
LP
869
870 return !streq(state, "inactive") && !streq(state, "failed");
871}
bd16acf3 872
c3350683
LP
873int manager_job_is_active(Manager *manager, const char *path) {
874 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
875 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
876 int r;
bd16acf3 877
c3350683
LP
878 assert(manager);
879 assert(path);
bd16acf3 880
c3350683
LP
881 r = sd_bus_get_property(
882 manager->bus,
883 "org.freedesktop.systemd1",
884 path,
885 "org.freedesktop.systemd1.Job",
886 "State",
887 &error,
888 &reply,
889 "s");
890 if (r < 0) {
891 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
892 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
893 return true;
bd16acf3 894
c3350683
LP
895 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
896 return false;
bd16acf3 897
bd16acf3 898 return r;
c3350683 899 }
bd16acf3 900
c3350683
LP
901 /* We don't actually care about the state really. The fact
902 * that we could read the job state is enough for us */
bd16acf3 903
c3350683 904 return true;
bd16acf3 905}
ab49725f
KS
906
907int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
908 _cleanup_free_ char *unit = NULL;
909 Machine *mm;
910 int r;
911
912 assert(m);
913 assert(pid >= 1);
914 assert(machine);
915
916 r = cg_pid_get_unit(pid, &unit);
917 if (r < 0)
918 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
919 else
920 mm = hashmap_get(m->machine_units, unit);
921
922 if (!mm)
923 return 0;
924
925 *machine = mm;
926 return 1;
927}
928
929int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
930 Machine *machine;
931
932 assert(m);
933 assert(name);
934
935 machine = hashmap_get(m->machines, name);
936 if (!machine) {
937 machine = machine_new(m, name);
938 if (!machine)
939 return -ENOMEM;
940 }
941
942 if (_machine)
943 *_machine = machine;
944
945 return 0;
946}