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