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