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