]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
man: /usr/bin may contain binaries in any compatible arch, not just the primary one
[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"
718db961 39#include "bus-errors.h"
c3350683 40#include "time-util.h"
23c80348 41#include "cgroup-util.h"
c3350683 42#include "machined.h"
1ee306e1
LP
43
44static bool valid_machine_name(const char *p) {
45 size_t l;
46
47 if (!filename_is_safe(p))
48 return false;
49
50 if (!ascii_is_valid(p))
51 return false;
52
53 l = strlen(p);
54
55 if (l < 1 || l> 64)
56 return false;
57
58 return true;
59}
60
ebcf1f97 61static int method_get_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
62 _cleanup_free_ char *p = NULL;
63 Manager *m = userdata;
64 Machine *machine;
65 const char *name;
66 int r;
67
68 assert(bus);
69 assert(message);
70 assert(m);
71
72 r = sd_bus_message_read(message, "s", &name);
73 if (r < 0)
ebcf1f97 74 return r;
c3350683
LP
75
76 machine = hashmap_get(m->machines, name);
77 if (!machine)
ebcf1f97 78 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
c3350683
LP
79
80 p = machine_bus_path(machine);
81 if (!p)
ebcf1f97 82 return -ENOMEM;
c3350683 83
df2d202e 84 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
85}
86
ebcf1f97 87static int method_get_machine_by_pid(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
88 _cleanup_free_ char *p = NULL;
89 Manager *m = userdata;
90 Machine *machine = NULL;
4e724d9c 91 pid_t pid;
c3350683
LP
92 int r;
93
94 assert(bus);
95 assert(message);
96 assert(m);
97
4e724d9c
LP
98 assert_cc(sizeof(pid_t) == sizeof(uint32_t));
99
c3350683
LP
100 r = sd_bus_message_read(message, "u", &pid);
101 if (r < 0)
ebcf1f97 102 return r;
c3350683 103
4e724d9c 104 if (pid == 0) {
5b12334d
LP
105 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
106
107 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
108 if (r < 0)
109 return r;
110
111 r = sd_bus_creds_get_pid(creds, &pid);
4e724d9c 112 if (r < 0)
ebcf1f97 113 return r;
4e724d9c
LP
114 }
115
c3350683
LP
116 r = manager_get_machine_by_pid(m, pid, &machine);
117 if (r < 0)
ebcf1f97 118 return r;
c3350683 119 if (!machine)
de0671ee 120 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
121
122 p = machine_bus_path(machine);
123 if (!p)
ebcf1f97 124 return -ENOMEM;
c3350683 125
df2d202e 126 return sd_bus_reply_method_return(message, "o", p);
c3350683
LP
127}
128
ebcf1f97 129static int method_list_machines(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
130 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
131 Manager *m = userdata;
132 Machine *machine;
133 Iterator i;
134 int r;
135
136 assert(bus);
137 assert(message);
138 assert(m);
139
df2d202e 140 r = sd_bus_message_new_method_return(message, &reply);
c3350683 141 if (r < 0)
ebcf1f97 142 return sd_bus_error_set_errno(error, r);
c3350683
LP
143
144 r = sd_bus_message_open_container(reply, 'a', "(ssso)");
145 if (r < 0)
ebcf1f97 146 return sd_bus_error_set_errno(error, r);
c3350683
LP
147
148 HASHMAP_FOREACH(machine, m->machines, i) {
149 _cleanup_free_ char *p = NULL;
150
151 p = machine_bus_path(machine);
152 if (!p)
ebcf1f97 153 return -ENOMEM;
c3350683
LP
154
155 r = sd_bus_message_append(reply, "(ssso)",
156 machine->name,
157 strempty(machine_class_to_string(machine->class)),
158 machine->service,
159 p);
160 if (r < 0)
ebcf1f97 161 return sd_bus_error_set_errno(error, r);
c3350683 162 }
1ee306e1 163
c3350683
LP
164 r = sd_bus_message_close_container(reply);
165 if (r < 0)
ebcf1f97 166 return sd_bus_error_set_errno(error, r);
c3350683
LP
167
168 return sd_bus_send(bus, reply, NULL);
169}
170
89f7c846 171static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, Machine **_m, sd_bus_error *error) {
8aec412f 172 const char *name, *service, *class, *root_directory;
1ee306e1
LP
173 MachineClass c;
174 uint32_t leader;
175 sd_id128_t id;
c3350683 176 const void *v;
1ee306e1 177 Machine *m;
c3350683
LP
178 size_t n;
179 int r;
1ee306e1 180
c3350683 181 assert(manager);
89f7c846
LP
182 assert(message);
183 assert(_m);
1ee306e1 184
c3350683
LP
185 r = sd_bus_message_read(message, "s", &name);
186 if (r < 0)
ebcf1f97 187 return r;
c3350683 188 if (!valid_machine_name(name))
ebcf1f97 189 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 190
c3350683
LP
191 r = sd_bus_message_read_array(message, 'y', &v, &n);
192 if (r < 0)
ebcf1f97 193 return r;
1ee306e1
LP
194 if (n == 0)
195 id = SD_ID128_NULL;
196 else if (n == 16)
197 memcpy(&id, v, n);
198 else
ebcf1f97 199 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 200
c3350683
LP
201 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
202 if (r < 0)
ebcf1f97 203 return r;
1ee306e1
LP
204
205 if (isempty(class))
206 c = _MACHINE_CLASS_INVALID;
207 else {
208 c = machine_class_from_string(class);
209 if (c < 0)
ebcf1f97 210 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
211 }
212
c3350683 213 if (leader == 1)
ebcf1f97 214 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 215
c3350683 216 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 217 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 218
c3350683 219 if (leader == 0) {
5b12334d
LP
220 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
221
222 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
223 if (r < 0)
224 return r;
225
c3350683 226 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 227
5b12334d 228 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 229 if (r < 0)
ebcf1f97 230 return r;
c3350683 231 }
554604b3 232
1ee306e1 233 if (hashmap_get(manager->machines, name))
ebcf1f97 234 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
235
236 r = manager_add_machine(manager, name, &m);
237 if (r < 0)
ebcf1f97 238 return r;
1ee306e1
LP
239
240 m->leader = leader;
241 m->class = c;
242 m->id = id;
243
244 if (!isempty(service)) {
245 m->service = strdup(service);
246 if (!m->service) {
ebcf1f97 247 r = -ENOMEM;
1ee306e1
LP
248 goto fail;
249 }
250 }
251
252 if (!isempty(root_directory)) {
253 m->root_directory = strdup(root_directory);
254 if (!m->root_directory) {
ebcf1f97 255 r = -ENOMEM;
1ee306e1
LP
256 goto fail;
257 }
258 }
259
89f7c846
LP
260 *_m = m;
261
262 return 1;
263
264fail:
265 machine_add_to_gc_queue(m);
266 return r;
267}
268
269static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
270 Manager *manager = userdata;
271 Machine *m = NULL;
272 int r;
273
274 r = method_create_or_register_machine(manager, message, &m, error);
275 if (r < 0)
276 return r;
277
278 r = sd_bus_message_enter_container(message, 'a', "(sv)");
279 if (r < 0)
280 goto fail;
281
ebcf1f97
LP
282 r = machine_start(m, message, error);
283 if (r < 0)
1ee306e1
LP
284 goto fail;
285
c3350683 286 m->create_message = sd_bus_message_ref(message);
c3350683 287 return 1;
1ee306e1
LP
288
289fail:
a3e7f417 290 machine_add_to_gc_queue(m);
89f7c846
LP
291 return r;
292}
1ee306e1 293
89f7c846
LP
294static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
295 Manager *manager = userdata;
296 _cleanup_free_ char *p = NULL;
297 Machine *m = NULL;
298 int r;
299
300 r = method_create_or_register_machine(manager, message, &m, error);
301 if (r < 0)
302 return r;
303
304 r = cg_pid_get_unit(m->leader, &m->unit);
305 if (r < 0) {
306 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
307 goto fail;
308 }
309
310 r = machine_start(m, NULL, error);
311 if (r < 0)
312 goto fail;
313
314 p = machine_bus_path(m);
315 if (!p) {
316 r = -ENOMEM;
317 goto fail;
318 }
319
320 return sd_bus_reply_method_return(message, "o", p);
321
322fail:
323 machine_add_to_gc_queue(m);
1ee306e1
LP
324 return r;
325}
326
ebcf1f97 327static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 328 Manager *m = userdata;
c3350683
LP
329 Machine *machine;
330 const char *name;
1ee306e1
LP
331 int r;
332
c3350683 333 assert(bus);
1ee306e1
LP
334 assert(message);
335 assert(m);
336
c3350683
LP
337 r = sd_bus_message_read(message, "s", &name);
338 if (r < 0)
ebcf1f97 339 return sd_bus_error_set_errno(error, r);
1ee306e1 340
c3350683
LP
341 machine = hashmap_get(m->machines, name);
342 if (!machine)
ebcf1f97 343 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 344
878cd7e9 345 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 346}
1ee306e1 347
ebcf1f97 348static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
349 Manager *m = userdata;
350 Machine *machine;
351 const char *name;
c3350683 352 int r;
1ee306e1 353
c3350683
LP
354 assert(bus);
355 assert(message);
356 assert(m);
1ee306e1 357
878cd7e9 358 r = sd_bus_message_read(message, "s", &name);
c3350683 359 if (r < 0)
ebcf1f97 360 return sd_bus_error_set_errno(error, r);
1ee306e1 361
c3350683
LP
362 machine = hashmap_get(m->machines, name);
363 if (!machine)
ebcf1f97 364 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 365
878cd7e9
LP
366 return bus_machine_method_kill(bus, message, machine, error);
367}
368
369static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
370 Manager *m = userdata;
371 Machine *machine;
372 const char *name;
373 int r;
374
375 assert(bus);
376 assert(message);
377 assert(m);
378
379 r = sd_bus_message_read(message, "s", &name);
c3350683 380 if (r < 0)
ebcf1f97 381 return sd_bus_error_set_errno(error, r);
1ee306e1 382
878cd7e9
LP
383 machine = hashmap_get(m->machines, name);
384 if (!machine)
385 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
386
387 return bus_machine_method_get_addresses(bus, message, machine, error);
c3350683 388}
1ee306e1 389
c3350683
LP
390const sd_bus_vtable manager_vtable[] = {
391 SD_BUS_VTABLE_START(0),
adacb957
LP
392 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
393 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
394 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 395 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
89f7c846 396 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
adacb957
LP
397 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
398 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
878cd7e9 399 SD_BUS_METHOD("GetMachineAddresses", "s", "a(yay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
400 SD_BUS_SIGNAL("MachineNew", "so", 0),
401 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
402 SD_BUS_VTABLE_END
403};
1ee306e1 404
ebcf1f97 405int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 406 const char *path, *result, *unit;
1ee306e1 407 Manager *m = userdata;
c3350683
LP
408 Machine *machine;
409 uint32_t id;
410 int r;
1ee306e1 411
c3350683 412 assert(bus);
1ee306e1 413 assert(message);
c3350683 414 assert(m);
1ee306e1 415
c3350683
LP
416 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
417 if (r < 0) {
ebcf1f97
LP
418 bus_log_parse_error(r);
419 return r;
c3350683 420 }
6797c324 421
c3350683
LP
422 machine = hashmap_get(m->machine_units, unit);
423 if (!machine)
424 return 0;
6797c324 425
c3350683
LP
426 if (streq_ptr(path, machine->scope_job)) {
427 free(machine->scope_job);
428 machine->scope_job = NULL;
6797c324 429
c3350683
LP
430 if (machine->started) {
431 if (streq(result, "done"))
432 machine_send_create_reply(machine, NULL);
433 else {
ebcf1f97 434 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 435
ebcf1f97 436 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 437
ebcf1f97 438 machine_send_create_reply(machine, &e);
c3350683
LP
439 }
440 } else
441 machine_save(machine);
1ee306e1
LP
442 }
443
c3350683
LP
444 machine_add_to_gc_queue(machine);
445 return 0;
1ee306e1
LP
446}
447
ebcf1f97 448int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
449 _cleanup_free_ char *unit = NULL;
450 Manager *m = userdata;
451 Machine *machine;
452 const char *path;
ebcf1f97 453 int r;
554604b3 454
c3350683
LP
455 assert(bus);
456 assert(message);
457 assert(m);
554604b3 458
c3350683
LP
459 path = sd_bus_message_get_path(message);
460 if (!path)
554604b3 461 return 0;
554604b3 462
ebcf1f97
LP
463 r = unit_name_from_dbus_path(path, &unit);
464 if (r < 0)
465 return r;
554604b3 466
c3350683
LP
467 machine = hashmap_get(m->machine_units, unit);
468 if (machine)
469 machine_add_to_gc_queue(machine);
554604b3 470
c3350683
LP
471 return 0;
472}
554604b3 473
ebcf1f97 474int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
475 const char *path, *unit;
476 Manager *m = userdata;
477 Machine *machine;
478 int r;
554604b3 479
c3350683
LP
480 assert(bus);
481 assert(message);
482 assert(m);
554604b3 483
c3350683
LP
484 r = sd_bus_message_read(message, "so", &unit, &path);
485 if (r < 0) {
ebcf1f97
LP
486 bus_log_parse_error(r);
487 return r;
554604b3
LP
488 }
489
c3350683
LP
490 machine = hashmap_get(m->machine_units, unit);
491 if (machine)
492 machine_add_to_gc_queue(machine);
554604b3 493
c3350683
LP
494 return 0;
495}
554604b3 496
ebcf1f97 497int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 498 Manager *m = userdata;
a658cafa
LP
499 Machine *machine;
500 Iterator i;
c3350683 501 int b, r;
554604b3 502
c3350683 503 assert(bus);
554604b3 504
c3350683
LP
505 r = sd_bus_message_read(message, "b", &b);
506 if (r < 0) {
ebcf1f97
LP
507 bus_log_parse_error(r);
508 return r;
554604b3 509 }
a658cafa
LP
510 if (b)
511 return 0;
554604b3 512
a658cafa
LP
513 /* systemd finished reloading, let's recheck all our machines */
514 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 515
a658cafa
LP
516 HASHMAP_FOREACH(machine, m->machines, i)
517 machine_add_to_gc_queue(machine);
554604b3
LP
518
519 return 0;
520}
521
1ee306e1
LP
522int manager_start_scope(
523 Manager *manager,
524 const char *scope,
525 pid_t pid,
526 const char *slice,
527 const char *description,
c3350683
LP
528 sd_bus_message *more_properties,
529 sd_bus_error *error,
1ee306e1
LP
530 char **job) {
531
c3350683 532 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 533 int r;
1ee306e1
LP
534
535 assert(manager);
536 assert(scope);
537 assert(pid > 1);
538
c3350683
LP
539 r = sd_bus_message_new_method_call(
540 manager->bus,
151b9b96 541 &m,
1ee306e1
LP
542 "org.freedesktop.systemd1",
543 "/org/freedesktop/systemd1",
544 "org.freedesktop.systemd1.Manager",
151b9b96 545 "StartTransientUnit");
c3350683
LP
546 if (r < 0)
547 return r;
1ee306e1 548
a658cafa 549 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
550 if (r < 0)
551 return r;
1ee306e1 552
c3350683
LP
553 r = sd_bus_message_open_container(m, 'a', "(sv)");
554 if (r < 0)
555 return r;
1ee306e1
LP
556
557 if (!isempty(slice)) {
c3350683
LP
558 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
559 if (r < 0)
560 return r;
1ee306e1
LP
561 }
562
563 if (!isempty(description)) {
c3350683
LP
564 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
565 if (r < 0)
566 return r;
1ee306e1
LP
567 }
568
c3350683
LP
569 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
570 if (r < 0)
571 return r;
554604b3
LP
572
573 if (more_properties) {
c3350683 574 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
575 if (r < 0)
576 return r;
577 }
578
c3350683
LP
579 r = sd_bus_message_close_container(m);
580 if (r < 0)
581 return r;
1ee306e1 582
86b8d289
LP
583 r = sd_bus_message_append(m, "a(sa(sv))", 0);
584 if (r < 0)
585 return r;
586
c49b30a2 587 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
588 if (r < 0)
589 return r;
1ee306e1
LP
590
591 if (job) {
592 const char *j;
593 char *copy;
594
c3350683
LP
595 r = sd_bus_message_read(reply, "o", &j);
596 if (r < 0)
597 return r;
1ee306e1
LP
598
599 copy = strdup(j);
600 if (!copy)
601 return -ENOMEM;
602
603 *job = copy;
604 }
605
c3350683 606 return 1;
1ee306e1
LP
607}
608
c3350683
LP
609int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
610 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
611 int r;
612
613 assert(manager);
614 assert(unit);
615
c3350683 616 r = sd_bus_call_method(
1ee306e1
LP
617 manager->bus,
618 "org.freedesktop.systemd1",
619 "/org/freedesktop/systemd1",
620 "org.freedesktop.systemd1.Manager",
621 "StopUnit",
1ee306e1 622 error,
c3350683
LP
623 &reply,
624 "ss", unit, "fail");
1ee306e1 625 if (r < 0) {
c3350683
LP
626 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
627 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
628
629 if (job)
630 *job = NULL;
631
c3350683 632 sd_bus_error_free(error);
6797c324
LP
633 return 0;
634 }
635
1ee306e1
LP
636 return r;
637 }
638
639 if (job) {
640 const char *j;
641 char *copy;
642
c3350683
LP
643 r = sd_bus_message_read(reply, "o", &j);
644 if (r < 0)
645 return r;
1ee306e1
LP
646
647 copy = strdup(j);
648 if (!copy)
649 return -ENOMEM;
650
651 *job = copy;
652 }
653
6797c324 654 return 1;
1ee306e1
LP
655}
656
de58a50e 657int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
658 assert(manager);
659 assert(unit);
660
a658cafa 661 return sd_bus_call_method(
1ee306e1
LP
662 manager->bus,
663 "org.freedesktop.systemd1",
664 "/org/freedesktop/systemd1",
665 "org.freedesktop.systemd1.Manager",
666 "KillUnit",
1ee306e1 667 error,
a658cafa 668 NULL,
de58a50e 669 "ssi", unit, "all", signo);
1ee306e1
LP
670}
671
672int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
673 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
674 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 675 _cleanup_free_ char *path = NULL;
1ee306e1 676 const char *state;
1ee306e1
LP
677 int r;
678
679 assert(manager);
680 assert(unit);
681
1ee306e1
LP
682 path = unit_dbus_path_from_name(unit);
683 if (!path)
684 return -ENOMEM;
685
c3350683 686 r = sd_bus_get_property(
1ee306e1
LP
687 manager->bus,
688 "org.freedesktop.systemd1",
689 path,
c3350683
LP
690 "org.freedesktop.systemd1.Unit",
691 "ActiveState",
1ee306e1 692 &error,
c3350683
LP
693 &reply,
694 "s");
1ee306e1 695 if (r < 0) {
c3350683
LP
696 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
697 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 698 return true;
6797c324 699
c3350683
LP
700 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
701 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 702 return false;
6797c324 703
1ee306e1
LP
704 return r;
705 }
706
c3350683
LP
707 r = sd_bus_message_read(reply, "s", &state);
708 if (r < 0)
1ee306e1 709 return -EINVAL;
1ee306e1
LP
710
711 return !streq(state, "inactive") && !streq(state, "failed");
712}
bd16acf3 713
c3350683
LP
714int manager_job_is_active(Manager *manager, const char *path) {
715 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
716 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
717 int r;
bd16acf3 718
c3350683
LP
719 assert(manager);
720 assert(path);
bd16acf3 721
c3350683
LP
722 r = sd_bus_get_property(
723 manager->bus,
724 "org.freedesktop.systemd1",
725 path,
726 "org.freedesktop.systemd1.Job",
727 "State",
728 &error,
729 &reply,
730 "s");
731 if (r < 0) {
732 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
733 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
734 return true;
bd16acf3 735
c3350683
LP
736 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
737 return false;
bd16acf3 738
bd16acf3 739 return r;
c3350683 740 }
bd16acf3 741
c3350683
LP
742 /* We don't actually care about the state really. The fact
743 * that we could read the job state is enough for us */
bd16acf3 744
c3350683 745 return true;
bd16acf3 746}
ab49725f
KS
747
748int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
749 _cleanup_free_ char *unit = NULL;
750 Machine *mm;
751 int r;
752
753 assert(m);
754 assert(pid >= 1);
755 assert(machine);
756
757 r = cg_pid_get_unit(pid, &unit);
758 if (r < 0)
759 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
760 else
761 mm = hashmap_get(m->machine_units, unit);
762
763 if (!mm)
764 return 0;
765
766 *machine = mm;
767 return 1;
768}
769
770int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
771 Machine *machine;
772
773 assert(m);
774 assert(name);
775
776 machine = hashmap_get(m->machines, name);
777 if (!machine) {
778 machine = machine_new(m, name);
779 if (!machine)
780 return -ENOMEM;
781 }
782
783 if (_machine)
784 *_machine = machine;
785
786 return 0;
787}