]>
Commit | Line | Data |
---|---|---|
53e1b683 | 1 | /* SPDX-License-Identifier: LGPL-2.1+ */ |
a7334b09 LP |
2 | /*** |
3 | This file is part of systemd. | |
4 | ||
5 | Copyright 2010 Lennart Poettering | |
6 | ||
7 | systemd is free software; you can redistribute it and/or modify it | |
5430f7f2 LP |
8 | under the terms of the GNU Lesser General Public License as published by |
9 | the Free Software Foundation; either version 2.1 of the License, or | |
a7334b09 LP |
10 | (at your option) any later version. |
11 | ||
12 | systemd is distributed in the hope that it will be useful, but | |
13 | WITHOUT ANY WARRANTY; without even the implied warranty of | |
14 | MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU | |
5430f7f2 | 15 | Lesser General Public License for more details. |
a7334b09 | 16 | |
5430f7f2 | 17 | You should have received a copy of the GNU Lesser General Public License |
a7334b09 LP |
18 | along with systemd; If not, see <http://www.gnu.org/licenses/>. |
19 | ***/ | |
20 | ||
718db961 | 21 | #include "sd-bus.h" |
07630cea | 22 | |
b5efdb8a | 23 | #include "alloc-util.h" |
906c06f6 | 24 | #include "bpf-firewall.h" |
07630cea LP |
25 | #include "bus-common-errors.h" |
26 | #include "cgroup-util.h" | |
c5a97ed1 | 27 | #include "dbus-job.h" |
8752c575 | 28 | #include "dbus-unit.h" |
07630cea | 29 | #include "dbus.h" |
291d565a | 30 | #include "fd-util.h" |
8752c575 | 31 | #include "locale-util.h" |
ea430986 | 32 | #include "log.h" |
291d565a | 33 | #include "process-util.h" |
e2417e41 | 34 | #include "selinux-access.h" |
6eb7c172 | 35 | #include "signal-util.h" |
efdb0237 | 36 | #include "special.h" |
07630cea LP |
37 | #include "string-util.h" |
38 | #include "strv.h" | |
ee104e11 | 39 | #include "user-util.h" |
718db961 | 40 | |
5afe510c | 41 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_collect_mode, collect_mode, CollectMode); |
718db961 | 42 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_load_state, unit_load_state, UnitLoadState); |
d420282b | 43 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_job_mode, job_mode, JobMode); |
87a47f99 | 44 | static BUS_DEFINE_PROPERTY_GET_ENUM(property_get_emergency_action, emergency_action, EmergencyAction); |
718db961 LP |
45 | |
46 | static int property_get_names( | |
47 | sd_bus *bus, | |
48 | const char *path, | |
49 | const char *interface, | |
50 | const char *property, | |
51 | sd_bus_message *reply, | |
ebcf1f97 LP |
52 | void *userdata, |
53 | sd_bus_error *error) { | |
718db961 LP |
54 | |
55 | Unit *u = userdata; | |
56 | Iterator i; | |
57 | const char *t; | |
58 | int r; | |
ea430986 | 59 | |
718db961 LP |
60 | assert(bus); |
61 | assert(reply); | |
62 | assert(u); | |
4139c1b2 | 63 | |
718db961 LP |
64 | r = sd_bus_message_open_container(reply, 'a', "s"); |
65 | if (r < 0) | |
66 | return r; | |
4139c1b2 | 67 | |
718db961 LP |
68 | SET_FOREACH(t, u->names, i) { |
69 | r = sd_bus_message_append(reply, "s", t); | |
70 | if (r < 0) | |
71 | return r; | |
72 | } | |
4139c1b2 | 73 | |
718db961 | 74 | return sd_bus_message_close_container(reply); |
4139c1b2 LP |
75 | } |
76 | ||
718db961 LP |
77 | static int property_get_following( |
78 | sd_bus *bus, | |
79 | const char *path, | |
80 | const char *interface, | |
81 | const char *property, | |
82 | sd_bus_message *reply, | |
ebcf1f97 LP |
83 | void *userdata, |
84 | sd_bus_error *error) { | |
718db961 LP |
85 | |
86 | Unit *u = userdata, *f; | |
8fe914ec | 87 | |
718db961 LP |
88 | assert(bus); |
89 | assert(reply); | |
8fe914ec LP |
90 | assert(u); |
91 | ||
a7f241db | 92 | f = unit_following(u); |
718db961 | 93 | return sd_bus_message_append(reply, "s", f ? f->id : ""); |
8fe914ec LP |
94 | } |
95 | ||
718db961 LP |
96 | static int property_get_dependencies( |
97 | sd_bus *bus, | |
98 | const char *path, | |
99 | const char *interface, | |
100 | const char *property, | |
101 | sd_bus_message *reply, | |
ebcf1f97 LP |
102 | void *userdata, |
103 | sd_bus_error *error) { | |
4ec9a8a4 | 104 | |
eef85c4a | 105 | Hashmap *h = *(Hashmap**) userdata; |
5301be81 | 106 | Iterator j; |
718db961 | 107 | Unit *u; |
eef85c4a | 108 | void *v; |
718db961 | 109 | int r; |
5301be81 | 110 | |
718db961 LP |
111 | assert(bus); |
112 | assert(reply); | |
5301be81 | 113 | |
718db961 LP |
114 | r = sd_bus_message_open_container(reply, 'a', "s"); |
115 | if (r < 0) | |
116 | return r; | |
5301be81 | 117 | |
eef85c4a | 118 | HASHMAP_FOREACH_KEY(v, u, h, j) { |
718db961 LP |
119 | r = sd_bus_message_append(reply, "s", u->id); |
120 | if (r < 0) | |
121 | return r; | |
122 | } | |
5301be81 | 123 | |
718db961 | 124 | return sd_bus_message_close_container(reply); |
5301be81 LP |
125 | } |
126 | ||
f32b43bd LP |
127 | static int property_get_obsolete_dependencies( |
128 | sd_bus *bus, | |
129 | const char *path, | |
130 | const char *interface, | |
131 | const char *property, | |
132 | sd_bus_message *reply, | |
133 | void *userdata, | |
134 | sd_bus_error *error) { | |
135 | ||
136 | assert(bus); | |
137 | assert(reply); | |
138 | ||
139 | /* For dependency types we don't support anymore always return an empty array */ | |
140 | return sd_bus_message_append(reply, "as", 0); | |
141 | } | |
142 | ||
99c14018 YW |
143 | static int property_get_requires_mounts_for( |
144 | sd_bus *bus, | |
145 | const char *path, | |
146 | const char *interface, | |
147 | const char *property, | |
148 | sd_bus_message *reply, | |
149 | void *userdata, | |
150 | sd_bus_error *error) { | |
151 | ||
f6e11b39 | 152 | Hashmap *h = *(Hashmap**) userdata; |
99c14018 | 153 | const char *p; |
f6e11b39 | 154 | Iterator j; |
99c14018 YW |
155 | void *v; |
156 | int r; | |
157 | ||
158 | assert(bus); | |
159 | assert(reply); | |
160 | ||
161 | r = sd_bus_message_open_container(reply, 'a', "s"); | |
162 | if (r < 0) | |
163 | return r; | |
164 | ||
165 | HASHMAP_FOREACH_KEY(v, p, h, j) { | |
166 | r = sd_bus_message_append(reply, "s", p); | |
167 | if (r < 0) | |
168 | return r; | |
169 | } | |
170 | ||
171 | return sd_bus_message_close_container(reply); | |
172 | } | |
173 | ||
718db961 LP |
174 | static int property_get_description( |
175 | sd_bus *bus, | |
176 | const char *path, | |
177 | const char *interface, | |
178 | const char *property, | |
179 | sd_bus_message *reply, | |
ebcf1f97 LP |
180 | void *userdata, |
181 | sd_bus_error *error) { | |
ea430986 | 182 | |
718db961 | 183 | Unit *u = userdata; |
ea430986 | 184 | |
718db961 LP |
185 | assert(bus); |
186 | assert(reply); | |
187 | assert(u); | |
ea430986 | 188 | |
718db961 | 189 | return sd_bus_message_append(reply, "s", unit_description(u)); |
ea430986 LP |
190 | } |
191 | ||
718db961 LP |
192 | static int property_get_active_state( |
193 | sd_bus *bus, | |
194 | const char *path, | |
195 | const char *interface, | |
196 | const char *property, | |
197 | sd_bus_message *reply, | |
ebcf1f97 LP |
198 | void *userdata, |
199 | sd_bus_error *error) { | |
ea430986 | 200 | |
718db961 | 201 | Unit *u = userdata; |
ea430986 | 202 | |
718db961 LP |
203 | assert(bus); |
204 | assert(reply); | |
ea430986 LP |
205 | assert(u); |
206 | ||
718db961 | 207 | return sd_bus_message_append(reply, "s", unit_active_state_to_string(unit_active_state(u))); |
ea430986 LP |
208 | } |
209 | ||
718db961 LP |
210 | static int property_get_sub_state( |
211 | sd_bus *bus, | |
212 | const char *path, | |
213 | const char *interface, | |
214 | const char *property, | |
215 | sd_bus_message *reply, | |
ebcf1f97 LP |
216 | void *userdata, |
217 | sd_bus_error *error) { | |
10a94420 | 218 | |
718db961 | 219 | Unit *u = userdata; |
10a94420 | 220 | |
718db961 LP |
221 | assert(bus); |
222 | assert(reply); | |
223 | assert(u); | |
10a94420 | 224 | |
718db961 | 225 | return sd_bus_message_append(reply, "s", unit_sub_state_to_string(u)); |
10a94420 LP |
226 | } |
227 | ||
d2dc52db LP |
228 | static int property_get_unit_file_preset( |
229 | sd_bus *bus, | |
230 | const char *path, | |
231 | const char *interface, | |
232 | const char *property, | |
233 | sd_bus_message *reply, | |
234 | void *userdata, | |
235 | sd_bus_error *error) { | |
236 | ||
237 | Unit *u = userdata; | |
238 | int r; | |
239 | ||
240 | assert(bus); | |
241 | assert(reply); | |
242 | assert(u); | |
243 | ||
244 | r = unit_get_unit_file_preset(u); | |
245 | ||
246 | return sd_bus_message_append(reply, "s", | |
247 | r < 0 ? "": | |
248 | r > 0 ? "enabled" : "disabled"); | |
249 | } | |
250 | ||
718db961 LP |
251 | static int property_get_unit_file_state( |
252 | sd_bus *bus, | |
253 | const char *path, | |
254 | const char *interface, | |
255 | const char *property, | |
256 | sd_bus_message *reply, | |
ebcf1f97 LP |
257 | void *userdata, |
258 | sd_bus_error *error) { | |
a4375746 | 259 | |
718db961 | 260 | Unit *u = userdata; |
a4375746 | 261 | |
718db961 LP |
262 | assert(bus); |
263 | assert(reply); | |
264 | assert(u); | |
a4375746 | 265 | |
76445832 | 266 | return sd_bus_message_append(reply, "s", unit_file_state_to_string(unit_get_unit_file_state(u))); |
a4375746 LP |
267 | } |
268 | ||
718db961 LP |
269 | static int property_get_can_start( |
270 | sd_bus *bus, | |
271 | const char *path, | |
272 | const char *interface, | |
273 | const char *property, | |
274 | sd_bus_message *reply, | |
ebcf1f97 LP |
275 | void *userdata, |
276 | sd_bus_error *error) { | |
38131695 | 277 | |
718db961 | 278 | Unit *u = userdata; |
b5e9dba8 | 279 | |
718db961 LP |
280 | assert(bus); |
281 | assert(reply); | |
282 | assert(u); | |
b5e9dba8 | 283 | |
718db961 | 284 | return sd_bus_message_append(reply, "b", unit_can_start(u) && !u->refuse_manual_start); |
b5e9dba8 LP |
285 | } |
286 | ||
718db961 LP |
287 | static int property_get_can_stop( |
288 | sd_bus *bus, | |
289 | const char *path, | |
290 | const char *interface, | |
291 | const char *property, | |
292 | sd_bus_message *reply, | |
ebcf1f97 LP |
293 | void *userdata, |
294 | sd_bus_error *error) { | |
718db961 LP |
295 | |
296 | Unit *u = userdata; | |
b5e9dba8 | 297 | |
718db961 LP |
298 | assert(bus); |
299 | assert(reply); | |
b5e9dba8 LP |
300 | assert(u); |
301 | ||
f5869324 | 302 | return sd_bus_message_append(reply, "b", unit_can_stop(u) && !u->refuse_manual_stop); |
38131695 LP |
303 | } |
304 | ||
718db961 LP |
305 | static int property_get_can_reload( |
306 | sd_bus *bus, | |
307 | const char *path, | |
308 | const char *interface, | |
309 | const char *property, | |
310 | sd_bus_message *reply, | |
ebcf1f97 LP |
311 | void *userdata, |
312 | sd_bus_error *error) { | |
38131695 | 313 | |
718db961 | 314 | Unit *u = userdata; |
38131695 | 315 | |
718db961 LP |
316 | assert(bus); |
317 | assert(reply); | |
318 | assert(u); | |
38131695 | 319 | |
718db961 | 320 | return sd_bus_message_append(reply, "b", unit_can_reload(u)); |
38131695 LP |
321 | } |
322 | ||
718db961 LP |
323 | static int property_get_can_isolate( |
324 | sd_bus *bus, | |
325 | const char *path, | |
326 | const char *interface, | |
327 | const char *property, | |
328 | sd_bus_message *reply, | |
ebcf1f97 LP |
329 | void *userdata, |
330 | sd_bus_error *error) { | |
2528a7a6 | 331 | |
718db961 | 332 | Unit *u = userdata; |
2528a7a6 | 333 | |
718db961 LP |
334 | assert(bus); |
335 | assert(reply); | |
336 | assert(u); | |
2528a7a6 | 337 | |
718db961 | 338 | return sd_bus_message_append(reply, "b", unit_can_isolate(u) && !u->refuse_manual_start); |
2528a7a6 LP |
339 | } |
340 | ||
718db961 LP |
341 | static int property_get_job( |
342 | sd_bus *bus, | |
343 | const char *path, | |
344 | const char *interface, | |
345 | const char *property, | |
346 | sd_bus_message *reply, | |
ebcf1f97 LP |
347 | void *userdata, |
348 | sd_bus_error *error) { | |
718db961 | 349 | |
f93891f3 | 350 | _cleanup_free_ char *p = NULL; |
718db961 | 351 | Unit *u = userdata; |
38131695 | 352 | |
718db961 LP |
353 | assert(bus); |
354 | assert(reply); | |
38131695 LP |
355 | assert(u); |
356 | ||
718db961 LP |
357 | if (!u->job) |
358 | return sd_bus_message_append(reply, "(uo)", 0, "/"); | |
38131695 | 359 | |
718db961 LP |
360 | p = job_dbus_path(u->job); |
361 | if (!p) | |
362 | return -ENOMEM; | |
38131695 | 363 | |
718db961 LP |
364 | return sd_bus_message_append(reply, "(uo)", u->job->id, p); |
365 | } | |
38131695 | 366 | |
718db961 LP |
367 | static int property_get_need_daemon_reload( |
368 | sd_bus *bus, | |
369 | const char *path, | |
370 | const char *interface, | |
371 | const char *property, | |
372 | sd_bus_message *reply, | |
ebcf1f97 LP |
373 | void *userdata, |
374 | sd_bus_error *error) { | |
38131695 | 375 | |
718db961 | 376 | Unit *u = userdata; |
38131695 | 377 | |
718db961 LP |
378 | assert(bus); |
379 | assert(reply); | |
380 | assert(u); | |
38131695 | 381 | |
718db961 | 382 | return sd_bus_message_append(reply, "b", unit_need_daemon_reload(u)); |
38131695 LP |
383 | } |
384 | ||
718db961 LP |
385 | static int property_get_conditions( |
386 | sd_bus *bus, | |
387 | const char *path, | |
388 | const char *interface, | |
389 | const char *property, | |
390 | sd_bus_message *reply, | |
ebcf1f97 LP |
391 | void *userdata, |
392 | sd_bus_error *error) { | |
45fb0699 | 393 | |
59fccdc5 LP |
394 | const char *(*to_string)(ConditionType type) = NULL; |
395 | Condition **list = userdata, *c; | |
718db961 | 396 | int r; |
45fb0699 | 397 | |
718db961 LP |
398 | assert(bus); |
399 | assert(reply); | |
59fccdc5 LP |
400 | assert(list); |
401 | ||
402 | to_string = streq(property, "Asserts") ? assert_type_to_string : condition_type_to_string; | |
45fb0699 | 403 | |
718db961 LP |
404 | r = sd_bus_message_open_container(reply, 'a', "(sbbsi)"); |
405 | if (r < 0) | |
406 | return r; | |
45fb0699 | 407 | |
59fccdc5 | 408 | LIST_FOREACH(conditions, c, *list) { |
cc50ef13 LP |
409 | int tristate; |
410 | ||
411 | tristate = | |
412 | c->result == CONDITION_UNTESTED ? 0 : | |
413 | c->result == CONDITION_SUCCEEDED ? 1 : -1; | |
414 | ||
2c7e050f | 415 | r = sd_bus_message_append(reply, "(sbbsi)", |
59fccdc5 | 416 | to_string(c->type), |
2c7e050f | 417 | c->trigger, c->negate, |
cc50ef13 | 418 | c->parameter, tristate); |
718db961 LP |
419 | if (r < 0) |
420 | return r; | |
45fb0699 | 421 | |
718db961 | 422 | } |
52990c2e | 423 | |
718db961 | 424 | return sd_bus_message_close_container(reply); |
52990c2e ZJS |
425 | } |
426 | ||
718db961 LP |
427 | static int property_get_load_error( |
428 | sd_bus *bus, | |
429 | const char *path, | |
430 | const char *interface, | |
431 | const char *property, | |
432 | sd_bus_message *reply, | |
ebcf1f97 LP |
433 | void *userdata, |
434 | sd_bus_error *error) { | |
52990c2e | 435 | |
4afd3348 | 436 | _cleanup_(sd_bus_error_free) sd_bus_error e = SD_BUS_ERROR_NULL; |
718db961 | 437 | Unit *u = userdata; |
52990c2e | 438 | |
718db961 LP |
439 | assert(bus); |
440 | assert(reply); | |
441 | assert(u); | |
52990c2e | 442 | |
718db961 LP |
443 | if (u->load_error != 0) |
444 | sd_bus_error_set_errno(&e, u->load_error); | |
52990c2e | 445 | |
718db961 | 446 | return sd_bus_message_append(reply, "(ss)", e.name, e.message); |
52990c2e ZJS |
447 | } |
448 | ||
88ced61b MC |
449 | static int bus_verify_manage_units_async_full( |
450 | Unit *u, | |
451 | const char *verb, | |
452 | int capability, | |
453 | const char *polkit_message, | |
05a98afd | 454 | bool interactive, |
88ced61b MC |
455 | sd_bus_message *call, |
456 | sd_bus_error *error) { | |
457 | ||
458 | const char *details[9] = { | |
459 | "unit", u->id, | |
460 | "verb", verb, | |
461 | }; | |
462 | ||
463 | if (polkit_message) { | |
464 | details[4] = "polkit.message"; | |
465 | details[5] = polkit_message; | |
466 | details[6] = "polkit.gettext_domain"; | |
467 | details[7] = GETTEXT_PACKAGE; | |
468 | } | |
469 | ||
05a98afd LP |
470 | return bus_verify_polkit_async( |
471 | call, | |
472 | capability, | |
473 | "org.freedesktop.systemd1.manage-units", | |
474 | details, | |
475 | interactive, | |
476 | UID_INVALID, | |
477 | &u->manager->polkit_registry, | |
478 | error); | |
88ced61b MC |
479 | } |
480 | ||
1d22e906 | 481 | int bus_unit_method_start_generic( |
1d22e906 LP |
482 | sd_bus_message *message, |
483 | Unit *u, | |
484 | JobType job_type, | |
485 | bool reload_if_possible, | |
486 | sd_bus_error *error) { | |
487 | ||
718db961 LP |
488 | const char *smode; |
489 | JobMode mode; | |
88ced61b MC |
490 | _cleanup_free_ char *verb = NULL; |
491 | static const char *const polkit_message_for_job[_JOB_TYPE_MAX] = { | |
492 | [JOB_START] = N_("Authentication is required to start '$(unit)'."), | |
493 | [JOB_STOP] = N_("Authentication is required to stop '$(unit)'."), | |
494 | [JOB_RELOAD] = N_("Authentication is required to reload '$(unit)'."), | |
495 | [JOB_RESTART] = N_("Authentication is required to restart '$(unit)'."), | |
496 | [JOB_TRY_RESTART] = N_("Authentication is required to restart '$(unit)'."), | |
497 | }; | |
718db961 | 498 | int r; |
9f39404c | 499 | |
718db961 | 500 | assert(message); |
9f39404c | 501 | assert(u); |
718db961 | 502 | assert(job_type >= 0 && job_type < _JOB_TYPE_MAX); |
9f39404c | 503 | |
61ea63f1 EV |
504 | r = mac_selinux_unit_access_check( |
505 | u, message, | |
94bd7323 EV |
506 | job_type_to_access_method(job_type), |
507 | error); | |
1d22e906 LP |
508 | if (r < 0) |
509 | return r; | |
510 | ||
718db961 LP |
511 | r = sd_bus_message_read(message, "s", &smode); |
512 | if (r < 0) | |
ebcf1f97 | 513 | return r; |
9f39404c | 514 | |
718db961 LP |
515 | mode = job_mode_from_string(smode); |
516 | if (mode < 0) | |
ebcf1f97 | 517 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Job mode %s invalid", smode); |
9f39404c | 518 | |
88ced61b | 519 | if (reload_if_possible) |
605405c6 | 520 | verb = strjoin("reload-or-", job_type_to_string(job_type)); |
88ced61b MC |
521 | else |
522 | verb = strdup(job_type_to_string(job_type)); | |
523 | if (!verb) | |
524 | return -ENOMEM; | |
525 | ||
526 | r = bus_verify_manage_units_async_full( | |
527 | u, | |
528 | verb, | |
529 | CAP_SYS_ADMIN, | |
530 | job_type < _JOB_TYPE_MAX ? polkit_message_for_job[job_type] : NULL, | |
05a98afd | 531 | true, |
88ced61b MC |
532 | message, |
533 | error); | |
1d22e906 LP |
534 | if (r < 0) |
535 | return r; | |
536 | if (r == 0) | |
537 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
538 | ||
19070062 | 539 | return bus_unit_queue_job(message, u, job_type, mode, reload_if_possible, error); |
9f39404c LP |
540 | } |
541 | ||
19070062 LP |
542 | static int method_start(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
543 | return bus_unit_method_start_generic(message, userdata, JOB_START, false, error); | |
718db961 | 544 | } |
b548631a | 545 | |
19070062 LP |
546 | static int method_stop(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
547 | return bus_unit_method_start_generic(message, userdata, JOB_STOP, false, error); | |
718db961 LP |
548 | } |
549 | ||
19070062 LP |
550 | static int method_reload(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
551 | return bus_unit_method_start_generic(message, userdata, JOB_RELOAD, false, error); | |
718db961 | 552 | } |
0a524ba7 | 553 | |
19070062 LP |
554 | static int method_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
555 | return bus_unit_method_start_generic(message, userdata, JOB_RESTART, false, error); | |
718db961 | 556 | } |
8a0867d6 | 557 | |
19070062 LP |
558 | static int method_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
559 | return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, false, error); | |
718db961 | 560 | } |
cad45ba1 | 561 | |
19070062 LP |
562 | static int method_reload_or_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
563 | return bus_unit_method_start_generic(message, userdata, JOB_RESTART, true, error); | |
718db961 | 564 | } |
8a0867d6 | 565 | |
19070062 LP |
566 | static int method_reload_or_try_restart(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
567 | return bus_unit_method_start_generic(message, userdata, JOB_TRY_RESTART, true, error); | |
718db961 | 568 | } |
8a0867d6 | 569 | |
19070062 | 570 | int bus_unit_method_kill(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
571 | Unit *u = userdata; |
572 | const char *swho; | |
573 | int32_t signo; | |
574 | KillWho who; | |
575 | int r; | |
5632e374 | 576 | |
718db961 LP |
577 | assert(message); |
578 | assert(u); | |
cad45ba1 | 579 | |
1d22e906 | 580 | r = mac_selinux_unit_access_check(u, message, "stop", error); |
283868e1 SW |
581 | if (r < 0) |
582 | return r; | |
283868e1 | 583 | |
718db961 LP |
584 | r = sd_bus_message_read(message, "si", &swho, &signo); |
585 | if (r < 0) | |
ebcf1f97 | 586 | return r; |
718db961 LP |
587 | |
588 | if (isempty(swho)) | |
589 | who = KILL_ALL; | |
590 | else { | |
591 | who = kill_who_from_string(swho); | |
592 | if (who < 0) | |
ebcf1f97 | 593 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid who argument %s", swho); |
718db961 | 594 | } |
5632e374 | 595 | |
6eb7c172 | 596 | if (!SIGNAL_VALID(signo)) |
ebcf1f97 | 597 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Signal number out of range."); |
8e2af478 | 598 | |
88ced61b MC |
599 | r = bus_verify_manage_units_async_full( |
600 | u, | |
601 | "kill", | |
602 | CAP_KILL, | |
603 | N_("Authentication is required to kill '$(unit)'."), | |
05a98afd | 604 | true, |
88ced61b MC |
605 | message, |
606 | error); | |
ebcf1f97 LP |
607 | if (r < 0) |
608 | return r; | |
1d22e906 LP |
609 | if (r == 0) |
610 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
8e2af478 | 611 | |
ebcf1f97 | 612 | r = unit_kill(u, who, signo, error); |
718db961 | 613 | if (r < 0) |
ebcf1f97 | 614 | return r; |
8e2af478 | 615 | |
df2d202e | 616 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 617 | } |
8e2af478 | 618 | |
19070062 | 619 | int bus_unit_method_reset_failed(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 | 620 | Unit *u = userdata; |
ebcf1f97 | 621 | int r; |
b548631a | 622 | |
718db961 LP |
623 | assert(message); |
624 | assert(u); | |
b548631a | 625 | |
1d22e906 | 626 | r = mac_selinux_unit_access_check(u, message, "reload", error); |
283868e1 SW |
627 | if (r < 0) |
628 | return r; | |
283868e1 | 629 | |
88ced61b MC |
630 | r = bus_verify_manage_units_async_full( |
631 | u, | |
632 | "reset-failed", | |
633 | CAP_SYS_ADMIN, | |
634 | N_("Authentication is required to reset the \"failed\" state of '$(unit)'."), | |
05a98afd | 635 | true, |
88ced61b MC |
636 | message, |
637 | error); | |
ebcf1f97 LP |
638 | if (r < 0) |
639 | return r; | |
1d22e906 LP |
640 | if (r == 0) |
641 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
b548631a | 642 | |
718db961 | 643 | unit_reset_failed(u); |
b548631a | 644 | |
df2d202e | 645 | return sd_bus_reply_method_return(message, NULL); |
ea430986 LP |
646 | } |
647 | ||
19070062 | 648 | int bus_unit_method_set_properties(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
718db961 LP |
649 | Unit *u = userdata; |
650 | int runtime, r; | |
ea430986 | 651 | |
ea430986 | 652 | assert(message); |
718db961 | 653 | assert(u); |
80fbf05e | 654 | |
1d22e906 | 655 | r = mac_selinux_unit_access_check(u, message, "start", error); |
283868e1 SW |
656 | if (r < 0) |
657 | return r; | |
283868e1 | 658 | |
718db961 LP |
659 | r = sd_bus_message_read(message, "b", &runtime); |
660 | if (r < 0) | |
ebcf1f97 | 661 | return r; |
2cccbca4 | 662 | |
88ced61b MC |
663 | r = bus_verify_manage_units_async_full( |
664 | u, | |
665 | "set-property", | |
666 | CAP_SYS_ADMIN, | |
667 | N_("Authentication is required to set properties on '$(unit)'."), | |
05a98afd | 668 | true, |
88ced61b MC |
669 | message, |
670 | error); | |
ebcf1f97 LP |
671 | if (r < 0) |
672 | return r; | |
1d22e906 LP |
673 | if (r == 0) |
674 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
cad45ba1 | 675 | |
ebcf1f97 | 676 | r = bus_unit_set_properties(u, message, runtime ? UNIT_RUNTIME : UNIT_PERSISTENT, true, error); |
718db961 | 677 | if (r < 0) |
ebcf1f97 | 678 | return r; |
2cccbca4 | 679 | |
df2d202e | 680 | return sd_bus_reply_method_return(message, NULL); |
718db961 | 681 | } |
2cccbca4 | 682 | |
05a98afd LP |
683 | int bus_unit_method_ref(sd_bus_message *message, void *userdata, sd_bus_error *error) { |
684 | Unit *u = userdata; | |
685 | int r; | |
686 | ||
687 | assert(message); | |
688 | assert(u); | |
689 | ||
690 | r = mac_selinux_unit_access_check(u, message, "start", error); | |
691 | if (r < 0) | |
692 | return r; | |
693 | ||
694 | r = bus_verify_manage_units_async_full( | |
695 | u, | |
696 | "ref", | |
697 | CAP_SYS_ADMIN, | |
698 | NULL, | |
699 | false, | |
700 | message, | |
701 | error); | |
702 | if (r < 0) | |
703 | return r; | |
704 | if (r == 0) | |
705 | return 1; /* No authorization for now, but the async polkit stuff will call us again when it has it */ | |
706 | ||
707 | r = bus_unit_track_add_sender(u, message); | |
708 | if (r < 0) | |
709 | return r; | |
710 | ||
711 | return sd_bus_reply_method_return(message, NULL); | |
712 | } | |
713 | ||
714 | int bus_unit_method_unref(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |
715 | Unit *u = userdata; | |
716 | int r; | |
717 | ||
718 | assert(message); | |
719 | assert(u); | |
720 | ||
721 | r = bus_unit_track_remove_sender(u, message); | |
722 | if (r == -EUNATCH) | |
723 | return sd_bus_error_setf(error, BUS_ERROR_NOT_REFERENCED, "Unit has not been referenced yet."); | |
724 | if (r < 0) | |
725 | return r; | |
726 | ||
727 | return sd_bus_reply_method_return(message, NULL); | |
728 | } | |
729 | ||
718db961 LP |
730 | const sd_bus_vtable bus_unit_vtable[] = { |
731 | SD_BUS_VTABLE_START(0), | |
732 | ||
556089dc LP |
733 | SD_BUS_PROPERTY("Id", "s", NULL, offsetof(Unit, id), SD_BUS_VTABLE_PROPERTY_CONST), |
734 | SD_BUS_PROPERTY("Names", "as", property_get_names, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 735 | SD_BUS_PROPERTY("Following", "s", property_get_following, 0, 0), |
556089dc | 736 | SD_BUS_PROPERTY("Requires", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRES]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc | 737 | SD_BUS_PROPERTY("Requisite", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
738 | SD_BUS_PROPERTY("Wants", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTS]), SD_BUS_VTABLE_PROPERTY_CONST), |
739 | SD_BUS_PROPERTY("BindsTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BINDS_TO]), SD_BUS_VTABLE_PROPERTY_CONST), | |
740 | SD_BUS_PROPERTY("PartOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PART_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
741 | SD_BUS_PROPERTY("RequiredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUIRED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
be7d9ff7 | 742 | SD_BUS_PROPERTY("RequisiteOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_REQUISITE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
743 | SD_BUS_PROPERTY("WantedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_WANTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), |
744 | SD_BUS_PROPERTY("BoundBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BOUND_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
745 | SD_BUS_PROPERTY("ConsistsOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONSISTS_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
746 | SD_BUS_PROPERTY("Conflicts", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTS]), SD_BUS_VTABLE_PROPERTY_CONST), | |
747 | SD_BUS_PROPERTY("ConflictedBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_CONFLICTED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
748 | SD_BUS_PROPERTY("Before", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_BEFORE]), SD_BUS_VTABLE_PROPERTY_CONST), | |
749 | SD_BUS_PROPERTY("After", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_AFTER]), SD_BUS_VTABLE_PROPERTY_CONST), | |
750 | SD_BUS_PROPERTY("OnFailure", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_ON_FAILURE]), SD_BUS_VTABLE_PROPERTY_CONST), | |
751 | SD_BUS_PROPERTY("Triggers", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERS]), SD_BUS_VTABLE_PROPERTY_CONST), | |
752 | SD_BUS_PROPERTY("TriggeredBy", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_TRIGGERED_BY]), SD_BUS_VTABLE_PROPERTY_CONST), | |
753 | SD_BUS_PROPERTY("PropagatesReloadTo", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_PROPAGATES_RELOAD_TO]), SD_BUS_VTABLE_PROPERTY_CONST), | |
754 | SD_BUS_PROPERTY("ReloadPropagatedFrom", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_RELOAD_PROPAGATED_FROM]), SD_BUS_VTABLE_PROPERTY_CONST), | |
755 | SD_BUS_PROPERTY("JoinsNamespaceOf", "as", property_get_dependencies, offsetof(Unit, dependencies[UNIT_JOINS_NAMESPACE_OF]), SD_BUS_VTABLE_PROPERTY_CONST), | |
99c14018 | 756 | SD_BUS_PROPERTY("RequiresMountsFor", "as", property_get_requires_mounts_for, offsetof(Unit, requires_mounts_for), SD_BUS_VTABLE_PROPERTY_CONST), |
556089dc LP |
757 | SD_BUS_PROPERTY("Documentation", "as", NULL, offsetof(Unit, documentation), SD_BUS_VTABLE_PROPERTY_CONST), |
758 | SD_BUS_PROPERTY("Description", "s", property_get_description, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
759 | SD_BUS_PROPERTY("LoadState", "s", property_get_load_state, offsetof(Unit, load_state), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 LP |
760 | SD_BUS_PROPERTY("ActiveState", "s", property_get_active_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
761 | SD_BUS_PROPERTY("SubState", "s", property_get_sub_state, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
556089dc LP |
762 | SD_BUS_PROPERTY("FragmentPath", "s", NULL, offsetof(Unit, fragment_path), SD_BUS_VTABLE_PROPERTY_CONST), |
763 | SD_BUS_PROPERTY("SourcePath", "s", NULL, offsetof(Unit, source_path), SD_BUS_VTABLE_PROPERTY_CONST), | |
764 | SD_BUS_PROPERTY("DropInPaths", "as", NULL, offsetof(Unit, dropin_paths), SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 765 | SD_BUS_PROPERTY("UnitFileState", "s", property_get_unit_file_state, 0, 0), |
d2dc52db | 766 | SD_BUS_PROPERTY("UnitFilePreset", "s", property_get_unit_file_preset, 0, 0), |
a483fb59 | 767 | BUS_PROPERTY_DUAL_TIMESTAMP("StateChangeTimestamp", offsetof(Unit, state_change_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
718db961 LP |
768 | BUS_PROPERTY_DUAL_TIMESTAMP("InactiveExitTimestamp", offsetof(Unit, inactive_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
769 | BUS_PROPERTY_DUAL_TIMESTAMP("ActiveEnterTimestamp", offsetof(Unit, active_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
770 | BUS_PROPERTY_DUAL_TIMESTAMP("ActiveExitTimestamp", offsetof(Unit, active_exit_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
771 | BUS_PROPERTY_DUAL_TIMESTAMP("InactiveEnterTimestamp", offsetof(Unit, inactive_enter_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), | |
556089dc LP |
772 | SD_BUS_PROPERTY("CanStart", "b", property_get_can_start, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
773 | SD_BUS_PROPERTY("CanStop", "b", property_get_can_stop, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
774 | SD_BUS_PROPERTY("CanReload", "b", property_get_can_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
775 | SD_BUS_PROPERTY("CanIsolate", "b", property_get_can_isolate, 0, SD_BUS_VTABLE_PROPERTY_CONST), | |
718db961 | 776 | SD_BUS_PROPERTY("Job", "(uo)", property_get_job, 0, SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
556089dc LP |
777 | SD_BUS_PROPERTY("StopWhenUnneeded", "b", bus_property_get_bool, offsetof(Unit, stop_when_unneeded), SD_BUS_VTABLE_PROPERTY_CONST), |
778 | SD_BUS_PROPERTY("RefuseManualStart", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_start), SD_BUS_VTABLE_PROPERTY_CONST), | |
779 | SD_BUS_PROPERTY("RefuseManualStop", "b", bus_property_get_bool, offsetof(Unit, refuse_manual_stop), SD_BUS_VTABLE_PROPERTY_CONST), | |
780 | SD_BUS_PROPERTY("AllowIsolate", "b", bus_property_get_bool, offsetof(Unit, allow_isolate), SD_BUS_VTABLE_PROPERTY_CONST), | |
781 | SD_BUS_PROPERTY("DefaultDependencies", "b", bus_property_get_bool, offsetof(Unit, default_dependencies), SD_BUS_VTABLE_PROPERTY_CONST), | |
782 | SD_BUS_PROPERTY("OnFailureJobMode", "s", property_get_job_mode, offsetof(Unit, on_failure_job_mode), SD_BUS_VTABLE_PROPERTY_CONST), | |
783 | SD_BUS_PROPERTY("IgnoreOnIsolate", "b", bus_property_get_bool, offsetof(Unit, ignore_on_isolate), SD_BUS_VTABLE_PROPERTY_CONST), | |
556089dc LP |
784 | SD_BUS_PROPERTY("NeedDaemonReload", "b", property_get_need_daemon_reload, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
785 | SD_BUS_PROPERTY("JobTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_timeout), SD_BUS_VTABLE_PROPERTY_CONST), | |
a2df3ea4 | 786 | SD_BUS_PROPERTY("JobRunningTimeoutUSec", "t", bus_property_get_usec, offsetof(Unit, job_running_timeout), SD_BUS_VTABLE_PROPERTY_CONST), |
87a47f99 | 787 | SD_BUS_PROPERTY("JobTimeoutAction", "s", property_get_emergency_action, offsetof(Unit, job_timeout_action), SD_BUS_VTABLE_PROPERTY_CONST), |
f189ab18 | 788 | SD_BUS_PROPERTY("JobTimeoutRebootArgument", "s", NULL, offsetof(Unit, job_timeout_reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), |
718db961 | 789 | SD_BUS_PROPERTY("ConditionResult", "b", bus_property_get_bool, offsetof(Unit, condition_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
59fccdc5 | 790 | SD_BUS_PROPERTY("AssertResult", "b", bus_property_get_bool, offsetof(Unit, assert_result), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
718db961 | 791 | BUS_PROPERTY_DUAL_TIMESTAMP("ConditionTimestamp", offsetof(Unit, condition_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
59fccdc5 LP |
792 | BUS_PROPERTY_DUAL_TIMESTAMP("AssertTimestamp", offsetof(Unit, assert_timestamp), SD_BUS_VTABLE_PROPERTY_EMITS_CHANGE), |
793 | SD_BUS_PROPERTY("Conditions", "a(sbbsi)", property_get_conditions, offsetof(Unit, conditions), 0), | |
794 | SD_BUS_PROPERTY("Asserts", "a(sbbsi)", property_get_conditions, offsetof(Unit, asserts), 0), | |
556089dc LP |
795 | SD_BUS_PROPERTY("LoadError", "(ss)", property_get_load_error, 0, SD_BUS_VTABLE_PROPERTY_CONST), |
796 | SD_BUS_PROPERTY("Transient", "b", bus_property_get_bool, offsetof(Unit, transient), SD_BUS_VTABLE_PROPERTY_CONST), | |
f5869324 | 797 | SD_BUS_PROPERTY("Perpetual", "b", bus_property_get_bool, offsetof(Unit, perpetual), SD_BUS_VTABLE_PROPERTY_CONST), |
f0367da7 | 798 | SD_BUS_PROPERTY("StartLimitIntervalSec", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST), |
6bf0f408 | 799 | SD_BUS_PROPERTY("StartLimitBurst", "u", bus_property_get_unsigned, offsetof(Unit, start_limit.burst), SD_BUS_VTABLE_PROPERTY_CONST), |
87a47f99 | 800 | SD_BUS_PROPERTY("StartLimitAction", "s", property_get_emergency_action, offsetof(Unit, start_limit_action), SD_BUS_VTABLE_PROPERTY_CONST), |
6bf0f408 | 801 | SD_BUS_PROPERTY("RebootArgument", "s", NULL, offsetof(Unit, reboot_arg), SD_BUS_VTABLE_PROPERTY_CONST), |
4b58153d | 802 | SD_BUS_PROPERTY("InvocationID", "ay", bus_property_get_id128, offsetof(Unit, invocation_id), 0), |
5afe510c | 803 | SD_BUS_PROPERTY("CollectMode", "s", property_get_collect_mode, offsetof(Unit, collect_mode), 0), |
718db961 | 804 | |
1d22e906 LP |
805 | SD_BUS_METHOD("Start", "s", "o", method_start, SD_BUS_VTABLE_UNPRIVILEGED), |
806 | SD_BUS_METHOD("Stop", "s", "o", method_stop, SD_BUS_VTABLE_UNPRIVILEGED), | |
807 | SD_BUS_METHOD("Reload", "s", "o", method_reload, SD_BUS_VTABLE_UNPRIVILEGED), | |
808 | SD_BUS_METHOD("Restart", "s", "o", method_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
809 | SD_BUS_METHOD("TryRestart", "s", "o", method_try_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
810 | SD_BUS_METHOD("ReloadOrRestart", "s", "o", method_reload_or_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
811 | SD_BUS_METHOD("ReloadOrTryRestart", "s", "o", method_reload_or_try_restart, SD_BUS_VTABLE_UNPRIVILEGED), | |
812 | SD_BUS_METHOD("Kill", "si", NULL, bus_unit_method_kill, SD_BUS_VTABLE_UNPRIVILEGED), | |
813 | SD_BUS_METHOD("ResetFailed", NULL, NULL, bus_unit_method_reset_failed, SD_BUS_VTABLE_UNPRIVILEGED), | |
814 | SD_BUS_METHOD("SetProperties", "ba(sv)", NULL, bus_unit_method_set_properties, SD_BUS_VTABLE_UNPRIVILEGED), | |
05a98afd LP |
815 | SD_BUS_METHOD("Ref", NULL, NULL, bus_unit_method_ref, SD_BUS_VTABLE_UNPRIVILEGED), |
816 | SD_BUS_METHOD("Unref", NULL, NULL, bus_unit_method_unref, SD_BUS_VTABLE_UNPRIVILEGED), | |
718db961 | 817 | |
51d73fd9 LP |
818 | /* Obsolete properties or obsolete alias names */ |
819 | SD_BUS_PROPERTY("RequiresOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
820 | SD_BUS_PROPERTY("RequisiteOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
821 | SD_BUS_PROPERTY("RequiredByOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
822 | SD_BUS_PROPERTY("RequisiteOfOverridable", "as", property_get_obsolete_dependencies, 0, SD_BUS_VTABLE_HIDDEN), | |
823 | SD_BUS_PROPERTY("StartLimitInterval", "t", bus_property_get_usec, offsetof(Unit, start_limit.interval), SD_BUS_VTABLE_PROPERTY_CONST|SD_BUS_VTABLE_HIDDEN), | |
718db961 LP |
824 | SD_BUS_VTABLE_END |
825 | }; | |
2cccbca4 | 826 | |
718db961 LP |
827 | static int property_get_slice( |
828 | sd_bus *bus, | |
829 | const char *path, | |
830 | const char *interface, | |
831 | const char *property, | |
832 | sd_bus_message *reply, | |
ebcf1f97 LP |
833 | void *userdata, |
834 | sd_bus_error *error) { | |
2cccbca4 | 835 | |
718db961 | 836 | Unit *u = userdata; |
2cccbca4 | 837 | |
718db961 LP |
838 | assert(bus); |
839 | assert(reply); | |
840 | assert(u); | |
2cccbca4 | 841 | |
718db961 LP |
842 | return sd_bus_message_append(reply, "s", unit_slice_name(u)); |
843 | } | |
2cccbca4 | 844 | |
934277fe LP |
845 | static int property_get_current_memory( |
846 | sd_bus *bus, | |
847 | const char *path, | |
848 | const char *interface, | |
849 | const char *property, | |
850 | sd_bus_message *reply, | |
851 | void *userdata, | |
852 | sd_bus_error *error) { | |
853 | ||
934277fe | 854 | uint64_t sz = (uint64_t) -1; |
5ad096b3 | 855 | Unit *u = userdata; |
934277fe LP |
856 | int r; |
857 | ||
858 | assert(bus); | |
859 | assert(reply); | |
860 | assert(u); | |
861 | ||
5ad096b3 LP |
862 | r = unit_get_memory_current(u, &sz); |
863 | if (r < 0 && r != -ENODATA) | |
f2341e0a | 864 | log_unit_warning_errno(u, r, "Failed to get memory.usage_in_bytes attribute: %m"); |
934277fe | 865 | |
5ad096b3 LP |
866 | return sd_bus_message_append(reply, "t", sz); |
867 | } | |
934277fe | 868 | |
03a7b521 LP |
869 | static int property_get_current_tasks( |
870 | sd_bus *bus, | |
871 | const char *path, | |
872 | const char *interface, | |
873 | const char *property, | |
874 | sd_bus_message *reply, | |
875 | void *userdata, | |
876 | sd_bus_error *error) { | |
877 | ||
878 | uint64_t cn = (uint64_t) -1; | |
879 | Unit *u = userdata; | |
880 | int r; | |
881 | ||
882 | assert(bus); | |
883 | assert(reply); | |
884 | assert(u); | |
885 | ||
886 | r = unit_get_tasks_current(u, &cn); | |
887 | if (r < 0 && r != -ENODATA) | |
888 | log_unit_warning_errno(u, r, "Failed to get pids.current attribute: %m"); | |
889 | ||
890 | return sd_bus_message_append(reply, "t", cn); | |
891 | } | |
892 | ||
5ad096b3 LP |
893 | static int property_get_cpu_usage( |
894 | sd_bus *bus, | |
895 | const char *path, | |
896 | const char *interface, | |
897 | const char *property, | |
898 | sd_bus_message *reply, | |
899 | void *userdata, | |
900 | sd_bus_error *error) { | |
934277fe | 901 | |
5ad096b3 LP |
902 | nsec_t ns = (nsec_t) -1; |
903 | Unit *u = userdata; | |
904 | int r; | |
905 | ||
906 | assert(bus); | |
907 | assert(reply); | |
908 | assert(u); | |
909 | ||
910 | r = unit_get_cpu_usage(u, &ns); | |
911 | if (r < 0 && r != -ENODATA) | |
f2341e0a | 912 | log_unit_warning_errno(u, r, "Failed to get cpuacct.usage attribute: %m"); |
5ad096b3 LP |
913 | |
914 | return sd_bus_message_append(reply, "t", ns); | |
934277fe LP |
915 | } |
916 | ||
98bac605 LP |
917 | static int property_get_cgroup( |
918 | sd_bus *bus, | |
919 | const char *path, | |
920 | const char *interface, | |
921 | const char *property, | |
922 | sd_bus_message *reply, | |
923 | void *userdata, | |
924 | sd_bus_error *error) { | |
925 | ||
926 | Unit *u = userdata; | |
927 | const char *t; | |
928 | ||
929 | assert(bus); | |
930 | assert(reply); | |
931 | assert(u); | |
932 | ||
933 | /* Three cases: a) u->cgroup_path is NULL, in which case the | |
934 | * unit has no control group, which we report as the empty | |
935 | * string. b) u->cgroup_path is the empty string, which | |
936 | * indicates the root cgroup, which we report as "/". c) all | |
937 | * other cases we report as-is. */ | |
938 | ||
939 | if (u->cgroup_path) | |
940 | t = isempty(u->cgroup_path) ? "/" : u->cgroup_path; | |
941 | else | |
942 | t = ""; | |
943 | ||
944 | return sd_bus_message_append(reply, "s", t); | |
945 | } | |
946 | ||
291d565a LP |
947 | static int append_process(sd_bus_message *reply, const char *p, pid_t pid, Set *pids) { |
948 | _cleanup_free_ char *buf = NULL, *cmdline = NULL; | |
949 | int r; | |
950 | ||
951 | assert(reply); | |
952 | assert(pid > 0); | |
953 | ||
954 | r = set_put(pids, PID_TO_PTR(pid)); | |
4c701096 | 955 | if (IN_SET(r, 0, -EEXIST)) |
291d565a LP |
956 | return 0; |
957 | if (r < 0) | |
958 | return r; | |
959 | ||
960 | if (!p) { | |
961 | r = cg_pid_get_path(SYSTEMD_CGROUP_CONTROLLER, pid, &buf); | |
962 | if (r == -ESRCH) | |
963 | return 0; | |
964 | if (r < 0) | |
965 | return r; | |
966 | ||
967 | p = buf; | |
968 | } | |
969 | ||
970 | (void) get_process_cmdline(pid, 0, true, &cmdline); | |
971 | ||
972 | return sd_bus_message_append(reply, | |
973 | "(sus)", | |
974 | p, | |
975 | (uint32_t) pid, | |
976 | cmdline); | |
977 | } | |
978 | ||
979 | static int append_cgroup(sd_bus_message *reply, const char *p, Set *pids) { | |
980 | _cleanup_closedir_ DIR *d = NULL; | |
981 | _cleanup_fclose_ FILE *f = NULL; | |
982 | int r; | |
983 | ||
984 | assert(reply); | |
985 | assert(p); | |
986 | ||
987 | r = cg_enumerate_processes(SYSTEMD_CGROUP_CONTROLLER, p, &f); | |
988 | if (r == ENOENT) | |
989 | return 0; | |
990 | if (r < 0) | |
991 | return r; | |
992 | ||
993 | for (;;) { | |
994 | pid_t pid; | |
995 | ||
996 | r = cg_read_pid(f, &pid); | |
997 | if (r < 0) | |
998 | return r; | |
999 | if (r == 0) | |
1000 | break; | |
1001 | ||
1002 | if (is_kernel_thread(pid) > 0) | |
1003 | continue; | |
1004 | ||
1005 | r = append_process(reply, p, pid, pids); | |
1006 | if (r < 0) | |
1007 | return r; | |
1008 | } | |
1009 | ||
1010 | r = cg_enumerate_subgroups(SYSTEMD_CGROUP_CONTROLLER, p, &d); | |
1011 | if (r == -ENOENT) | |
1012 | return 0; | |
1013 | if (r < 0) | |
1014 | return r; | |
1015 | ||
1016 | for (;;) { | |
1017 | _cleanup_free_ char *g = NULL, *j = NULL; | |
1018 | ||
1019 | r = cg_read_subgroup(d, &g); | |
1020 | if (r < 0) | |
1021 | return r; | |
1022 | if (r == 0) | |
1023 | break; | |
1024 | ||
605405c6 | 1025 | j = strjoin(p, "/", g); |
291d565a LP |
1026 | if (!j) |
1027 | return -ENOMEM; | |
1028 | ||
1029 | r = append_cgroup(reply, j, pids); | |
1030 | if (r < 0) | |
1031 | return r; | |
1032 | } | |
1033 | ||
1034 | return 0; | |
1035 | } | |
1036 | ||
1037 | int bus_unit_method_get_processes(sd_bus_message *message, void *userdata, sd_bus_error *error) { | |
1038 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *reply = NULL; | |
1039 | _cleanup_(set_freep) Set *pids = NULL; | |
291d565a LP |
1040 | Unit *u = userdata; |
1041 | pid_t pid; | |
1042 | int r; | |
1043 | ||
1044 | assert(message); | |
1045 | ||
807fa5d9 LP |
1046 | r = mac_selinux_unit_access_check(u, message, "status", error); |
1047 | if (r < 0) | |
1048 | return r; | |
1049 | ||
291d565a LP |
1050 | pids = set_new(NULL); |
1051 | if (!pids) | |
1052 | return -ENOMEM; | |
1053 | ||
1054 | r = sd_bus_message_new_method_return(message, &reply); | |
1055 | if (r < 0) | |
1056 | return r; | |
1057 | ||
1058 | r = sd_bus_message_open_container(reply, 'a', "(sus)"); | |
1059 | if (r < 0) | |
1060 | return r; | |
1061 | ||
1062 | if (u->cgroup_path) { | |
1063 | r = append_cgroup(reply, u->cgroup_path, pids); | |
1064 | if (r < 0) | |
1065 | return r; | |
1066 | } | |
1067 | ||
1068 | /* The main and control pids might live outside of the cgroup, hence fetch them separately */ | |
1069 | pid = unit_main_pid(u); | |
1070 | if (pid > 0) { | |
1071 | r = append_process(reply, NULL, pid, pids); | |
1072 | if (r < 0) | |
1073 | return r; | |
1074 | } | |
1075 | ||
1076 | pid = unit_control_pid(u); | |
1077 | if (pid > 0) { | |
1078 | r = append_process(reply, NULL, pid, pids); | |
1079 | if (r < 0) | |
1080 | return r; | |
1081 | } | |
1082 | ||
1083 | r = sd_bus_message_close_container(reply); | |
1084 | if (r < 0) | |
1085 | return r; | |
1086 | ||
1087 | return sd_bus_send(NULL, reply, NULL); | |
1088 | } | |
1089 | ||
906c06f6 DM |
1090 | static int property_get_ip_counter( |
1091 | sd_bus *bus, | |
1092 | const char *path, | |
1093 | const char *interface, | |
1094 | const char *property, | |
1095 | sd_bus_message *reply, | |
1096 | void *userdata, | |
1097 | sd_bus_error *error) { | |
1098 | ||
1099 | CGroupIPAccountingMetric metric; | |
1100 | uint64_t value = (uint64_t) -1; | |
1101 | Unit *u = userdata; | |
1102 | ||
1103 | assert(bus); | |
1104 | assert(reply); | |
1105 | assert(property); | |
1106 | assert(u); | |
1107 | ||
1108 | if (streq(property, "IPIngressBytes")) | |
1109 | metric = CGROUP_IP_INGRESS_BYTES; | |
1110 | else if (streq(property, "IPIngressPackets")) | |
1111 | metric = CGROUP_IP_INGRESS_PACKETS; | |
1112 | else if (streq(property, "IPEgressBytes")) | |
1113 | metric = CGROUP_IP_EGRESS_BYTES; | |
1114 | else { | |
1115 | assert(streq(property, "IPEgressPackets")); | |
1116 | metric = CGROUP_IP_EGRESS_PACKETS; | |
1117 | } | |
1118 | ||
1119 | (void) unit_get_ip_accounting(u, metric, &value); | |
1120 | return sd_bus_message_append(reply, "t", value); | |
1121 | } | |
1122 | ||
718db961 LP |
1123 | const sd_bus_vtable bus_unit_cgroup_vtable[] = { |
1124 | SD_BUS_VTABLE_START(0), | |
1125 | SD_BUS_PROPERTY("Slice", "s", property_get_slice, 0, 0), | |
98bac605 | 1126 | SD_BUS_PROPERTY("ControlGroup", "s", property_get_cgroup, 0, 0), |
934277fe | 1127 | SD_BUS_PROPERTY("MemoryCurrent", "t", property_get_current_memory, 0, 0), |
5ad096b3 | 1128 | SD_BUS_PROPERTY("CPUUsageNSec", "t", property_get_cpu_usage, 0, 0), |
03a7b521 | 1129 | SD_BUS_PROPERTY("TasksCurrent", "t", property_get_current_tasks, 0, 0), |
906c06f6 DM |
1130 | SD_BUS_PROPERTY("IPIngressBytes", "t", property_get_ip_counter, 0, 0), |
1131 | SD_BUS_PROPERTY("IPIngressPackets", "t", property_get_ip_counter, 0, 0), | |
1132 | SD_BUS_PROPERTY("IPEgressBytes", "t", property_get_ip_counter, 0, 0), | |
1133 | SD_BUS_PROPERTY("IPEgressPackets", "t", property_get_ip_counter, 0, 0), | |
291d565a | 1134 | SD_BUS_METHOD("GetProcesses", NULL, "a(sus)", bus_unit_method_get_processes, SD_BUS_VTABLE_UNPRIVILEGED), |
718db961 LP |
1135 | SD_BUS_VTABLE_END |
1136 | }; | |
2cccbca4 | 1137 | |
8f8f05a9 | 1138 | static int send_new_signal(sd_bus *bus, void *userdata) { |
4afd3348 | 1139 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
718db961 LP |
1140 | _cleanup_free_ char *p = NULL; |
1141 | Unit *u = userdata; | |
1142 | int r; | |
2cccbca4 | 1143 | |
718db961 LP |
1144 | assert(bus); |
1145 | assert(u); | |
2cccbca4 | 1146 | |
718db961 | 1147 | p = unit_dbus_path(u); |
e861098b | 1148 | if (!p) |
718db961 | 1149 | return -ENOMEM; |
2cccbca4 | 1150 | |
718db961 LP |
1151 | r = sd_bus_message_new_signal( |
1152 | bus, | |
151b9b96 | 1153 | &m, |
718db961 LP |
1154 | "/org/freedesktop/systemd1", |
1155 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 1156 | "UnitNew"); |
718db961 LP |
1157 | if (r < 0) |
1158 | return r; | |
2cccbca4 | 1159 | |
718db961 LP |
1160 | r = sd_bus_message_append(m, "so", u->id, p); |
1161 | if (r < 0) | |
1162 | return r; | |
2cccbca4 | 1163 | |
8f8f05a9 | 1164 | return sd_bus_send(bus, m, NULL); |
718db961 | 1165 | } |
2cccbca4 | 1166 | |
8f8f05a9 | 1167 | static int send_changed_signal(sd_bus *bus, void *userdata) { |
718db961 LP |
1168 | _cleanup_free_ char *p = NULL; |
1169 | Unit *u = userdata; | |
1170 | int r; | |
2cccbca4 | 1171 | |
718db961 LP |
1172 | assert(bus); |
1173 | assert(u); | |
2cccbca4 | 1174 | |
718db961 | 1175 | p = unit_dbus_path(u); |
9ceefc81 | 1176 | if (!p) |
718db961 | 1177 | return -ENOMEM; |
2cccbca4 | 1178 | |
718db961 LP |
1179 | /* Send a properties changed signal. First for the specific |
1180 | * type, then for the generic unit. The clients may rely on | |
1181 | * this order to get atomic behavior if needed. */ | |
ea430986 | 1182 | |
aec8de63 LP |
1183 | r = sd_bus_emit_properties_changed_strv( |
1184 | bus, p, | |
21b735e7 | 1185 | unit_dbus_interface_from_type(u->type), |
aec8de63 | 1186 | NULL); |
fe7f06f1 | 1187 | if (r < 0) |
aec8de63 | 1188 | return r; |
80fbf05e | 1189 | |
fe7f06f1 | 1190 | return sd_bus_emit_properties_changed_strv( |
718db961 LP |
1191 | bus, p, |
1192 | "org.freedesktop.systemd1.Unit", | |
718db961 | 1193 | NULL); |
ea430986 LP |
1194 | } |
1195 | ||
c1e1601e | 1196 | void bus_unit_send_change_signal(Unit *u) { |
b170dd80 | 1197 | int r; |
c1e1601e | 1198 | assert(u); |
c1e1601e | 1199 | |
ac155bb8 | 1200 | if (u->in_dbus_queue) { |
71fda00f | 1201 | LIST_REMOVE(dbus_queue, u->manager->dbus_unit_queue, u); |
ac155bb8 | 1202 | u->in_dbus_queue = false; |
c0bd0cf7 | 1203 | } |
c1e1601e | 1204 | |
ac155bb8 | 1205 | if (!u->id) |
04ade7d2 LP |
1206 | return; |
1207 | ||
ae572acd | 1208 | r = bus_foreach_bus(u->manager, u->bus_track, u->sent_dbus_new_signal ? send_changed_signal : send_new_signal, u); |
718db961 | 1209 | if (r < 0) |
f2341e0a | 1210 | log_unit_debug_errno(u, r, "Failed to send unit change signal for %s: %m", u->id); |
c1e1601e | 1211 | |
718db961 LP |
1212 | u->sent_dbus_new_signal = true; |
1213 | } | |
c4e2ceae | 1214 | |
8f8f05a9 | 1215 | static int send_removed_signal(sd_bus *bus, void *userdata) { |
4afd3348 | 1216 | _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL; |
718db961 LP |
1217 | _cleanup_free_ char *p = NULL; |
1218 | Unit *u = userdata; | |
1219 | int r; | |
c4e2ceae | 1220 | |
718db961 LP |
1221 | assert(bus); |
1222 | assert(u); | |
c1e1601e | 1223 | |
718db961 | 1224 | p = unit_dbus_path(u); |
e861098b | 1225 | if (!p) |
718db961 | 1226 | return -ENOMEM; |
c1e1601e | 1227 | |
718db961 LP |
1228 | r = sd_bus_message_new_signal( |
1229 | bus, | |
151b9b96 | 1230 | &m, |
718db961 LP |
1231 | "/org/freedesktop/systemd1", |
1232 | "org.freedesktop.systemd1.Manager", | |
151b9b96 | 1233 | "UnitRemoved"); |
718db961 LP |
1234 | if (r < 0) |
1235 | return r; | |
c1e1601e | 1236 | |
718db961 LP |
1237 | r = sd_bus_message_append(m, "so", u->id, p); |
1238 | if (r < 0) | |
1239 | return r; | |
c1e1601e | 1240 | |
8f8f05a9 | 1241 | return sd_bus_send(bus, m, NULL); |
c1e1601e LP |
1242 | } |
1243 | ||
1244 | void bus_unit_send_removed_signal(Unit *u) { | |
718db961 | 1245 | int r; |
c1e1601e LP |
1246 | assert(u); |
1247 | ||
0dd99f86 | 1248 | if (!u->sent_dbus_new_signal || u->in_dbus_queue) |
7535cc78 LP |
1249 | bus_unit_send_change_signal(u); |
1250 | ||
ac155bb8 | 1251 | if (!u->id) |
04ade7d2 LP |
1252 | return; |
1253 | ||
ae572acd | 1254 | r = bus_foreach_bus(u->manager, u->bus_track, send_removed_signal, u); |
718db961 | 1255 | if (r < 0) |
f2341e0a | 1256 | log_unit_debug_errno(u, r, "Failed to send unit remove signal for %s: %m", u->id); |
c1e1601e | 1257 | } |
e2110e5d | 1258 | |
718db961 | 1259 | int bus_unit_queue_job( |
718db961 | 1260 | sd_bus_message *message, |
cad45ba1 LP |
1261 | Unit *u, |
1262 | JobType type, | |
1263 | JobMode mode, | |
ebcf1f97 LP |
1264 | bool reload_if_possible, |
1265 | sd_bus_error *error) { | |
cad45ba1 | 1266 | |
cad45ba1 LP |
1267 | _cleanup_free_ char *path = NULL; |
1268 | Job *j; | |
cad45ba1 LP |
1269 | int r; |
1270 | ||
cad45ba1 LP |
1271 | assert(message); |
1272 | assert(u); | |
1273 | assert(type >= 0 && type < _JOB_TYPE_MAX); | |
1274 | assert(mode >= 0 && mode < _JOB_MODE_MAX); | |
1275 | ||
f596e00f EV |
1276 | r = mac_selinux_unit_access_check( |
1277 | u, message, | |
1278 | job_type_to_access_method(type), | |
1279 | error); | |
1280 | if (r < 0) | |
1281 | return r; | |
1282 | ||
cad45ba1 LP |
1283 | if (reload_if_possible && unit_can_reload(u)) { |
1284 | if (type == JOB_RESTART) | |
1285 | type = JOB_RELOAD_OR_START; | |
1286 | else if (type == JOB_TRY_RESTART) | |
3282591d | 1287 | type = JOB_TRY_RELOAD; |
cad45ba1 LP |
1288 | } |
1289 | ||
718db961 | 1290 | if (type == JOB_STOP && |
3742095b | 1291 | (IN_SET(u->load_state, UNIT_NOT_FOUND, UNIT_ERROR)) && |
718db961 | 1292 | unit_active_state(u) == UNIT_INACTIVE) |
ebcf1f97 | 1293 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not loaded.", u->id); |
cad45ba1 LP |
1294 | |
1295 | if ((type == JOB_START && u->refuse_manual_start) || | |
1296 | (type == JOB_STOP && u->refuse_manual_stop) || | |
3742095b | 1297 | (IN_SET(type, JOB_RESTART, JOB_TRY_RESTART) && (u->refuse_manual_start || u->refuse_manual_stop)) || |
efb30ba1 | 1298 | (type == JOB_RELOAD_OR_START && job_type_collapse(type, u) == JOB_START && u->refuse_manual_start)) |
7e974e85 | 1299 | return sd_bus_error_setf(error, BUS_ERROR_ONLY_BY_DEPENDENCY, "Operation refused, unit %s may be requested by dependency only (it is configured to refuse manual start/stop).", u->id); |
cad45ba1 | 1300 | |
4bd29fe5 | 1301 | r = manager_add_job(u->manager, type, u, mode, error, &j); |
cad45ba1 | 1302 | if (r < 0) |
ebcf1f97 | 1303 | return r; |
cad45ba1 | 1304 | |
c5a97ed1 LP |
1305 | r = bus_job_track_sender(j, message); |
1306 | if (r < 0) | |
1307 | return r; | |
cad45ba1 LP |
1308 | |
1309 | path = job_dbus_path(j); | |
1310 | if (!path) | |
6ce270b1 | 1311 | return -ENOMEM; |
cad45ba1 | 1312 | |
df2d202e | 1313 | return sd_bus_reply_method_return(message, "o", path); |
cad45ba1 LP |
1314 | } |
1315 | ||
9f2e86af LP |
1316 | static int bus_unit_set_transient_property( |
1317 | Unit *u, | |
1318 | const char *name, | |
718db961 | 1319 | sd_bus_message *message, |
9f2e86af | 1320 | UnitSetPropertiesMode mode, |
718db961 | 1321 | sd_bus_error *error) { |
9f2e86af LP |
1322 | |
1323 | int r; | |
1324 | ||
1325 | assert(u); | |
1326 | assert(name); | |
718db961 | 1327 | assert(message); |
9f2e86af LP |
1328 | |
1329 | if (streq(name, "Description")) { | |
718db961 | 1330 | const char *d; |
9f2e86af | 1331 | |
718db961 LP |
1332 | r = sd_bus_message_read(message, "s", &d); |
1333 | if (r < 0) | |
1334 | return r; | |
8aec412f | 1335 | |
718db961 LP |
1336 | if (mode != UNIT_CHECK) { |
1337 | r = unit_set_description(u, d); | |
8aec412f LP |
1338 | if (r < 0) |
1339 | return r; | |
b9316fb0 | 1340 | |
b27b4b51 | 1341 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDescription=%s", d); |
8aec412f | 1342 | } |
9f2e86af LP |
1343 | |
1344 | return 1; | |
261420ba LP |
1345 | |
1346 | } else if (streq(name, "DefaultDependencies")) { | |
1347 | int b; | |
1348 | ||
1349 | r = sd_bus_message_read(message, "b", &b); | |
1350 | if (r < 0) | |
1351 | return r; | |
1352 | ||
1353 | if (mode != UNIT_CHECK) { | |
1354 | u->default_dependencies = b; | |
b27b4b51 | 1355 | unit_write_drop_in_format(u, mode, name, "[Unit]\nDefaultDependencies=%s", yes_no(b)); |
261420ba LP |
1356 | } |
1357 | ||
1358 | return 1; | |
c221420b | 1359 | |
5afe510c LP |
1360 | } else if (streq(name, "CollectMode")) { |
1361 | const char *s; | |
1362 | CollectMode m; | |
1363 | ||
1364 | r = sd_bus_message_read(message, "s", &s); | |
1365 | if (r < 0) | |
1366 | return r; | |
1367 | ||
1368 | m = collect_mode_from_string(s); | |
1369 | if (m < 0) | |
1370 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unknown garbage collection mode: %s", s); | |
1371 | ||
1372 | if (mode != UNIT_CHECK) { | |
1373 | u->collect_mode = m; | |
1374 | unit_write_drop_in_format(u, mode, name, "[Unit]\nCollectMode=%s", collect_mode_to_string(m)); | |
1375 | } | |
1376 | ||
1377 | return 1; | |
1378 | ||
d79200e2 LP |
1379 | } else if (streq(name, "Slice")) { |
1380 | Unit *slice; | |
c221420b | 1381 | const char *s; |
c221420b | 1382 | |
d79200e2 LP |
1383 | if (!UNIT_HAS_CGROUP_CONTEXT(u)) |
1384 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "The slice property is only available for units with control groups."); | |
1385 | if (u->type == UNIT_SLICE) | |
1386 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Slice may not be set for slice units."); | |
efdb0237 LP |
1387 | if (unit_has_name(u, SPECIAL_INIT_SCOPE)) |
1388 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Cannot set slice for init.scope"); | |
d79200e2 | 1389 | |
718db961 LP |
1390 | r = sd_bus_message_read(message, "s", &s); |
1391 | if (r < 0) | |
1392 | return r; | |
c221420b | 1393 | |
d79200e2 LP |
1394 | if (!unit_name_is_valid(s, UNIT_NAME_PLAIN)) |
1395 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name '%s'", s); | |
1396 | ||
aea529e5 LP |
1397 | /* Note that we do not dispatch the load queue here yet, as we don't want our own transient unit to be |
1398 | * loaded while we are still setting it up. Or in other words, we use manager_load_unit_prepare() | |
1399 | * instead of manager_load_unit() on purpose, here. */ | |
1400 | r = manager_load_unit_prepare(u->manager, s, NULL, error, &slice); | |
d79200e2 LP |
1401 | if (r < 0) |
1402 | return r; | |
c221420b | 1403 | |
d79200e2 LP |
1404 | if (slice->type != UNIT_SLICE) |
1405 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Unit name '%s' is not a slice", s); | |
b9316fb0 | 1406 | |
d79200e2 LP |
1407 | if (mode != UNIT_CHECK) { |
1408 | r = unit_set_slice(u, slice); | |
8aec412f LP |
1409 | if (r < 0) |
1410 | return r; | |
c221420b | 1411 | |
b27b4b51 | 1412 | unit_write_drop_in_private_format(u, mode, name, "Slice=%s", s); |
8aec412f | 1413 | } |
b9ec9359 | 1414 | |
c221420b | 1415 | return 1; |
d79200e2 | 1416 | |
311f6cf3 WC |
1417 | } else if (STR_IN_SET(name, |
1418 | "Requires", "RequiresOverridable", | |
1419 | "Requisite", "RequisiteOverridable", | |
1420 | "Wants", | |
1421 | "BindsTo", | |
1422 | "Conflicts", | |
1423 | "Before", "After", | |
1424 | "OnFailure", | |
1425 | "PropagatesReloadTo", "ReloadPropagatedFrom", | |
1426 | "PartOf")) { | |
7fb3ee51 LP |
1427 | |
1428 | UnitDependency d; | |
718db961 | 1429 | const char *other; |
7fb3ee51 | 1430 | |
f32b43bd LP |
1431 | if (streq(name, "RequiresOverridable")) |
1432 | d = UNIT_REQUIRES; /* redirect for obsolete unit dependency type */ | |
1433 | else if (streq(name, "RequisiteOverridable")) | |
1434 | d = UNIT_REQUISITE; /* same here */ | |
1435 | else { | |
1436 | d = unit_dependency_from_string(name); | |
1437 | if (d < 0) | |
1438 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit dependency: %s", name); | |
1439 | } | |
7fb3ee51 | 1440 | |
718db961 LP |
1441 | r = sd_bus_message_enter_container(message, 'a', "s"); |
1442 | if (r < 0) | |
1443 | return r; | |
7fb3ee51 | 1444 | |
718db961 | 1445 | while ((r = sd_bus_message_read(message, "s", &other)) > 0) { |
7410616c | 1446 | if (!unit_name_is_valid(other, UNIT_NAME_PLAIN|UNIT_NAME_INSTANCE)) |
718db961 | 1447 | return sd_bus_error_setf(error, SD_BUS_ERROR_INVALID_ARGS, "Invalid unit name %s", other); |
7fb3ee51 LP |
1448 | |
1449 | if (mode != UNIT_CHECK) { | |
b9ec9359 | 1450 | _cleanup_free_ char *label = NULL; |
7fb3ee51 | 1451 | |
eef85c4a | 1452 | r = unit_add_dependency_by_name(u, d, other, NULL, true, UNIT_DEPENDENCY_FILE); |
7fb3ee51 LP |
1453 | if (r < 0) |
1454 | return r; | |
1455 | ||
605405c6 | 1456 | label = strjoin(name, "-", other); |
7fb3ee51 LP |
1457 | if (!label) |
1458 | return -ENOMEM; | |
1459 | ||
b27b4b51 | 1460 | unit_write_drop_in_format(u, mode, label, "[Unit]\n%s=%s", name, other); |
7fb3ee51 LP |
1461 | } |
1462 | ||
7fb3ee51 | 1463 | } |
718db961 LP |
1464 | if (r < 0) |
1465 | return r; | |
7fb3ee51 | 1466 | |
6ce270b1 LP |
1467 | r = sd_bus_message_exit_container(message); |
1468 | if (r < 0) | |
1469 | return r; | |
1470 | ||
7fb3ee51 | 1471 | return 1; |
05a98afd LP |
1472 | |
1473 | } else if (streq(name, "AddRef")) { | |
1474 | ||
1475 | int b; | |
1476 | ||
1477 | /* Why is this called "AddRef" rather than just "Ref", or "Reference"? There's already a "Ref()" method | |
1478 | * on the Unit interface, and it's probably not a good idea to expose a property and a method on the | |
1479 | * same interface (well, strictly speaking AddRef isn't exposed as full property, we just read it for | |
1480 | * transient units, but still). And "References" and "ReferencedBy" is already used as unit reference | |
1481 | * dependency type, hence let's not confuse things with that. | |
1482 | * | |
1483 | * Note that we don't acually add the reference to the bus track. We do that only after the setup of | |
1484 | * the transient unit is complete, so that setting this property multiple times in the same transient | |
1485 | * unit creation call doesn't count as individual references. */ | |
1486 | ||
1487 | r = sd_bus_message_read(message, "b", &b); | |
1488 | if (r < 0) | |
1489 | return r; | |
1490 | ||
1491 | if (mode != UNIT_CHECK) | |
1492 | u->bus_track_add = b; | |
1493 | ||
1494 | return 1; | |
9f2e86af LP |
1495 | } |
1496 | ||
1497 | return 0; | |
1498 | } | |
1499 | ||
c2756a68 LP |
1500 | int bus_unit_set_properties( |
1501 | Unit *u, | |
718db961 | 1502 | sd_bus_message *message, |
c2756a68 LP |
1503 | UnitSetPropertiesMode mode, |
1504 | bool commit, | |
718db961 | 1505 | sd_bus_error *error) { |
c2756a68 | 1506 | |
8e2af478 | 1507 | bool for_real = false; |
8e2af478 LP |
1508 | unsigned n = 0; |
1509 | int r; | |
1510 | ||
1511 | assert(u); | |
718db961 | 1512 | assert(message); |
8e2af478 LP |
1513 | |
1514 | /* We iterate through the array twice. First run we just check | |
1515 | * if all passed data is valid, second run actually applies | |
1516 | * it. This is to implement transaction-like behaviour without | |
1517 | * actually providing full transactions. */ | |
1518 | ||
718db961 LP |
1519 | r = sd_bus_message_enter_container(message, 'a', "(sv)"); |
1520 | if (r < 0) | |
1521 | return r; | |
8e2af478 | 1522 | |
8e2af478 | 1523 | for (;;) { |
8e2af478 LP |
1524 | const char *name; |
1525 | ||
718db961 LP |
1526 | r = sd_bus_message_enter_container(message, 'r', "sv"); |
1527 | if (r < 0) | |
1528 | return r; | |
1529 | if (r == 0) { | |
a255a7f1 | 1530 | if (for_real || mode == UNIT_CHECK) |
8e2af478 LP |
1531 | break; |
1532 | ||
1533 | /* Reached EOF. Let's try again, and this time for realz... */ | |
718db961 LP |
1534 | r = sd_bus_message_rewind(message, false); |
1535 | if (r < 0) | |
1536 | return r; | |
6ce270b1 | 1537 | |
8e2af478 LP |
1538 | for_real = true; |
1539 | continue; | |
1540 | } | |
1541 | ||
718db961 LP |
1542 | r = sd_bus_message_read(message, "s", &name); |
1543 | if (r < 0) | |
1544 | return r; | |
8e2af478 | 1545 | |
718db961 LP |
1546 | if (!UNIT_VTABLE(u)->bus_set_property) |
1547 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Objects of this type do not support setting properties."); | |
8e2af478 | 1548 | |
718db961 LP |
1549 | r = sd_bus_message_enter_container(message, 'v', NULL); |
1550 | if (r < 0) | |
1551 | return r; | |
8e2af478 | 1552 | |
718db961 | 1553 | r = UNIT_VTABLE(u)->bus_set_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
9f2e86af | 1554 | if (r == 0 && u->transient && u->load_state == UNIT_STUB) |
718db961 LP |
1555 | r = bus_unit_set_transient_property(u, name, message, for_real ? mode : UNIT_CHECK, error); |
1556 | if (r < 0) | |
1557 | return r; | |
1558 | if (r == 0) | |
1559 | return sd_bus_error_setf(error, SD_BUS_ERROR_PROPERTY_READ_ONLY, "Cannot set property %s, or unknown property.", name); | |
1560 | ||
1561 | r = sd_bus_message_exit_container(message); | |
8e2af478 LP |
1562 | if (r < 0) |
1563 | return r; | |
8e2af478 | 1564 | |
718db961 LP |
1565 | r = sd_bus_message_exit_container(message); |
1566 | if (r < 0) | |
1567 | return r; | |
8e2af478 LP |
1568 | |
1569 | n += for_real; | |
1570 | } | |
1571 | ||
6ce270b1 LP |
1572 | r = sd_bus_message_exit_container(message); |
1573 | if (r < 0) | |
1574 | return r; | |
1575 | ||
c2756a68 | 1576 | if (commit && n > 0 && UNIT_VTABLE(u)->bus_commit_properties) |
8e2af478 LP |
1577 | UNIT_VTABLE(u)->bus_commit_properties(u); |
1578 | ||
241da328 | 1579 | return n; |
8e2af478 | 1580 | } |
000a996d FB |
1581 | |
1582 | int bus_unit_check_load_state(Unit *u, sd_bus_error *error) { | |
6eb7c172 | 1583 | assert(u); |
000a996d FB |
1584 | |
1585 | if (u->load_state == UNIT_LOADED) | |
1586 | return 0; | |
1587 | ||
1588 | /* Give a better description of the unit error when | |
1589 | * possible. Note that in the case of UNIT_MASKED, load_error | |
1590 | * is not set. */ | |
1591 | if (u->load_state == UNIT_MASKED) | |
b21d2f81 | 1592 | return sd_bus_error_setf(error, BUS_ERROR_UNIT_MASKED, "Unit %s is masked.", u->id); |
000a996d FB |
1593 | |
1594 | if (u->load_state == UNIT_NOT_FOUND) | |
b21d2f81 | 1595 | return sd_bus_error_setf(error, BUS_ERROR_NO_SUCH_UNIT, "Unit %s not found.", u->id); |
000a996d | 1596 | |
b21d2f81 | 1597 | return sd_bus_error_set_errnof(error, u->load_error, "Unit %s is not loaded properly: %m.", u->id); |
000a996d | 1598 | } |
05a98afd | 1599 | |
c5a97ed1 | 1600 | static int bus_unit_track_handler(sd_bus_track *t, void *userdata) { |
05a98afd LP |
1601 | Unit *u = userdata; |
1602 | ||
1603 | assert(t); | |
1604 | assert(u); | |
1605 | ||
1606 | u->bus_track = sd_bus_track_unref(u->bus_track); /* make sure we aren't called again */ | |
1607 | ||
1608 | unit_add_to_gc_queue(u); | |
1609 | return 0; | |
1610 | } | |
1611 | ||
c5a97ed1 | 1612 | static int bus_unit_allocate_bus_track(Unit *u) { |
05a98afd LP |
1613 | int r; |
1614 | ||
1615 | assert(u); | |
1616 | ||
1617 | if (u->bus_track) | |
1618 | return 0; | |
1619 | ||
c5a97ed1 | 1620 | r = sd_bus_track_new(u->manager->api_bus, &u->bus_track, bus_unit_track_handler, u); |
05a98afd LP |
1621 | if (r < 0) |
1622 | return r; | |
1623 | ||
1624 | r = sd_bus_track_set_recursive(u->bus_track, true); | |
1625 | if (r < 0) { | |
1626 | u->bus_track = sd_bus_track_unref(u->bus_track); | |
1627 | return r; | |
1628 | } | |
1629 | ||
1630 | return 0; | |
1631 | } | |
1632 | ||
1633 | int bus_unit_track_add_name(Unit *u, const char *name) { | |
1634 | int r; | |
1635 | ||
1636 | assert(u); | |
1637 | ||
c5a97ed1 | 1638 | r = bus_unit_allocate_bus_track(u); |
05a98afd LP |
1639 | if (r < 0) |
1640 | return r; | |
1641 | ||
1642 | return sd_bus_track_add_name(u->bus_track, name); | |
1643 | } | |
1644 | ||
1645 | int bus_unit_track_add_sender(Unit *u, sd_bus_message *m) { | |
1646 | int r; | |
1647 | ||
1648 | assert(u); | |
1649 | ||
c5a97ed1 | 1650 | r = bus_unit_allocate_bus_track(u); |
05a98afd LP |
1651 | if (r < 0) |
1652 | return r; | |
1653 | ||
1654 | return sd_bus_track_add_sender(u->bus_track, m); | |
1655 | } | |
1656 | ||
1657 | int bus_unit_track_remove_sender(Unit *u, sd_bus_message *m) { | |
1658 | assert(u); | |
1659 | ||
1660 | /* If we haven't allocated the bus track object yet, then there's definitely no reference taken yet, return an | |
1661 | * error */ | |
1662 | if (!u->bus_track) | |
1663 | return -EUNATCH; | |
1664 | ||
1665 | return sd_bus_track_remove_sender(u->bus_track, m); | |
1666 | } |