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