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