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