]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
switch-root: explain why we don't care about base_filesystem_create() failing
[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
9b5ed6fe 154static int method_create_or_register_machine(Manager *manager, sd_bus_message *message, bool read_network, Machine **_m, sd_bus_error *error) {
8aec412f 155 const char *name, *service, *class, *root_directory;
9b5ed6fe 156 const int32_t *netif = NULL;
1ee306e1
LP
157 MachineClass c;
158 uint32_t leader;
159 sd_id128_t id;
c3350683 160 const void *v;
1ee306e1 161 Machine *m;
9b5ed6fe 162 size_t n, n_netif = 0;
c3350683 163 int r;
1ee306e1 164
c3350683 165 assert(manager);
89f7c846
LP
166 assert(message);
167 assert(_m);
1ee306e1 168
c3350683
LP
169 r = sd_bus_message_read(message, "s", &name);
170 if (r < 0)
ebcf1f97 171 return r;
7f0d207d 172 if (!machine_name_is_valid(name))
ebcf1f97 173 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine name");
1ee306e1 174
c3350683
LP
175 r = sd_bus_message_read_array(message, 'y', &v, &n);
176 if (r < 0)
ebcf1f97 177 return r;
1ee306e1
LP
178 if (n == 0)
179 id = SD_ID128_NULL;
180 else if (n == 16)
181 memcpy(&id, v, n);
182 else
ebcf1f97 183 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine ID parameter");
1ee306e1 184
c3350683
LP
185 r = sd_bus_message_read(message, "ssus", &service, &class, &leader, &root_directory);
186 if (r < 0)
ebcf1f97 187 return r;
1ee306e1 188
9b5ed6fe
LP
189 if (read_network) {
190 size_t i;
191
192 r = sd_bus_message_read_array(message, 'i', (const void**) &netif, &n_netif);
193 if (r < 0)
194 return r;
195
196 n_netif /= sizeof(int32_t);
197
198 for (i = 0; i < n_netif; i++) {
199 if (netif[i] <= 0)
200 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid network interface index %i", netif[i]);
201 }
202 }
203
1ee306e1
LP
204 if (isempty(class))
205 c = _MACHINE_CLASS_INVALID;
206 else {
207 c = machine_class_from_string(class);
208 if (c < 0)
ebcf1f97 209 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid machine class parameter");
1ee306e1
LP
210 }
211
c3350683 212 if (leader == 1)
ebcf1f97 213 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid leader PID");
1ee306e1 214
c3350683 215 if (!isempty(root_directory) && !path_is_absolute(root_directory))
ebcf1f97 216 return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Root directory must be empty or an absolute path");
1ee306e1 217
c3350683 218 if (leader == 0) {
5b12334d
LP
219 _cleanup_bus_creds_unref_ sd_bus_creds *creds = NULL;
220
221 r = sd_bus_query_sender_creds(message, SD_BUS_CREDS_PID, &creds);
222 if (r < 0)
223 return r;
224
c3350683 225 assert_cc(sizeof(uint32_t) == sizeof(pid_t));
554604b3 226
5b12334d 227 r = sd_bus_creds_get_pid(creds, (pid_t*) &leader);
c3350683 228 if (r < 0)
ebcf1f97 229 return r;
c3350683 230 }
554604b3 231
1ee306e1 232 if (hashmap_get(manager->machines, name))
ebcf1f97 233 return sd_bus_error_setf(error, BUS_ERROR_MACHINE_EXISTS, "Machine '%s' already exists", name);
1ee306e1
LP
234
235 r = manager_add_machine(manager, name, &m);
236 if (r < 0)
ebcf1f97 237 return r;
1ee306e1
LP
238
239 m->leader = leader;
240 m->class = c;
241 m->id = id;
242
243 if (!isempty(service)) {
244 m->service = strdup(service);
245 if (!m->service) {
ebcf1f97 246 r = -ENOMEM;
1ee306e1
LP
247 goto fail;
248 }
249 }
250
251 if (!isempty(root_directory)) {
252 m->root_directory = strdup(root_directory);
253 if (!m->root_directory) {
ebcf1f97 254 r = -ENOMEM;
1ee306e1
LP
255 goto fail;
256 }
257 }
258
9b5ed6fe
LP
259 if (n_netif > 0) {
260 assert_cc(sizeof(int32_t) == sizeof(int));
261 m->netif = memdup(netif, sizeof(int32_t) * n_netif);
262 if (!m->netif) {
263 r = -ENOMEM;
264 goto fail;
265 }
266
267 m->n_netif = n_netif;
268 }
269
89f7c846
LP
270 *_m = m;
271
272 return 1;
273
274fail:
275 machine_add_to_gc_queue(m);
276 return r;
277}
278
9b5ed6fe 279static int method_create_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
280 Manager *manager = userdata;
281 Machine *m = NULL;
282 int r;
283
9b5ed6fe 284 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
285 if (r < 0)
286 return r;
287
288 r = sd_bus_message_enter_container(message, 'a', "(sv)");
289 if (r < 0)
290 goto fail;
291
ebcf1f97
LP
292 r = machine_start(m, message, error);
293 if (r < 0)
1ee306e1
LP
294 goto fail;
295
c3350683 296 m->create_message = sd_bus_message_ref(message);
c3350683 297 return 1;
1ee306e1
LP
298
299fail:
a3e7f417 300 machine_add_to_gc_queue(m);
89f7c846
LP
301 return r;
302}
1ee306e1 303
9b5ed6fe
LP
304static int method_create_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
305 return method_create_machine_internal(bus, message, true, userdata, error);
306}
307
308static int method_create_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
309 return method_create_machine_internal(bus, message, false, userdata, error);
310}
311
312static int method_register_machine_internal(sd_bus *bus, sd_bus_message *message, bool read_network, void *userdata, sd_bus_error *error) {
89f7c846
LP
313 Manager *manager = userdata;
314 _cleanup_free_ char *p = NULL;
315 Machine *m = NULL;
316 int r;
317
9b5ed6fe 318 r = method_create_or_register_machine(manager, message, read_network, &m, error);
89f7c846
LP
319 if (r < 0)
320 return r;
321
322 r = cg_pid_get_unit(m->leader, &m->unit);
323 if (r < 0) {
324 r = sd_bus_error_set_errnof(error, r, "Failed to determine unit of process "PID_FMT" : %s", m->leader, strerror(-r));
325 goto fail;
326 }
327
8d90c8a8
LP
328 m->registered = true;
329
89f7c846
LP
330 r = machine_start(m, NULL, error);
331 if (r < 0)
332 goto fail;
333
334 p = machine_bus_path(m);
335 if (!p) {
336 r = -ENOMEM;
337 goto fail;
338 }
339
340 return sd_bus_reply_method_return(message, "o", p);
341
342fail:
343 machine_add_to_gc_queue(m);
1ee306e1
LP
344 return r;
345}
346
9b5ed6fe
LP
347static int method_register_machine_with_network(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
348 return method_register_machine_internal(bus, message, true, userdata, error);
349}
350
351static int method_register_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
352 return method_register_machine_internal(bus, message, false, userdata, error);
353}
354
ebcf1f97 355static int method_terminate_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
1ee306e1 356 Manager *m = userdata;
c3350683
LP
357 Machine *machine;
358 const char *name;
1ee306e1
LP
359 int r;
360
c3350683 361 assert(bus);
1ee306e1
LP
362 assert(message);
363 assert(m);
364
c3350683
LP
365 r = sd_bus_message_read(message, "s", &name);
366 if (r < 0)
ebcf1f97 367 return sd_bus_error_set_errno(error, r);
1ee306e1 368
c3350683
LP
369 machine = hashmap_get(m->machines, name);
370 if (!machine)
ebcf1f97 371 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 372
878cd7e9 373 return bus_machine_method_terminate(bus, message, machine, error);
c3350683 374}
1ee306e1 375
ebcf1f97 376static int method_kill_machine(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
377 Manager *m = userdata;
378 Machine *machine;
379 const char *name;
c3350683 380 int r;
1ee306e1 381
c3350683
LP
382 assert(bus);
383 assert(message);
384 assert(m);
1ee306e1 385
878cd7e9 386 r = sd_bus_message_read(message, "s", &name);
c3350683 387 if (r < 0)
ebcf1f97 388 return sd_bus_error_set_errno(error, r);
1ee306e1 389
c3350683
LP
390 machine = hashmap_get(m->machines, name);
391 if (!machine)
ebcf1f97 392 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
1ee306e1 393
878cd7e9
LP
394 return bus_machine_method_kill(bus, message, machine, error);
395}
396
397static int method_get_machine_addresses(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
398 Manager *m = userdata;
399 Machine *machine;
400 const char *name;
401 int r;
402
403 assert(bus);
404 assert(message);
405 assert(m);
406
407 r = sd_bus_message_read(message, "s", &name);
c3350683 408 if (r < 0)
ebcf1f97 409 return sd_bus_error_set_errno(error, r);
1ee306e1 410
878cd7e9
LP
411 machine = hashmap_get(m->machines, name);
412 if (!machine)
413 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
414
415 return bus_machine_method_get_addresses(bus, message, machine, error);
c3350683 416}
1ee306e1 417
717603e3
LP
418static int method_get_machine_os_release(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
419 Manager *m = userdata;
420 Machine *machine;
421 const char *name;
422 int r;
423
424 assert(bus);
425 assert(message);
426 assert(m);
427
428 r = sd_bus_message_read(message, "s", &name);
429 if (r < 0)
430 return sd_bus_error_set_errno(error, r);
431
432 machine = hashmap_get(m->machines, name);
433 if (!machine)
434 return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_MACHINE, "No machine '%s' known", name);
435
436 return bus_machine_method_get_os_release(bus, message, machine, error);
437}
438
c3350683
LP
439const sd_bus_vtable manager_vtable[] = {
440 SD_BUS_VTABLE_START(0),
adacb957
LP
441 SD_BUS_METHOD("GetMachine", "s", "o", method_get_machine, SD_BUS_VTABLE_UNPRIVILEGED),
442 SD_BUS_METHOD("GetMachineByPID", "u", "o", method_get_machine_by_pid, SD_BUS_VTABLE_UNPRIVILEGED),
443 SD_BUS_METHOD("ListMachines", NULL, "a(ssso)", method_list_machines, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683 444 SD_BUS_METHOD("CreateMachine", "sayssusa(sv)", "o", method_create_machine, 0),
89f7c846 445 SD_BUS_METHOD("RegisterMachine", "sayssus", "o", method_register_machine, 0),
9b5ed6fe
LP
446 SD_BUS_METHOD("CreateMachineWithNetwork", "sayssusaia(sv)", "o", method_create_machine_with_network, 0),
447 SD_BUS_METHOD("RegisterMachineWithNetwork", "sayssusai", "o", method_register_machine_with_network, 0),
adacb957
LP
448 SD_BUS_METHOD("KillMachine", "ssi", NULL, method_kill_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
449 SD_BUS_METHOD("TerminateMachine", "s", NULL, method_terminate_machine, SD_BUS_VTABLE_CAPABILITY(CAP_KILL)),
3a6fb33c 450 SD_BUS_METHOD("GetMachineAddresses", "s", "a(iay)", method_get_machine_addresses, SD_BUS_VTABLE_UNPRIVILEGED),
717603e3 451 SD_BUS_METHOD("GetMachineOSRelease", "s", "a{ss}", method_get_machine_os_release, SD_BUS_VTABLE_UNPRIVILEGED),
c3350683
LP
452 SD_BUS_SIGNAL("MachineNew", "so", 0),
453 SD_BUS_SIGNAL("MachineRemoved", "so", 0),
454 SD_BUS_VTABLE_END
455};
1ee306e1 456
ebcf1f97 457int match_job_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 458 const char *path, *result, *unit;
1ee306e1 459 Manager *m = userdata;
c3350683
LP
460 Machine *machine;
461 uint32_t id;
462 int r;
1ee306e1 463
c3350683 464 assert(bus);
1ee306e1 465 assert(message);
c3350683 466 assert(m);
1ee306e1 467
c3350683
LP
468 r = sd_bus_message_read(message, "uoss", &id, &path, &unit, &result);
469 if (r < 0) {
ebcf1f97
LP
470 bus_log_parse_error(r);
471 return r;
c3350683 472 }
6797c324 473
c3350683
LP
474 machine = hashmap_get(m->machine_units, unit);
475 if (!machine)
476 return 0;
6797c324 477
c3350683
LP
478 if (streq_ptr(path, machine->scope_job)) {
479 free(machine->scope_job);
480 machine->scope_job = NULL;
6797c324 481
c3350683
LP
482 if (machine->started) {
483 if (streq(result, "done"))
484 machine_send_create_reply(machine, NULL);
485 else {
ebcf1f97 486 _cleanup_bus_error_free_ sd_bus_error e = SD_BUS_ERROR_NULL;
6797c324 487
ebcf1f97 488 sd_bus_error_setf(&e, BUS_ERROR_JOB_FAILED, "Start job for unit %s failed with '%s'", unit, result);
6797c324 489
ebcf1f97 490 machine_send_create_reply(machine, &e);
c3350683
LP
491 }
492 } else
493 machine_save(machine);
1ee306e1
LP
494 }
495
c3350683
LP
496 machine_add_to_gc_queue(machine);
497 return 0;
1ee306e1
LP
498}
499
ebcf1f97 500int match_properties_changed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
501 _cleanup_free_ char *unit = NULL;
502 Manager *m = userdata;
503 Machine *machine;
504 const char *path;
ebcf1f97 505 int r;
554604b3 506
c3350683
LP
507 assert(bus);
508 assert(message);
509 assert(m);
554604b3 510
c3350683
LP
511 path = sd_bus_message_get_path(message);
512 if (!path)
554604b3 513 return 0;
554604b3 514
ebcf1f97
LP
515 r = unit_name_from_dbus_path(path, &unit);
516 if (r < 0)
517 return r;
554604b3 518
c3350683
LP
519 machine = hashmap_get(m->machine_units, unit);
520 if (machine)
521 machine_add_to_gc_queue(machine);
554604b3 522
c3350683
LP
523 return 0;
524}
554604b3 525
ebcf1f97 526int match_unit_removed(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683
LP
527 const char *path, *unit;
528 Manager *m = userdata;
529 Machine *machine;
530 int r;
554604b3 531
c3350683
LP
532 assert(bus);
533 assert(message);
534 assert(m);
554604b3 535
c3350683
LP
536 r = sd_bus_message_read(message, "so", &unit, &path);
537 if (r < 0) {
ebcf1f97
LP
538 bus_log_parse_error(r);
539 return r;
554604b3
LP
540 }
541
c3350683
LP
542 machine = hashmap_get(m->machine_units, unit);
543 if (machine)
544 machine_add_to_gc_queue(machine);
554604b3 545
c3350683
LP
546 return 0;
547}
554604b3 548
ebcf1f97 549int match_reloading(sd_bus *bus, sd_bus_message *message, void *userdata, sd_bus_error *error) {
c3350683 550 Manager *m = userdata;
a658cafa
LP
551 Machine *machine;
552 Iterator i;
c3350683 553 int b, r;
554604b3 554
c3350683 555 assert(bus);
554604b3 556
c3350683
LP
557 r = sd_bus_message_read(message, "b", &b);
558 if (r < 0) {
ebcf1f97
LP
559 bus_log_parse_error(r);
560 return r;
554604b3 561 }
a658cafa
LP
562 if (b)
563 return 0;
554604b3 564
a658cafa
LP
565 /* systemd finished reloading, let's recheck all our machines */
566 log_debug("System manager has been reloaded, rechecking machines...");
554604b3 567
a658cafa
LP
568 HASHMAP_FOREACH(machine, m->machines, i)
569 machine_add_to_gc_queue(machine);
554604b3
LP
570
571 return 0;
572}
573
1ee306e1
LP
574int manager_start_scope(
575 Manager *manager,
576 const char *scope,
577 pid_t pid,
578 const char *slice,
579 const char *description,
c3350683
LP
580 sd_bus_message *more_properties,
581 sd_bus_error *error,
1ee306e1
LP
582 char **job) {
583
c3350683 584 _cleanup_bus_message_unref_ sd_bus_message *m = NULL, *reply = NULL;
554604b3 585 int r;
1ee306e1
LP
586
587 assert(manager);
588 assert(scope);
589 assert(pid > 1);
590
c3350683
LP
591 r = sd_bus_message_new_method_call(
592 manager->bus,
151b9b96 593 &m,
1ee306e1
LP
594 "org.freedesktop.systemd1",
595 "/org/freedesktop/systemd1",
596 "org.freedesktop.systemd1.Manager",
151b9b96 597 "StartTransientUnit");
c3350683
LP
598 if (r < 0)
599 return r;
1ee306e1 600
a658cafa 601 r = sd_bus_message_append(m, "ss", strempty(scope), "fail");
c3350683
LP
602 if (r < 0)
603 return r;
1ee306e1 604
c3350683
LP
605 r = sd_bus_message_open_container(m, 'a', "(sv)");
606 if (r < 0)
607 return r;
1ee306e1
LP
608
609 if (!isempty(slice)) {
c3350683
LP
610 r = sd_bus_message_append(m, "(sv)", "Slice", "s", slice);
611 if (r < 0)
612 return r;
1ee306e1
LP
613 }
614
615 if (!isempty(description)) {
c3350683
LP
616 r = sd_bus_message_append(m, "(sv)", "Description", "s", description);
617 if (r < 0)
618 return r;
1ee306e1
LP
619 }
620
c3350683
LP
621 r = sd_bus_message_append(m, "(sv)", "PIDs", "au", 1, pid);
622 if (r < 0)
623 return r;
554604b3 624
a931ad47
LP
625 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", 1);
626 if (r < 0)
627 return r;
628
554604b3 629 if (more_properties) {
c3350683 630 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
631 if (r < 0)
632 return r;
633 }
634
c3350683
LP
635 r = sd_bus_message_close_container(m);
636 if (r < 0)
637 return r;
1ee306e1 638
86b8d289
LP
639 r = sd_bus_message_append(m, "a(sa(sv))", 0);
640 if (r < 0)
641 return r;
642
c49b30a2 643 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
644 if (r < 0)
645 return r;
1ee306e1
LP
646
647 if (job) {
648 const char *j;
649 char *copy;
650
c3350683
LP
651 r = sd_bus_message_read(reply, "o", &j);
652 if (r < 0)
653 return r;
1ee306e1
LP
654
655 copy = strdup(j);
656 if (!copy)
657 return -ENOMEM;
658
659 *job = copy;
660 }
661
c3350683 662 return 1;
1ee306e1
LP
663}
664
c3350683
LP
665int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
666 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
667 int r;
668
669 assert(manager);
670 assert(unit);
671
c3350683 672 r = sd_bus_call_method(
1ee306e1
LP
673 manager->bus,
674 "org.freedesktop.systemd1",
675 "/org/freedesktop/systemd1",
676 "org.freedesktop.systemd1.Manager",
677 "StopUnit",
1ee306e1 678 error,
c3350683
LP
679 &reply,
680 "ss", unit, "fail");
1ee306e1 681 if (r < 0) {
c3350683
LP
682 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
683 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
684
685 if (job)
686 *job = NULL;
687
c3350683 688 sd_bus_error_free(error);
6797c324
LP
689 return 0;
690 }
691
1ee306e1
LP
692 return r;
693 }
694
695 if (job) {
696 const char *j;
697 char *copy;
698
c3350683
LP
699 r = sd_bus_message_read(reply, "o", &j);
700 if (r < 0)
701 return r;
1ee306e1
LP
702
703 copy = strdup(j);
704 if (!copy)
705 return -ENOMEM;
706
707 *job = copy;
708 }
709
6797c324 710 return 1;
1ee306e1
LP
711}
712
de58a50e 713int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
714 assert(manager);
715 assert(unit);
716
a658cafa 717 return sd_bus_call_method(
1ee306e1
LP
718 manager->bus,
719 "org.freedesktop.systemd1",
720 "/org/freedesktop/systemd1",
721 "org.freedesktop.systemd1.Manager",
722 "KillUnit",
1ee306e1 723 error,
a658cafa 724 NULL,
de58a50e 725 "ssi", unit, "all", signo);
1ee306e1
LP
726}
727
728int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
729 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
730 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 731 _cleanup_free_ char *path = NULL;
1ee306e1 732 const char *state;
1ee306e1
LP
733 int r;
734
735 assert(manager);
736 assert(unit);
737
1ee306e1
LP
738 path = unit_dbus_path_from_name(unit);
739 if (!path)
740 return -ENOMEM;
741
c3350683 742 r = sd_bus_get_property(
1ee306e1
LP
743 manager->bus,
744 "org.freedesktop.systemd1",
745 path,
c3350683
LP
746 "org.freedesktop.systemd1.Unit",
747 "ActiveState",
1ee306e1 748 &error,
c3350683
LP
749 &reply,
750 "s");
1ee306e1 751 if (r < 0) {
c3350683
LP
752 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
753 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 754 return true;
6797c324 755
c3350683
LP
756 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
757 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 758 return false;
6797c324 759
1ee306e1
LP
760 return r;
761 }
762
c3350683
LP
763 r = sd_bus_message_read(reply, "s", &state);
764 if (r < 0)
1ee306e1 765 return -EINVAL;
1ee306e1
LP
766
767 return !streq(state, "inactive") && !streq(state, "failed");
768}
bd16acf3 769
c3350683
LP
770int manager_job_is_active(Manager *manager, const char *path) {
771 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
772 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
773 int r;
bd16acf3 774
c3350683
LP
775 assert(manager);
776 assert(path);
bd16acf3 777
c3350683
LP
778 r = sd_bus_get_property(
779 manager->bus,
780 "org.freedesktop.systemd1",
781 path,
782 "org.freedesktop.systemd1.Job",
783 "State",
784 &error,
785 &reply,
786 "s");
787 if (r < 0) {
788 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
789 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
790 return true;
bd16acf3 791
c3350683
LP
792 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
793 return false;
bd16acf3 794
bd16acf3 795 return r;
c3350683 796 }
bd16acf3 797
c3350683
LP
798 /* We don't actually care about the state really. The fact
799 * that we could read the job state is enough for us */
bd16acf3 800
c3350683 801 return true;
bd16acf3 802}
ab49725f
KS
803
804int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
805 _cleanup_free_ char *unit = NULL;
806 Machine *mm;
807 int r;
808
809 assert(m);
810 assert(pid >= 1);
811 assert(machine);
812
813 r = cg_pid_get_unit(pid, &unit);
814 if (r < 0)
815 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
816 else
817 mm = hashmap_get(m->machine_units, unit);
818
819 if (!mm)
820 return 0;
821
822 *machine = mm;
823 return 1;
824}
825
826int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
827 Machine *machine;
828
829 assert(m);
830 assert(name);
831
832 machine = hashmap_get(m->machines, name);
833 if (!machine) {
834 machine = machine_new(m, name);
835 if (!machine)
836 return -ENOMEM;
837 }
838
839 if (_machine)
840 *_machine = machine;
841
842 return 0;
843}