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