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