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