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