]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
build(deps): bump pkg/arch from `b13e94a` to `b578e90`
[thirdparty/systemd.git] / src / shared / bus-unit-util.c
CommitLineData
db9ecf05 1/* SPDX-License-Identifier: LGPL-2.1-or-later */
291d565a 2
a4817536 3#include "af-list.h"
291d565a 4#include "alloc-util.h"
e45c81b8 5#include "bus-error.h"
a9399358 6#include "bus-locator.h"
291d565a
LP
7#include "bus-unit-util.h"
8#include "bus-util.h"
cffaed83 9#include "cap-list.h"
fdb3deca 10#include "cgroup-setup.h"
291d565a 11#include "cgroup-util.h"
3d63c749 12#include "condition.h"
ad21e542 13#include "coredump-util.h"
cffaed83 14#include "cpu-set-util.h"
9ece6444 15#include "dissect-image.h"
291d565a 16#include "escape.h"
b3d59367 17#include "exec-util.h"
2e2ed880 18#include "exit-status.h"
0389f4fa 19#include "fileio.h"
dc7d69b3 20#include "firewall-util.h"
08f3be7a 21#include "hexdecoct.h"
3dc5ca97
LP
22#include "hostname-util.h"
23#include "in-addr-util.h"
032b3afb 24#include "ioprio-util.h"
da96ad5a 25#include "ip-protocol-list.h"
b3d13314 26#include "libmount-util.h"
291d565a 27#include "locale-util.h"
e45c81b8 28#include "log.h"
211a3d87 29#include "macro.h"
89382935 30#include "missing_fs.h"
049af8ad 31#include "mountpoint-util.h"
add00535 32#include "nsflags.h"
1808f768 33#include "numa-util.h"
cd48e23f 34#include "open-file.h"
3fb72d63 35#include "parse-helpers.h"
291d565a 36#include "parse-util.h"
0389f4fa 37#include "path-util.h"
ed5033fd 38#include "percent-util.h"
291d565a
LP
39#include "process-util.h"
40#include "rlimit-util.h"
005bfaf1 41#include "seccomp-util.h"
cffaed83 42#include "securebits-util.h"
291d565a 43#include "signal-util.h"
e45c81b8 44#include "socket-util.h"
760877e9 45#include "sort-util.h"
e2b2fb7f 46#include "stdio-util.h"
291d565a
LP
47#include "string-util.h"
48#include "syslog-util.h"
49#include "terminal-util.h"
89ada3ba 50#include "unit-def.h"
cffaed83 51#include "user-util.h"
291d565a 52#include "utf8.h"
291d565a 53
20b16441
LP
54int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
55 assert(message);
56 assert(u);
57
58 u->machine = NULL;
59
60 return sd_bus_message_read(
61 message,
62 "(ssssssouso)",
63 &u->id,
64 &u->description,
65 &u->load_state,
66 &u->active_state,
67 &u->sub_state,
68 &u->following,
69 &u->unit_path,
70 &u->job_id,
71 &u->job_type,
72 &u->job_path);
73}
74
0cf6628e
YW
75#define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
76 static int bus_append_##parse_func( \
77 sd_bus_message *m, \
78 const char *field, \
79 const char *eq) { \
80 type val; \
81 int r; \
82 \
83 r = parse_func(eq, &val); \
84 if (r < 0) \
85 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
86 \
87 r = sd_bus_message_append(m, "(sv)", field, \
88 bus_type, (cast_type) val); \
89 if (r < 0) \
90 return bus_log_create_error(r); \
91 \
92 return 1; \
f6a8265b 93 }
3dc5ca97 94
0cf6628e
YW
95#define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func) \
96 static int bus_append_##parse_func( \
97 sd_bus_message *m, \
98 const char *field, \
99 const char *eq) { \
100 int r; \
101 \
102 r = parse_func(eq); \
baaa35ad
ZJS
103 if (r < 0) \
104 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq); \
0cf6628e
YW
105 \
106 r = sd_bus_message_append(m, "(sv)", field, \
107 bus_type, (int32_t) r); \
108 if (r < 0) \
109 return bus_log_create_error(r); \
110 \
111 return 1; \
f6a8265b 112 }
3dc5ca97 113
0cf6628e
YW
114DEFINE_BUS_APPEND_PARSE("b", parse_boolean);
115DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
116DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
117DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
118DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
005bfaf1 119DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
0cf6628e
YW
120DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
121DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
29a3db75 122DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
d2b42d63 123DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
0cf6628e
YW
124DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
125DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
126DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
127DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
128DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_blkio_weight_parse);
129DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_shares_parse);
130DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
c8340822 131DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
b205e59a 132DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string);
0cf6628e
YW
133DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
134DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
135DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
136DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
ad21e542 137DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
89ada3ba 138
a1e92eee 139static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba
YW
140 int r;
141
142 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
3dc5ca97 143 if (r < 0)
89ada3ba 144 return bus_log_create_error(r);
3dc5ca97 145
89ada3ba
YW
146 return 1;
147}
148
149static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
150 const char *p;
151 int r;
152
153 r = sd_bus_message_open_container(m, 'r', "sv");
3dc5ca97 154 if (r < 0)
89ada3ba 155 return bus_log_create_error(r);
3dc5ca97 156
89ada3ba 157 r = sd_bus_message_append_basic(m, 's', field);
3dc5ca97 158 if (r < 0)
89ada3ba 159 return bus_log_create_error(r);
3dc5ca97 160
89ada3ba 161 r = sd_bus_message_open_container(m, 'v', "as");
3dc5ca97 162 if (r < 0)
89ada3ba 163 return bus_log_create_error(r);
3dc5ca97 164
89ada3ba
YW
165 r = sd_bus_message_open_container(m, 'a', "s");
166 if (r < 0)
167 return bus_log_create_error(r);
3dc5ca97 168
89ada3ba
YW
169 for (p = eq;;) {
170 _cleanup_free_ char *word = NULL;
20b16441 171
89ada3ba
YW
172 r = extract_first_word(&p, &word, NULL, flags);
173 if (r == 0)
174 break;
175 if (r == -ENOMEM)
176 return log_oom();
177 if (r < 0)
178 return log_error_errno(r, "Invalid syntax: %s", eq);
20b16441 179
89ada3ba
YW
180 r = sd_bus_message_append_basic(m, 's', word);
181 if (r < 0)
182 return bus_log_create_error(r);
20b16441
LP
183 }
184
89ada3ba 185 r = sd_bus_message_close_container(m);
20b16441
LP
186 if (r < 0)
187 return bus_log_create_error(r);
188
89ada3ba
YW
189 r = sd_bus_message_close_container(m);
190 if (r < 0)
191 return bus_log_create_error(r);
20b16441 192
89ada3ba
YW
193 r = sd_bus_message_close_container(m);
194 if (r < 0)
195 return bus_log_create_error(r);
20b16441 196
89ada3ba
YW
197 return 1;
198}
20b16441 199
89ada3ba
YW
200static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
201 int r;
20b16441 202
89ada3ba
YW
203 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
204 if (r < 0)
205 return bus_log_create_error(r);
20b16441 206
89ada3ba
YW
207 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
208 if (r < 0)
209 return bus_log_create_error(r);
20b16441 210
89ada3ba
YW
211 r = sd_bus_message_open_container(m, 'v', "ay");
212 if (r < 0)
213 return bus_log_create_error(r);
20b16441 214
89ada3ba
YW
215 r = sd_bus_message_append_array(m, 'y', buf, n);
216 if (r < 0)
217 return bus_log_create_error(r);
9184ca48 218
89ada3ba
YW
219 r = sd_bus_message_close_container(m);
220 if (r < 0)
221 return bus_log_create_error(r);
20b16441 222
89ada3ba
YW
223 r = sd_bus_message_close_container(m);
224 if (r < 0)
225 return bus_log_create_error(r);
20b16441 226
89ada3ba
YW
227 return 1;
228}
d58d600e 229
89ada3ba
YW
230static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
231 char *n;
232 usec_t t;
233 size_t l;
234 int r;
d3070fbd 235
89ada3ba
YW
236 r = parse_sec(eq, &t);
237 if (r < 0)
238 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
d3070fbd 239
89ada3ba
YW
240 l = strlen(field);
241 n = newa(char, l + 2);
242 /* Change suffix Sec → USec */
243 strcpy(mempcpy(n, field, l - 3), "USec");
d3070fbd 244
89ada3ba
YW
245 r = sd_bus_message_append(m, "(sv)", n, "t", t);
246 if (r < 0)
247 return bus_log_create_error(r);
d3070fbd 248
89ada3ba
YW
249 return 1;
250}
d3070fbd 251
b48e508d 252static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
89ada3ba
YW
253 uint64_t v;
254 int r;
d3070fbd 255
b48e508d
YW
256 r = parse_size(eq, base, &v);
257 if (r < 0)
89ada3ba 258 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
d3070fbd 259
89ada3ba
YW
260 r = sd_bus_message_append(m, "(sv)", field, "t", v);
261 if (r < 0)
262 return bus_log_create_error(r);
d58d600e 263
89ada3ba
YW
264 return 1;
265}
d58d600e 266
89ada3ba 267static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
b3d59367
AZ
268 bool explicit_path = false, done = false;
269 _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
270 _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
271 ExecCommandFlags flags = 0;
272 bool is_ex_prop = endswith(field, "Ex");
89ada3ba 273 int r;
d58d600e 274
89ada3ba
YW
275 do {
276 switch (*eq) {
d58d600e 277
89ada3ba 278 case '-':
b3d59367 279 if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
89ada3ba
YW
280 done = true;
281 else {
b3d59367 282 flags |= EXEC_COMMAND_IGNORE_FAILURE;
89ada3ba 283 eq++;
d58d600e 284 }
89ada3ba 285 break;
02638280 286
89ada3ba
YW
287 case '@':
288 if (explicit_path)
289 done = true;
290 else {
291 explicit_path = true;
292 eq++;
02638280 293 }
89ada3ba 294 break;
02638280 295
b3d59367
AZ
296 case ':':
297 if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
298 done = true;
299 else {
300 flags |= EXEC_COMMAND_NO_ENV_EXPAND;
301 eq++;
302 }
303 break;
304
89ada3ba 305 case '+':
b3d59367
AZ
306 if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))
307 done = true;
308 else {
309 flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
310 eq++;
311 }
312 break;
313
89ada3ba 314 case '!':
b3d59367
AZ
315 if (flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_AMBIENT_MAGIC))
316 done = true;
317 else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
318 flags &= ~EXEC_COMMAND_NO_SETUID;
319 flags |= EXEC_COMMAND_AMBIENT_MAGIC;
320 eq++;
321 } else {
322 flags |= EXEC_COMMAND_NO_SETUID;
323 eq++;
324 }
325 break;
83f8e808 326
89ada3ba
YW
327 default:
328 done = true;
329 break;
83f8e808 330 }
89ada3ba 331 } while (!done);
83f8e808 332
b3d59367
AZ
333 if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_AMBIENT_MAGIC))) {
334 /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
335 is_ex_prop = true;
b910cc72 336 upgraded_name = strjoin(field, "Ex");
b3d59367
AZ
337 if (!upgraded_name)
338 return log_oom();
339 }
340
341 if (is_ex_prop) {
342 r = exec_command_flags_to_strv(flags, &ex_opts);
343 if (r < 0)
344 return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
345 }
346
89ada3ba 347 if (explicit_path) {
4ec85141 348 r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
89ada3ba
YW
349 if (r < 0)
350 return log_error_errno(r, "Failed to parse path: %m");
351 }
2038c3f5 352
90e30d76 353 r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
89ada3ba
YW
354 if (r < 0)
355 return log_error_errno(r, "Failed to parse command line: %m");
2038c3f5 356
89ada3ba
YW
357 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
358 if (r < 0)
359 return bus_log_create_error(r);
2038c3f5 360
b3d59367 361 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, upgraded_name ?: field);
89ada3ba
YW
362 if (r < 0)
363 return bus_log_create_error(r);
2038c3f5 364
b3d59367 365 r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
89ada3ba
YW
366 if (r < 0)
367 return bus_log_create_error(r);
08f3be7a 368
b3d59367 369 r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
89ada3ba
YW
370 if (r < 0)
371 return bus_log_create_error(r);
08f3be7a 372
89ada3ba 373 if (!strv_isempty(l)) {
08f3be7a 374
b3d59367 375 r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
89ada3ba
YW
376 if (r < 0)
377 return bus_log_create_error(r);
08f3be7a 378
89ada3ba 379 r = sd_bus_message_append(m, "s", path ?: l[0]);
08f3be7a
LP
380 if (r < 0)
381 return bus_log_create_error(r);
382
89ada3ba 383 r = sd_bus_message_append_strv(m, l);
08f3be7a
LP
384 if (r < 0)
385 return bus_log_create_error(r);
386
b3d59367 387 r = is_ex_prop ? sd_bus_message_append_strv(m, ex_opts) : sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
08f3be7a
LP
388 if (r < 0)
389 return bus_log_create_error(r);
390
391 r = sd_bus_message_close_container(m);
89ada3ba
YW
392 if (r < 0)
393 return bus_log_create_error(r);
20b16441
LP
394 }
395
89ada3ba 396 r = sd_bus_message_close_container(m);
20b16441
LP
397 if (r < 0)
398 return bus_log_create_error(r);
399
89ada3ba
YW
400 r = sd_bus_message_close_container(m);
401 if (r < 0)
402 return bus_log_create_error(r);
20b16441 403
89ada3ba
YW
404 r = sd_bus_message_close_container(m);
405 if (r < 0)
406 return bus_log_create_error(r);
20b16441 407
89ada3ba
YW
408 return 1;
409}
20b16441 410
cd48e23f
RP
411static int bus_append_open_file(sd_bus_message *m, const char *field, const char *eq) {
412 _cleanup_(open_file_freep) OpenFile *of = NULL;
413 int r;
414
415 assert(m);
416
417 r = open_file_parse(eq, &of);
418 if (r < 0)
419 return log_error_errno(r, "Failed to parse OpenFile= setting: %m");
420
421 r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
422 if (r < 0)
423 return bus_log_create_error(r);
424
425 return 1;
426}
427
89ada3ba
YW
428static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
429 int r;
20b16441 430
89ada3ba
YW
431 assert(m);
432 assert(prefix);
20b16441 433
89ada3ba
YW
434 r = sd_bus_message_open_container(m, 'r', "iayu");
435 if (r < 0)
436 return r;
20b16441 437
89ada3ba
YW
438 r = sd_bus_message_append(m, "i", family);
439 if (r < 0)
440 return r;
66ebf6c0 441
89ada3ba
YW
442 r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
443 if (r < 0)
444 return r;
66ebf6c0 445
89ada3ba
YW
446 r = sd_bus_message_append(m, "u", prefixlen);
447 if (r < 0)
448 return r;
66ebf6c0 449
89ada3ba
YW
450 return sd_bus_message_close_container(m);
451}
20b16441 452
dc7d69b3
TM
453static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
454 int r;
455
456 assert(m);
457 assert(field);
458 assert(eq);
459
460 if (isempty(eq)) {
461 r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
462 if (r < 0)
463 return bus_log_create_error(r);
464
465 return 1;
466 }
467
468 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
469 if (r < 0)
470 return bus_log_create_error(r);
471
472 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
473 if (r < 0)
474 return bus_log_create_error(r);
475
476 r = sd_bus_message_open_container(m, 'v', "a(iiss)");
477 if (r < 0)
478 return bus_log_create_error(r);
479
480 r = sd_bus_message_open_container(m, 'a', "(iiss)");
481 if (r < 0)
482 return bus_log_create_error(r);
483
484 for (const char *p = eq;;) {
485 _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
486 const char *q = NULL;
487 int source, nfproto;
488
489 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
490 if (r == -ENOMEM)
491 return log_oom();
492 if (r < 0)
493 return log_error_errno(r, "Failed to parse %s: %m", field);
494 if (r == 0)
495 break;
496 if (isempty(tuple))
4e494e6a 497 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
dc7d69b3
TM
498
499 q = tuple;
4f495126 500 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
dc7d69b3
TM
501 if (r == -ENOMEM)
502 return log_oom();
503 if (r != 4 || !isempty(q))
4e494e6a 504 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
dc7d69b3
TM
505
506 assert(source_str);
507 assert(nfproto_str);
508 assert(table);
509 assert(set);
510
511 source = nft_set_source_from_string(source_str);
3bb48b19 512 if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
4e494e6a 513 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
dc7d69b3
TM
514
515 nfproto = nfproto_from_string(nfproto_str);
516 if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set))
4e494e6a 517 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
dc7d69b3
TM
518
519 r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
520 if (r < 0)
521 return bus_log_create_error(r);
522 }
523 r = sd_bus_message_close_container(m);
524 if (r < 0)
525 return bus_log_create_error(r);
526
527 r = sd_bus_message_close_container(m);
528 if (r < 0)
529 return bus_log_create_error(r);
530
531 r = sd_bus_message_close_container(m);
532 if (r < 0)
533 return bus_log_create_error(r);
534
535 return 1;
536}
537
89ada3ba
YW
538static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
539 int r;
20b16441 540
4d824a4e
AZ
541 if (STR_IN_SET(field, "DevicePolicy",
542 "Slice",
543 "ManagedOOMSwap",
4e806bfa 544 "ManagedOOMMemoryPressure",
6bb00842 545 "ManagedOOMPreference",
a8b993dc
LP
546 "MemoryPressureWatch",
547 "DelegateSubgroup"))
89ada3ba 548 return bus_append_string(m, field, eq);
13c31542 549
0a9f9344 550 if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
0a9f9344
AZ
551 r = parse_permyriad(eq);
552 if (r < 0)
553 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
554
d9d3f05d
LP
555 /* Pass around scaled to 2^32-1 == 100% */
556 r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
0a9f9344
AZ
557 if (r < 0)
558 return bus_log_create_error(r);
559
560 return 1;
561 }
562
c57d2a76
ZJS
563 if (STR_IN_SET(field, "CPUAccounting",
564 "MemoryAccounting",
1ea275f1 565 "MemoryZSwapWriteback",
c57d2a76
ZJS
566 "IOAccounting",
567 "BlockIOAccounting",
568 "TasksAccounting",
6cf96ab4
NR
569 "IPAccounting",
570 "CoredumpReceive"))
89ada3ba 571 return bus_append_parse_boolean(m, field, eq);
13c31542 572
c57d2a76 573 if (STR_IN_SET(field, "CPUWeight",
c8340822 574 "StartupCPUWeight"))
575 return bus_append_cg_cpu_weight_parse(m, field, eq);
576
577 if (STR_IN_SET(field, "IOWeight",
c57d2a76 578 "StartupIOWeight"))
89ada3ba 579 return bus_append_cg_weight_parse(m, field, eq);
20b16441 580
c57d2a76
ZJS
581 if (STR_IN_SET(field, "CPUShares",
582 "StartupCPUShares"))
89ada3ba 583 return bus_append_cg_cpu_shares_parse(m, field, eq);
268833ed 584
c57d2a76 585 if (STR_IN_SET(field, "AllowedCPUs",
31d3a520
PM
586 "StartupAllowedCPUs",
587 "AllowedMemoryNodes",
588 "StartupAllowedMemoryNodes")) {
047f5d63
PH
589 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
590 _cleanup_free_ uint8_t *array = NULL;
591 size_t allocated;
592
593 r = parse_cpu_set(eq, &cpuset);
594 if (r < 0)
595 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
596
597 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
598 if (r < 0)
599 return log_error_errno(r, "Failed to serialize CPUSet: %m");
600
601 return bus_append_byte_array(m, field, array, allocated);
602 }
603
c57d2a76
ZJS
604 if (STR_IN_SET(field, "BlockIOWeight",
605 "StartupBlockIOWeight"))
89ada3ba 606 return bus_append_cg_blkio_weight_parse(m, field, eq);
08f3be7a 607
25cc30c4 608 if (streq(field, "DisableControllers"))
4ec85141 609 return bus_append_strv(m, "DisableControllers", eq, EXTRACT_UNQUOTE);
25cc30c4 610
89ada3ba 611 if (streq(field, "Delegate")) {
89ada3ba 612 r = parse_boolean(eq);
08f3be7a 613 if (r < 0)
4ec85141 614 return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_UNQUOTE);
08f3be7a 615
89ada3ba 616 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
08f3be7a
LP
617 if (r < 0)
618 return bus_log_create_error(r);
619
89ada3ba
YW
620 return 1;
621 }
08f3be7a 622
27e946a5
ZJS
623 if (STR_IN_SET(field, "MemoryMin",
624 "DefaultMemoryLow",
625 "DefaultMemoryMin",
626 "MemoryLow",
627 "MemoryHigh",
628 "MemoryMax",
629 "MemorySwapMax",
d7fe0a67 630 "MemoryZSwapMax",
27e946a5
ZJS
631 "MemoryLimit",
632 "TasksMax")) {
cffaed83 633
db2b8d2e 634 if (streq(eq, "infinity")) {
89ada3ba
YW
635 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
636 if (r < 0)
637 return bus_log_create_error(r);
638 return 1;
db2b8d2e 639 } else if (isempty(eq)) {
311a0e2e
ZJS
640 uint64_t empty_value = STR_IN_SET(field,
641 "DefaultMemoryLow",
642 "DefaultMemoryMin",
643 "MemoryLow",
644 "MemoryMin") ?
645 CGROUP_LIMIT_MIN :
646 CGROUP_LIMIT_MAX;
647
648 r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
89ada3ba
YW
649 if (r < 0)
650 return bus_log_create_error(r);
651 return 1;
cffaed83
YW
652 }
653
fe845b5e 654 r = parse_permyriad(eq);
89ada3ba
YW
655 if (r >= 0) {
656 char *n;
20b16441 657
f806dfd3
LP
658 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
659 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
660 * size can be determined server-side. */
20b16441 661
89ada3ba 662 n = strjoina(field, "Scale");
9cba32bc 663 r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
89ada3ba
YW
664 if (r < 0)
665 return bus_log_create_error(r);
20b16441 666
89ada3ba 667 return 1;
20b16441
LP
668 }
669
89ada3ba 670 if (streq(field, "TasksMax"))
62b749a9 671 return bus_append_safe_atou64(m, field, eq);
20b16441 672
62b749a9 673 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 674 }
cffaed83 675
89ada3ba 676 if (streq(field, "CPUQuota")) {
89ada3ba
YW
677 if (isempty(eq))
678 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
679 else {
fe845b5e 680 r = parse_permyriad_unbounded(eq);
baaa35ad 681 if (r == 0)
4e494e6a 682 return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small.");
f806dfd3
LP
683 if (r < 0)
684 return log_error_errno(r, "CPU quota '%s' invalid.", eq);
89ada3ba 685
fe845b5e 686 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
cffaed83
YW
687 }
688
6bbfdc67 689 if (r < 0)
89ada3ba 690 return bus_log_create_error(r);
cffaed83 691
89ada3ba
YW
692 return 1;
693 }
cffaed83 694
10f28641
FB
695 if (streq(field, "CPUQuotaPeriodSec")) {
696 usec_t u = USEC_INFINITY;
697
698 r = parse_sec_def_infinity(eq, &u);
699 if (r < 0)
700 return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
701
702 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
703 if (r < 0)
704 return bus_log_create_error(r);
705
706 return 1;
707 }
708
89ada3ba 709 if (streq(field, "DeviceAllow")) {
20b16441 710 if (isempty(eq))
89ada3ba 711 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
20b16441 712 else {
d9f7305f 713 const char *path = eq, *rwm = NULL, *e;
20b16441
LP
714
715 e = strchr(eq, ' ');
716 if (e) {
2f82562b 717 path = strndupa_safe(eq, e - eq);
20b16441 718 rwm = e+1;
20b16441
LP
719 }
720
d9f7305f 721 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
20b16441
LP
722 }
723
89ada3ba
YW
724 if (r < 0)
725 return bus_log_create_error(r);
726
727 return 1;
728 }
729
730 if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
20b16441 731 if (isempty(eq))
89ada3ba 732 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
20b16441
LP
733 else {
734 const char *path, *bandwidth, *e;
735 uint64_t bytes;
736
737 e = strchr(eq, ' ');
baaa35ad
ZJS
738 if (!e)
739 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
740 "Failed to parse %s value %s.",
741 field, eq);
20b16441 742
2f82562b 743 path = strndupa_safe(eq, e - eq);
d9f7305f 744 bandwidth = e+1;
20b16441 745
79d53eb8 746 if (streq(bandwidth, "infinity"))
13c31542 747 bytes = CGROUP_LIMIT_MAX;
79d53eb8 748 else {
13c31542 749 r = parse_size(bandwidth, 1000, &bytes);
6bbfdc67
LP
750 if (r < 0)
751 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
20b16441
LP
752 }
753
89ada3ba 754 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
20b16441
LP
755 }
756
89ada3ba
YW
757 if (r < 0)
758 return bus_log_create_error(r);
759
760 return 1;
761 }
762
c57d2a76
ZJS
763 if (STR_IN_SET(field, "IODeviceWeight",
764 "BlockIODeviceWeight")) {
20b16441 765 if (isempty(eq))
89ada3ba 766 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
20b16441
LP
767 else {
768 const char *path, *weight, *e;
769 uint64_t u;
770
771 e = strchr(eq, ' ');
baaa35ad
ZJS
772 if (!e)
773 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
774 "Failed to parse %s value %s.",
775 field, eq);
20b16441 776
2f82562b 777 path = strndupa_safe(eq, e - eq);
d9f7305f 778 weight = e+1;
20b16441
LP
779
780 r = safe_atou64(weight, &u);
6bbfdc67
LP
781 if (r < 0)
782 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
783
89ada3ba 784 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
20b16441
LP
785 }
786
89ada3ba
YW
787 if (r < 0)
788 return bus_log_create_error(r);
3dc5ca97 789
89ada3ba
YW
790 return 1;
791 }
3dc5ca97 792
6ae4283c
TH
793 if (streq(field, "IODeviceLatencyTargetSec")) {
794 const char *field_usec = "IODeviceLatencyTargetUSec";
795
796 if (isempty(eq))
797 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
798 else {
799 const char *path, *target, *e;
800 usec_t usec;
801
802 e = strchr(eq, ' ');
baaa35ad
ZJS
803 if (!e)
804 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
805 "Failed to parse %s value %s.",
806 field, eq);
6ae4283c 807
2f82562b 808 path = strndupa_safe(eq, e - eq);
6ae4283c
TH
809 target = e+1;
810
811 r = parse_sec(target, &usec);
812 if (r < 0)
813 return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
814
815 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
816 }
817
818 if (r < 0)
819 return bus_log_create_error(r);
820
821 return 1;
822 }
823
c57d2a76
ZJS
824 if (STR_IN_SET(field, "IPAddressAllow",
825 "IPAddressDeny")) {
89ada3ba
YW
826 unsigned char prefixlen;
827 union in_addr_union prefix = {};
828 int family;
3dc5ca97 829
89ada3ba
YW
830 if (isempty(eq)) {
831 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
3dc5ca97
LP
832 if (r < 0)
833 return bus_log_create_error(r);
834
89ada3ba
YW
835 return 1;
836 }
3dc5ca97 837
89ada3ba
YW
838 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
839 if (r < 0)
840 return bus_log_create_error(r);
3dc5ca97 841
89ada3ba
YW
842 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
843 if (r < 0)
844 return bus_log_create_error(r);
3dc5ca97 845
89ada3ba
YW
846 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
847 if (r < 0)
848 return bus_log_create_error(r);
3dc5ca97 849
89ada3ba
YW
850 r = sd_bus_message_open_container(m, 'a', "(iayu)");
851 if (r < 0)
852 return bus_log_create_error(r);
3dc5ca97 853
89ada3ba
YW
854 if (streq(eq, "any")) {
855 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
3dc5ca97 856
89ada3ba
YW
857 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
858 if (r < 0)
859 return bus_log_create_error(r);
3dc5ca97 860
89ada3ba
YW
861 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
862 if (r < 0)
863 return bus_log_create_error(r);
3dc5ca97 864
89ada3ba
YW
865 } else if (is_localhost(eq)) {
866 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
3dc5ca97 867
89ada3ba
YW
868 prefix.in.s_addr = htobe32(0x7f000000);
869 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
870 if (r < 0)
871 return bus_log_create_error(r);
3dc5ca97 872
89ada3ba
YW
873 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
874 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
875 if (r < 0)
876 return r;
3dc5ca97 877
89ada3ba
YW
878 } else if (streq(eq, "link-local")) {
879 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
3dc5ca97 880
89ada3ba
YW
881 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
882 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
883 if (r < 0)
884 return bus_log_create_error(r);
3dc5ca97 885
89ada3ba
YW
886 prefix.in6 = (struct in6_addr) {
887 .s6_addr32[0] = htobe32(0xfe800000)
888 };
889 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
890 if (r < 0)
891 return bus_log_create_error(r);
3dc5ca97 892
89ada3ba
YW
893 } else if (streq(eq, "multicast")) {
894 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
3dc5ca97 895
89ada3ba
YW
896 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
897 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
898 if (r < 0)
899 return bus_log_create_error(r);
3dc5ca97 900
89ada3ba
YW
901 prefix.in6 = (struct in6_addr) {
902 .s6_addr32[0] = htobe32(0xff000000)
903 };
904 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
3dc5ca97
LP
905 if (r < 0)
906 return bus_log_create_error(r);
907
89ada3ba 908 } else {
afc1feae
RC
909 for (;;) {
910 _cleanup_free_ char *word = NULL;
911
912 r = extract_first_word(&eq, &word, NULL, 0);
913 if (r == 0)
914 break;
915 if (r == -ENOMEM)
916 return log_oom();
917 if (r < 0)
918 return log_error_errno(r, "Failed to parse %s: %s", field, eq);
89ada3ba 919
afc1feae
RC
920 r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
921 if (r < 0)
922 return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
923
924 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
925 if (r < 0)
926 return bus_log_create_error(r);
927 }
3dc5ca97
LP
928 }
929
89ada3ba
YW
930 r = sd_bus_message_close_container(m);
931 if (r < 0)
932 return bus_log_create_error(r);
cffaed83 933
89ada3ba
YW
934 r = sd_bus_message_close_container(m);
935 if (r < 0)
936 return bus_log_create_error(r);
cffaed83 937
89ada3ba
YW
938 r = sd_bus_message_close_container(m);
939 if (r < 0)
940 return bus_log_create_error(r);
fab34748
KL
941
942 return 1;
943 }
944
c57d2a76
ZJS
945 if (STR_IN_SET(field, "IPIngressFilterPath",
946 "IPEgressFilterPath")) {
fab34748
KL
947 if (isempty(eq))
948 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
949 else
950 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
951
952 if (r < 0)
953 return bus_log_create_error(r);
cffaed83 954
89ada3ba
YW
955 return 1;
956 }
cffaed83 957
9e009a14
JK
958 if (streq(field, "BPFProgram")) {
959 if (isempty(eq))
960 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
961 else {
962 _cleanup_free_ char *word = NULL;
963
964 r = extract_first_word(&eq, &word, ":", 0);
965 if (r == -ENOMEM)
966 return log_oom();
967 if (r < 0)
968 return log_error_errno(r, "Failed to parse %s: %m", field);
969
970 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
971 }
972 if (r < 0)
973 return bus_log_create_error(r);
974
975 return 1;
976 }
977
dcf4781c
JK
978 if (STR_IN_SET(field, "SocketBindAllow",
979 "SocketBindDeny")) {
980 if (isempty(eq))
4883a04f 981 r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
dcf4781c 982 else {
60477eb9
JK
983 int32_t family, ip_protocol;
984 uint16_t nr_ports, port_min;
dcf4781c 985
60477eb9 986 r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
dcf4781c
JK
987 if (r == -ENOMEM)
988 return log_oom();
989 if (r < 0)
60477eb9 990 return log_error_errno(r, "Failed to parse %s", field);
dcf4781c 991
60477eb9
JK
992 r = sd_bus_message_append(
993 m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
dcf4781c
JK
994 }
995 if (r < 0)
996 return bus_log_create_error(r);
997
998 return 1;
999 }
1000
6bb00842
LP
1001 if (streq(field, "MemoryPressureThresholdSec"))
1002 return bus_append_parse_sec_rename(m, field, eq);
1003
dc7d69b3
TM
1004 if (streq(field, "NFTSet"))
1005 return bus_append_nft_set(m, field, eq);
1006
89ada3ba
YW
1007 return 0;
1008}
cffaed83 1009
3d63c749 1010static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
7c5cef22
AS
1011 if (STR_IN_SET(field, "Where",
1012 "ExtraOptions"))
3d63c749
YW
1013 return bus_append_string(m, field, eq);
1014
1015 if (streq(field, "DirectoryMode"))
3d63c749
YW
1016 return bus_append_parse_mode(m, field, eq);
1017
1018 if (streq(field, "TimeoutIdleSec"))
3d63c749
YW
1019 return bus_append_parse_sec_rename(m, field, eq);
1020
1021 return 0;
1022}
1023
89ada3ba 1024static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
6550c24c
LP
1025 const char *suffix;
1026 int r;
cffaed83 1027
c57d2a76
ZJS
1028 if (STR_IN_SET(field, "User",
1029 "Group",
1030 "UtmpIdentifier",
1031 "UtmpMode",
1032 "PAMName",
1033 "TTYPath",
1034 "WorkingDirectory",
1035 "RootDirectory",
1036 "SyslogIdentifier",
1037 "ProtectSystem",
1038 "ProtectHome",
1039 "SELinuxContext",
1040 "RootImage",
0389f4fa 1041 "RootVerity",
c57d2a76
ZJS
1042 "RuntimeDirectoryPreserve",
1043 "Personality",
1044 "KeyringMode",
4e399953
LP
1045 "ProtectProc",
1046 "ProcSubset",
91dd5f7c 1047 "NetworkNamespacePath",
a70581ff 1048 "IPCNamespacePath",
84be0c71
LP
1049 "LogNamespace",
1050 "RootImagePolicy",
1051 "MountImagePolicy",
1052 "ExtensionImagePolicy"))
89ada3ba 1053 return bus_append_string(m, field, eq);
cffaed83 1054
c57d2a76
ZJS
1055 if (STR_IN_SET(field, "IgnoreSIGPIPE",
1056 "TTYVHangup",
1057 "TTYReset",
1058 "TTYVTDisallocate",
1059 "PrivateTmp",
1060 "PrivateDevices",
1061 "PrivateNetwork",
1062 "PrivateUsers",
1063 "PrivateMounts",
a70581ff 1064 "PrivateIPC",
c57d2a76
ZJS
1065 "NoNewPrivileges",
1066 "SyslogLevelPrefix",
1067 "MemoryDenyWriteExecute",
1068 "RestrictRealtime",
1069 "DynamicUser",
1070 "RemoveIPC",
1071 "ProtectKernelTunables",
1072 "ProtectKernelModules",
1073 "ProtectKernelLogs",
fc64760d 1074 "ProtectClock",
c57d2a76
ZJS
1075 "ProtectControlGroups",
1076 "MountAPIVFS",
1077 "CPUSchedulingResetOnFork",
1078 "LockPersonality",
1079 "ProtectHostname",
85614c6e 1080 "MemoryKSM",
9c0c6701 1081 "RestrictSUIDSGID",
854eca4a
MY
1082 "RootEphemeral",
1083 "SetLoginEnvironment"))
89ada3ba 1084 return bus_append_parse_boolean(m, field, eq);
cffaed83 1085
c57d2a76
ZJS
1086 if (STR_IN_SET(field, "ReadWriteDirectories",
1087 "ReadOnlyDirectories",
1088 "InaccessibleDirectories",
1089 "ReadWritePaths",
1090 "ReadOnlyPaths",
1091 "InaccessiblePaths",
ddc155b2
TM
1092 "ExecPaths",
1093 "NoExecPaths",
8c35c10d 1094 "ExecSearchPath",
a07b9926 1095 "ExtensionDirectories",
c57d2a76
ZJS
1096 "ConfigurationDirectory",
1097 "SupplementaryGroups",
1098 "SystemCallArchitectures"))
4ec85141 1099 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
20b16441 1100
c57d2a76
ZJS
1101 if (STR_IN_SET(field, "SyslogLevel",
1102 "LogLevelMax"))
89ada3ba 1103 return bus_append_log_level_from_string(m, field, eq);
20b16441 1104
89ada3ba 1105 if (streq(field, "SyslogFacility"))
89ada3ba 1106 return bus_append_log_facility_unshifted_from_string(m, field, eq);
cffaed83 1107
89ada3ba 1108 if (streq(field, "SecureBits"))
89ada3ba 1109 return bus_append_secure_bits_from_string(m, field, eq);
cffaed83 1110
89ada3ba 1111 if (streq(field, "CPUSchedulingPolicy"))
89ada3ba 1112 return bus_append_sched_policy_from_string(m, field, eq);
cffaed83 1113
c57d2a76
ZJS
1114 if (STR_IN_SET(field, "CPUSchedulingPriority",
1115 "OOMScoreAdjust"))
89ada3ba 1116 return bus_append_safe_atoi(m, field, eq);
3f856a28 1117
ad21e542
ZJS
1118 if (streq(field, "CoredumpFilter"))
1119 return bus_append_coredump_filter_mask_from_string(m, field, eq);
1120
89ada3ba 1121 if (streq(field, "Nice"))
89ada3ba 1122 return bus_append_parse_nice(m, field, eq);
3f856a28 1123
89ada3ba 1124 if (streq(field, "SystemCallErrorNumber"))
005bfaf1 1125 return bus_append_seccomp_parse_errno_or_action(m, field, eq);
cffaed83 1126
89ada3ba 1127 if (streq(field, "IOSchedulingClass"))
89ada3ba 1128 return bus_append_ioprio_class_from_string(m, field, eq);
cffaed83 1129
89ada3ba 1130 if (streq(field, "IOSchedulingPriority"))
89ada3ba 1131 return bus_append_ioprio_parse_priority(m, field, eq);
cffaed83 1132
c57d2a76
ZJS
1133 if (STR_IN_SET(field, "RuntimeDirectoryMode",
1134 "StateDirectoryMode",
1135 "CacheDirectoryMode",
1136 "LogsDirectoryMode",
1137 "ConfigurationDirectoryMode",
1138 "UMask"))
89ada3ba 1139 return bus_append_parse_mode(m, field, eq);
cffaed83 1140
89ada3ba 1141 if (streq(field, "TimerSlackNSec"))
89ada3ba 1142 return bus_append_parse_nsec(m, field, eq);
cffaed83 1143
691d6f6d 1144 if (streq(field, "LogRateLimitIntervalSec"))
90fc172e
AZ
1145 return bus_append_parse_sec_rename(m, field, eq);
1146
51462135
DDM
1147 if (STR_IN_SET(field, "LogRateLimitBurst",
1148 "TTYRows",
1149 "TTYColumns"))
90fc172e
AZ
1150 return bus_append_safe_atou(m, field, eq);
1151
89ada3ba 1152 if (streq(field, "MountFlags"))
b205e59a 1153 return bus_append_mount_propagation_flag_from_string(m, field, eq);
cffaed83 1154
c57d2a76
ZJS
1155 if (STR_IN_SET(field, "Environment",
1156 "UnsetEnvironment",
1157 "PassEnvironment"))
4ec85141 1158 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
cffaed83 1159
89ada3ba 1160 if (streq(field, "EnvironmentFile")) {
89ada3ba
YW
1161 if (isempty(eq))
1162 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1163 else
1164 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1165 eq[0] == '-' ? eq + 1 : eq,
1166 eq[0] == '-');
1167 if (r < 0)
1168 return bus_log_create_error(r);
cffaed83 1169
89ada3ba
YW
1170 return 1;
1171 }
cffaed83 1172
43144be4 1173 if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
bb0c0d6f
LP
1174 r = sd_bus_message_open_container(m, 'r', "sv");
1175 if (r < 0)
1176 return bus_log_create_error(r);
1177
43144be4 1178 r = sd_bus_message_append_basic(m, 's', field);
bb0c0d6f
LP
1179 if (r < 0)
1180 return bus_log_create_error(r);
1181
1182 r = sd_bus_message_open_container(m, 'v', "a(say)");
1183 if (r < 0)
1184 return bus_log_create_error(r);
1185
1186 if (isempty(eq))
1187 r = sd_bus_message_append(m, "a(say)", 0);
1188 else {
43144be4 1189 _cleanup_free_ char *word = NULL;
bb0c0d6f 1190 const char *p = eq;
bb0c0d6f
LP
1191
1192 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1193 if (r == -ENOMEM)
1194 return log_oom();
1195 if (r < 0)
43144be4 1196 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
bb0c0d6f 1197 if (r == 0 || !p)
43144be4 1198 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f
LP
1199
1200 r = sd_bus_message_open_container(m, 'a', "(say)");
1201 if (r < 0)
1202 return bus_log_create_error(r);
1203
1204 r = sd_bus_message_open_container(m, 'r', "say");
1205 if (r < 0)
1206 return bus_log_create_error(r);
1207
1208 r = sd_bus_message_append(m, "s", word);
1209 if (r < 0)
1210 return bus_log_create_error(r);
1211
43144be4
LP
1212 if (streq(field, "SetCredentialEncrypted")) {
1213 _cleanup_free_ void *decoded = NULL;
1214 size_t decoded_size;
1215
bdd2036e 1216 r = unbase64mem(p, &decoded, &decoded_size);
43144be4
LP
1217 if (r < 0)
1218 return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
1219
1220 r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
1221 } else {
1222 _cleanup_free_ char *unescaped = NULL;
e437538f 1223 ssize_t l;
43144be4
LP
1224
1225 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
1226 if (l < 0)
1227 return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
1228
1229 r = sd_bus_message_append_array(m, 'y', unescaped, l);
1230 }
bb0c0d6f
LP
1231 if (r < 0)
1232 return bus_log_create_error(r);
1233
1234 r = sd_bus_message_close_container(m);
1235 if (r < 0)
1236 return bus_log_create_error(r);
1237
1238 r = sd_bus_message_close_container(m);
1239 }
1240 if (r < 0)
1241 return bus_log_create_error(r);
1242
1243 r = sd_bus_message_close_container(m);
1244 if (r < 0)
1245 return bus_log_create_error(r);
1246
1247 r = sd_bus_message_close_container(m);
1248 if (r < 0)
1249 return bus_log_create_error(r);
1250
1251 return 1;
1252 }
1253
43144be4 1254 if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
bb0c0d6f
LP
1255 r = sd_bus_message_open_container(m, 'r', "sv");
1256 if (r < 0)
1257 return bus_log_create_error(r);
1258
43144be4 1259 r = sd_bus_message_append_basic(m, 's', field);
bb0c0d6f
LP
1260 if (r < 0)
1261 return bus_log_create_error(r);
1262
1263 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1264 if (r < 0)
1265 return bus_log_create_error(r);
1266
1267 if (isempty(eq))
1268 r = sd_bus_message_append(m, "a(ss)", 0);
1269 else {
1270 _cleanup_free_ char *word = NULL;
1271 const char *p = eq;
1272
1273 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1274 if (r == -ENOMEM)
1275 return log_oom();
1276 if (r < 0)
43144be4 1277 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
255689ae 1278 if (r == 0)
43144be4 1279 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f 1280
255689ae
LP
1281 if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
1282 p = eq;
1283
bb0c0d6f
LP
1284 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1285 }
1286 if (r < 0)
1287 return bus_log_create_error(r);
1288
1289 r = sd_bus_message_close_container(m);
1290 if (r < 0)
1291 return bus_log_create_error(r);
1292
1293 r = sd_bus_message_close_container(m);
1294 if (r < 0)
1295 return bus_log_create_error(r);
1296
1297 return 1;
1298 }
1299
bbfb25f4
DDM
1300 if (streq(field, "ImportCredential")) {
1301 if (isempty(eq))
1302 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
1303 else
1304 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
1305 if (r < 0)
1306 return bus_log_create_error(r);
1307
1308 return 1;
1309 }
1310
89ada3ba 1311 if (streq(field, "LogExtraFields")) {
89ada3ba 1312 r = sd_bus_message_open_container(m, 'r', "sv");
3f856a28
YW
1313 if (r < 0)
1314 return bus_log_create_error(r);
1315
89ada3ba 1316 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
3f856a28
YW
1317 if (r < 0)
1318 return bus_log_create_error(r);
1319
89ada3ba 1320 r = sd_bus_message_open_container(m, 'v', "aay");
3f856a28
YW
1321 if (r < 0)
1322 return bus_log_create_error(r);
1323
89ada3ba 1324 r = sd_bus_message_open_container(m, 'a', "ay");
cffaed83
YW
1325 if (r < 0)
1326 return bus_log_create_error(r);
1327
89ada3ba 1328 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
3f856a28
YW
1329 if (r < 0)
1330 return bus_log_create_error(r);
cffaed83 1331
3f856a28
YW
1332 r = sd_bus_message_close_container(m);
1333 if (r < 0)
1334 return bus_log_create_error(r);
9f617cd0 1335
89ada3ba
YW
1336 r = sd_bus_message_close_container(m);
1337 if (r < 0)
1338 return bus_log_create_error(r);
9efb9df9 1339
89ada3ba 1340 r = sd_bus_message_close_container(m);
9efb9df9 1341 if (r < 0)
89ada3ba
YW
1342 return bus_log_create_error(r);
1343
1344 return 1;
1345 }
9efb9df9 1346
523ea123
QD
1347 if (streq(field, "LogFilterPatterns")) {
1348 r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1349 eq[0] != '~',
1350 eq[0] != '~' ? eq : eq + 1);
1351 if (r < 0)
1352 return bus_log_create_error(r);
1353
1354 return 1;
1355 }
1356
c57d2a76
ZJS
1357 if (STR_IN_SET(field, "StandardInput",
1358 "StandardOutput",
1359 "StandardError")) {
89ada3ba 1360 const char *n, *appended;
9efb9df9 1361
89ada3ba
YW
1362 if ((n = startswith(eq, "fd:"))) {
1363 appended = strjoina(field, "FileDescriptorName");
1364 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1365 } else if ((n = startswith(eq, "file:"))) {
1366 appended = strjoina(field, "File");
1367 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d33232e
LP
1368 } else if ((n = startswith(eq, "append:"))) {
1369 appended = strjoina(field, "FileToAppend");
1370 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d7dab1f
LW
1371 } else if ((n = startswith(eq, "truncate:"))) {
1372 appended = strjoina(field, "FileToTruncate");
1373 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
89ada3ba
YW
1374 } else
1375 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
89ada3ba
YW
1376 if (r < 0)
1377 return bus_log_create_error(r);
7f452159 1378
89ada3ba
YW
1379 return 1;
1380 }
7f452159 1381
89ada3ba
YW
1382 if (streq(field, "StandardInputText")) {
1383 _cleanup_free_ char *unescaped = NULL;
e437538f 1384 ssize_t l;
7f452159 1385
e437538f
ZJS
1386 l = cunescape(eq, 0, &unescaped);
1387 if (l < 0)
1388 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
7f452159 1389
c2bc710b 1390 if (!strextend(&unescaped, "\n"))
89ada3ba 1391 return log_oom();
7f452159 1392
e437538f
ZJS
1393 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1394 * programmatic interface anyway */
20b16441 1395
e437538f 1396 return bus_append_byte_array(m, field, unescaped, l + 1);
89ada3ba 1397 }
20b16441 1398
89ada3ba
YW
1399 if (streq(field, "StandardInputData")) {
1400 _cleanup_free_ void *decoded = NULL;
1401 size_t sz;
1402
bdd2036e 1403 r = unbase64mem(eq, &decoded, &sz);
20b16441 1404 if (r < 0)
89ada3ba 1405 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
20b16441 1406
89ada3ba
YW
1407 return bus_append_byte_array(m, field, decoded, sz);
1408 }
20b16441 1409
6550c24c
LP
1410 if ((suffix = startswith(field, "Limit"))) {
1411 int rl;
20b16441 1412
6550c24c
LP
1413 rl = rlimit_from_string(suffix);
1414 if (rl >= 0) {
1415 const char *sn;
1416 struct rlimit l;
20b16441 1417
6550c24c
LP
1418 r = rlimit_parse(rl, eq, &l);
1419 if (r < 0)
1420 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
20b16441 1421
04a3af3c 1422 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
6550c24c
LP
1423 if (r < 0)
1424 return bus_log_create_error(r);
20b16441 1425
6550c24c 1426 sn = strjoina(field, "Soft");
04a3af3c 1427 r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
6550c24c
LP
1428 if (r < 0)
1429 return bus_log_create_error(r);
1430
1431 return 1;
1432 }
89ada3ba 1433 }
20b16441 1434
c57d2a76
ZJS
1435 if (STR_IN_SET(field, "AppArmorProfile",
1436 "SmackProcessLabel")) {
89ada3ba
YW
1437 int ignore = 0;
1438 const char *s = eq;
20b16441 1439
89ada3ba
YW
1440 if (eq[0] == '-') {
1441 ignore = 1;
1442 s = eq + 1;
20b16441
LP
1443 }
1444
89ada3ba 1445 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
6bbfdc67 1446 if (r < 0)
89ada3ba 1447 return bus_log_create_error(r);
20b16441 1448
89ada3ba
YW
1449 return 1;
1450 }
20b16441 1451
c57d2a76
ZJS
1452 if (STR_IN_SET(field, "CapabilityBoundingSet",
1453 "AmbientCapabilities")) {
89ada3ba
YW
1454 uint64_t sum = 0;
1455 bool invert = false;
1456 const char *p = eq;
afcb1cd3 1457
89ada3ba
YW
1458 if (*p == '~') {
1459 invert = true;
1460 p++;
1461 }
20b16441 1462
89ada3ba 1463 r = capability_set_from_string(p, &sum);
20b16441 1464 if (r < 0)
89ada3ba 1465 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
20b16441 1466
89ada3ba
YW
1467 sum = invert ? ~sum : sum;
1468
1469 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
20b16441
LP
1470 if (r < 0)
1471 return bus_log_create_error(r);
1472
89ada3ba
YW
1473 return 1;
1474 }
20b16441 1475
89ada3ba 1476 if (streq(field, "CPUAffinity")) {
0985c7c4 1477 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
c367f996
MS
1478 _cleanup_free_ uint8_t *array = NULL;
1479 size_t allocated;
20b16441 1480
e2b2fb7f
MS
1481 if (eq && streq(eq, "numa")) {
1482 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1483 if (r < 0)
1484 return bus_log_create_error(r);
1485 return r;
1486 }
1487
89ada3ba
YW
1488 r = parse_cpu_set(eq, &cpuset);
1489 if (r < 0)
1490 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
20b16441 1491
c367f996
MS
1492 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1493 if (r < 0)
1494 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1495
1496 return bus_append_byte_array(m, field, array, allocated);
89ada3ba 1497 }
20b7a007 1498
b070c7c0
MS
1499 if (streq(field, "NUMAPolicy")) {
1500 r = mpol_from_string(eq);
1501 if (r < 0)
1502 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1503
1504 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1505 if (r < 0)
1506 return bus_log_create_error(r);
1507
1508 return 1;
1509 }
1510
1511 if (streq(field, "NUMAMask")) {
1512 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1513 _cleanup_free_ uint8_t *array = NULL;
1514 size_t allocated;
1515
332d387f
MS
1516 if (eq && streq(eq, "all")) {
1517 r = numa_mask_add_all(&nodes);
1518 if (r < 0)
1519 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1520 } else {
1521 r = parse_cpu_set(eq, &nodes);
1522 if (r < 0)
1523 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1524 }
b070c7c0
MS
1525
1526 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1527 if (r < 0)
1528 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1529
1530 return bus_append_byte_array(m, field, array, allocated);
1531 }
1532
c57d2a76 1533 if (STR_IN_SET(field, "RestrictAddressFamilies",
cc86a278 1534 "RestrictFileSystems",
9df2cdd8 1535 "SystemCallFilter",
a59cb62c
MV
1536 "SystemCallLog",
1537 "RestrictNetworkInterfaces")) {
6b000af4 1538 int allow_list = 1;
89ada3ba 1539 const char *p = eq;
20b16441 1540
89ada3ba 1541 if (*p == '~') {
6b000af4 1542 allow_list = 0;
89ada3ba 1543 p++;
20b16441
LP
1544 }
1545
89ada3ba 1546 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1547 if (r < 0)
1548 return bus_log_create_error(r);
1549
89ada3ba
YW
1550 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1551 if (r < 0)
1552 return bus_log_create_error(r);
1553
1554 r = sd_bus_message_open_container(m, 'v', "(bas)");
1555 if (r < 0)
1556 return bus_log_create_error(r);
20b16441 1557
89ada3ba
YW
1558 r = sd_bus_message_open_container(m, 'r', "bas");
1559 if (r < 0)
1560 return bus_log_create_error(r);
cffaed83 1561
6b000af4 1562 r = sd_bus_message_append_basic(m, 'b', &allow_list);
cffaed83
YW
1563 if (r < 0)
1564 return bus_log_create_error(r);
1565
1566 r = sd_bus_message_open_container(m, 'a', "s");
1567 if (r < 0)
1568 return bus_log_create_error(r);
1569
98008caa 1570 for (;;) {
cffaed83
YW
1571 _cleanup_free_ char *word = NULL;
1572
4ec85141 1573 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
cffaed83
YW
1574 if (r == 0)
1575 break;
89ada3ba
YW
1576 if (r == -ENOMEM)
1577 return log_oom();
1578 if (r < 0)
1579 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1580
1581 r = sd_bus_message_append_basic(m, 's', word);
1582 if (r < 0)
1583 return bus_log_create_error(r);
1584 }
1585
1586 r = sd_bus_message_close_container(m);
1587 if (r < 0)
1588 return bus_log_create_error(r);
1589
1590 r = sd_bus_message_close_container(m);
20b16441
LP
1591 if (r < 0)
1592 return bus_log_create_error(r);
1593
89ada3ba 1594 r = sd_bus_message_close_container(m);
20b16441
LP
1595 if (r < 0)
1596 return bus_log_create_error(r);
1597
20b16441
LP
1598 r = sd_bus_message_close_container(m);
1599 if (r < 0)
1600 return bus_log_create_error(r);
1601
89ada3ba
YW
1602 return 1;
1603 }
20b16441 1604
89ada3ba 1605 if (streq(field, "RestrictNamespaces")) {
add00535 1606 bool invert = false;
aa9d574d 1607 unsigned long flags;
add00535
LP
1608
1609 r = parse_boolean(eq);
1610 if (r > 0)
1611 flags = 0;
1612 else if (r == 0)
1613 flags = NAMESPACE_FLAGS_ALL;
1614 else {
aa9d574d
YW
1615 if (eq[0] == '~') {
1616 invert = true;
1617 eq++;
1618 }
1619
86c2a9f1 1620 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1621 if (r < 0)
1622 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1623 }
1624
1625 if (invert)
1626 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1627
89ada3ba
YW
1628 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1629 if (r < 0)
1630 return bus_log_create_error(r);
afcb1cd3 1631
89ada3ba
YW
1632 return 1;
1633 }
afcb1cd3 1634
c57d2a76
ZJS
1635 if (STR_IN_SET(field, "BindPaths",
1636 "BindReadOnlyPaths")) {
89ada3ba 1637 const char *p = eq;
83555251 1638
89ada3ba 1639 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1640 if (r < 0)
89ada3ba 1641 return bus_log_create_error(r);
afcb1cd3 1642
89ada3ba
YW
1643 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1644 if (r < 0)
1645 return bus_log_create_error(r);
d2d6c096
LP
1646
1647 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1648 if (r < 0)
89ada3ba 1649 return bus_log_create_error(r);
d2d6c096
LP
1650
1651 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1652 if (r < 0)
89ada3ba 1653 return bus_log_create_error(r);
d2d6c096
LP
1654
1655 for (;;) {
1656 _cleanup_free_ char *source = NULL, *destination = NULL;
1657 char *s = NULL, *d = NULL;
1658 bool ignore_enoent = false;
1659 uint64_t flags = MS_REC;
1660
4ec85141 1661 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1662 if (r < 0)
1663 return log_error_errno(r, "Failed to parse argument: %m");
1664 if (r == 0)
1665 break;
1666
1667 s = source;
1668 if (s[0] == '-') {
1669 ignore_enoent = true;
1670 s++;
1671 }
1672
1673 if (p && p[-1] == ':') {
4ec85141 1674 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1675 if (r < 0)
1676 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1677 if (r == 0)
1678 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1679 "Missing argument after ':': %s",
1680 eq);
d2d6c096
LP
1681
1682 d = destination;
1683
1684 if (p && p[-1] == ':') {
1685 _cleanup_free_ char *options = NULL;
1686
4ec85141 1687 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
d2d6c096
LP
1688 if (r < 0)
1689 return log_error_errno(r, "Failed to parse argument: %m");
1690
1691 if (isempty(options) || streq(options, "rbind"))
1692 flags = MS_REC;
1693 else if (streq(options, "norbind"))
1694 flags = 0;
baaa35ad
ZJS
1695 else
1696 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1697 "Unknown options: %s",
1698 eq);
d2d6c096
LP
1699 }
1700 } else
1701 d = s;
1702
d2d6c096
LP
1703 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1704 if (r < 0)
89ada3ba 1705 return bus_log_create_error(r);
d2d6c096
LP
1706 }
1707
1708 r = sd_bus_message_close_container(m);
1709 if (r < 0)
89ada3ba
YW
1710 return bus_log_create_error(r);
1711
1712 r = sd_bus_message_close_container(m);
1713 if (r < 0)
1714 return bus_log_create_error(r);
d2d6c096
LP
1715
1716 r = sd_bus_message_close_container(m);
89ada3ba
YW
1717 if (r < 0)
1718 return bus_log_create_error(r);
f6c66be1 1719
89ada3ba
YW
1720 return 1;
1721 }
f6c66be1 1722
784ad252
YW
1723 if (streq(field, "TemporaryFileSystem")) {
1724 const char *p = eq;
1725
1726 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1727 if (r < 0)
1728 return bus_log_create_error(r);
1729
1730 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1731 if (r < 0)
1732 return bus_log_create_error(r);
1733
1734 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1735 if (r < 0)
1736 return bus_log_create_error(r);
1737
1738 r = sd_bus_message_open_container(m, 'a', "(ss)");
1739 if (r < 0)
1740 return bus_log_create_error(r);
1741
1742 for (;;) {
1743 _cleanup_free_ char *word = NULL, *path = NULL;
1744 const char *w;
1745
4ec85141 1746 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
784ad252
YW
1747 if (r < 0)
1748 return log_error_errno(r, "Failed to parse argument: %m");
1749 if (r == 0)
1750 break;
1751
1752 w = word;
1753 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1754 if (r < 0)
1755 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1756 if (r == 0)
1757 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1758 "Failed to parse argument: %s",
1759 p);
784ad252
YW
1760
1761 r = sd_bus_message_append(m, "(ss)", path, w);
1762 if (r < 0)
1763 return bus_log_create_error(r);
1764 }
1765
1766 r = sd_bus_message_close_container(m);
1767 if (r < 0)
1768 return bus_log_create_error(r);
1769
1770 r = sd_bus_message_close_container(m);
1771 if (r < 0)
1772 return bus_log_create_error(r);
1773
1774 r = sd_bus_message_close_container(m);
1775 if (r < 0)
1776 return bus_log_create_error(r);
1777
1778 return 1;
1779 }
1780
0389f4fa
LB
1781 if (streq(field, "RootHash")) {
1782 _cleanup_free_ void *roothash_decoded = NULL;
1783 size_t roothash_decoded_size = 0;
1784
1785 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1786 if (path_is_absolute(eq))
1787 return bus_append_string(m, "RootHashPath", eq);
1788
1789 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
bdd2036e 1790 r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
0389f4fa
LB
1791 if (r < 0)
1792 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1793 if (roothash_decoded_size < sizeof(sd_id128_t))
4e494e6a 1794 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
0389f4fa
LB
1795
1796 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1797 }
1798
d4d55b0d
LB
1799 if (streq(field, "RootHashSignature")) {
1800 _cleanup_free_ void *roothash_sig_decoded = NULL;
1801 char *value;
1802 size_t roothash_sig_decoded_size = 0;
1803
1804 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1805 if (path_is_absolute(eq))
1806 return bus_append_string(m, "RootHashSignaturePath", eq);
1807
1808 if (!(value = startswith(eq, "base64:")))
4e494e6a 1809 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:'.", eq);
d4d55b0d
LB
1810
1811 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
bdd2036e 1812 r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
d4d55b0d
LB
1813 if (r < 0)
1814 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1815
1816 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1817 }
1818
18d73705 1819 if (streq(field, "RootImageOptions")) {
bc8d56d3 1820 _cleanup_strv_free_ char **l = NULL;
18d73705
LB
1821 const char *p = eq;
1822
1823 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1824 if (r < 0)
1825 return bus_log_create_error(r);
1826
1827 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1828 if (r < 0)
1829 return bus_log_create_error(r);
1830
9ece6444 1831 r = sd_bus_message_open_container(m, 'v', "a(ss)");
18d73705
LB
1832 if (r < 0)
1833 return bus_log_create_error(r);
1834
9ece6444 1835 r = sd_bus_message_open_container(m, 'a', "(ss)");
18d73705
LB
1836 if (r < 0)
1837 return bus_log_create_error(r);
1838
bc8d56d3
LB
1839 r = strv_split_colon_pairs(&l, p);
1840 if (r < 0)
1841 return log_error_errno(r, "Failed to parse argument: %m");
18d73705 1842
bc8d56d3 1843 STRV_FOREACH_PAIR(first, second, l) {
9ece6444
LB
1844 r = sd_bus_message_append(m, "(ss)",
1845 !isempty(*second) ? *first : "root",
1846 !isempty(*second) ? *second : *first);
18d73705
LB
1847 if (r < 0)
1848 return bus_log_create_error(r);
1849 }
1850
1851 r = sd_bus_message_close_container(m);
1852 if (r < 0)
b3d13314
LB
1853 return bus_log_create_error(r);
1854
1855 r = sd_bus_message_close_container(m);
1856 if (r < 0)
1857 return bus_log_create_error(r);
1858
1859 r = sd_bus_message_close_container(m);
1860 if (r < 0)
1861 return bus_log_create_error(r);
1862
1863 return 1;
1864 }
1865
1866 if (streq(field, "MountImages")) {
b3d13314
LB
1867 const char *p = eq;
1868
1869 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1870 if (r < 0)
1871 return bus_log_create_error(r);
1872
1873 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1874 if (r < 0)
1875 return bus_log_create_error(r);
1876
427353f6 1877 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
b3d13314
LB
1878 if (r < 0)
1879 return bus_log_create_error(r);
1880
427353f6 1881 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
b3d13314
LB
1882 if (r < 0)
1883 return bus_log_create_error(r);
1884
427353f6
LB
1885 for (;;) {
1886 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1887 const char *q = NULL, *source = NULL;
b3d13314
LB
1888 bool permissive = false;
1889
427353f6
LB
1890 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1891 if (r < 0)
de4abc3f 1892 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1893 if (r == 0)
1894 break;
1895
1896 q = tuple;
4f495126 1897 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
427353f6 1898 if (r < 0)
de4abc3f 1899 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1900 if (r == 0)
1901 continue;
1902
1903 source = first;
1904 if (source[0] == '-') {
b3d13314 1905 permissive = true;
427353f6 1906 source++;
b3d13314
LB
1907 }
1908
427353f6 1909 if (isempty(second))
b3d13314
LB
1910 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1911 "Missing argument after ':': %s",
1912 eq);
1913
427353f6
LB
1914 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
1915 if (r < 0)
1916 return bus_log_create_error(r);
1917
1918 r = sd_bus_message_append(m, "ssb", source, second, permissive);
1919 if (r < 0)
1920 return bus_log_create_error(r);
1921
1922 r = sd_bus_message_open_container(m, 'a', "(ss)");
1923 if (r < 0)
1924 return bus_log_create_error(r);
1925
1926 for (;;) {
1927 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1928
4f495126 1929 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
427353f6 1930 if (r < 0)
de4abc3f 1931 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
93f59701
LB
1932 if (r == 0)
1933 break;
1934 /* Single set of options, applying to the root partition/single filesystem */
1935 if (r == 1) {
1936 r = sd_bus_message_append(m, "(ss)", "root", partition);
1937 if (r < 0)
1938 return bus_log_create_error(r);
1939
1940 break;
1941 }
1942
93f59701
LB
1943 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1944 if (r < 0)
1945 return bus_log_create_error(r);
1946 }
1947
1948 r = sd_bus_message_close_container(m);
1949 if (r < 0)
1950 return bus_log_create_error(r);
1951
1952 r = sd_bus_message_close_container(m);
1953 if (r < 0)
1954 return bus_log_create_error(r);
1955 }
1956
1957 r = sd_bus_message_close_container(m);
1958 if (r < 0)
1959 return bus_log_create_error(r);
1960
1961 r = sd_bus_message_close_container(m);
1962 if (r < 0)
1963 return bus_log_create_error(r);
1964
1965 r = sd_bus_message_close_container(m);
1966 if (r < 0)
1967 return bus_log_create_error(r);
1968
1969 return 1;
1970 }
1971
1972 if (streq(field, "ExtensionImages")) {
1973 const char *p = eq;
1974
1975 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1976 if (r < 0)
1977 return bus_log_create_error(r);
1978
1979 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1980 if (r < 0)
1981 return bus_log_create_error(r);
1982
1983 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
1984 if (r < 0)
1985 return bus_log_create_error(r);
1986
1987 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
1988 if (r < 0)
1989 return bus_log_create_error(r);
1990
1991 for (;;) {
1992 _cleanup_free_ char *source = NULL, *tuple = NULL;
1993 const char *q = NULL, *s = NULL;
1994 bool permissive = false;
1995
1996 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1997 if (r < 0)
de4abc3f 1998 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1999 if (r == 0)
2000 break;
2001
2002 q = tuple;
2003 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
2004 if (r < 0)
de4abc3f 2005 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
2006 if (r == 0)
2007 continue;
2008
2009 s = source;
2010 if (s[0] == '-') {
2011 permissive = true;
2012 s++;
2013 }
2014
2015 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
2016 if (r < 0)
2017 return bus_log_create_error(r);
2018
2019 r = sd_bus_message_append(m, "sb", s, permissive);
2020 if (r < 0)
2021 return bus_log_create_error(r);
2022
2023 r = sd_bus_message_open_container(m, 'a', "(ss)");
2024 if (r < 0)
2025 return bus_log_create_error(r);
2026
2027 for (;;) {
2028 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2029
4f495126 2030 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
93f59701 2031 if (r < 0)
de4abc3f 2032 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
427353f6
LB
2033 if (r == 0)
2034 break;
2035 /* Single set of options, applying to the root partition/single filesystem */
2036 if (r == 1) {
2037 r = sd_bus_message_append(m, "(ss)", "root", partition);
2038 if (r < 0)
2039 return bus_log_create_error(r);
2040
2041 break;
2042 }
2043
427353f6
LB
2044 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2045 if (r < 0)
2046 return bus_log_create_error(r);
2047 }
2048
2049 r = sd_bus_message_close_container(m);
2050 if (r < 0)
2051 return bus_log_create_error(r);
2052
2053 r = sd_bus_message_close_container(m);
b3d13314
LB
2054 if (r < 0)
2055 return bus_log_create_error(r);
2056 }
2057
2058 r = sd_bus_message_close_container(m);
2059 if (r < 0)
18d73705
LB
2060 return bus_log_create_error(r);
2061
2062 r = sd_bus_message_close_container(m);
2063 if (r < 0)
2064 return bus_log_create_error(r);
2065
2066 r = sd_bus_message_close_container(m);
2067 if (r < 0)
2068 return bus_log_create_error(r);
2069
2070 return 1;
2071 }
2072
211a3d87
LB
2073 if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
2074 _cleanup_strv_free_ char **symlinks = NULL, **sources = NULL;
2075 const char *p = eq;
2076
2077 /* Adding new directories is supported from both *DirectorySymlink methods and the
2078 * older ones, so first parse the input, and if we are given a new-style src:dst
2079 * tuple use the new method, else use the old one. */
2080
2081 for (;;) {
2082 _cleanup_free_ char *tuple = NULL, *source = NULL, *destination = NULL;
2083
2084 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
2085 if (r < 0)
2086 return log_error_errno(r, "Failed to parse argument: %m");
2087 if (r == 0)
2088 break;
2089
2090 const char *t = tuple;
4f495126 2091 r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination);
211a3d87
LB
2092 if (r <= 0)
2093 return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
2094
2095 path_simplify(source);
2096
2097 if (isempty(destination)) {
2aaf6d40 2098 r = strv_consume(&sources, TAKE_PTR(source));
211a3d87
LB
2099 if (r < 0)
2100 return bus_log_create_error(r);
2101 } else {
2102 path_simplify(destination);
2103
2104 r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(destination));
2105 if (r < 0)
2106 return log_oom();
2107 }
2108 }
2109
2110 if (!strv_isempty(sources)) {
2111 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2112 if (r < 0)
2113 return bus_log_create_error(r);
2114
2115 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2116 if (r < 0)
2117 return bus_log_create_error(r);
2118
2119 r = sd_bus_message_open_container(m, 'v', "as");
2120 if (r < 0)
2121 return bus_log_create_error(r);
2122
2123 r = sd_bus_message_append_strv(m, sources);
2124 if (r < 0)
2125 return bus_log_create_error(r);
2126
2127 r = sd_bus_message_close_container(m);
2128 if (r < 0)
2129 return bus_log_create_error(r);
2130
2131 r = sd_bus_message_close_container(m);
2132 if (r < 0)
2133 return bus_log_create_error(r);
2134 }
2135
2136 /* For State and Runtime directories we support an optional destination parameter, which
2137 * will be used to create a symlink to the source. But it is new so we cannot change the
2138 * old DBUS signatures, so append a new message type. */
2139 if (!strv_isempty(symlinks)) {
2140 const char *symlink_field;
2141
2142 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2143 if (r < 0)
2144 return bus_log_create_error(r);
2145
2146 if (streq(field, "StateDirectory"))
2147 symlink_field = "StateDirectorySymlink";
2148 else if (streq(field, "RuntimeDirectory"))
2149 symlink_field = "RuntimeDirectorySymlink";
2150 else if (streq(field, "CacheDirectory"))
2151 symlink_field = "CacheDirectorySymlink";
2152 else if (streq(field, "LogsDirectory"))
2153 symlink_field = "LogsDirectorySymlink";
2154 else
2155 assert_not_reached();
2156
2157 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
2158 if (r < 0)
2159 return bus_log_create_error(r);
2160
2161 r = sd_bus_message_open_container(m, 'v', "a(sst)");
2162 if (r < 0)
2163 return bus_log_create_error(r);
2164
2165 r = sd_bus_message_open_container(m, 'a', "(sst)");
2166 if (r < 0)
2167 return bus_log_create_error(r);
2168
211a3d87 2169 STRV_FOREACH_PAIR(source, destination, symlinks) {
04a3af3c 2170 r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
211a3d87
LB
2171 if (r < 0)
2172 return bus_log_create_error(r);
2173 }
2174
2175 r = sd_bus_message_close_container(m);
2176 if (r < 0)
2177 return bus_log_create_error(r);
2178
2179 r = sd_bus_message_close_container(m);
2180 if (r < 0)
2181 return bus_log_create_error(r);
2182
2183 r = sd_bus_message_close_container(m);
2184 if (r < 0)
2185 return bus_log_create_error(r);
2186 }
2187
2188 return 1;
2189 }
2190
89ada3ba
YW
2191 return 0;
2192}
f6c66be1 2193
89ada3ba 2194static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2195 if (streq(field, "KillMode"))
89ada3ba 2196 return bus_append_string(m, field, eq);
f6c66be1 2197
c57d2a76
ZJS
2198 if (STR_IN_SET(field, "SendSIGHUP",
2199 "SendSIGKILL"))
89ada3ba 2200 return bus_append_parse_boolean(m, field, eq);
f6c66be1 2201
c57d2a76
ZJS
2202 if (STR_IN_SET(field, "KillSignal",
2203 "RestartKillSignal",
2204 "FinalKillSignal",
3bd28bf7
LP
2205 "WatchdogSignal",
2206 "ReloadSignal"))
29a3db75 2207 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
2208
2209 return 0;
2210}
2211
3d63c749 2212static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2213
c57d2a76
ZJS
2214 if (STR_IN_SET(field, "What",
2215 "Where",
2216 "Options",
2217 "Type"))
89ada3ba
YW
2218 return bus_append_string(m, field, eq);
2219
3d63c749 2220 if (streq(field, "TimeoutSec"))
3d63c749
YW
2221 return bus_append_parse_sec_rename(m, field, eq);
2222
2223 if (streq(field, "DirectoryMode"))
3d63c749
YW
2224 return bus_append_parse_mode(m, field, eq);
2225
c57d2a76
ZJS
2226 if (STR_IN_SET(field, "SloppyOptions",
2227 "LazyUnmount",
c600357b
MH
2228 "ForceUnmount",
2229 "ReadwriteOnly"))
3d63c749
YW
2230 return bus_append_parse_boolean(m, field, eq);
2231
2232 return 0;
2233}
2234
2235static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
2236 int r;
2237
89ada3ba 2238 if (streq(field, "MakeDirectory"))
89ada3ba
YW
2239 return bus_append_parse_boolean(m, field, eq);
2240
2241 if (streq(field, "DirectoryMode"))
89ada3ba
YW
2242 return bus_append_parse_mode(m, field, eq);
2243
c57d2a76
ZJS
2244 if (STR_IN_SET(field, "PathExists",
2245 "PathExistsGlob",
2246 "PathChanged",
2247 "PathModified",
2248 "DirectoryNotEmpty")) {
3d63c749
YW
2249 if (isempty(eq))
2250 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
2251 else
2252 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
2253 if (r < 0)
2254 return bus_log_create_error(r);
2255
2256 return 1;
2257 }
2258
2bec84e7 2259 if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
47dba9fb
LB
2260 return bus_append_safe_atou(m, field, eq);
2261
2bec84e7 2262 if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
47dba9fb
LB
2263 return bus_append_parse_sec_rename(m, field, eq);
2264
89ada3ba
YW
2265 return 0;
2266}
2267
5a70a68f 2268static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
9ed7de60 2269 if (streq(field, "RuntimeMaxSec"))
9ed7de60
PW
2270 return bus_append_parse_sec_rename(m, field, eq);
2271
5918a933
AB
2272 if (streq(field, "RuntimeRandomizedExtraSec"))
2273 return bus_append_parse_sec_rename(m, field, eq);
2274
5a70a68f 2275 if (streq(field, "TimeoutStopSec"))
5a70a68f
PW
2276 return bus_append_parse_sec_rename(m, field, eq);
2277
03860190
MS
2278 /* Scope units don't have execution context but we still want to allow setting these two,
2279 * so let's handle them separately. */
2280 if (STR_IN_SET(field, "User", "Group"))
2281 return bus_append_string(m, field, eq);
2282
5fa09835
ML
2283 if (streq(field, "OOMPolicy"))
2284 return bus_append_string(m, field, eq);
2285
5a70a68f
PW
2286 return 0;
2287}
2288
89ada3ba 2289static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2290 int r;
89ada3ba 2291
c57d2a76
ZJS
2292 if (STR_IN_SET(field, "PIDFile",
2293 "Type",
596e4470 2294 "ExitType",
c57d2a76 2295 "Restart",
e568fea9 2296 "RestartMode",
c57d2a76
ZJS
2297 "BusName",
2298 "NotifyAccess",
2299 "USBFunctionDescriptors",
2300 "USBFunctionStrings",
bf760801
JK
2301 "OOMPolicy",
2302 "TimeoutStartFailureMode",
b9c1883a
LP
2303 "TimeoutStopFailureMode",
2304 "FileDescriptorStorePreserve"))
89ada3ba 2305 return bus_append_string(m, field, eq);
f6c66be1 2306
c57d2a76
ZJS
2307 if (STR_IN_SET(field, "PermissionsStartOnly",
2308 "RootDirectoryStartOnly",
2309 "RemainAfterExit",
2310 "GuessMainPID"))
89ada3ba
YW
2311 return bus_append_parse_boolean(m, field, eq);
2312
c57d2a76 2313 if (STR_IN_SET(field, "RestartSec",
a559ea15 2314 "RestartMaxDelaySec",
c57d2a76
ZJS
2315 "TimeoutStartSec",
2316 "TimeoutStopSec",
e737017b 2317 "TimeoutAbortSec",
c57d2a76 2318 "RuntimeMaxSec",
5918a933 2319 "RuntimeRandomizedExtraSec",
c57d2a76 2320 "WatchdogSec"))
89ada3ba
YW
2321 return bus_append_parse_sec_rename(m, field, eq);
2322
3d63c749 2323 if (streq(field, "TimeoutSec")) {
3d63c749
YW
2324 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2325 if (r < 0)
2326 return r;
2327
2328 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2329 }
2330
a559ea15
MY
2331 if (STR_IN_SET(field, "FileDescriptorStoreMax",
2332 "RestartSteps"))
89ada3ba
YW
2333 return bus_append_safe_atou(m, field, eq);
2334
c57d2a76
ZJS
2335 if (STR_IN_SET(field, "ExecCondition",
2336 "ExecStartPre",
2337 "ExecStart",
2338 "ExecStartPost",
2339 "ExecConditionEx",
2340 "ExecStartPreEx",
2341 "ExecStartEx",
2342 "ExecStartPostEx",
2343 "ExecReload",
2344 "ExecStop",
2345 "ExecStopPost",
2346 "ExecReloadEx",
2347 "ExecStopEx",
2348 "ExecStopPostEx"))
89ada3ba
YW
2349 return bus_append_exec_command(m, field, eq);
2350
c57d2a76
ZJS
2351 if (STR_IN_SET(field, "RestartPreventExitStatus",
2352 "RestartForceExitStatus",
2353 "SuccessExitStatus")) {
3d63c749 2354 _cleanup_free_ int *status = NULL, *signal = NULL;
62b21e2e 2355 size_t n_status = 0, n_signal = 0;
3d63c749
YW
2356 const char *p;
2357
2358 for (p = eq;;) {
2359 _cleanup_free_ char *word = NULL;
3d63c749 2360
4ec85141 2361 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3d63c749
YW
2362 if (r == 0)
2363 break;
2364 if (r == -ENOMEM)
2365 return log_oom();
2366 if (r < 0)
2367 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2368
2e2ed880
ZJS
2369 /* We need to call exit_status_from_string() first, because we want
2370 * to parse numbers as exit statuses, not signals. */
3d63c749 2371
2e2ed880
ZJS
2372 r = exit_status_from_string(word);
2373 if (r >= 0) {
2374 assert(r >= 0 && r < 256);
3d63c749 2375
62b21e2e 2376 status = reallocarray(status, n_status + 1, sizeof(int));
3d63c749
YW
2377 if (!status)
2378 return log_oom();
2379
2e2ed880
ZJS
2380 status[n_status++] = r;
2381
2382 } else if ((r = signal_from_string(word)) >= 0) {
2383 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2384 if (!signal)
2385 return log_oom();
2386
2387 signal[n_signal++] = r;
2388
2389 } else
2390 /* original r from exit_status_to_string() */
2391 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2392 word, field);
3d63c749
YW
2393 }
2394
2395 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2396 if (r < 0)
2397 return bus_log_create_error(r);
2398
2399 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2400 if (r < 0)
2401 return bus_log_create_error(r);
2402
2403 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2404 if (r < 0)
2405 return bus_log_create_error(r);
2406
2407 r = sd_bus_message_open_container(m, 'r', "aiai");
2408 if (r < 0)
2409 return bus_log_create_error(r);
2410
62b21e2e 2411 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
3d63c749
YW
2412 if (r < 0)
2413 return bus_log_create_error(r);
2414
62b21e2e 2415 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
3d63c749
YW
2416 if (r < 0)
2417 return bus_log_create_error(r);
2418
2419 r = sd_bus_message_close_container(m);
2420 if (r < 0)
2421 return bus_log_create_error(r);
2422
2423 r = sd_bus_message_close_container(m);
2424 if (r < 0)
2425 return bus_log_create_error(r);
2426
2427 r = sd_bus_message_close_container(m);
2428 if (r < 0)
2429 return bus_log_create_error(r);
2430
2431 return 1;
2432 }
2433
cd48e23f
RP
2434 if (streq(field, "OpenFile"))
2435 return bus_append_open_file(m, field, eq);
2436
89ada3ba
YW
2437 return 0;
2438}
2439
2440static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2441 int r;
2442
c57d2a76 2443 if (STR_IN_SET(field, "Accept",
3e5f04bf 2444 "FlushPending",
c57d2a76
ZJS
2445 "Writable",
2446 "KeepAlive",
2447 "NoDelay",
2448 "FreeBind",
2449 "Transparent",
2450 "Broadcast",
2451 "PassCredentials",
97df75d7 2452 "PassFileDescriptorsToExec",
c57d2a76 2453 "PassSecurity",
a3d19f5d 2454 "PassPacketInfo",
c57d2a76
ZJS
2455 "ReusePort",
2456 "RemoveOnStop",
2457 "SELinuxContextFromNet"))
89ada3ba
YW
2458 return bus_append_parse_boolean(m, field, eq);
2459
c57d2a76
ZJS
2460 if (STR_IN_SET(field, "Priority",
2461 "IPTTL",
2462 "Mark"))
89ada3ba
YW
2463 return bus_append_safe_atoi(m, field, eq);
2464
2465 if (streq(field, "IPTOS"))
89ada3ba
YW
2466 return bus_append_ip_tos_from_string(m, field, eq);
2467
c57d2a76
ZJS
2468 if (STR_IN_SET(field, "Backlog",
2469 "MaxConnections",
2470 "MaxConnectionsPerSource",
2471 "KeepAliveProbes",
2bec84e7
LP
2472 "TriggerLimitBurst",
2473 "PollLimitBurst"))
89ada3ba
YW
2474 return bus_append_safe_atou(m, field, eq);
2475
c57d2a76
ZJS
2476 if (STR_IN_SET(field, "SocketMode",
2477 "DirectoryMode"))
89ada3ba
YW
2478 return bus_append_parse_mode(m, field, eq);
2479
c57d2a76
ZJS
2480 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2481 "MessageQueueMessageSize"))
89ada3ba
YW
2482 return bus_append_safe_atoi64(m, field, eq);
2483
c57d2a76
ZJS
2484 if (STR_IN_SET(field, "TimeoutSec",
2485 "KeepAliveTimeSec",
2486 "KeepAliveIntervalSec",
2487 "DeferAcceptSec",
2bec84e7
LP
2488 "TriggerLimitIntervalSec",
2489 "PollLimitIntervalSec"))
89ada3ba
YW
2490 return bus_append_parse_sec_rename(m, field, eq);
2491
c57d2a76
ZJS
2492 if (STR_IN_SET(field, "ReceiveBuffer",
2493 "SendBuffer",
2494 "PipeSize"))
b48e508d 2495 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 2496
c57d2a76
ZJS
2497 if (STR_IN_SET(field, "ExecStartPre",
2498 "ExecStartPost",
2499 "ExecReload",
2500 "ExecStopPost"))
89ada3ba
YW
2501 return bus_append_exec_command(m, field, eq);
2502
c57d2a76
ZJS
2503 if (STR_IN_SET(field, "SmackLabel",
2504 "SmackLabelIPIn",
2505 "SmackLabelIPOut",
2506 "TCPCongestion",
2507 "BindToDevice",
2508 "BindIPv6Only",
2509 "FileDescriptorName",
2510 "SocketUser",
9b191525
LP
2511 "SocketGroup",
2512 "Timestamping"))
89ada3ba
YW
2513 return bus_append_string(m, field, eq);
2514
2515 if (streq(field, "Symlinks"))
4ec85141 2516 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2517
e045e325 2518 if (streq(field, "SocketProtocol"))
d2b42d63 2519 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba 2520
c57d2a76
ZJS
2521 if (STR_IN_SET(field, "ListenStream",
2522 "ListenDatagram",
2523 "ListenSequentialPacket",
2524 "ListenNetlink",
2525 "ListenSpecial",
2526 "ListenMessageQueue",
2527 "ListenFIFO",
2528 "ListenUSBFunction")) {
3d63c749
YW
2529 if (isempty(eq))
2530 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2531 else
81b1dc27 2532 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 2533 if (r < 0)
89ada3ba
YW
2534 return bus_log_create_error(r);
2535
2536 return 1;
2537 }
2538
2539 return 0;
2540}
2541static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2542 int r;
89ada3ba 2543
c57d2a76
ZJS
2544 if (STR_IN_SET(field, "WakeSystem",
2545 "RemainAfterElapse",
2546 "Persistent",
2547 "OnTimezoneChange",
acf24a1a
KG
2548 "OnClockChange",
2549 "FixedRandomDelay"))
89ada3ba
YW
2550 return bus_append_parse_boolean(m, field, eq);
2551
c57d2a76
ZJS
2552 if (STR_IN_SET(field, "AccuracySec",
2553 "RandomizedDelaySec"))
3d63c749
YW
2554 return bus_append_parse_sec_rename(m, field, eq);
2555
c57d2a76
ZJS
2556 if (STR_IN_SET(field, "OnActiveSec",
2557 "OnBootSec",
2558 "OnStartupSec",
2559 "OnUnitActiveSec",
2560 "OnUnitInactiveSec")) {
3d63c749
YW
2561 if (isempty(eq))
2562 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2563 else {
2564 usec_t t;
2565 r = parse_sec(eq, &t);
2566 if (r < 0)
2567 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 2568
3d63c749
YW
2569 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2570 }
2571 if (r < 0)
2572 return bus_log_create_error(r);
89ada3ba 2573
3d63c749
YW
2574 return 1;
2575 }
2576
2577 if (streq(field, "OnCalendar")) {
3d63c749
YW
2578 if (isempty(eq))
2579 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2580 else
2581 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2582 if (r < 0)
2583 return bus_log_create_error(r);
2584
2585 return 1;
2586 }
89ada3ba
YW
2587
2588 return 0;
2589}
2590
2591static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
2592 ConditionType t = _CONDITION_TYPE_INVALID;
2593 bool is_condition = false;
2594 int r;
f6c66be1 2595
c57d2a76
ZJS
2596 if (STR_IN_SET(field, "Description",
2597 "SourcePath",
2598 "OnFailureJobMode",
2599 "JobTimeoutAction",
2600 "JobTimeoutRebootArgument",
2601 "StartLimitAction",
2602 "FailureAction",
2603 "SuccessAction",
2604 "RebootArgument",
2605 "CollectMode"))
89ada3ba
YW
2606 return bus_append_string(m, field, eq);
2607
c57d2a76
ZJS
2608 if (STR_IN_SET(field, "StopWhenUnneeded",
2609 "RefuseManualStart",
2610 "RefuseManualStop",
2611 "AllowIsolate",
2612 "IgnoreOnIsolate",
559214cb 2613 "SurviveFinalKillSignal",
c57d2a76 2614 "DefaultDependencies"))
89ada3ba
YW
2615 return bus_append_parse_boolean(m, field, eq);
2616
c57d2a76
ZJS
2617 if (STR_IN_SET(field, "JobTimeoutSec",
2618 "JobRunningTimeoutSec",
2619 "StartLimitIntervalSec"))
3d63c749
YW
2620 return bus_append_parse_sec_rename(m, field, eq);
2621
2622 if (streq(field, "StartLimitBurst"))
3d63c749
YW
2623 return bus_append_safe_atou(m, field, eq);
2624
c57d2a76
ZJS
2625 if (STR_IN_SET(field, "SuccessActionExitStatus",
2626 "FailureActionExitStatus")) {
7af67e9a
LP
2627 if (isempty(eq))
2628 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2629 else {
2630 uint8_t u;
2631
2632 r = safe_atou8(eq, &u);
2633 if (r < 0)
2634 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2635
2636 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2637 }
2638 if (r < 0)
2639 return bus_log_create_error(r);
2640
2641 return 1;
2642 }
2643
3d63c749 2644 if (unit_dependency_from_string(field) >= 0 ||
c57d2a76 2645 STR_IN_SET(field, "Documentation",
0dd3c090 2646 "RequiresMountsFor",
9e615fa3 2647 "WantsMountsFor",
0dd3c090 2648 "Markers"))
4ec85141 2649 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2650
3d63c749
YW
2651 t = condition_type_from_string(field);
2652 if (t >= 0)
2653 is_condition = true;
2654 else
2655 t = assert_type_from_string(field);
2656 if (t >= 0) {
2657 if (isempty(eq))
2658 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2659 else {
2660 const char *p = eq;
2661 int trigger, negate;
2662
2663 trigger = *p == '|';
2664 if (trigger)
2665 p++;
2666
2667 negate = *p == '!';
2668 if (negate)
2669 p++;
2670
2671 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2672 field, trigger, negate, p);
2673 }
2674 if (r < 0)
2675 return bus_log_create_error(r);
2676
2677 return 1;
2678 }
2679
89ada3ba
YW
2680 return 0;
2681}
2682
2683int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2684 const char *eq, *field;
2685 int r;
2686
2687 assert(m);
2688 assert(assignment);
2689
2690 eq = strchr(assignment, '=');
baaa35ad
ZJS
2691 if (!eq)
2692 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2693 "Not an assignment: %s", assignment);
89ada3ba 2694
2f82562b 2695 field = strndupa_safe(assignment, eq - assignment);
89ada3ba
YW
2696 eq++;
2697
2698 switch (t) {
2699 case UNIT_SERVICE:
2700 r = bus_append_cgroup_property(m, field, eq);
2701 if (r != 0)
f6c66be1
LP
2702 return r;
2703
89ada3ba
YW
2704 r = bus_append_execute_property(m, field, eq);
2705 if (r != 0)
2706 return r;
f6c66be1 2707
89ada3ba
YW
2708 r = bus_append_kill_property(m, field, eq);
2709 if (r != 0)
2710 return r;
f6c66be1 2711
89ada3ba
YW
2712 r = bus_append_service_property(m, field, eq);
2713 if (r != 0)
2714 return r;
2715 break;
f6c66be1 2716
89ada3ba
YW
2717 case UNIT_SOCKET:
2718 r = bus_append_cgroup_property(m, field, eq);
2719 if (r != 0)
2720 return r;
f6c66be1 2721
89ada3ba
YW
2722 r = bus_append_execute_property(m, field, eq);
2723 if (r != 0)
2724 return r;
f6c66be1 2725
89ada3ba
YW
2726 r = bus_append_kill_property(m, field, eq);
2727 if (r != 0)
2728 return r;
f6c66be1 2729
89ada3ba
YW
2730 r = bus_append_socket_property(m, field, eq);
2731 if (r != 0)
f6c66be1 2732 return r;
89ada3ba 2733 break;
f6c66be1 2734
89ada3ba
YW
2735 case UNIT_TIMER:
2736 r = bus_append_timer_property(m, field, eq);
2737 if (r != 0)
2738 return r;
2739 break;
f6c66be1 2740
89ada3ba
YW
2741 case UNIT_PATH:
2742 r = bus_append_path_property(m, field, eq);
2743 if (r != 0)
2744 return r;
2745 break;
268833ed 2746
89ada3ba
YW
2747 case UNIT_SLICE:
2748 r = bus_append_cgroup_property(m, field, eq);
2749 if (r != 0)
2750 return r;
2751 break;
268833ed 2752
89ada3ba
YW
2753 case UNIT_SCOPE:
2754 r = bus_append_cgroup_property(m, field, eq);
2755 if (r != 0)
2756 return r;
268833ed 2757
89ada3ba 2758 r = bus_append_kill_property(m, field, eq);
5a70a68f
PW
2759 if (r != 0)
2760 return r;
2761
2762 r = bus_append_scope_property(m, field, eq);
89ada3ba
YW
2763 if (r != 0)
2764 return r;
2765 break;
535e0d19 2766
89ada3ba 2767 case UNIT_MOUNT:
3d63c749
YW
2768 r = bus_append_cgroup_property(m, field, eq);
2769 if (r != 0)
2770 return r;
2771
2772 r = bus_append_execute_property(m, field, eq);
2773 if (r != 0)
2774 return r;
2775
2776 r = bus_append_kill_property(m, field, eq);
2777 if (r != 0)
2778 return r;
2779
2780 r = bus_append_mount_property(m, field, eq);
2781 if (r != 0)
2782 return r;
2783
2784 break;
2785
89ada3ba 2786 case UNIT_AUTOMOUNT:
3d63c749
YW
2787 r = bus_append_automount_property(m, field, eq);
2788 if (r != 0)
2789 return r;
2790
89ada3ba 2791 break;
535e0d19 2792
89ada3ba
YW
2793 case UNIT_TARGET:
2794 case UNIT_DEVICE:
2795 case UNIT_SWAP:
eab62c01 2796 break;
535e0d19 2797
89ada3ba 2798 default:
eab62c01 2799 assert_not_reached();
20b16441
LP
2800 }
2801
89ada3ba
YW
2802 r = bus_append_unit_property(m, field, eq);
2803 if (r != 0)
2804 return r;
20b16441 2805
baaa35ad
ZJS
2806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2807 "Unknown assignment: %s", assignment);
20b16441
LP
2808}
2809
89ada3ba 2810int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
2811 int r;
2812
2813 assert(m);
2814
2815 STRV_FOREACH(i, l) {
89ada3ba 2816 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
2817 if (r < 0)
2818 return r;
2819 }
2820
2821 return 0;
2822}
2823
66b574b0 2824int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
7eda208f
LP
2825 assert(m);
2826
2827 if (!pidref_is_set(pidref))
2828 return -ESRCH;
2829
66b574b0 2830 if (pidref->fd >= 0 && allow_pidfd)
7eda208f
LP
2831 return sd_bus_message_append(
2832 m, "(sv)",
2833 "PIDFDs", "ah", 1, pidref->fd);
2834
2835 return sd_bus_message_append(
2836 m, "(sv)",
2837 "PIDs", "au", 1, pidref->pid);
2838}
2839
5e891cbb 2840int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
20b16441 2841 const char *type, *path, *source;
5e891cbb
DT
2842 InstallChange *changes = NULL;
2843 size_t n_changes = 0;
20b16441
LP
2844 int r;
2845
5e891cbb 2846 CLEANUP_ARRAY(changes, n_changes, install_changes_free);
acc0269c 2847
20b16441
LP
2848 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2849 if (r < 0)
2850 return bus_log_parse_error(r);
2851
2852 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
f8662fee
LP
2853 InstallChangeType t;
2854
2855 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2856 * negative. */
2857 t = install_change_type_from_string(type);
2858 if (t < 0) {
2859 log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
c1b48a7f 2860 type, path);
20b16441
LP
2861 continue;
2862 }
2863
5e891cbb 2864 r = install_changes_add(&changes, &n_changes, t, path, source);
20b16441
LP
2865 if (r < 0)
2866 return r;
2867 }
2868 if (r < 0)
2869 return bus_log_parse_error(r);
2870
2871 r = sd_bus_message_exit_container(m);
2872 if (r < 0)
2873 return bus_log_parse_error(r);
2874
5e891cbb
DT
2875 install_changes_dump(0, NULL, changes, n_changes, quiet);
2876
20b16441
LP
2877 return 0;
2878}
2879
bd062910
ZJS
2880int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2881 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2882 _cleanup_free_ char *path = NULL;
2883 int r;
2884
2885 path = unit_dbus_path_from_name(name);
2886 if (!path)
2887 return log_oom();
2888
18fe76eb 2889 /* This function warns on its own, because otherwise it'd be awkward to pass
bd062910
ZJS
2890 * the dbus error message around. */
2891
2892 r = sd_bus_get_property_string(
2893 bus,
2894 "org.freedesktop.systemd1",
2895 path,
2896 "org.freedesktop.systemd1.Unit",
2897 "LoadState",
2898 &error,
2899 load_state);
2900 if (r < 0)
2901 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2902
2903 return 0;
2904}
4dcc0653
LP
2905
2906int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2907 int r;
2908
2909 /* First, order by machine */
2910 r = strcasecmp_ptr(a->machine, b->machine);
2911 if (r != 0)
2912 return r;
2913
2914 /* Second, order by unit type */
2915 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2916 if (r != 0)
2917 return r;
2918
2919 /* Third, order by name */
2920 return strcasecmp(a->id, b->id);
2921}
a9399358
LP
2922
2923int bus_service_manager_reload(sd_bus *bus) {
2924 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2925 _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
2926 int r;
2927
2928 assert(bus);
2929
2930 r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
2931 if (r < 0)
2932 return bus_log_create_error(r);
2933
2934 /* Reloading the daemon may take long, hence set a longer timeout here */
2935 r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
2936 if (r < 0)
2937 return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
2938
2939 return 0;
2940}
74837081 2941
5ba6321d
MY
2942/* Wait for 1.5 seconds at maximum for freeze operation */
2943#define FREEZE_BUS_CALL_TIMEOUT (1500 * USEC_PER_MSEC)
2944
74837081
AV
2945int unit_freezer_new(const char *name, UnitFreezer *ret) {
2946 _cleanup_(sd_bus_flush_close_unrefp) sd_bus *bus = NULL;
2947 _cleanup_free_ char *namedup = NULL;
2948 int r;
2949
2950 assert(name);
2951 assert(ret);
2952
2953 namedup = strdup(name);
2954 if (!namedup)
2955 return log_oom_debug();
2956
2957 r = bus_connect_system_systemd(&bus);
2958 if (r < 0)
2959 return log_debug_errno(r, "Failed to open connection to systemd: %m");
2960
5ba6321d 2961 (void) sd_bus_set_method_call_timeout(bus, FREEZE_BUS_CALL_TIMEOUT);
74837081
AV
2962
2963 *ret = (UnitFreezer) {
2964 .name = TAKE_PTR(namedup),
2965 .bus = TAKE_PTR(bus),
2966 };
2967 return 0;
2968}
2969
dc35af47
MY
2970void unit_freezer_done(UnitFreezer *f) {
2971 assert(f);
2972
2973 f->name = mfree(f->name);
2974 f->bus = sd_bus_flush_close_unref(f->bus);
2975}
2976
2977static int unit_freezer_action(UnitFreezer *f, bool freeze) {
74837081
AV
2978 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2979 int r;
2980
2981 assert(f);
74837081 2982 assert(f->name);
dc35af47 2983 assert(f->bus);
74837081 2984
dc35af47
MY
2985 r = bus_call_method(f->bus, bus_systemd_mgr,
2986 freeze ? "FreezeUnit" : "ThawUnit",
2987 &error,
2988 /* reply = */ NULL,
2989 "s",
2990 f->name);
74837081 2991 if (r < 0)
dc35af47
MY
2992 return log_debug_errno(r, "Failed to %s unit %s: %s",
2993 freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
74837081
AV
2994
2995 return 0;
2996}
2997
2998int unit_freezer_freeze(UnitFreezer *f) {
dc35af47 2999 return unit_freezer_action(f, true);
74837081
AV
3000}
3001
3002int unit_freezer_thaw(UnitFreezer *f) {
dc35af47 3003 return unit_freezer_action(f, false);
74837081
AV
3004}
3005
3006int unit_freezer_new_freeze(const char *name, UnitFreezer *ret) {
3007 _cleanup_(unit_freezer_done) UnitFreezer f = {};
3008 int r;
3009
3010 assert(name);
3011 assert(ret);
3012
3013 r = unit_freezer_new(name, &f);
3014 if (r < 0)
3015 return r;
3016
3017 r = unit_freezer_freeze(&f);
3018 if (r < 0)
3019 return r;
3020
3021 *ret = TAKE_STRUCT(f);
3022 return 0;
3023}
3024
3025void unit_freezer_done_thaw(UnitFreezer *f) {
3026 assert(f);
3027
3028 if (!f->name)
3029 return;
3030
3031 (void) unit_freezer_thaw(f);
3032 unit_freezer_done(f);
3033}