]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
man: fix typo
[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 337int machine_node_enumerator(sd_bus *bus, const char *path, char ***nodes, void *userdata) {
a658cafa 338 _cleanup_strv_free_ char **l = NULL;
c3350683
LP
339 Machine *machine = NULL;
340 Manager *m = userdata;
c3350683
LP
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 362 *nodes = l;
a658cafa
LP
363 l = NULL;
364
c3350683 365 return 1;
1ee306e1
LP
366}
367
c3350683
LP
368int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
369 const char *path, *result, *unit;
1ee306e1 370 Manager *m = userdata;
c3350683
LP
371 Machine *machine;
372 uint32_t id;
373 int r;
1ee306e1 374
c3350683 375 assert(bus);
1ee306e1 376 assert(message);
c3350683 377 assert(m);
1ee306e1 378
c3350683
LP
379 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
380 if (r < 0) {
381 log_error("Failed to parse JobRemoved message: %s", strerror(-r));
382 return 0;
383 }
6797c324 384
c3350683
LP
385 machine = hashmap_get(m->machine_units, unit);
386 if (!machine)
387 return 0;
6797c324 388
c3350683
LP
389 if (streq_ptr(path, machine->scope_job)) {
390 free(machine->scope_job);
391 machine->scope_job = NULL;
6797c324 392
c3350683
LP
393 if (machine->started) {
394 if (streq(result, "done"))
395 machine_send_create_reply(machine, NULL);
396 else {
397 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
6797c324 398
c3350683 399 sd_bus_error_setf(&error, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 400
c3350683
LP
401 machine_send_create_reply(machine, &error);
402 }
403 } else
404 machine_save(machine);
1ee306e1
LP
405 }
406
c3350683
LP
407 machine_add_to_gc_queue(machine);
408 return 0;
1ee306e1
LP
409}
410
c3350683
LP
411int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata) {
412 _cleanup_free_ char *unit = NULL;
413 Manager *m = userdata;
414 Machine *machine;
415 const char *path;
554604b3 416
c3350683
LP
417 assert(bus);
418 assert(message);
419 assert(m);
554604b3 420
c3350683
LP
421 path = sd_bus_message_get_path(message);
422 if (!path)
554604b3 423 return 0;
554604b3 424
c3350683
LP
425 unit_name_from_dbus_path(path, &unit);
426 if (!unit)
427 return 0;
554604b3 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_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata) {
437 const char *path, *unit;
438 Manager *m = userdata;
439 Machine *machine;
440 int r;
554604b3 441
c3350683
LP
442 assert(bus);
443 assert(message);
444 assert(m);
554604b3 445
c3350683
LP
446 r = sd_bus_message_read(message, "so", &unit, &path);
447 if (r < 0) {
448 log_error("Failed to parse UnitRemoved message: %s", strerror(-r));
554604b3
LP
449 return 0;
450 }
451
c3350683
LP
452 machine = hashmap_get(m->machine_units, unit);
453 if (machine)
454 machine_add_to_gc_queue(machine);
554604b3 455
c3350683
LP
456 return 0;
457}
554604b3 458
c3350683
LP
459int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata) {
460 Manager *m = userdata;
a658cafa
LP
461 Machine *machine;
462 Iterator i;
c3350683 463 int b, r;
554604b3 464
c3350683 465 assert(bus);
554604b3 466
c3350683
LP
467 r = sd_bus_message_read(message, "b", &b);
468 if (r < 0) {
469 log_error("Failed to parse Reloading message: %s", strerror(-r));
554604b3
LP
470 return 0;
471 }
472
a658cafa
LP
473 if (b)
474 return 0;
554604b3 475
a658cafa
LP
476 /* systemd finished reloading, let's recheck all our machines */
477 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 478
a658cafa
LP
479 HASHMAP_FOREACH(machine, m->machines, i)
480 machine_add_to_gc_queue(machine);
554604b3
LP
481
482 return 0;
483}
484
1ee306e1
LP
485int manager_start_scope(
486 Manager *manager,
487 const char *scope,
488 pid_t pid,
489 const char *slice,
490 const char *description,
c3350683
LP
491 sd_bus_message *more_properties,
492 sd_bus_error *error,
1ee306e1
LP
493 char **job) {
494
c3350683 495 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 496 int r;
1ee306e1
LP
497
498 assert(manager);
499 assert(scope);
500 assert(pid > 1);
501
c3350683
LP
502 r = sd_bus_message_new_method_call(
503 manager->bus,
1ee306e1
LP
504 "org.freedesktop.systemd1",
505 "/org/freedesktop/systemd1",
506 "org.freedesktop.systemd1.Manager",
c3350683
LP
507 "StartTransientUnit",
508 &m);
509 if (r < 0)
510 return r;
1ee306e1 511
a658cafa 512 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
513 if (r < 0)
514 return r;
1ee306e1 515
c3350683
LP
516 r = sd_bus_message_open_container(m, 'a', "(sv)");
517 if (r < 0)
518 return r;
1ee306e1
LP
519
520 if (!isempty(slice)) {
c3350683
LP
521 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
522 if (r < 0)
523 return r;
1ee306e1
LP
524 }
525
526 if (!isempty(description)) {
c3350683
LP
527 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
528 if (r < 0)
529 return r;
1ee306e1
LP
530 }
531
532 /* cgroup empty notification is not available in containers
533 * currently. To make this less problematic, let's shorten the
c3350683 534 * stop timeout for machines, so that we don't wait
1ee306e1 535 * forever. */
c3350683
LP
536 r = sd_bus_message_append(m, "(sv)", "TimeoutStopUSec", "t", 500 * USEC_PER_MSEC);
537 if (r < 0)
538 return r;
1ee306e1 539
c3350683
LP
540 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
541 if (r < 0)
542 return r;
554604b3
LP
543
544 if (more_properties) {
c3350683 545 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
546 if (r < 0)
547 return r;
548 }
549
c3350683
LP
550 r = sd_bus_message_close_container(m);
551 if (r < 0)
552 return r;
1ee306e1 553
c3350683
LP
554 r = sd_bus_send_with_reply_and_block(manager->bus, m, 0, error, &reply);
555 if (r < 0)
556 return r;
1ee306e1
LP
557
558 if (job) {
559 const char *j;
560 char *copy;
561
c3350683
LP
562 r = sd_bus_message_read(reply, "o", &j);
563 if (r < 0)
564 return r;
1ee306e1
LP
565
566 copy = strdup(j);
567 if (!copy)
568 return -ENOMEM;
569
570 *job = copy;
571 }
572
c3350683 573 return 1;
1ee306e1
LP
574}
575
c3350683
LP
576int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
577 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
578 int r;
579
580 assert(manager);
581 assert(unit);
582
c3350683 583 r = sd_bus_call_method(
1ee306e1
LP
584 manager->bus,
585 "org.freedesktop.systemd1",
586 "/org/freedesktop/systemd1",
587 "org.freedesktop.systemd1.Manager",
588 "StopUnit",
1ee306e1 589 error,
c3350683
LP
590 &reply,
591 "ss", unit, "fail");
1ee306e1 592 if (r < 0) {
c3350683
LP
593 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
594 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
595
596 if (job)
597 *job = NULL;
598
c3350683 599 sd_bus_error_free(error);
6797c324
LP
600 return 0;
601 }
602
1ee306e1
LP
603 return r;
604 }
605
606 if (job) {
607 const char *j;
608 char *copy;
609
c3350683
LP
610 r = sd_bus_message_read(reply, "o", &j);
611 if (r < 0)
612 return r;
1ee306e1
LP
613
614 copy = strdup(j);
615 if (!copy)
616 return -ENOMEM;
617
618 *job = copy;
619 }
620
6797c324 621 return 1;
1ee306e1
LP
622}
623
c3350683 624int manager_kill_unit(Manager *manager, const char *unit, KillWho who, int signo, sd_bus_error *error) {
1ee306e1
LP
625 assert(manager);
626 assert(unit);
627
a658cafa 628 return sd_bus_call_method(
1ee306e1
LP
629 manager->bus,
630 "org.freedesktop.systemd1",
631 "/org/freedesktop/systemd1",
632 "org.freedesktop.systemd1.Manager",
633 "KillUnit",
1ee306e1 634 error,
a658cafa 635 NULL,
c3350683 636 "ssi", unit, who == KILL_LEADER ? "main" : "all", signo);
1ee306e1
LP
637}
638
639int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
640 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
641 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 642 _cleanup_free_ char *path = NULL;
1ee306e1 643 const char *state;
1ee306e1
LP
644 int r;
645
646 assert(manager);
647 assert(unit);
648
1ee306e1
LP
649 path = unit_dbus_path_from_name(unit);
650 if (!path)
651 return -ENOMEM;
652
c3350683 653 r = sd_bus_get_property(
1ee306e1
LP
654 manager->bus,
655 "org.freedesktop.systemd1",
656 path,
c3350683
LP
657 "org.freedesktop.systemd1.Unit",
658 "ActiveState",
1ee306e1 659 &error,
c3350683
LP
660 &reply,
661 "s");
1ee306e1 662 if (r < 0) {
c3350683
LP
663 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
664 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 665 return true;
6797c324 666
c3350683
LP
667 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
668 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 669 return false;
6797c324 670
1ee306e1
LP
671 return r;
672 }
673
c3350683
LP
674 r = sd_bus_message_read(reply, "s", &state);
675 if (r < 0)
1ee306e1 676 return -EINVAL;
1ee306e1
LP
677
678 return !streq(state, "inactive") && !streq(state, "failed");
679}
bd16acf3 680
c3350683
LP
681int manager_job_is_active(Manager *manager, const char *path) {
682 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
683 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
684 int r;
bd16acf3 685
c3350683
LP
686 assert(manager);
687 assert(path);
bd16acf3 688
c3350683
LP
689 r = sd_bus_get_property(
690 manager->bus,
691 "org.freedesktop.systemd1",
692 path,
693 "org.freedesktop.systemd1.Job",
694 "State",
695 &error,
696 &reply,
697 "s");
698 if (r < 0) {
699 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
700 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
701 return true;
bd16acf3 702
c3350683
LP
703 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
704 return false;
bd16acf3 705
bd16acf3 706 return r;
c3350683 707 }
bd16acf3 708
c3350683
LP
709 /* We don't actually care about the state really. The fact
710 * that we could read the job state is enough for us */
bd16acf3 711
c3350683 712 return true;
bd16acf3 713}