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