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