]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
bus: add missing bus-policy.[ch]
[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
5f8cc96a
LP
539static int method_open_machine_login(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
540 Manager *m = userdata;
541 Machine *machine;
542 const char *name;
543 int r;
544
545 assert(bus);
546 assert(message);
547 assert(m);
548
549 r = sd_bus_message_read(message, "s", &name);
550 if (r < 0)
551 return sd_bus_error_set_errno(error, r);
552
553 machine = hashmap_get(m->machines, name);
554 if (!machine)
555 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
556
557 return bus_machine_method_open_login(bus, message, machine, error);
558}
559
c3350683
LP
560const sd_bus_vtable manager_vtable[] = {
561 SD_BUS_VTABLE_START(0),
adacb957 562 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
c2ce6a3d 563 SD_BUS_METHOD("GetImage", "s", "o", method_get_image, SD_BUS_VTABLE_UNPRIVILEGED),
adacb957
LP
564 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
565 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
cd61c3bf 566 SD_BUS_METHOD("ListImages", NULL, "a(ssbo)", method_list_images, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 567 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
9b5ed6fe 568 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
8d07a7c4 569 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe 570 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
571 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
572 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
3a6fb33c 573 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 574 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
40205d70 575 SD_BUS_METHOD("OpenMachinePTY", "s", "hs", method_open_machine_pty, 0),
5f8cc96a 576 SD_BUS_METHOD("OpenMachineLogin", "s", "hs", method_open_machine_login, 0),
c3350683
LP
577 SD_BUS_SIGNAL("MachineNew", "so", 0),
578 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
579 SD_BUS_VTABLE_END
580};
1ee306e1 581
ebcf1f97 582int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 583 const char *path, *result, *unit;
1ee306e1 584 Manager *m = userdata;
c3350683
LP
585 Machine *machine;
586 uint32_t id;
587 int r;
1ee306e1 588
c3350683 589 assert(bus);
1ee306e1 590 assert(message);
c3350683 591 assert(m);
1ee306e1 592
c3350683
LP
593 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
594 if (r < 0) {
ebcf1f97
LP
595 bus_log_parse_error(r);
596 return r;
c3350683 597 }
6797c324 598
c3350683
LP
599 machine = hashmap_get(m->machine_units, unit);
600 if (!machine)
601 return 0;
6797c324 602
c3350683
LP
603 if (streq_ptr(path, machine->scope_job)) {
604 free(machine->scope_job);
605 machine->scope_job = NULL;
6797c324 606
c3350683
LP
607 if (machine->started) {
608 if (streq(result, "done"))
609 machine_send_create_reply(machine, NULL);
610 else {
ebcf1f97 611 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 612
ebcf1f97 613 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 614
ebcf1f97 615 machine_send_create_reply(machine, &e);
c3350683
LP
616 }
617 } else
618 machine_save(machine);
1ee306e1
LP
619 }
620
c3350683
LP
621 machine_add_to_gc_queue(machine);
622 return 0;
1ee306e1
LP
623}
624
ebcf1f97 625int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
626 _cleanup_free_ char *unit = NULL;
627 Manager *m = userdata;
628 Machine *machine;
629 const char *path;
ebcf1f97 630 int r;
554604b3 631
c3350683
LP
632 assert(bus);
633 assert(message);
634 assert(m);
554604b3 635
c3350683
LP
636 path = sd_bus_message_get_path(message);
637 if (!path)
554604b3 638 return 0;
554604b3 639
ebcf1f97
LP
640 r = unit_name_from_dbus_path(path, &unit);
641 if (r < 0)
642 return r;
554604b3 643
c3350683
LP
644 machine = hashmap_get(m->machine_units, unit);
645 if (machine)
646 machine_add_to_gc_queue(machine);
554604b3 647
c3350683
LP
648 return 0;
649}
554604b3 650
ebcf1f97 651int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
652 const char *path, *unit;
653 Manager *m = userdata;
654 Machine *machine;
655 int r;
554604b3 656
c3350683
LP
657 assert(bus);
658 assert(message);
659 assert(m);
554604b3 660
c3350683
LP
661 r = sd_bus_message_read(message, "so", &unit, &path);
662 if (r < 0) {
ebcf1f97
LP
663 bus_log_parse_error(r);
664 return r;
554604b3
LP
665 }
666
c3350683
LP
667 machine = hashmap_get(m->machine_units, unit);
668 if (machine)
669 machine_add_to_gc_queue(machine);
554604b3 670
c3350683
LP
671 return 0;
672}
554604b3 673
ebcf1f97 674int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 675 Manager *m = userdata;
a658cafa
LP
676 Machine *machine;
677 Iterator i;
c3350683 678 int b, r;
554604b3 679
c3350683 680 assert(bus);
554604b3 681
c3350683
LP
682 r = sd_bus_message_read(message, "b", &b);
683 if (r < 0) {
ebcf1f97
LP
684 bus_log_parse_error(r);
685 return r;
554604b3 686 }
a658cafa
LP
687 if (b)
688 return 0;
554604b3 689
a658cafa
LP
690 /* systemd finished reloading, let's recheck all our machines */
691 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 692
a658cafa
LP
693 HASHMAP_FOREACH(machine, m->machines, i)
694 machine_add_to_gc_queue(machine);
554604b3
LP
695
696 return 0;
697}
698
1ee306e1
LP
699int manager_start_scope(
700 Manager *manager,
701 const char *scope,
702 pid_t pid,
703 const char *slice,
704 const char *description,
c3350683
LP
705 sd_bus_message *more_properties,
706 sd_bus_error *error,
1ee306e1
LP
707 char **job) {
708
c3350683 709 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 710 int r;
1ee306e1
LP
711
712 assert(manager);
713 assert(scope);
714 assert(pid > 1);
715
c3350683
LP
716 r = sd_bus_message_new_method_call(
717 manager->bus,
151b9b96 718 &m,
1ee306e1
LP
719 "org.freedesktop.systemd1",
720 "/org/freedesktop/systemd1",
721 "org.freedesktop.systemd1.Manager",
151b9b96 722 "StartTransientUnit");
c3350683
LP
723 if (r < 0)
724 return r;
1ee306e1 725
a658cafa 726 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
727 if (r < 0)
728 return r;
1ee306e1 729
c3350683
LP
730 r = sd_bus_message_open_container(m, 'a', "(sv)");
731 if (r < 0)
732 return r;
1ee306e1
LP
733
734 if (!isempty(slice)) {
c3350683
LP
735 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
736 if (r < 0)
737 return r;
1ee306e1
LP
738 }
739
740 if (!isempty(description)) {
c3350683
LP
741 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
742 if (r < 0)
743 return r;
1ee306e1
LP
744 }
745
c3350683
LP
746 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
747 if (r < 0)
748 return r;
554604b3 749
a931ad47
LP
750 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
751 if (r < 0)
752 return r;
753
554604b3 754 if (more_properties) {
c3350683 755 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
756 if (r < 0)
757 return r;
758 }
759
c3350683
LP
760 r = sd_bus_message_close_container(m);
761 if (r < 0)
762 return r;
1ee306e1 763
86b8d289
LP
764 r = sd_bus_message_append(m, "a(sa(sv))", 0);
765 if (r < 0)
766 return r;
767
c49b30a2 768 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
769 if (r < 0)
770 return r;
1ee306e1
LP
771
772 if (job) {
773 const char *j;
774 char *copy;
775
c3350683
LP
776 r = sd_bus_message_read(reply, "o", &j);
777 if (r < 0)
778 return r;
1ee306e1
LP
779
780 copy = strdup(j);
781 if (!copy)
782 return -ENOMEM;
783
784 *job = copy;
785 }
786
c3350683 787 return 1;
1ee306e1
LP
788}
789
c3350683
LP
790int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
791 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
792 int r;
793
794 assert(manager);
795 assert(unit);
796
c3350683 797 r = sd_bus_call_method(
1ee306e1
LP
798 manager->bus,
799 "org.freedesktop.systemd1",
800 "/org/freedesktop/systemd1",
801 "org.freedesktop.systemd1.Manager",
802 "StopUnit",
1ee306e1 803 error,
c3350683
LP
804 &reply,
805 "ss", unit, "fail");
1ee306e1 806 if (r < 0) {
c3350683
LP
807 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
808 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
809
810 if (job)
811 *job = NULL;
812
c3350683 813 sd_bus_error_free(error);
6797c324
LP
814 return 0;
815 }
816
1ee306e1
LP
817 return r;
818 }
819
820 if (job) {
821 const char *j;
822 char *copy;
823
c3350683
LP
824 r = sd_bus_message_read(reply, "o", &j);
825 if (r < 0)
826 return r;
1ee306e1
LP
827
828 copy = strdup(j);
829 if (!copy)
830 return -ENOMEM;
831
832 *job = copy;
833 }
834
6797c324 835 return 1;
1ee306e1
LP
836}
837
de58a50e 838int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
839 assert(manager);
840 assert(unit);
841
a658cafa 842 return sd_bus_call_method(
1ee306e1
LP
843 manager->bus,
844 "org.freedesktop.systemd1",
845 "/org/freedesktop/systemd1",
846 "org.freedesktop.systemd1.Manager",
847 "KillUnit",
1ee306e1 848 error,
a658cafa 849 NULL,
de58a50e 850 "ssi", unit, "all", signo);
1ee306e1
LP
851}
852
853int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
854 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
855 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 856 _cleanup_free_ char *path = NULL;
1ee306e1 857 const char *state;
1ee306e1
LP
858 int r;
859
860 assert(manager);
861 assert(unit);
862
1ee306e1
LP
863 path = unit_dbus_path_from_name(unit);
864 if (!path)
865 return -ENOMEM;
866
c3350683 867 r = sd_bus_get_property(
1ee306e1
LP
868 manager->bus,
869 "org.freedesktop.systemd1",
870 path,
c3350683
LP
871 "org.freedesktop.systemd1.Unit",
872 "ActiveState",
1ee306e1 873 &error,
c3350683
LP
874 &reply,
875 "s");
1ee306e1 876 if (r < 0) {
c3350683
LP
877 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
878 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 879 return true;
6797c324 880
c3350683
LP
881 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
882 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 883 return false;
6797c324 884
1ee306e1
LP
885 return r;
886 }
887
c3350683
LP
888 r = sd_bus_message_read(reply, "s", &state);
889 if (r < 0)
1ee306e1 890 return -EINVAL;
1ee306e1
LP
891
892 return !streq(state, "inactive") && !streq(state, "failed");
893}
bd16acf3 894
c3350683
LP
895int manager_job_is_active(Manager *manager, const char *path) {
896 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
897 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
898 int r;
bd16acf3 899
c3350683
LP
900 assert(manager);
901 assert(path);
bd16acf3 902
c3350683
LP
903 r = sd_bus_get_property(
904 manager->bus,
905 "org.freedesktop.systemd1",
906 path,
907 "org.freedesktop.systemd1.Job",
908 "State",
909 &error,
910 &reply,
911 "s");
912 if (r < 0) {
913 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
914 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
915 return true;
bd16acf3 916
c3350683
LP
917 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
918 return false;
bd16acf3 919
bd16acf3 920 return r;
c3350683 921 }
bd16acf3 922
c3350683
LP
923 /* We don't actually care about the state really. The fact
924 * that we could read the job state is enough for us */
bd16acf3 925
c3350683 926 return true;
bd16acf3 927}
ab49725f
KS
928
929int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
930 _cleanup_free_ char *unit = NULL;
931 Machine *mm;
932 int r;
933
934 assert(m);
935 assert(pid >= 1);
936 assert(machine);
937
938 r = cg_pid_get_unit(pid, &unit);
939 if (r < 0)
940 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
941 else
942 mm = hashmap_get(m->machine_units, unit);
943
944 if (!mm)
945 return 0;
946
947 *machine = mm;
948 return 1;
949}
950
951int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
952 Machine *machine;
953
954 assert(m);
955 assert(name);
956
957 machine = hashmap_get(m->machines, name);
958 if (!machine) {
959 machine = machine_new(m, name);
960 if (!machine)
961 return -ENOMEM;
962 }
963
964 if (_machine)
965 *_machine = machine;
966
967 return 0;
968}