]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/machine/machined-dbus.c
machine: make sure unpriviliged "machinectl status" can show the machine's OS version
[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)),
878cd7e9 450 SD_BUS_METHOD("GetMachineAddresses", "s", "a(yay)", 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
LP
624
625 if (more_properties) {
c3350683 626 r = sd_bus_message_copy(m, more_properties, true);
554604b3
LP
627 if (r < 0)
628 return r;
629 }
630
c3350683
LP
631 r = sd_bus_message_close_container(m);
632 if (r < 0)
633 return r;
1ee306e1 634
86b8d289
LP
635 r = sd_bus_message_append(m, "a(sa(sv))", 0);
636 if (r < 0)
637 return r;
638
c49b30a2 639 r = sd_bus_call(manager->bus, m, 0, error, &reply);
c3350683
LP
640 if (r < 0)
641 return r;
1ee306e1
LP
642
643 if (job) {
644 const char *j;
645 char *copy;
646
c3350683
LP
647 r = sd_bus_message_read(reply, "o", &j);
648 if (r < 0)
649 return r;
1ee306e1
LP
650
651 copy = strdup(j);
652 if (!copy)
653 return -ENOMEM;
654
655 *job = copy;
656 }
657
c3350683 658 return 1;
1ee306e1
LP
659}
660
c3350683
LP
661int manager_stop_unit(Manager *manager, const char *unit, sd_bus_error *error, char **job) {
662 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1
LP
663 int r;
664
665 assert(manager);
666 assert(unit);
667
c3350683 668 r = sd_bus_call_method(
1ee306e1
LP
669 manager->bus,
670 "org.freedesktop.systemd1",
671 "/org/freedesktop/systemd1",
672 "org.freedesktop.systemd1.Manager",
673 "StopUnit",
1ee306e1 674 error,
c3350683
LP
675 &reply,
676 "ss", unit, "fail");
1ee306e1 677 if (r < 0) {
c3350683
LP
678 if (sd_bus_error_has_name(error, BUS_ERROR_NO_SUCH_UNIT) ||
679 sd_bus_error_has_name(error, BUS_ERROR_LOAD_FAILED)) {
6797c324
LP
680
681 if (job)
682 *job = NULL;
683
c3350683 684 sd_bus_error_free(error);
6797c324
LP
685 return 0;
686 }
687
1ee306e1
LP
688 return r;
689 }
690
691 if (job) {
692 const char *j;
693 char *copy;
694
c3350683
LP
695 r = sd_bus_message_read(reply, "o", &j);
696 if (r < 0)
697 return r;
1ee306e1
LP
698
699 copy = strdup(j);
700 if (!copy)
701 return -ENOMEM;
702
703 *job = copy;
704 }
705
6797c324 706 return 1;
1ee306e1
LP
707}
708
de58a50e 709int manager_kill_unit(Manager *manager, const char *unit, int signo, sd_bus_error *error) {
1ee306e1
LP
710 assert(manager);
711 assert(unit);
712
a658cafa 713 return sd_bus_call_method(
1ee306e1
LP
714 manager->bus,
715 "org.freedesktop.systemd1",
716 "/org/freedesktop/systemd1",
717 "org.freedesktop.systemd1.Manager",
718 "KillUnit",
1ee306e1 719 error,
a658cafa 720 NULL,
de58a50e 721 "ssi", unit, "all", signo);
1ee306e1
LP
722}
723
724int manager_unit_is_active(Manager *manager, const char *unit) {
c3350683
LP
725 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
726 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
1ee306e1 727 _cleanup_free_ char *path = NULL;
1ee306e1 728 const char *state;
1ee306e1
LP
729 int r;
730
731 assert(manager);
732 assert(unit);
733
1ee306e1
LP
734 path = unit_dbus_path_from_name(unit);
735 if (!path)
736 return -ENOMEM;
737
c3350683 738 r = sd_bus_get_property(
1ee306e1
LP
739 manager->bus,
740 "org.freedesktop.systemd1",
741 path,
c3350683
LP
742 "org.freedesktop.systemd1.Unit",
743 "ActiveState",
1ee306e1 744 &error,
c3350683
LP
745 &reply,
746 "s");
1ee306e1 747 if (r < 0) {
c3350683
LP
748 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
749 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
6797c324 750 return true;
6797c324 751
c3350683
LP
752 if (sd_bus_error_has_name(&error, BUS_ERROR_NO_SUCH_UNIT) ||
753 sd_bus_error_has_name(&error, BUS_ERROR_LOAD_FAILED))
6797c324 754 return false;
6797c324 755
1ee306e1
LP
756 return r;
757 }
758
c3350683
LP
759 r = sd_bus_message_read(reply, "s", &state);
760 if (r < 0)
1ee306e1 761 return -EINVAL;
1ee306e1
LP
762
763 return !streq(state, "inactive") && !streq(state, "failed");
764}
bd16acf3 765
c3350683
LP
766int manager_job_is_active(Manager *manager, const char *path) {
767 _cleanup_bus_error_free_ sd_bus_error error = SD_BUS_ERROR_NULL;
768 _cleanup_bus_message_unref_ sd_bus_message *reply = NULL;
769 int r;
bd16acf3 770
c3350683
LP
771 assert(manager);
772 assert(path);
bd16acf3 773
c3350683
LP
774 r = sd_bus_get_property(
775 manager->bus,
776 "org.freedesktop.systemd1",
777 path,
778 "org.freedesktop.systemd1.Job",
779 "State",
780 &error,
781 &reply,
782 "s");
783 if (r < 0) {
784 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_NO_REPLY) ||
785 sd_bus_error_has_name(&error, SD_BUS_ERROR_DISCONNECTED))
786 return true;
bd16acf3 787
c3350683
LP
788 if (sd_bus_error_has_name(&error, SD_BUS_ERROR_UNKNOWN_OBJECT))
789 return false;
bd16acf3 790
bd16acf3 791 return r;
c3350683 792 }
bd16acf3 793
c3350683
LP
794 /* We don't actually care about the state really. The fact
795 * that we could read the job state is enough for us */
bd16acf3 796
c3350683 797 return true;
bd16acf3 798}
ab49725f
KS
799
800int manager_get_machine_by_pid(Manager *m, pid_t pid, Machine **machine) {
801 _cleanup_free_ char *unit = NULL;
802 Machine *mm;
803 int r;
804
805 assert(m);
806 assert(pid >= 1);
807 assert(machine);
808
809 r = cg_pid_get_unit(pid, &unit);
810 if (r < 0)
811 mm = hashmap_get(m->machine_leaders, UINT_TO_PTR(pid));
812 else
813 mm = hashmap_get(m->machine_units, unit);
814
815 if (!mm)
816 return 0;
817
818 *machine = mm;
819 return 1;
820}
821
822int manager_add_machine(Manager *m, const char *name, Machine **_machine) {
823 Machine *machine;
824
825 assert(m);
826 assert(name);
827
828 machine = hashmap_get(m->machines, name);
829 if (!machine) {
830 machine = machine_new(m, name);
831 if (!machine)
832 return -ENOMEM;
833 }
834
835 if (_machine)
836 *_machine = machine;
837
838 return 0;
839}