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