]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
Merge pull request #23148 from poettering/creds-util-mini-tweaks
[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);
bb0c0d6f 1159 if (r == 0 || !p)
43144be4 1160 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f
LP
1161
1162 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1163 }
1164 if (r < 0)
1165 return bus_log_create_error(r);
1166
1167 r = sd_bus_message_close_container(m);
1168 if (r < 0)
1169 return bus_log_create_error(r);
1170
1171 r = sd_bus_message_close_container(m);
1172 if (r < 0)
1173 return bus_log_create_error(r);
1174
1175 return 1;
1176 }
1177
89ada3ba 1178 if (streq(field, "LogExtraFields")) {
89ada3ba 1179 r = sd_bus_message_open_container(m, 'r', "sv");
3f856a28
YW
1180 if (r < 0)
1181 return bus_log_create_error(r);
1182
89ada3ba 1183 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
3f856a28
YW
1184 if (r < 0)
1185 return bus_log_create_error(r);
1186
89ada3ba 1187 r = sd_bus_message_open_container(m, 'v', "aay");
3f856a28
YW
1188 if (r < 0)
1189 return bus_log_create_error(r);
1190
89ada3ba 1191 r = sd_bus_message_open_container(m, 'a', "ay");
cffaed83
YW
1192 if (r < 0)
1193 return bus_log_create_error(r);
1194
89ada3ba 1195 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
3f856a28
YW
1196 if (r < 0)
1197 return bus_log_create_error(r);
cffaed83 1198
3f856a28
YW
1199 r = sd_bus_message_close_container(m);
1200 if (r < 0)
1201 return bus_log_create_error(r);
9f617cd0 1202
89ada3ba
YW
1203 r = sd_bus_message_close_container(m);
1204 if (r < 0)
1205 return bus_log_create_error(r);
9efb9df9 1206
89ada3ba 1207 r = sd_bus_message_close_container(m);
9efb9df9 1208 if (r < 0)
89ada3ba
YW
1209 return bus_log_create_error(r);
1210
1211 return 1;
1212 }
9efb9df9 1213
c57d2a76
ZJS
1214 if (STR_IN_SET(field, "StandardInput",
1215 "StandardOutput",
1216 "StandardError")) {
89ada3ba 1217 const char *n, *appended;
9efb9df9 1218
89ada3ba
YW
1219 if ((n = startswith(eq, "fd:"))) {
1220 appended = strjoina(field, "FileDescriptorName");
1221 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1222 } else if ((n = startswith(eq, "file:"))) {
1223 appended = strjoina(field, "File");
1224 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d33232e
LP
1225 } else if ((n = startswith(eq, "append:"))) {
1226 appended = strjoina(field, "FileToAppend");
1227 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d7dab1f
LW
1228 } else if ((n = startswith(eq, "truncate:"))) {
1229 appended = strjoina(field, "FileToTruncate");
1230 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
89ada3ba
YW
1231 } else
1232 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
89ada3ba
YW
1233 if (r < 0)
1234 return bus_log_create_error(r);
7f452159 1235
89ada3ba
YW
1236 return 1;
1237 }
7f452159 1238
89ada3ba
YW
1239 if (streq(field, "StandardInputText")) {
1240 _cleanup_free_ char *unescaped = NULL;
e437538f 1241 ssize_t l;
7f452159 1242
e437538f
ZJS
1243 l = cunescape(eq, 0, &unescaped);
1244 if (l < 0)
1245 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
7f452159 1246
c2bc710b 1247 if (!strextend(&unescaped, "\n"))
89ada3ba 1248 return log_oom();
7f452159 1249
e437538f
ZJS
1250 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1251 * programmatic interface anyway */
20b16441 1252
e437538f 1253 return bus_append_byte_array(m, field, unescaped, l + 1);
89ada3ba 1254 }
20b16441 1255
89ada3ba
YW
1256 if (streq(field, "StandardInputData")) {
1257 _cleanup_free_ void *decoded = NULL;
1258 size_t sz;
1259
f5fbe71d 1260 r = unbase64mem(eq, SIZE_MAX, &decoded, &sz);
20b16441 1261 if (r < 0)
89ada3ba 1262 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
20b16441 1263
89ada3ba
YW
1264 return bus_append_byte_array(m, field, decoded, sz);
1265 }
20b16441 1266
6550c24c
LP
1267 if ((suffix = startswith(field, "Limit"))) {
1268 int rl;
20b16441 1269
6550c24c
LP
1270 rl = rlimit_from_string(suffix);
1271 if (rl >= 0) {
1272 const char *sn;
1273 struct rlimit l;
20b16441 1274
6550c24c
LP
1275 r = rlimit_parse(rl, eq, &l);
1276 if (r < 0)
1277 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
20b16441 1278
6550c24c
LP
1279 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
1280 if (r < 0)
1281 return bus_log_create_error(r);
20b16441 1282
6550c24c
LP
1283 sn = strjoina(field, "Soft");
1284 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
1285 if (r < 0)
1286 return bus_log_create_error(r);
1287
1288 return 1;
1289 }
89ada3ba 1290 }
20b16441 1291
c57d2a76
ZJS
1292 if (STR_IN_SET(field, "AppArmorProfile",
1293 "SmackProcessLabel")) {
89ada3ba
YW
1294 int ignore = 0;
1295 const char *s = eq;
20b16441 1296
89ada3ba
YW
1297 if (eq[0] == '-') {
1298 ignore = 1;
1299 s = eq + 1;
20b16441
LP
1300 }
1301
89ada3ba 1302 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
6bbfdc67 1303 if (r < 0)
89ada3ba 1304 return bus_log_create_error(r);
20b16441 1305
89ada3ba
YW
1306 return 1;
1307 }
20b16441 1308
c57d2a76
ZJS
1309 if (STR_IN_SET(field, "CapabilityBoundingSet",
1310 "AmbientCapabilities")) {
89ada3ba
YW
1311 uint64_t sum = 0;
1312 bool invert = false;
1313 const char *p = eq;
afcb1cd3 1314
89ada3ba
YW
1315 if (*p == '~') {
1316 invert = true;
1317 p++;
1318 }
20b16441 1319
89ada3ba 1320 r = capability_set_from_string(p, &sum);
20b16441 1321 if (r < 0)
89ada3ba 1322 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
20b16441 1323
89ada3ba
YW
1324 sum = invert ? ~sum : sum;
1325
1326 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
20b16441
LP
1327 if (r < 0)
1328 return bus_log_create_error(r);
1329
89ada3ba
YW
1330 return 1;
1331 }
20b16441 1332
89ada3ba 1333 if (streq(field, "CPUAffinity")) {
0985c7c4 1334 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
c367f996
MS
1335 _cleanup_free_ uint8_t *array = NULL;
1336 size_t allocated;
20b16441 1337
e2b2fb7f
MS
1338 if (eq && streq(eq, "numa")) {
1339 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1340 if (r < 0)
1341 return bus_log_create_error(r);
1342 return r;
1343 }
1344
89ada3ba
YW
1345 r = parse_cpu_set(eq, &cpuset);
1346 if (r < 0)
1347 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
20b16441 1348
c367f996
MS
1349 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1350 if (r < 0)
1351 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1352
1353 return bus_append_byte_array(m, field, array, allocated);
89ada3ba 1354 }
20b7a007 1355
b070c7c0
MS
1356 if (streq(field, "NUMAPolicy")) {
1357 r = mpol_from_string(eq);
1358 if (r < 0)
1359 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1360
1361 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1362 if (r < 0)
1363 return bus_log_create_error(r);
1364
1365 return 1;
1366 }
1367
1368 if (streq(field, "NUMAMask")) {
1369 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1370 _cleanup_free_ uint8_t *array = NULL;
1371 size_t allocated;
1372
332d387f
MS
1373 if (eq && streq(eq, "all")) {
1374 r = numa_mask_add_all(&nodes);
1375 if (r < 0)
1376 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1377 } else {
1378 r = parse_cpu_set(eq, &nodes);
1379 if (r < 0)
1380 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1381 }
b070c7c0
MS
1382
1383 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1384 if (r < 0)
1385 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1386
1387 return bus_append_byte_array(m, field, array, allocated);
1388 }
1389
c57d2a76 1390 if (STR_IN_SET(field, "RestrictAddressFamilies",
cc86a278 1391 "RestrictFileSystems",
9df2cdd8 1392 "SystemCallFilter",
a59cb62c
MV
1393 "SystemCallLog",
1394 "RestrictNetworkInterfaces")) {
6b000af4 1395 int allow_list = 1;
89ada3ba 1396 const char *p = eq;
20b16441 1397
89ada3ba 1398 if (*p == '~') {
6b000af4 1399 allow_list = 0;
89ada3ba 1400 p++;
20b16441
LP
1401 }
1402
89ada3ba 1403 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1404 if (r < 0)
1405 return bus_log_create_error(r);
1406
89ada3ba
YW
1407 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1408 if (r < 0)
1409 return bus_log_create_error(r);
1410
1411 r = sd_bus_message_open_container(m, 'v', "(bas)");
1412 if (r < 0)
1413 return bus_log_create_error(r);
20b16441 1414
89ada3ba
YW
1415 r = sd_bus_message_open_container(m, 'r', "bas");
1416 if (r < 0)
1417 return bus_log_create_error(r);
cffaed83 1418
6b000af4 1419 r = sd_bus_message_append_basic(m, 'b', &allow_list);
cffaed83
YW
1420 if (r < 0)
1421 return bus_log_create_error(r);
1422
1423 r = sd_bus_message_open_container(m, 'a', "s");
1424 if (r < 0)
1425 return bus_log_create_error(r);
1426
98008caa 1427 for (;;) {
cffaed83
YW
1428 _cleanup_free_ char *word = NULL;
1429
4ec85141 1430 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
cffaed83
YW
1431 if (r == 0)
1432 break;
89ada3ba
YW
1433 if (r == -ENOMEM)
1434 return log_oom();
1435 if (r < 0)
1436 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1437
1438 r = sd_bus_message_append_basic(m, 's', word);
1439 if (r < 0)
1440 return bus_log_create_error(r);
1441 }
1442
1443 r = sd_bus_message_close_container(m);
1444 if (r < 0)
1445 return bus_log_create_error(r);
1446
1447 r = sd_bus_message_close_container(m);
20b16441
LP
1448 if (r < 0)
1449 return bus_log_create_error(r);
1450
89ada3ba 1451 r = sd_bus_message_close_container(m);
20b16441
LP
1452 if (r < 0)
1453 return bus_log_create_error(r);
1454
20b16441
LP
1455 r = sd_bus_message_close_container(m);
1456 if (r < 0)
1457 return bus_log_create_error(r);
1458
89ada3ba
YW
1459 return 1;
1460 }
20b16441 1461
89ada3ba 1462 if (streq(field, "RestrictNamespaces")) {
add00535 1463 bool invert = false;
aa9d574d 1464 unsigned long flags;
add00535
LP
1465
1466 r = parse_boolean(eq);
1467 if (r > 0)
1468 flags = 0;
1469 else if (r == 0)
1470 flags = NAMESPACE_FLAGS_ALL;
1471 else {
aa9d574d
YW
1472 if (eq[0] == '~') {
1473 invert = true;
1474 eq++;
1475 }
1476
86c2a9f1 1477 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1478 if (r < 0)
1479 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1480 }
1481
1482 if (invert)
1483 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1484
89ada3ba
YW
1485 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1486 if (r < 0)
1487 return bus_log_create_error(r);
afcb1cd3 1488
89ada3ba
YW
1489 return 1;
1490 }
afcb1cd3 1491
c57d2a76
ZJS
1492 if (STR_IN_SET(field, "BindPaths",
1493 "BindReadOnlyPaths")) {
89ada3ba 1494 const char *p = eq;
83555251 1495
89ada3ba 1496 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1497 if (r < 0)
89ada3ba 1498 return bus_log_create_error(r);
afcb1cd3 1499
89ada3ba
YW
1500 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1501 if (r < 0)
1502 return bus_log_create_error(r);
d2d6c096
LP
1503
1504 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1505 if (r < 0)
89ada3ba 1506 return bus_log_create_error(r);
d2d6c096
LP
1507
1508 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1509 if (r < 0)
89ada3ba 1510 return bus_log_create_error(r);
d2d6c096
LP
1511
1512 for (;;) {
1513 _cleanup_free_ char *source = NULL, *destination = NULL;
1514 char *s = NULL, *d = NULL;
1515 bool ignore_enoent = false;
1516 uint64_t flags = MS_REC;
1517
4ec85141 1518 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1519 if (r < 0)
1520 return log_error_errno(r, "Failed to parse argument: %m");
1521 if (r == 0)
1522 break;
1523
1524 s = source;
1525 if (s[0] == '-') {
1526 ignore_enoent = true;
1527 s++;
1528 }
1529
1530 if (p && p[-1] == ':') {
4ec85141 1531 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1532 if (r < 0)
1533 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1534 if (r == 0)
1535 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1536 "Missing argument after ':': %s",
1537 eq);
d2d6c096
LP
1538
1539 d = destination;
1540
1541 if (p && p[-1] == ':') {
1542 _cleanup_free_ char *options = NULL;
1543
4ec85141 1544 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
d2d6c096
LP
1545 if (r < 0)
1546 return log_error_errno(r, "Failed to parse argument: %m");
1547
1548 if (isempty(options) || streq(options, "rbind"))
1549 flags = MS_REC;
1550 else if (streq(options, "norbind"))
1551 flags = 0;
baaa35ad
ZJS
1552 else
1553 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1554 "Unknown options: %s",
1555 eq);
d2d6c096
LP
1556 }
1557 } else
1558 d = s;
1559
d2d6c096
LP
1560 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1561 if (r < 0)
89ada3ba 1562 return bus_log_create_error(r);
d2d6c096
LP
1563 }
1564
1565 r = sd_bus_message_close_container(m);
1566 if (r < 0)
89ada3ba
YW
1567 return bus_log_create_error(r);
1568
1569 r = sd_bus_message_close_container(m);
1570 if (r < 0)
1571 return bus_log_create_error(r);
d2d6c096
LP
1572
1573 r = sd_bus_message_close_container(m);
89ada3ba
YW
1574 if (r < 0)
1575 return bus_log_create_error(r);
f6c66be1 1576
89ada3ba
YW
1577 return 1;
1578 }
f6c66be1 1579
784ad252
YW
1580 if (streq(field, "TemporaryFileSystem")) {
1581 const char *p = eq;
1582
1583 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1584 if (r < 0)
1585 return bus_log_create_error(r);
1586
1587 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1588 if (r < 0)
1589 return bus_log_create_error(r);
1590
1591 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1592 if (r < 0)
1593 return bus_log_create_error(r);
1594
1595 r = sd_bus_message_open_container(m, 'a', "(ss)");
1596 if (r < 0)
1597 return bus_log_create_error(r);
1598
1599 for (;;) {
1600 _cleanup_free_ char *word = NULL, *path = NULL;
1601 const char *w;
1602
4ec85141 1603 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
784ad252
YW
1604 if (r < 0)
1605 return log_error_errno(r, "Failed to parse argument: %m");
1606 if (r == 0)
1607 break;
1608
1609 w = word;
1610 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1611 if (r < 0)
1612 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1613 if (r == 0)
1614 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1615 "Failed to parse argument: %s",
1616 p);
784ad252
YW
1617
1618 r = sd_bus_message_append(m, "(ss)", path, w);
1619 if (r < 0)
1620 return bus_log_create_error(r);
1621 }
1622
1623 r = sd_bus_message_close_container(m);
1624 if (r < 0)
1625 return bus_log_create_error(r);
1626
1627 r = sd_bus_message_close_container(m);
1628 if (r < 0)
1629 return bus_log_create_error(r);
1630
1631 r = sd_bus_message_close_container(m);
1632 if (r < 0)
1633 return bus_log_create_error(r);
1634
1635 return 1;
1636 }
1637
0389f4fa
LB
1638 if (streq(field, "RootHash")) {
1639 _cleanup_free_ void *roothash_decoded = NULL;
1640 size_t roothash_decoded_size = 0;
1641
1642 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1643 if (path_is_absolute(eq))
1644 return bus_append_string(m, "RootHashPath", eq);
1645
1646 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1647 r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
1648 if (r < 0)
1649 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1650 if (roothash_decoded_size < sizeof(sd_id128_t))
1651 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
1652
1653 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1654 }
1655
d4d55b0d
LB
1656 if (streq(field, "RootHashSignature")) {
1657 _cleanup_free_ void *roothash_sig_decoded = NULL;
1658 char *value;
1659 size_t roothash_sig_decoded_size = 0;
1660
1661 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1662 if (path_is_absolute(eq))
1663 return bus_append_string(m, "RootHashSignaturePath", eq);
1664
1665 if (!(value = startswith(eq, "base64:")))
1666 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
1667
1668 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1669 r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
1670 if (r < 0)
1671 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1672
1673 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1674 }
1675
18d73705 1676 if (streq(field, "RootImageOptions")) {
bc8d56d3 1677 _cleanup_strv_free_ char **l = NULL;
18d73705
LB
1678 const char *p = eq;
1679
1680 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1681 if (r < 0)
1682 return bus_log_create_error(r);
1683
1684 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1685 if (r < 0)
1686 return bus_log_create_error(r);
1687
9ece6444 1688 r = sd_bus_message_open_container(m, 'v', "a(ss)");
18d73705
LB
1689 if (r < 0)
1690 return bus_log_create_error(r);
1691
9ece6444 1692 r = sd_bus_message_open_container(m, 'a', "(ss)");
18d73705
LB
1693 if (r < 0)
1694 return bus_log_create_error(r);
1695
bc8d56d3
LB
1696 r = strv_split_colon_pairs(&l, p);
1697 if (r < 0)
1698 return log_error_errno(r, "Failed to parse argument: %m");
18d73705 1699
bc8d56d3 1700 STRV_FOREACH_PAIR(first, second, l) {
9ece6444
LB
1701 r = sd_bus_message_append(m, "(ss)",
1702 !isempty(*second) ? *first : "root",
1703 !isempty(*second) ? *second : *first);
18d73705
LB
1704 if (r < 0)
1705 return bus_log_create_error(r);
1706 }
1707
1708 r = sd_bus_message_close_container(m);
1709 if (r < 0)
b3d13314
LB
1710 return bus_log_create_error(r);
1711
1712 r = sd_bus_message_close_container(m);
1713 if (r < 0)
1714 return bus_log_create_error(r);
1715
1716 r = sd_bus_message_close_container(m);
1717 if (r < 0)
1718 return bus_log_create_error(r);
1719
1720 return 1;
1721 }
1722
1723 if (streq(field, "MountImages")) {
b3d13314
LB
1724 const char *p = eq;
1725
1726 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1727 if (r < 0)
1728 return bus_log_create_error(r);
1729
1730 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1731 if (r < 0)
1732 return bus_log_create_error(r);
1733
427353f6 1734 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
b3d13314
LB
1735 if (r < 0)
1736 return bus_log_create_error(r);
1737
427353f6 1738 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
b3d13314
LB
1739 if (r < 0)
1740 return bus_log_create_error(r);
1741
427353f6
LB
1742 for (;;) {
1743 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1744 const char *q = NULL, *source = NULL;
b3d13314
LB
1745 bool permissive = false;
1746
427353f6
LB
1747 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1748 if (r < 0)
de4abc3f 1749 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1750 if (r == 0)
1751 break;
1752
1753 q = tuple;
1754 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
1755 if (r < 0)
de4abc3f 1756 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1757 if (r == 0)
1758 continue;
1759
1760 source = first;
1761 if (source[0] == '-') {
b3d13314 1762 permissive = true;
427353f6 1763 source++;
b3d13314
LB
1764 }
1765
427353f6 1766 if (isempty(second))
b3d13314
LB
1767 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1768 "Missing argument after ':': %s",
1769 eq);
1770
427353f6
LB
1771 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
1772 if (r < 0)
1773 return bus_log_create_error(r);
1774
1775 r = sd_bus_message_append(m, "ssb", source, second, permissive);
1776 if (r < 0)
1777 return bus_log_create_error(r);
1778
1779 r = sd_bus_message_open_container(m, 'a', "(ss)");
1780 if (r < 0)
1781 return bus_log_create_error(r);
1782
1783 for (;;) {
1784 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1785
1786 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1787 if (r < 0)
de4abc3f 1788 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
93f59701
LB
1789 if (r == 0)
1790 break;
1791 /* Single set of options, applying to the root partition/single filesystem */
1792 if (r == 1) {
1793 r = sd_bus_message_append(m, "(ss)", "root", partition);
1794 if (r < 0)
1795 return bus_log_create_error(r);
1796
1797 break;
1798 }
1799
93f59701
LB
1800 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1801 if (r < 0)
1802 return bus_log_create_error(r);
1803 }
1804
1805 r = sd_bus_message_close_container(m);
1806 if (r < 0)
1807 return bus_log_create_error(r);
1808
1809 r = sd_bus_message_close_container(m);
1810 if (r < 0)
1811 return bus_log_create_error(r);
1812 }
1813
1814 r = sd_bus_message_close_container(m);
1815 if (r < 0)
1816 return bus_log_create_error(r);
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 return 1;
1827 }
1828
1829 if (streq(field, "ExtensionImages")) {
1830 const char *p = eq;
1831
1832 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1833 if (r < 0)
1834 return bus_log_create_error(r);
1835
1836 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1837 if (r < 0)
1838 return bus_log_create_error(r);
1839
1840 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
1841 if (r < 0)
1842 return bus_log_create_error(r);
1843
1844 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
1845 if (r < 0)
1846 return bus_log_create_error(r);
1847
1848 for (;;) {
1849 _cleanup_free_ char *source = NULL, *tuple = NULL;
1850 const char *q = NULL, *s = NULL;
1851 bool permissive = false;
1852
1853 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1854 if (r < 0)
de4abc3f 1855 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1856 if (r == 0)
1857 break;
1858
1859 q = tuple;
1860 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
1861 if (r < 0)
de4abc3f 1862 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1863 if (r == 0)
1864 continue;
1865
1866 s = source;
1867 if (s[0] == '-') {
1868 permissive = true;
1869 s++;
1870 }
1871
1872 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
1873 if (r < 0)
1874 return bus_log_create_error(r);
1875
1876 r = sd_bus_message_append(m, "sb", s, permissive);
1877 if (r < 0)
1878 return bus_log_create_error(r);
1879
1880 r = sd_bus_message_open_container(m, 'a', "(ss)");
1881 if (r < 0)
1882 return bus_log_create_error(r);
1883
1884 for (;;) {
1885 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1886
1887 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1888 if (r < 0)
de4abc3f 1889 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
427353f6
LB
1890 if (r == 0)
1891 break;
1892 /* Single set of options, applying to the root partition/single filesystem */
1893 if (r == 1) {
1894 r = sd_bus_message_append(m, "(ss)", "root", partition);
1895 if (r < 0)
1896 return bus_log_create_error(r);
1897
1898 break;
1899 }
1900
427353f6
LB
1901 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1902 if (r < 0)
1903 return bus_log_create_error(r);
1904 }
1905
1906 r = sd_bus_message_close_container(m);
1907 if (r < 0)
1908 return bus_log_create_error(r);
1909
1910 r = sd_bus_message_close_container(m);
b3d13314
LB
1911 if (r < 0)
1912 return bus_log_create_error(r);
1913 }
1914
1915 r = sd_bus_message_close_container(m);
1916 if (r < 0)
18d73705
LB
1917 return bus_log_create_error(r);
1918
1919 r = sd_bus_message_close_container(m);
1920 if (r < 0)
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 return 1;
1928 }
1929
211a3d87
LB
1930 if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
1931 _cleanup_strv_free_ char **symlinks = NULL, **sources = NULL;
1932 const char *p = eq;
1933
1934 /* Adding new directories is supported from both *DirectorySymlink methods and the
1935 * older ones, so first parse the input, and if we are given a new-style src:dst
1936 * tuple use the new method, else use the old one. */
1937
1938 for (;;) {
1939 _cleanup_free_ char *tuple = NULL, *source = NULL, *destination = NULL;
1940
1941 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
1942 if (r < 0)
1943 return log_error_errno(r, "Failed to parse argument: %m");
1944 if (r == 0)
1945 break;
1946
1947 const char *t = tuple;
1948 r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
1949 if (r <= 0)
1950 return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
1951
1952 path_simplify(source);
1953
1954 if (isempty(destination)) {
1955 r = strv_extend(&sources, TAKE_PTR(source));
1956 if (r < 0)
1957 return bus_log_create_error(r);
1958 } else {
1959 path_simplify(destination);
1960
1961 r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(destination));
1962 if (r < 0)
1963 return log_oom();
1964 }
1965 }
1966
1967 if (!strv_isempty(sources)) {
1968 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1969 if (r < 0)
1970 return bus_log_create_error(r);
1971
1972 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1973 if (r < 0)
1974 return bus_log_create_error(r);
1975
1976 r = sd_bus_message_open_container(m, 'v', "as");
1977 if (r < 0)
1978 return bus_log_create_error(r);
1979
1980 r = sd_bus_message_append_strv(m, sources);
1981 if (r < 0)
1982 return bus_log_create_error(r);
1983
1984 r = sd_bus_message_close_container(m);
1985 if (r < 0)
1986 return bus_log_create_error(r);
1987
1988 r = sd_bus_message_close_container(m);
1989 if (r < 0)
1990 return bus_log_create_error(r);
1991 }
1992
1993 /* For State and Runtime directories we support an optional destination parameter, which
1994 * will be used to create a symlink to the source. But it is new so we cannot change the
1995 * old DBUS signatures, so append a new message type. */
1996 if (!strv_isempty(symlinks)) {
1997 const char *symlink_field;
1998
1999 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2000 if (r < 0)
2001 return bus_log_create_error(r);
2002
2003 if (streq(field, "StateDirectory"))
2004 symlink_field = "StateDirectorySymlink";
2005 else if (streq(field, "RuntimeDirectory"))
2006 symlink_field = "RuntimeDirectorySymlink";
2007 else if (streq(field, "CacheDirectory"))
2008 symlink_field = "CacheDirectorySymlink";
2009 else if (streq(field, "LogsDirectory"))
2010 symlink_field = "LogsDirectorySymlink";
2011 else
2012 assert_not_reached();
2013
2014 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
2015 if (r < 0)
2016 return bus_log_create_error(r);
2017
2018 r = sd_bus_message_open_container(m, 'v', "a(sst)");
2019 if (r < 0)
2020 return bus_log_create_error(r);
2021
2022 r = sd_bus_message_open_container(m, 'a', "(sst)");
2023 if (r < 0)
2024 return bus_log_create_error(r);
2025
211a3d87
LB
2026 STRV_FOREACH_PAIR(source, destination, symlinks) {
2027 r = sd_bus_message_append(m, "(sst)", *source, *destination, 0);
2028 if (r < 0)
2029 return bus_log_create_error(r);
2030 }
2031
2032 r = sd_bus_message_close_container(m);
2033 if (r < 0)
2034 return bus_log_create_error(r);
2035
2036 r = sd_bus_message_close_container(m);
2037 if (r < 0)
2038 return bus_log_create_error(r);
2039
2040 r = sd_bus_message_close_container(m);
2041 if (r < 0)
2042 return bus_log_create_error(r);
2043 }
2044
2045 return 1;
2046 }
2047
89ada3ba
YW
2048 return 0;
2049}
f6c66be1 2050
89ada3ba 2051static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2052 if (streq(field, "KillMode"))
89ada3ba 2053 return bus_append_string(m, field, eq);
f6c66be1 2054
c57d2a76
ZJS
2055 if (STR_IN_SET(field, "SendSIGHUP",
2056 "SendSIGKILL"))
89ada3ba 2057 return bus_append_parse_boolean(m, field, eq);
f6c66be1 2058
c57d2a76
ZJS
2059 if (STR_IN_SET(field, "KillSignal",
2060 "RestartKillSignal",
2061 "FinalKillSignal",
2062 "WatchdogSignal"))
29a3db75 2063 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
2064
2065 return 0;
2066}
2067
3d63c749 2068static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2069
c57d2a76
ZJS
2070 if (STR_IN_SET(field, "What",
2071 "Where",
2072 "Options",
2073 "Type"))
89ada3ba
YW
2074 return bus_append_string(m, field, eq);
2075
3d63c749 2076 if (streq(field, "TimeoutSec"))
3d63c749
YW
2077 return bus_append_parse_sec_rename(m, field, eq);
2078
2079 if (streq(field, "DirectoryMode"))
3d63c749
YW
2080 return bus_append_parse_mode(m, field, eq);
2081
c57d2a76
ZJS
2082 if (STR_IN_SET(field, "SloppyOptions",
2083 "LazyUnmount",
c600357b
MH
2084 "ForceUnmount",
2085 "ReadwriteOnly"))
3d63c749
YW
2086 return bus_append_parse_boolean(m, field, eq);
2087
2088 return 0;
2089}
2090
2091static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
2092 int r;
2093
89ada3ba 2094 if (streq(field, "MakeDirectory"))
89ada3ba
YW
2095 return bus_append_parse_boolean(m, field, eq);
2096
2097 if (streq(field, "DirectoryMode"))
89ada3ba
YW
2098 return bus_append_parse_mode(m, field, eq);
2099
c57d2a76
ZJS
2100 if (STR_IN_SET(field, "PathExists",
2101 "PathExistsGlob",
2102 "PathChanged",
2103 "PathModified",
2104 "DirectoryNotEmpty")) {
3d63c749
YW
2105 if (isempty(eq))
2106 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
2107 else
2108 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
2109 if (r < 0)
2110 return bus_log_create_error(r);
2111
2112 return 1;
2113 }
2114
47dba9fb
LB
2115 if (streq(field, "TriggerLimitBurst"))
2116 return bus_append_safe_atou(m, field, eq);
2117
2118 if (streq(field, "TriggerLimitIntervalSec"))
2119 return bus_append_parse_sec_rename(m, field, eq);
2120
89ada3ba
YW
2121 return 0;
2122}
2123
5a70a68f 2124static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
9ed7de60 2125 if (streq(field, "RuntimeMaxSec"))
9ed7de60
PW
2126 return bus_append_parse_sec_rename(m, field, eq);
2127
5918a933
AB
2128 if (streq(field, "RuntimeRandomizedExtraSec"))
2129 return bus_append_parse_sec_rename(m, field, eq);
2130
5a70a68f 2131 if (streq(field, "TimeoutStopSec"))
5a70a68f
PW
2132 return bus_append_parse_sec_rename(m, field, eq);
2133
2134 return 0;
2135}
2136
89ada3ba 2137static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2138 int r;
89ada3ba 2139
c57d2a76
ZJS
2140 if (STR_IN_SET(field, "PIDFile",
2141 "Type",
596e4470 2142 "ExitType",
c57d2a76
ZJS
2143 "Restart",
2144 "BusName",
2145 "NotifyAccess",
2146 "USBFunctionDescriptors",
2147 "USBFunctionStrings",
bf760801
JK
2148 "OOMPolicy",
2149 "TimeoutStartFailureMode",
2150 "TimeoutStopFailureMode"))
89ada3ba 2151 return bus_append_string(m, field, eq);
f6c66be1 2152
c57d2a76
ZJS
2153 if (STR_IN_SET(field, "PermissionsStartOnly",
2154 "RootDirectoryStartOnly",
2155 "RemainAfterExit",
2156 "GuessMainPID"))
89ada3ba
YW
2157 return bus_append_parse_boolean(m, field, eq);
2158
c57d2a76
ZJS
2159 if (STR_IN_SET(field, "RestartSec",
2160 "TimeoutStartSec",
2161 "TimeoutStopSec",
e737017b 2162 "TimeoutAbortSec",
c57d2a76 2163 "RuntimeMaxSec",
5918a933 2164 "RuntimeRandomizedExtraSec",
c57d2a76 2165 "WatchdogSec"))
89ada3ba
YW
2166 return bus_append_parse_sec_rename(m, field, eq);
2167
3d63c749 2168 if (streq(field, "TimeoutSec")) {
3d63c749
YW
2169 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2170 if (r < 0)
2171 return r;
2172
2173 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2174 }
2175
89ada3ba 2176 if (streq(field, "FileDescriptorStoreMax"))
89ada3ba
YW
2177 return bus_append_safe_atou(m, field, eq);
2178
c57d2a76
ZJS
2179 if (STR_IN_SET(field, "ExecCondition",
2180 "ExecStartPre",
2181 "ExecStart",
2182 "ExecStartPost",
2183 "ExecConditionEx",
2184 "ExecStartPreEx",
2185 "ExecStartEx",
2186 "ExecStartPostEx",
2187 "ExecReload",
2188 "ExecStop",
2189 "ExecStopPost",
2190 "ExecReloadEx",
2191 "ExecStopEx",
2192 "ExecStopPostEx"))
89ada3ba
YW
2193 return bus_append_exec_command(m, field, eq);
2194
c57d2a76
ZJS
2195 if (STR_IN_SET(field, "RestartPreventExitStatus",
2196 "RestartForceExitStatus",
2197 "SuccessExitStatus")) {
3d63c749 2198 _cleanup_free_ int *status = NULL, *signal = NULL;
62b21e2e 2199 size_t n_status = 0, n_signal = 0;
3d63c749
YW
2200 const char *p;
2201
2202 for (p = eq;;) {
2203 _cleanup_free_ char *word = NULL;
3d63c749 2204
4ec85141 2205 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3d63c749
YW
2206 if (r == 0)
2207 break;
2208 if (r == -ENOMEM)
2209 return log_oom();
2210 if (r < 0)
2211 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2212
2e2ed880
ZJS
2213 /* We need to call exit_status_from_string() first, because we want
2214 * to parse numbers as exit statuses, not signals. */
3d63c749 2215
2e2ed880
ZJS
2216 r = exit_status_from_string(word);
2217 if (r >= 0) {
2218 assert(r >= 0 && r < 256);
3d63c749 2219
62b21e2e 2220 status = reallocarray(status, n_status + 1, sizeof(int));
3d63c749
YW
2221 if (!status)
2222 return log_oom();
2223
2e2ed880
ZJS
2224 status[n_status++] = r;
2225
2226 } else if ((r = signal_from_string(word)) >= 0) {
2227 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2228 if (!signal)
2229 return log_oom();
2230
2231 signal[n_signal++] = r;
2232
2233 } else
2234 /* original r from exit_status_to_string() */
2235 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2236 word, field);
3d63c749
YW
2237 }
2238
2239 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2240 if (r < 0)
2241 return bus_log_create_error(r);
2242
2243 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2244 if (r < 0)
2245 return bus_log_create_error(r);
2246
2247 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2248 if (r < 0)
2249 return bus_log_create_error(r);
2250
2251 r = sd_bus_message_open_container(m, 'r', "aiai");
2252 if (r < 0)
2253 return bus_log_create_error(r);
2254
62b21e2e 2255 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
3d63c749
YW
2256 if (r < 0)
2257 return bus_log_create_error(r);
2258
62b21e2e 2259 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
3d63c749
YW
2260 if (r < 0)
2261 return bus_log_create_error(r);
2262
2263 r = sd_bus_message_close_container(m);
2264 if (r < 0)
2265 return bus_log_create_error(r);
2266
2267 r = sd_bus_message_close_container(m);
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 return 1;
2276 }
2277
89ada3ba
YW
2278 return 0;
2279}
2280
2281static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2282 int r;
2283
c57d2a76 2284 if (STR_IN_SET(field, "Accept",
3e5f04bf 2285 "FlushPending",
c57d2a76
ZJS
2286 "Writable",
2287 "KeepAlive",
2288 "NoDelay",
2289 "FreeBind",
2290 "Transparent",
2291 "Broadcast",
2292 "PassCredentials",
2293 "PassSecurity",
a3d19f5d 2294 "PassPacketInfo",
c57d2a76
ZJS
2295 "ReusePort",
2296 "RemoveOnStop",
2297 "SELinuxContextFromNet"))
89ada3ba
YW
2298 return bus_append_parse_boolean(m, field, eq);
2299
c57d2a76
ZJS
2300 if (STR_IN_SET(field, "Priority",
2301 "IPTTL",
2302 "Mark"))
89ada3ba
YW
2303 return bus_append_safe_atoi(m, field, eq);
2304
2305 if (streq(field, "IPTOS"))
89ada3ba
YW
2306 return bus_append_ip_tos_from_string(m, field, eq);
2307
c57d2a76
ZJS
2308 if (STR_IN_SET(field, "Backlog",
2309 "MaxConnections",
2310 "MaxConnectionsPerSource",
2311 "KeepAliveProbes",
2312 "TriggerLimitBurst"))
89ada3ba
YW
2313 return bus_append_safe_atou(m, field, eq);
2314
c57d2a76
ZJS
2315 if (STR_IN_SET(field, "SocketMode",
2316 "DirectoryMode"))
89ada3ba
YW
2317 return bus_append_parse_mode(m, field, eq);
2318
c57d2a76
ZJS
2319 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2320 "MessageQueueMessageSize"))
89ada3ba
YW
2321 return bus_append_safe_atoi64(m, field, eq);
2322
c57d2a76
ZJS
2323 if (STR_IN_SET(field, "TimeoutSec",
2324 "KeepAliveTimeSec",
2325 "KeepAliveIntervalSec",
2326 "DeferAcceptSec",
2327 "TriggerLimitIntervalSec"))
89ada3ba
YW
2328 return bus_append_parse_sec_rename(m, field, eq);
2329
c57d2a76
ZJS
2330 if (STR_IN_SET(field, "ReceiveBuffer",
2331 "SendBuffer",
2332 "PipeSize"))
b48e508d 2333 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 2334
c57d2a76
ZJS
2335 if (STR_IN_SET(field, "ExecStartPre",
2336 "ExecStartPost",
2337 "ExecReload",
2338 "ExecStopPost"))
89ada3ba
YW
2339 return bus_append_exec_command(m, field, eq);
2340
c57d2a76
ZJS
2341 if (STR_IN_SET(field, "SmackLabel",
2342 "SmackLabelIPIn",
2343 "SmackLabelIPOut",
2344 "TCPCongestion",
2345 "BindToDevice",
2346 "BindIPv6Only",
2347 "FileDescriptorName",
2348 "SocketUser",
9b191525
LP
2349 "SocketGroup",
2350 "Timestamping"))
89ada3ba
YW
2351 return bus_append_string(m, field, eq);
2352
2353 if (streq(field, "Symlinks"))
4ec85141 2354 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2355
e045e325 2356 if (streq(field, "SocketProtocol"))
d2b42d63 2357 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba 2358
c57d2a76
ZJS
2359 if (STR_IN_SET(field, "ListenStream",
2360 "ListenDatagram",
2361 "ListenSequentialPacket",
2362 "ListenNetlink",
2363 "ListenSpecial",
2364 "ListenMessageQueue",
2365 "ListenFIFO",
2366 "ListenUSBFunction")) {
3d63c749
YW
2367 if (isempty(eq))
2368 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2369 else
81b1dc27 2370 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 2371 if (r < 0)
89ada3ba
YW
2372 return bus_log_create_error(r);
2373
2374 return 1;
2375 }
2376
2377 return 0;
2378}
2379static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2380 int r;
89ada3ba 2381
c57d2a76
ZJS
2382 if (STR_IN_SET(field, "WakeSystem",
2383 "RemainAfterElapse",
2384 "Persistent",
2385 "OnTimezoneChange",
acf24a1a
KG
2386 "OnClockChange",
2387 "FixedRandomDelay"))
89ada3ba
YW
2388 return bus_append_parse_boolean(m, field, eq);
2389
c57d2a76
ZJS
2390 if (STR_IN_SET(field, "AccuracySec",
2391 "RandomizedDelaySec"))
3d63c749
YW
2392 return bus_append_parse_sec_rename(m, field, eq);
2393
c57d2a76
ZJS
2394 if (STR_IN_SET(field, "OnActiveSec",
2395 "OnBootSec",
2396 "OnStartupSec",
2397 "OnUnitActiveSec",
2398 "OnUnitInactiveSec")) {
3d63c749
YW
2399 if (isempty(eq))
2400 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2401 else {
2402 usec_t t;
2403 r = parse_sec(eq, &t);
2404 if (r < 0)
2405 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 2406
3d63c749
YW
2407 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2408 }
2409 if (r < 0)
2410 return bus_log_create_error(r);
89ada3ba 2411
3d63c749
YW
2412 return 1;
2413 }
2414
2415 if (streq(field, "OnCalendar")) {
3d63c749
YW
2416 if (isempty(eq))
2417 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2418 else
2419 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2420 if (r < 0)
2421 return bus_log_create_error(r);
2422
2423 return 1;
2424 }
89ada3ba
YW
2425
2426 return 0;
2427}
2428
2429static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
2430 ConditionType t = _CONDITION_TYPE_INVALID;
2431 bool is_condition = false;
2432 int r;
f6c66be1 2433
c57d2a76
ZJS
2434 if (STR_IN_SET(field, "Description",
2435 "SourcePath",
2436 "OnFailureJobMode",
2437 "JobTimeoutAction",
2438 "JobTimeoutRebootArgument",
2439 "StartLimitAction",
2440 "FailureAction",
2441 "SuccessAction",
2442 "RebootArgument",
2443 "CollectMode"))
89ada3ba
YW
2444 return bus_append_string(m, field, eq);
2445
c57d2a76
ZJS
2446 if (STR_IN_SET(field, "StopWhenUnneeded",
2447 "RefuseManualStart",
2448 "RefuseManualStop",
2449 "AllowIsolate",
2450 "IgnoreOnIsolate",
2451 "DefaultDependencies"))
89ada3ba
YW
2452 return bus_append_parse_boolean(m, field, eq);
2453
c57d2a76
ZJS
2454 if (STR_IN_SET(field, "JobTimeoutSec",
2455 "JobRunningTimeoutSec",
2456 "StartLimitIntervalSec"))
3d63c749
YW
2457 return bus_append_parse_sec_rename(m, field, eq);
2458
2459 if (streq(field, "StartLimitBurst"))
3d63c749
YW
2460 return bus_append_safe_atou(m, field, eq);
2461
c57d2a76
ZJS
2462 if (STR_IN_SET(field, "SuccessActionExitStatus",
2463 "FailureActionExitStatus")) {
7af67e9a
LP
2464 if (isempty(eq))
2465 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2466 else {
2467 uint8_t u;
2468
2469 r = safe_atou8(eq, &u);
2470 if (r < 0)
2471 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2472
2473 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2474 }
2475 if (r < 0)
2476 return bus_log_create_error(r);
2477
2478 return 1;
2479 }
2480
3d63c749 2481 if (unit_dependency_from_string(field) >= 0 ||
c57d2a76 2482 STR_IN_SET(field, "Documentation",
0dd3c090
ZJS
2483 "RequiresMountsFor",
2484 "Markers"))
4ec85141 2485 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2486
3d63c749
YW
2487 t = condition_type_from_string(field);
2488 if (t >= 0)
2489 is_condition = true;
2490 else
2491 t = assert_type_from_string(field);
2492 if (t >= 0) {
2493 if (isempty(eq))
2494 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2495 else {
2496 const char *p = eq;
2497 int trigger, negate;
2498
2499 trigger = *p == '|';
2500 if (trigger)
2501 p++;
2502
2503 negate = *p == '!';
2504 if (negate)
2505 p++;
2506
2507 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2508 field, trigger, negate, p);
2509 }
2510 if (r < 0)
2511 return bus_log_create_error(r);
2512
2513 return 1;
2514 }
2515
89ada3ba
YW
2516 return 0;
2517}
2518
2519int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2520 const char *eq, *field;
2521 int r;
2522
2523 assert(m);
2524 assert(assignment);
2525
2526 eq = strchr(assignment, '=');
baaa35ad
ZJS
2527 if (!eq)
2528 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2529 "Not an assignment: %s", assignment);
89ada3ba 2530
2f82562b 2531 field = strndupa_safe(assignment, eq - assignment);
89ada3ba
YW
2532 eq++;
2533
2534 switch (t) {
2535 case UNIT_SERVICE:
2536 r = bus_append_cgroup_property(m, field, eq);
2537 if (r != 0)
f6c66be1
LP
2538 return r;
2539
89ada3ba
YW
2540 r = bus_append_execute_property(m, field, eq);
2541 if (r != 0)
2542 return r;
f6c66be1 2543
89ada3ba
YW
2544 r = bus_append_kill_property(m, field, eq);
2545 if (r != 0)
2546 return r;
f6c66be1 2547
89ada3ba
YW
2548 r = bus_append_service_property(m, field, eq);
2549 if (r != 0)
2550 return r;
2551 break;
f6c66be1 2552
89ada3ba
YW
2553 case UNIT_SOCKET:
2554 r = bus_append_cgroup_property(m, field, eq);
2555 if (r != 0)
2556 return r;
f6c66be1 2557
89ada3ba
YW
2558 r = bus_append_execute_property(m, field, eq);
2559 if (r != 0)
2560 return r;
f6c66be1 2561
89ada3ba
YW
2562 r = bus_append_kill_property(m, field, eq);
2563 if (r != 0)
2564 return r;
f6c66be1 2565
89ada3ba
YW
2566 r = bus_append_socket_property(m, field, eq);
2567 if (r != 0)
f6c66be1 2568 return r;
89ada3ba 2569 break;
f6c66be1 2570
89ada3ba
YW
2571 case UNIT_TIMER:
2572 r = bus_append_timer_property(m, field, eq);
2573 if (r != 0)
2574 return r;
2575 break;
f6c66be1 2576
89ada3ba
YW
2577 case UNIT_PATH:
2578 r = bus_append_path_property(m, field, eq);
2579 if (r != 0)
2580 return r;
2581 break;
268833ed 2582
89ada3ba
YW
2583 case UNIT_SLICE:
2584 r = bus_append_cgroup_property(m, field, eq);
2585 if (r != 0)
2586 return r;
2587 break;
268833ed 2588
89ada3ba
YW
2589 case UNIT_SCOPE:
2590 r = bus_append_cgroup_property(m, field, eq);
2591 if (r != 0)
2592 return r;
268833ed 2593
89ada3ba 2594 r = bus_append_kill_property(m, field, eq);
5a70a68f
PW
2595 if (r != 0)
2596 return r;
2597
2598 r = bus_append_scope_property(m, field, eq);
89ada3ba
YW
2599 if (r != 0)
2600 return r;
2601 break;
535e0d19 2602
89ada3ba 2603 case UNIT_MOUNT:
3d63c749
YW
2604 r = bus_append_cgroup_property(m, field, eq);
2605 if (r != 0)
2606 return r;
2607
2608 r = bus_append_execute_property(m, field, eq);
2609 if (r != 0)
2610 return r;
2611
2612 r = bus_append_kill_property(m, field, eq);
2613 if (r != 0)
2614 return r;
2615
2616 r = bus_append_mount_property(m, field, eq);
2617 if (r != 0)
2618 return r;
2619
2620 break;
2621
89ada3ba 2622 case UNIT_AUTOMOUNT:
3d63c749
YW
2623 r = bus_append_automount_property(m, field, eq);
2624 if (r != 0)
2625 return r;
2626
89ada3ba 2627 break;
535e0d19 2628
89ada3ba
YW
2629 case UNIT_TARGET:
2630 case UNIT_DEVICE:
2631 case UNIT_SWAP:
baaa35ad
ZJS
2632 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2633 "Not supported unit type");
535e0d19 2634
89ada3ba 2635 default:
baaa35ad
ZJS
2636 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2637 "Invalid unit type");
20b16441
LP
2638 }
2639
89ada3ba
YW
2640 r = bus_append_unit_property(m, field, eq);
2641 if (r != 0)
2642 return r;
20b16441 2643
baaa35ad
ZJS
2644 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2645 "Unknown assignment: %s", assignment);
20b16441
LP
2646}
2647
89ada3ba 2648int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
2649 int r;
2650
2651 assert(m);
2652
2653 STRV_FOREACH(i, l) {
89ada3ba 2654 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
2655 if (r < 0)
2656 return r;
2657 }
2658
2659 return 0;
2660}
2661
da6053d0 2662int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
2663 const char *type, *path, *source;
2664 int r;
2665
acc0269c
CH
2666 /* changes is dereferenced when calling unit_file_dump_changes() later,
2667 * so we have to make sure this is not NULL. */
2668 assert(changes);
2669 assert(n_changes);
2670
20b16441
LP
2671 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2672 if (r < 0)
2673 return bus_log_parse_error(r);
2674
2675 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2676 /* We expect only "success" changes to be sent over the bus.
2677 Hence, reject anything negative. */
93419a96 2678 int ch = unit_file_change_type_from_string(type);
20b16441 2679 if (ch < 0) {
c1b48a7f
BR
2680 log_notice_errno(ch, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2681 type, path);
20b16441
LP
2682 continue;
2683 }
2684
2685 r = unit_file_changes_add(changes, n_changes, ch, path, source);
2686 if (r < 0)
2687 return r;
2688 }
2689 if (r < 0)
2690 return bus_log_parse_error(r);
2691
2692 r = sd_bus_message_exit_container(m);
2693 if (r < 0)
2694 return bus_log_parse_error(r);
2695
35d379b2 2696 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
2697 return 0;
2698}
2699
bd062910
ZJS
2700int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2701 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2702 _cleanup_free_ char *path = NULL;
2703 int r;
2704
2705 path = unit_dbus_path_from_name(name);
2706 if (!path)
2707 return log_oom();
2708
2709 /* This function warns on it's own, because otherwise it'd be awkward to pass
2710 * the dbus error message around. */
2711
2712 r = sd_bus_get_property_string(
2713 bus,
2714 "org.freedesktop.systemd1",
2715 path,
2716 "org.freedesktop.systemd1.Unit",
2717 "LoadState",
2718 &error,
2719 load_state);
2720 if (r < 0)
2721 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2722
2723 return 0;
2724}
4dcc0653
LP
2725
2726int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2727 int r;
2728
2729 /* First, order by machine */
2730 r = strcasecmp_ptr(a->machine, b->machine);
2731 if (r != 0)
2732 return r;
2733
2734 /* Second, order by unit type */
2735 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2736 if (r != 0)
2737 return r;
2738
2739 /* Third, order by name */
2740 return strcasecmp(a->id, b->id);
2741}