]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
Merge pull request #22195 from keszybz/more-specifiers
[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"
60477eb9 32#include "parse-socket-bind-item.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",
c57d2a76
ZJS
976 "ConfigurationDirectory",
977 "SupplementaryGroups",
978 "SystemCallArchitectures"))
4ec85141 979 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
20b16441 980
c57d2a76
ZJS
981 if (STR_IN_SET(field, "SyslogLevel",
982 "LogLevelMax"))
89ada3ba 983 return bus_append_log_level_from_string(m, field, eq);
20b16441 984
89ada3ba 985 if (streq(field, "SyslogFacility"))
89ada3ba 986 return bus_append_log_facility_unshifted_from_string(m, field, eq);
cffaed83 987
89ada3ba 988 if (streq(field, "SecureBits"))
89ada3ba 989 return bus_append_secure_bits_from_string(m, field, eq);
cffaed83 990
89ada3ba 991 if (streq(field, "CPUSchedulingPolicy"))
89ada3ba 992 return bus_append_sched_policy_from_string(m, field, eq);
cffaed83 993
c57d2a76
ZJS
994 if (STR_IN_SET(field, "CPUSchedulingPriority",
995 "OOMScoreAdjust"))
89ada3ba 996 return bus_append_safe_atoi(m, field, eq);
3f856a28 997
ad21e542
ZJS
998 if (streq(field, "CoredumpFilter"))
999 return bus_append_coredump_filter_mask_from_string(m, field, eq);
1000
89ada3ba 1001 if (streq(field, "Nice"))
89ada3ba 1002 return bus_append_parse_nice(m, field, eq);
3f856a28 1003
89ada3ba 1004 if (streq(field, "SystemCallErrorNumber"))
005bfaf1 1005 return bus_append_seccomp_parse_errno_or_action(m, field, eq);
cffaed83 1006
89ada3ba 1007 if (streq(field, "IOSchedulingClass"))
89ada3ba 1008 return bus_append_ioprio_class_from_string(m, field, eq);
cffaed83 1009
89ada3ba 1010 if (streq(field, "IOSchedulingPriority"))
89ada3ba 1011 return bus_append_ioprio_parse_priority(m, field, eq);
cffaed83 1012
c57d2a76
ZJS
1013 if (STR_IN_SET(field, "RuntimeDirectoryMode",
1014 "StateDirectoryMode",
1015 "CacheDirectoryMode",
1016 "LogsDirectoryMode",
1017 "ConfigurationDirectoryMode",
1018 "UMask"))
89ada3ba 1019 return bus_append_parse_mode(m, field, eq);
cffaed83 1020
89ada3ba 1021 if (streq(field, "TimerSlackNSec"))
89ada3ba 1022 return bus_append_parse_nsec(m, field, eq);
cffaed83 1023
691d6f6d 1024 if (streq(field, "LogRateLimitIntervalSec"))
90fc172e
AZ
1025 return bus_append_parse_sec_rename(m, field, eq);
1026
51462135
DDM
1027 if (STR_IN_SET(field, "LogRateLimitBurst",
1028 "TTYRows",
1029 "TTYColumns"))
90fc172e
AZ
1030 return bus_append_safe_atou(m, field, eq);
1031
89ada3ba 1032 if (streq(field, "MountFlags"))
89ada3ba 1033 return bus_append_mount_propagation_flags_from_string(m, field, eq);
cffaed83 1034
c57d2a76
ZJS
1035 if (STR_IN_SET(field, "Environment",
1036 "UnsetEnvironment",
1037 "PassEnvironment"))
4ec85141 1038 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
cffaed83 1039
89ada3ba 1040 if (streq(field, "EnvironmentFile")) {
89ada3ba
YW
1041 if (isempty(eq))
1042 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1043 else
1044 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1045 eq[0] == '-' ? eq + 1 : eq,
1046 eq[0] == '-');
1047 if (r < 0)
1048 return bus_log_create_error(r);
cffaed83 1049
89ada3ba
YW
1050 return 1;
1051 }
cffaed83 1052
43144be4 1053 if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
bb0c0d6f
LP
1054 r = sd_bus_message_open_container(m, 'r', "sv");
1055 if (r < 0)
1056 return bus_log_create_error(r);
1057
43144be4 1058 r = sd_bus_message_append_basic(m, 's', field);
bb0c0d6f
LP
1059 if (r < 0)
1060 return bus_log_create_error(r);
1061
1062 r = sd_bus_message_open_container(m, 'v', "a(say)");
1063 if (r < 0)
1064 return bus_log_create_error(r);
1065
1066 if (isempty(eq))
1067 r = sd_bus_message_append(m, "a(say)", 0);
1068 else {
43144be4 1069 _cleanup_free_ char *word = NULL;
bb0c0d6f 1070 const char *p = eq;
bb0c0d6f
LP
1071
1072 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1073 if (r == -ENOMEM)
1074 return log_oom();
1075 if (r < 0)
43144be4 1076 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
bb0c0d6f 1077 if (r == 0 || !p)
43144be4 1078 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f
LP
1079
1080 r = sd_bus_message_open_container(m, 'a', "(say)");
1081 if (r < 0)
1082 return bus_log_create_error(r);
1083
1084 r = sd_bus_message_open_container(m, 'r', "say");
1085 if (r < 0)
1086 return bus_log_create_error(r);
1087
1088 r = sd_bus_message_append(m, "s", word);
1089 if (r < 0)
1090 return bus_log_create_error(r);
1091
43144be4
LP
1092 if (streq(field, "SetCredentialEncrypted")) {
1093 _cleanup_free_ void *decoded = NULL;
1094 size_t decoded_size;
1095
1096 r = unbase64mem(p, SIZE_MAX, &decoded, &decoded_size);
1097 if (r < 0)
1098 return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
1099
1100 r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
1101 } else {
1102 _cleanup_free_ char *unescaped = NULL;
e437538f 1103 ssize_t l;
43144be4
LP
1104
1105 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
1106 if (l < 0)
1107 return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
1108
1109 r = sd_bus_message_append_array(m, 'y', unescaped, l);
1110 }
bb0c0d6f
LP
1111 if (r < 0)
1112 return bus_log_create_error(r);
1113
1114 r = sd_bus_message_close_container(m);
1115 if (r < 0)
1116 return bus_log_create_error(r);
1117
1118 r = sd_bus_message_close_container(m);
1119 }
1120 if (r < 0)
1121 return bus_log_create_error(r);
1122
1123 r = sd_bus_message_close_container(m);
1124 if (r < 0)
1125 return bus_log_create_error(r);
1126
1127 r = sd_bus_message_close_container(m);
1128 if (r < 0)
1129 return bus_log_create_error(r);
1130
1131 return 1;
1132 }
1133
43144be4 1134 if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
bb0c0d6f
LP
1135 r = sd_bus_message_open_container(m, 'r', "sv");
1136 if (r < 0)
1137 return bus_log_create_error(r);
1138
43144be4 1139 r = sd_bus_message_append_basic(m, 's', field);
bb0c0d6f
LP
1140 if (r < 0)
1141 return bus_log_create_error(r);
1142
1143 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1144 if (r < 0)
1145 return bus_log_create_error(r);
1146
1147 if (isempty(eq))
1148 r = sd_bus_message_append(m, "a(ss)", 0);
1149 else {
1150 _cleanup_free_ char *word = NULL;
1151 const char *p = eq;
1152
1153 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1154 if (r == -ENOMEM)
1155 return log_oom();
1156 if (r < 0)
43144be4 1157 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
bb0c0d6f 1158 if (r == 0 || !p)
43144be4 1159 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f
LP
1160
1161 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1162 }
1163 if (r < 0)
1164 return bus_log_create_error(r);
1165
1166 r = sd_bus_message_close_container(m);
1167 if (r < 0)
1168 return bus_log_create_error(r);
1169
1170 r = sd_bus_message_close_container(m);
1171 if (r < 0)
1172 return bus_log_create_error(r);
1173
1174 return 1;
1175 }
1176
89ada3ba 1177 if (streq(field, "LogExtraFields")) {
89ada3ba 1178 r = sd_bus_message_open_container(m, 'r', "sv");
3f856a28
YW
1179 if (r < 0)
1180 return bus_log_create_error(r);
1181
89ada3ba 1182 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
3f856a28
YW
1183 if (r < 0)
1184 return bus_log_create_error(r);
1185
89ada3ba 1186 r = sd_bus_message_open_container(m, 'v', "aay");
3f856a28
YW
1187 if (r < 0)
1188 return bus_log_create_error(r);
1189
89ada3ba 1190 r = sd_bus_message_open_container(m, 'a', "ay");
cffaed83
YW
1191 if (r < 0)
1192 return bus_log_create_error(r);
1193
89ada3ba 1194 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
3f856a28
YW
1195 if (r < 0)
1196 return bus_log_create_error(r);
cffaed83 1197
3f856a28
YW
1198 r = sd_bus_message_close_container(m);
1199 if (r < 0)
1200 return bus_log_create_error(r);
9f617cd0 1201
89ada3ba
YW
1202 r = sd_bus_message_close_container(m);
1203 if (r < 0)
1204 return bus_log_create_error(r);
9efb9df9 1205
89ada3ba 1206 r = sd_bus_message_close_container(m);
9efb9df9 1207 if (r < 0)
89ada3ba
YW
1208 return bus_log_create_error(r);
1209
1210 return 1;
1211 }
9efb9df9 1212
c57d2a76
ZJS
1213 if (STR_IN_SET(field, "StandardInput",
1214 "StandardOutput",
1215 "StandardError")) {
89ada3ba 1216 const char *n, *appended;
9efb9df9 1217
89ada3ba
YW
1218 if ((n = startswith(eq, "fd:"))) {
1219 appended = strjoina(field, "FileDescriptorName");
1220 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1221 } else if ((n = startswith(eq, "file:"))) {
1222 appended = strjoina(field, "File");
1223 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d33232e
LP
1224 } else if ((n = startswith(eq, "append:"))) {
1225 appended = strjoina(field, "FileToAppend");
1226 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d7dab1f
LW
1227 } else if ((n = startswith(eq, "truncate:"))) {
1228 appended = strjoina(field, "FileToTruncate");
1229 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
89ada3ba
YW
1230 } else
1231 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
89ada3ba
YW
1232 if (r < 0)
1233 return bus_log_create_error(r);
7f452159 1234
89ada3ba
YW
1235 return 1;
1236 }
7f452159 1237
89ada3ba
YW
1238 if (streq(field, "StandardInputText")) {
1239 _cleanup_free_ char *unescaped = NULL;
e437538f 1240 ssize_t l;
7f452159 1241
e437538f
ZJS
1242 l = cunescape(eq, 0, &unescaped);
1243 if (l < 0)
1244 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
7f452159 1245
c2bc710b 1246 if (!strextend(&unescaped, "\n"))
89ada3ba 1247 return log_oom();
7f452159 1248
e437538f
ZJS
1249 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1250 * programmatic interface anyway */
20b16441 1251
e437538f 1252 return bus_append_byte_array(m, field, unescaped, l + 1);
89ada3ba 1253 }
20b16441 1254
89ada3ba
YW
1255 if (streq(field, "StandardInputData")) {
1256 _cleanup_free_ void *decoded = NULL;
1257 size_t sz;
1258
f5fbe71d 1259 r = unbase64mem(eq, SIZE_MAX, &decoded, &sz);
20b16441 1260 if (r < 0)
89ada3ba 1261 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
20b16441 1262
89ada3ba
YW
1263 return bus_append_byte_array(m, field, decoded, sz);
1264 }
20b16441 1265
6550c24c
LP
1266 if ((suffix = startswith(field, "Limit"))) {
1267 int rl;
20b16441 1268
6550c24c
LP
1269 rl = rlimit_from_string(suffix);
1270 if (rl >= 0) {
1271 const char *sn;
1272 struct rlimit l;
20b16441 1273
6550c24c
LP
1274 r = rlimit_parse(rl, eq, &l);
1275 if (r < 0)
1276 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
20b16441 1277
6550c24c
LP
1278 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
1279 if (r < 0)
1280 return bus_log_create_error(r);
20b16441 1281
6550c24c
LP
1282 sn = strjoina(field, "Soft");
1283 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
1284 if (r < 0)
1285 return bus_log_create_error(r);
1286
1287 return 1;
1288 }
89ada3ba 1289 }
20b16441 1290
c57d2a76
ZJS
1291 if (STR_IN_SET(field, "AppArmorProfile",
1292 "SmackProcessLabel")) {
89ada3ba
YW
1293 int ignore = 0;
1294 const char *s = eq;
20b16441 1295
89ada3ba
YW
1296 if (eq[0] == '-') {
1297 ignore = 1;
1298 s = eq + 1;
20b16441
LP
1299 }
1300
89ada3ba 1301 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
6bbfdc67 1302 if (r < 0)
89ada3ba 1303 return bus_log_create_error(r);
20b16441 1304
89ada3ba
YW
1305 return 1;
1306 }
20b16441 1307
c57d2a76
ZJS
1308 if (STR_IN_SET(field, "CapabilityBoundingSet",
1309 "AmbientCapabilities")) {
89ada3ba
YW
1310 uint64_t sum = 0;
1311 bool invert = false;
1312 const char *p = eq;
afcb1cd3 1313
89ada3ba
YW
1314 if (*p == '~') {
1315 invert = true;
1316 p++;
1317 }
20b16441 1318
89ada3ba 1319 r = capability_set_from_string(p, &sum);
20b16441 1320 if (r < 0)
89ada3ba 1321 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
20b16441 1322
89ada3ba
YW
1323 sum = invert ? ~sum : sum;
1324
1325 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
20b16441
LP
1326 if (r < 0)
1327 return bus_log_create_error(r);
1328
89ada3ba
YW
1329 return 1;
1330 }
20b16441 1331
89ada3ba 1332 if (streq(field, "CPUAffinity")) {
0985c7c4 1333 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
c367f996
MS
1334 _cleanup_free_ uint8_t *array = NULL;
1335 size_t allocated;
20b16441 1336
e2b2fb7f
MS
1337 if (eq && streq(eq, "numa")) {
1338 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1339 if (r < 0)
1340 return bus_log_create_error(r);
1341 return r;
1342 }
1343
89ada3ba
YW
1344 r = parse_cpu_set(eq, &cpuset);
1345 if (r < 0)
1346 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
20b16441 1347
c367f996
MS
1348 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1349 if (r < 0)
1350 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1351
1352 return bus_append_byte_array(m, field, array, allocated);
89ada3ba 1353 }
20b7a007 1354
b070c7c0
MS
1355 if (streq(field, "NUMAPolicy")) {
1356 r = mpol_from_string(eq);
1357 if (r < 0)
1358 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1359
1360 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1361 if (r < 0)
1362 return bus_log_create_error(r);
1363
1364 return 1;
1365 }
1366
1367 if (streq(field, "NUMAMask")) {
1368 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1369 _cleanup_free_ uint8_t *array = NULL;
1370 size_t allocated;
1371
332d387f
MS
1372 if (eq && streq(eq, "all")) {
1373 r = numa_mask_add_all(&nodes);
1374 if (r < 0)
1375 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1376 } else {
1377 r = parse_cpu_set(eq, &nodes);
1378 if (r < 0)
1379 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1380 }
b070c7c0
MS
1381
1382 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1383 if (r < 0)
1384 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1385
1386 return bus_append_byte_array(m, field, array, allocated);
1387 }
1388
c57d2a76 1389 if (STR_IN_SET(field, "RestrictAddressFamilies",
cc86a278 1390 "RestrictFileSystems",
9df2cdd8 1391 "SystemCallFilter",
a59cb62c
MV
1392 "SystemCallLog",
1393 "RestrictNetworkInterfaces")) {
6b000af4 1394 int allow_list = 1;
89ada3ba 1395 const char *p = eq;
20b16441 1396
89ada3ba 1397 if (*p == '~') {
6b000af4 1398 allow_list = 0;
89ada3ba 1399 p++;
20b16441
LP
1400 }
1401
89ada3ba 1402 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1403 if (r < 0)
1404 return bus_log_create_error(r);
1405
89ada3ba
YW
1406 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1407 if (r < 0)
1408 return bus_log_create_error(r);
1409
1410 r = sd_bus_message_open_container(m, 'v', "(bas)");
1411 if (r < 0)
1412 return bus_log_create_error(r);
20b16441 1413
89ada3ba
YW
1414 r = sd_bus_message_open_container(m, 'r', "bas");
1415 if (r < 0)
1416 return bus_log_create_error(r);
cffaed83 1417
6b000af4 1418 r = sd_bus_message_append_basic(m, 'b', &allow_list);
cffaed83
YW
1419 if (r < 0)
1420 return bus_log_create_error(r);
1421
1422 r = sd_bus_message_open_container(m, 'a', "s");
1423 if (r < 0)
1424 return bus_log_create_error(r);
1425
98008caa 1426 for (;;) {
cffaed83
YW
1427 _cleanup_free_ char *word = NULL;
1428
4ec85141 1429 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
cffaed83
YW
1430 if (r == 0)
1431 break;
89ada3ba
YW
1432 if (r == -ENOMEM)
1433 return log_oom();
1434 if (r < 0)
1435 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1436
1437 r = sd_bus_message_append_basic(m, 's', word);
1438 if (r < 0)
1439 return bus_log_create_error(r);
1440 }
1441
1442 r = sd_bus_message_close_container(m);
1443 if (r < 0)
1444 return bus_log_create_error(r);
1445
1446 r = sd_bus_message_close_container(m);
20b16441
LP
1447 if (r < 0)
1448 return bus_log_create_error(r);
1449
89ada3ba 1450 r = sd_bus_message_close_container(m);
20b16441
LP
1451 if (r < 0)
1452 return bus_log_create_error(r);
1453
20b16441
LP
1454 r = sd_bus_message_close_container(m);
1455 if (r < 0)
1456 return bus_log_create_error(r);
1457
89ada3ba
YW
1458 return 1;
1459 }
20b16441 1460
89ada3ba 1461 if (streq(field, "RestrictNamespaces")) {
add00535 1462 bool invert = false;
aa9d574d 1463 unsigned long flags;
add00535
LP
1464
1465 r = parse_boolean(eq);
1466 if (r > 0)
1467 flags = 0;
1468 else if (r == 0)
1469 flags = NAMESPACE_FLAGS_ALL;
1470 else {
aa9d574d
YW
1471 if (eq[0] == '~') {
1472 invert = true;
1473 eq++;
1474 }
1475
86c2a9f1 1476 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1477 if (r < 0)
1478 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1479 }
1480
1481 if (invert)
1482 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1483
89ada3ba
YW
1484 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1485 if (r < 0)
1486 return bus_log_create_error(r);
afcb1cd3 1487
89ada3ba
YW
1488 return 1;
1489 }
afcb1cd3 1490
c57d2a76
ZJS
1491 if (STR_IN_SET(field, "BindPaths",
1492 "BindReadOnlyPaths")) {
89ada3ba 1493 const char *p = eq;
83555251 1494
89ada3ba 1495 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1496 if (r < 0)
89ada3ba 1497 return bus_log_create_error(r);
afcb1cd3 1498
89ada3ba
YW
1499 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1500 if (r < 0)
1501 return bus_log_create_error(r);
d2d6c096
LP
1502
1503 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1504 if (r < 0)
89ada3ba 1505 return bus_log_create_error(r);
d2d6c096
LP
1506
1507 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1508 if (r < 0)
89ada3ba 1509 return bus_log_create_error(r);
d2d6c096
LP
1510
1511 for (;;) {
1512 _cleanup_free_ char *source = NULL, *destination = NULL;
1513 char *s = NULL, *d = NULL;
1514 bool ignore_enoent = false;
1515 uint64_t flags = MS_REC;
1516
4ec85141 1517 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1518 if (r < 0)
1519 return log_error_errno(r, "Failed to parse argument: %m");
1520 if (r == 0)
1521 break;
1522
1523 s = source;
1524 if (s[0] == '-') {
1525 ignore_enoent = true;
1526 s++;
1527 }
1528
1529 if (p && p[-1] == ':') {
4ec85141 1530 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1531 if (r < 0)
1532 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1533 if (r == 0)
1534 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1535 "Missing argument after ':': %s",
1536 eq);
d2d6c096
LP
1537
1538 d = destination;
1539
1540 if (p && p[-1] == ':') {
1541 _cleanup_free_ char *options = NULL;
1542
4ec85141 1543 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
d2d6c096
LP
1544 if (r < 0)
1545 return log_error_errno(r, "Failed to parse argument: %m");
1546
1547 if (isempty(options) || streq(options, "rbind"))
1548 flags = MS_REC;
1549 else if (streq(options, "norbind"))
1550 flags = 0;
baaa35ad
ZJS
1551 else
1552 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1553 "Unknown options: %s",
1554 eq);
d2d6c096
LP
1555 }
1556 } else
1557 d = s;
1558
d2d6c096
LP
1559 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1560 if (r < 0)
89ada3ba 1561 return bus_log_create_error(r);
d2d6c096
LP
1562 }
1563
1564 r = sd_bus_message_close_container(m);
1565 if (r < 0)
89ada3ba
YW
1566 return bus_log_create_error(r);
1567
1568 r = sd_bus_message_close_container(m);
1569 if (r < 0)
1570 return bus_log_create_error(r);
d2d6c096
LP
1571
1572 r = sd_bus_message_close_container(m);
89ada3ba
YW
1573 if (r < 0)
1574 return bus_log_create_error(r);
f6c66be1 1575
89ada3ba
YW
1576 return 1;
1577 }
f6c66be1 1578
784ad252
YW
1579 if (streq(field, "TemporaryFileSystem")) {
1580 const char *p = eq;
1581
1582 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1583 if (r < 0)
1584 return bus_log_create_error(r);
1585
1586 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1587 if (r < 0)
1588 return bus_log_create_error(r);
1589
1590 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1591 if (r < 0)
1592 return bus_log_create_error(r);
1593
1594 r = sd_bus_message_open_container(m, 'a', "(ss)");
1595 if (r < 0)
1596 return bus_log_create_error(r);
1597
1598 for (;;) {
1599 _cleanup_free_ char *word = NULL, *path = NULL;
1600 const char *w;
1601
4ec85141 1602 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
784ad252
YW
1603 if (r < 0)
1604 return log_error_errno(r, "Failed to parse argument: %m");
1605 if (r == 0)
1606 break;
1607
1608 w = word;
1609 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1610 if (r < 0)
1611 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1612 if (r == 0)
1613 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1614 "Failed to parse argument: %s",
1615 p);
784ad252
YW
1616
1617 r = sd_bus_message_append(m, "(ss)", path, w);
1618 if (r < 0)
1619 return bus_log_create_error(r);
1620 }
1621
1622 r = sd_bus_message_close_container(m);
1623 if (r < 0)
1624 return bus_log_create_error(r);
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 return 1;
1635 }
1636
0389f4fa
LB
1637 if (streq(field, "RootHash")) {
1638 _cleanup_free_ void *roothash_decoded = NULL;
1639 size_t roothash_decoded_size = 0;
1640
1641 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1642 if (path_is_absolute(eq))
1643 return bus_append_string(m, "RootHashPath", eq);
1644
1645 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1646 r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
1647 if (r < 0)
1648 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1649 if (roothash_decoded_size < sizeof(sd_id128_t))
1650 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
1651
1652 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1653 }
1654
d4d55b0d
LB
1655 if (streq(field, "RootHashSignature")) {
1656 _cleanup_free_ void *roothash_sig_decoded = NULL;
1657 char *value;
1658 size_t roothash_sig_decoded_size = 0;
1659
1660 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1661 if (path_is_absolute(eq))
1662 return bus_append_string(m, "RootHashSignaturePath", eq);
1663
1664 if (!(value = startswith(eq, "base64:")))
1665 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
1666
1667 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1668 r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
1669 if (r < 0)
1670 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1671
1672 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1673 }
1674
18d73705 1675 if (streq(field, "RootImageOptions")) {
bc8d56d3
LB
1676 _cleanup_strv_free_ char **l = NULL;
1677 char **first = NULL, **second = 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
2026 char **source, **destination;
2027 STRV_FOREACH_PAIR(source, destination, symlinks) {
2028 r = sd_bus_message_append(m, "(sst)", *source, *destination, 0);
2029 if (r < 0)
2030 return bus_log_create_error(r);
2031 }
2032
2033 r = sd_bus_message_close_container(m);
2034 if (r < 0)
2035 return bus_log_create_error(r);
2036
2037 r = sd_bus_message_close_container(m);
2038 if (r < 0)
2039 return bus_log_create_error(r);
2040
2041 r = sd_bus_message_close_container(m);
2042 if (r < 0)
2043 return bus_log_create_error(r);
2044 }
2045
2046 return 1;
2047 }
2048
89ada3ba
YW
2049 return 0;
2050}
f6c66be1 2051
89ada3ba 2052static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2053 if (streq(field, "KillMode"))
89ada3ba 2054 return bus_append_string(m, field, eq);
f6c66be1 2055
c57d2a76
ZJS
2056 if (STR_IN_SET(field, "SendSIGHUP",
2057 "SendSIGKILL"))
89ada3ba 2058 return bus_append_parse_boolean(m, field, eq);
f6c66be1 2059
c57d2a76
ZJS
2060 if (STR_IN_SET(field, "KillSignal",
2061 "RestartKillSignal",
2062 "FinalKillSignal",
2063 "WatchdogSignal"))
29a3db75 2064 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
2065
2066 return 0;
2067}
2068
3d63c749 2069static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2070
c57d2a76
ZJS
2071 if (STR_IN_SET(field, "What",
2072 "Where",
2073 "Options",
2074 "Type"))
89ada3ba
YW
2075 return bus_append_string(m, field, eq);
2076
3d63c749 2077 if (streq(field, "TimeoutSec"))
3d63c749
YW
2078 return bus_append_parse_sec_rename(m, field, eq);
2079
2080 if (streq(field, "DirectoryMode"))
3d63c749
YW
2081 return bus_append_parse_mode(m, field, eq);
2082
c57d2a76
ZJS
2083 if (STR_IN_SET(field, "SloppyOptions",
2084 "LazyUnmount",
c600357b
MH
2085 "ForceUnmount",
2086 "ReadwriteOnly"))
3d63c749
YW
2087 return bus_append_parse_boolean(m, field, eq);
2088
2089 return 0;
2090}
2091
2092static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
2093 int r;
2094
89ada3ba 2095 if (streq(field, "MakeDirectory"))
89ada3ba
YW
2096 return bus_append_parse_boolean(m, field, eq);
2097
2098 if (streq(field, "DirectoryMode"))
89ada3ba
YW
2099 return bus_append_parse_mode(m, field, eq);
2100
c57d2a76
ZJS
2101 if (STR_IN_SET(field, "PathExists",
2102 "PathExistsGlob",
2103 "PathChanged",
2104 "PathModified",
2105 "DirectoryNotEmpty")) {
3d63c749
YW
2106 if (isempty(eq))
2107 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
2108 else
2109 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
2110 if (r < 0)
2111 return bus_log_create_error(r);
2112
2113 return 1;
2114 }
2115
47dba9fb
LB
2116 if (streq(field, "TriggerLimitBurst"))
2117 return bus_append_safe_atou(m, field, eq);
2118
2119 if (streq(field, "TriggerLimitIntervalSec"))
2120 return bus_append_parse_sec_rename(m, field, eq);
2121
89ada3ba
YW
2122 return 0;
2123}
2124
5a70a68f 2125static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
9ed7de60 2126 if (streq(field, "RuntimeMaxSec"))
9ed7de60
PW
2127 return bus_append_parse_sec_rename(m, field, eq);
2128
5918a933
AB
2129 if (streq(field, "RuntimeRandomizedExtraSec"))
2130 return bus_append_parse_sec_rename(m, field, eq);
2131
5a70a68f 2132 if (streq(field, "TimeoutStopSec"))
5a70a68f
PW
2133 return bus_append_parse_sec_rename(m, field, eq);
2134
2135 return 0;
2136}
2137
89ada3ba 2138static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2139 int r;
89ada3ba 2140
c57d2a76
ZJS
2141 if (STR_IN_SET(field, "PIDFile",
2142 "Type",
596e4470 2143 "ExitType",
c57d2a76
ZJS
2144 "Restart",
2145 "BusName",
2146 "NotifyAccess",
2147 "USBFunctionDescriptors",
2148 "USBFunctionStrings",
bf760801
JK
2149 "OOMPolicy",
2150 "TimeoutStartFailureMode",
2151 "TimeoutStopFailureMode"))
89ada3ba 2152 return bus_append_string(m, field, eq);
f6c66be1 2153
c57d2a76
ZJS
2154 if (STR_IN_SET(field, "PermissionsStartOnly",
2155 "RootDirectoryStartOnly",
2156 "RemainAfterExit",
2157 "GuessMainPID"))
89ada3ba
YW
2158 return bus_append_parse_boolean(m, field, eq);
2159
c57d2a76
ZJS
2160 if (STR_IN_SET(field, "RestartSec",
2161 "TimeoutStartSec",
2162 "TimeoutStopSec",
e737017b 2163 "TimeoutAbortSec",
c57d2a76 2164 "RuntimeMaxSec",
5918a933 2165 "RuntimeRandomizedExtraSec",
c57d2a76 2166 "WatchdogSec"))
89ada3ba
YW
2167 return bus_append_parse_sec_rename(m, field, eq);
2168
3d63c749 2169 if (streq(field, "TimeoutSec")) {
3d63c749
YW
2170 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2171 if (r < 0)
2172 return r;
2173
2174 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2175 }
2176
89ada3ba 2177 if (streq(field, "FileDescriptorStoreMax"))
89ada3ba
YW
2178 return bus_append_safe_atou(m, field, eq);
2179
c57d2a76
ZJS
2180 if (STR_IN_SET(field, "ExecCondition",
2181 "ExecStartPre",
2182 "ExecStart",
2183 "ExecStartPost",
2184 "ExecConditionEx",
2185 "ExecStartPreEx",
2186 "ExecStartEx",
2187 "ExecStartPostEx",
2188 "ExecReload",
2189 "ExecStop",
2190 "ExecStopPost",
2191 "ExecReloadEx",
2192 "ExecStopEx",
2193 "ExecStopPostEx"))
89ada3ba
YW
2194 return bus_append_exec_command(m, field, eq);
2195
c57d2a76
ZJS
2196 if (STR_IN_SET(field, "RestartPreventExitStatus",
2197 "RestartForceExitStatus",
2198 "SuccessExitStatus")) {
3d63c749 2199 _cleanup_free_ int *status = NULL, *signal = NULL;
62b21e2e 2200 size_t n_status = 0, n_signal = 0;
3d63c749
YW
2201 const char *p;
2202
2203 for (p = eq;;) {
2204 _cleanup_free_ char *word = NULL;
3d63c749 2205
4ec85141 2206 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3d63c749
YW
2207 if (r == 0)
2208 break;
2209 if (r == -ENOMEM)
2210 return log_oom();
2211 if (r < 0)
2212 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2213
2e2ed880
ZJS
2214 /* We need to call exit_status_from_string() first, because we want
2215 * to parse numbers as exit statuses, not signals. */
3d63c749 2216
2e2ed880
ZJS
2217 r = exit_status_from_string(word);
2218 if (r >= 0) {
2219 assert(r >= 0 && r < 256);
3d63c749 2220
62b21e2e 2221 status = reallocarray(status, n_status + 1, sizeof(int));
3d63c749
YW
2222 if (!status)
2223 return log_oom();
2224
2e2ed880
ZJS
2225 status[n_status++] = r;
2226
2227 } else if ((r = signal_from_string(word)) >= 0) {
2228 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2229 if (!signal)
2230 return log_oom();
2231
2232 signal[n_signal++] = r;
2233
2234 } else
2235 /* original r from exit_status_to_string() */
2236 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2237 word, field);
3d63c749
YW
2238 }
2239
2240 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2241 if (r < 0)
2242 return bus_log_create_error(r);
2243
2244 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2245 if (r < 0)
2246 return bus_log_create_error(r);
2247
2248 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2249 if (r < 0)
2250 return bus_log_create_error(r);
2251
2252 r = sd_bus_message_open_container(m, 'r', "aiai");
2253 if (r < 0)
2254 return bus_log_create_error(r);
2255
62b21e2e 2256 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
3d63c749
YW
2257 if (r < 0)
2258 return bus_log_create_error(r);
2259
62b21e2e 2260 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
3d63c749
YW
2261 if (r < 0)
2262 return bus_log_create_error(r);
2263
2264 r = sd_bus_message_close_container(m);
2265 if (r < 0)
2266 return bus_log_create_error(r);
2267
2268 r = sd_bus_message_close_container(m);
2269 if (r < 0)
2270 return bus_log_create_error(r);
2271
2272 r = sd_bus_message_close_container(m);
2273 if (r < 0)
2274 return bus_log_create_error(r);
2275
2276 return 1;
2277 }
2278
89ada3ba
YW
2279 return 0;
2280}
2281
2282static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2283 int r;
2284
c57d2a76 2285 if (STR_IN_SET(field, "Accept",
3e5f04bf 2286 "FlushPending",
c57d2a76
ZJS
2287 "Writable",
2288 "KeepAlive",
2289 "NoDelay",
2290 "FreeBind",
2291 "Transparent",
2292 "Broadcast",
2293 "PassCredentials",
2294 "PassSecurity",
a3d19f5d 2295 "PassPacketInfo",
c57d2a76
ZJS
2296 "ReusePort",
2297 "RemoveOnStop",
2298 "SELinuxContextFromNet"))
89ada3ba
YW
2299 return bus_append_parse_boolean(m, field, eq);
2300
c57d2a76
ZJS
2301 if (STR_IN_SET(field, "Priority",
2302 "IPTTL",
2303 "Mark"))
89ada3ba
YW
2304 return bus_append_safe_atoi(m, field, eq);
2305
2306 if (streq(field, "IPTOS"))
89ada3ba
YW
2307 return bus_append_ip_tos_from_string(m, field, eq);
2308
c57d2a76
ZJS
2309 if (STR_IN_SET(field, "Backlog",
2310 "MaxConnections",
2311 "MaxConnectionsPerSource",
2312 "KeepAliveProbes",
2313 "TriggerLimitBurst"))
89ada3ba
YW
2314 return bus_append_safe_atou(m, field, eq);
2315
c57d2a76
ZJS
2316 if (STR_IN_SET(field, "SocketMode",
2317 "DirectoryMode"))
89ada3ba
YW
2318 return bus_append_parse_mode(m, field, eq);
2319
c57d2a76
ZJS
2320 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2321 "MessageQueueMessageSize"))
89ada3ba
YW
2322 return bus_append_safe_atoi64(m, field, eq);
2323
c57d2a76
ZJS
2324 if (STR_IN_SET(field, "TimeoutSec",
2325 "KeepAliveTimeSec",
2326 "KeepAliveIntervalSec",
2327 "DeferAcceptSec",
2328 "TriggerLimitIntervalSec"))
89ada3ba
YW
2329 return bus_append_parse_sec_rename(m, field, eq);
2330
c57d2a76
ZJS
2331 if (STR_IN_SET(field, "ReceiveBuffer",
2332 "SendBuffer",
2333 "PipeSize"))
b48e508d 2334 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 2335
c57d2a76
ZJS
2336 if (STR_IN_SET(field, "ExecStartPre",
2337 "ExecStartPost",
2338 "ExecReload",
2339 "ExecStopPost"))
89ada3ba
YW
2340 return bus_append_exec_command(m, field, eq);
2341
c57d2a76
ZJS
2342 if (STR_IN_SET(field, "SmackLabel",
2343 "SmackLabelIPIn",
2344 "SmackLabelIPOut",
2345 "TCPCongestion",
2346 "BindToDevice",
2347 "BindIPv6Only",
2348 "FileDescriptorName",
2349 "SocketUser",
9b191525
LP
2350 "SocketGroup",
2351 "Timestamping"))
89ada3ba
YW
2352 return bus_append_string(m, field, eq);
2353
2354 if (streq(field, "Symlinks"))
4ec85141 2355 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2356
e045e325 2357 if (streq(field, "SocketProtocol"))
d2b42d63 2358 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba 2359
c57d2a76
ZJS
2360 if (STR_IN_SET(field, "ListenStream",
2361 "ListenDatagram",
2362 "ListenSequentialPacket",
2363 "ListenNetlink",
2364 "ListenSpecial",
2365 "ListenMessageQueue",
2366 "ListenFIFO",
2367 "ListenUSBFunction")) {
3d63c749
YW
2368 if (isempty(eq))
2369 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2370 else
81b1dc27 2371 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 2372 if (r < 0)
89ada3ba
YW
2373 return bus_log_create_error(r);
2374
2375 return 1;
2376 }
2377
2378 return 0;
2379}
2380static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2381 int r;
89ada3ba 2382
c57d2a76
ZJS
2383 if (STR_IN_SET(field, "WakeSystem",
2384 "RemainAfterElapse",
2385 "Persistent",
2386 "OnTimezoneChange",
acf24a1a
KG
2387 "OnClockChange",
2388 "FixedRandomDelay"))
89ada3ba
YW
2389 return bus_append_parse_boolean(m, field, eq);
2390
c57d2a76
ZJS
2391 if (STR_IN_SET(field, "AccuracySec",
2392 "RandomizedDelaySec"))
3d63c749
YW
2393 return bus_append_parse_sec_rename(m, field, eq);
2394
c57d2a76
ZJS
2395 if (STR_IN_SET(field, "OnActiveSec",
2396 "OnBootSec",
2397 "OnStartupSec",
2398 "OnUnitActiveSec",
2399 "OnUnitInactiveSec")) {
3d63c749
YW
2400 if (isempty(eq))
2401 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2402 else {
2403 usec_t t;
2404 r = parse_sec(eq, &t);
2405 if (r < 0)
2406 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 2407
3d63c749
YW
2408 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2409 }
2410 if (r < 0)
2411 return bus_log_create_error(r);
89ada3ba 2412
3d63c749
YW
2413 return 1;
2414 }
2415
2416 if (streq(field, "OnCalendar")) {
3d63c749
YW
2417 if (isempty(eq))
2418 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2419 else
2420 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2421 if (r < 0)
2422 return bus_log_create_error(r);
2423
2424 return 1;
2425 }
89ada3ba
YW
2426
2427 return 0;
2428}
2429
2430static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
2431 ConditionType t = _CONDITION_TYPE_INVALID;
2432 bool is_condition = false;
2433 int r;
f6c66be1 2434
c57d2a76
ZJS
2435 if (STR_IN_SET(field, "Description",
2436 "SourcePath",
2437 "OnFailureJobMode",
2438 "JobTimeoutAction",
2439 "JobTimeoutRebootArgument",
2440 "StartLimitAction",
2441 "FailureAction",
2442 "SuccessAction",
2443 "RebootArgument",
2444 "CollectMode"))
89ada3ba
YW
2445 return bus_append_string(m, field, eq);
2446
c57d2a76
ZJS
2447 if (STR_IN_SET(field, "StopWhenUnneeded",
2448 "RefuseManualStart",
2449 "RefuseManualStop",
2450 "AllowIsolate",
2451 "IgnoreOnIsolate",
2452 "DefaultDependencies"))
89ada3ba
YW
2453 return bus_append_parse_boolean(m, field, eq);
2454
c57d2a76
ZJS
2455 if (STR_IN_SET(field, "JobTimeoutSec",
2456 "JobRunningTimeoutSec",
2457 "StartLimitIntervalSec"))
3d63c749
YW
2458 return bus_append_parse_sec_rename(m, field, eq);
2459
2460 if (streq(field, "StartLimitBurst"))
3d63c749
YW
2461 return bus_append_safe_atou(m, field, eq);
2462
c57d2a76
ZJS
2463 if (STR_IN_SET(field, "SuccessActionExitStatus",
2464 "FailureActionExitStatus")) {
7af67e9a
LP
2465 if (isempty(eq))
2466 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2467 else {
2468 uint8_t u;
2469
2470 r = safe_atou8(eq, &u);
2471 if (r < 0)
2472 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2473
2474 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2475 }
2476 if (r < 0)
2477 return bus_log_create_error(r);
2478
2479 return 1;
2480 }
2481
3d63c749 2482 if (unit_dependency_from_string(field) >= 0 ||
c57d2a76 2483 STR_IN_SET(field, "Documentation",
0dd3c090
ZJS
2484 "RequiresMountsFor",
2485 "Markers"))
4ec85141 2486 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2487
3d63c749
YW
2488 t = condition_type_from_string(field);
2489 if (t >= 0)
2490 is_condition = true;
2491 else
2492 t = assert_type_from_string(field);
2493 if (t >= 0) {
2494 if (isempty(eq))
2495 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2496 else {
2497 const char *p = eq;
2498 int trigger, negate;
2499
2500 trigger = *p == '|';
2501 if (trigger)
2502 p++;
2503
2504 negate = *p == '!';
2505 if (negate)
2506 p++;
2507
2508 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2509 field, trigger, negate, p);
2510 }
2511 if (r < 0)
2512 return bus_log_create_error(r);
2513
2514 return 1;
2515 }
2516
89ada3ba
YW
2517 return 0;
2518}
2519
2520int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2521 const char *eq, *field;
2522 int r;
2523
2524 assert(m);
2525 assert(assignment);
2526
2527 eq = strchr(assignment, '=');
baaa35ad
ZJS
2528 if (!eq)
2529 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2530 "Not an assignment: %s", assignment);
89ada3ba 2531
2f82562b 2532 field = strndupa_safe(assignment, eq - assignment);
89ada3ba
YW
2533 eq++;
2534
2535 switch (t) {
2536 case UNIT_SERVICE:
2537 r = bus_append_cgroup_property(m, field, eq);
2538 if (r != 0)
f6c66be1
LP
2539 return r;
2540
89ada3ba
YW
2541 r = bus_append_execute_property(m, field, eq);
2542 if (r != 0)
2543 return r;
f6c66be1 2544
89ada3ba
YW
2545 r = bus_append_kill_property(m, field, eq);
2546 if (r != 0)
2547 return r;
f6c66be1 2548
89ada3ba
YW
2549 r = bus_append_service_property(m, field, eq);
2550 if (r != 0)
2551 return r;
2552 break;
f6c66be1 2553
89ada3ba
YW
2554 case UNIT_SOCKET:
2555 r = bus_append_cgroup_property(m, field, eq);
2556 if (r != 0)
2557 return r;
f6c66be1 2558
89ada3ba
YW
2559 r = bus_append_execute_property(m, field, eq);
2560 if (r != 0)
2561 return r;
f6c66be1 2562
89ada3ba
YW
2563 r = bus_append_kill_property(m, field, eq);
2564 if (r != 0)
2565 return r;
f6c66be1 2566
89ada3ba
YW
2567 r = bus_append_socket_property(m, field, eq);
2568 if (r != 0)
f6c66be1 2569 return r;
89ada3ba 2570 break;
f6c66be1 2571
89ada3ba
YW
2572 case UNIT_TIMER:
2573 r = bus_append_timer_property(m, field, eq);
2574 if (r != 0)
2575 return r;
2576 break;
f6c66be1 2577
89ada3ba
YW
2578 case UNIT_PATH:
2579 r = bus_append_path_property(m, field, eq);
2580 if (r != 0)
2581 return r;
2582 break;
268833ed 2583
89ada3ba
YW
2584 case UNIT_SLICE:
2585 r = bus_append_cgroup_property(m, field, eq);
2586 if (r != 0)
2587 return r;
2588 break;
268833ed 2589
89ada3ba
YW
2590 case UNIT_SCOPE:
2591 r = bus_append_cgroup_property(m, field, eq);
2592 if (r != 0)
2593 return r;
268833ed 2594
89ada3ba 2595 r = bus_append_kill_property(m, field, eq);
5a70a68f
PW
2596 if (r != 0)
2597 return r;
2598
2599 r = bus_append_scope_property(m, field, eq);
89ada3ba
YW
2600 if (r != 0)
2601 return r;
2602 break;
535e0d19 2603
89ada3ba 2604 case UNIT_MOUNT:
3d63c749
YW
2605 r = bus_append_cgroup_property(m, field, eq);
2606 if (r != 0)
2607 return r;
2608
2609 r = bus_append_execute_property(m, field, eq);
2610 if (r != 0)
2611 return r;
2612
2613 r = bus_append_kill_property(m, field, eq);
2614 if (r != 0)
2615 return r;
2616
2617 r = bus_append_mount_property(m, field, eq);
2618 if (r != 0)
2619 return r;
2620
2621 break;
2622
89ada3ba 2623 case UNIT_AUTOMOUNT:
3d63c749
YW
2624 r = bus_append_automount_property(m, field, eq);
2625 if (r != 0)
2626 return r;
2627
89ada3ba 2628 break;
535e0d19 2629
89ada3ba
YW
2630 case UNIT_TARGET:
2631 case UNIT_DEVICE:
2632 case UNIT_SWAP:
baaa35ad
ZJS
2633 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2634 "Not supported unit type");
535e0d19 2635
89ada3ba 2636 default:
baaa35ad
ZJS
2637 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2638 "Invalid unit type");
20b16441
LP
2639 }
2640
89ada3ba
YW
2641 r = bus_append_unit_property(m, field, eq);
2642 if (r != 0)
2643 return r;
20b16441 2644
baaa35ad
ZJS
2645 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2646 "Unknown assignment: %s", assignment);
20b16441
LP
2647}
2648
89ada3ba 2649int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
2650 char **i;
2651 int r;
2652
2653 assert(m);
2654
2655 STRV_FOREACH(i, l) {
89ada3ba 2656 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
2657 if (r < 0)
2658 return r;
2659 }
2660
2661 return 0;
2662}
2663
da6053d0 2664int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
2665 const char *type, *path, *source;
2666 int r;
2667
acc0269c
CH
2668 /* changes is dereferenced when calling unit_file_dump_changes() later,
2669 * so we have to make sure this is not NULL. */
2670 assert(changes);
2671 assert(n_changes);
2672
20b16441
LP
2673 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2674 if (r < 0)
2675 return bus_log_parse_error(r);
2676
2677 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2678 /* We expect only "success" changes to be sent over the bus.
2679 Hence, reject anything negative. */
93419a96 2680 int ch = unit_file_change_type_from_string(type);
20b16441 2681 if (ch < 0) {
c1b48a7f
BR
2682 log_notice_errno(ch, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2683 type, path);
20b16441
LP
2684 continue;
2685 }
2686
2687 r = unit_file_changes_add(changes, n_changes, ch, path, source);
2688 if (r < 0)
2689 return r;
2690 }
2691 if (r < 0)
2692 return bus_log_parse_error(r);
2693
2694 r = sd_bus_message_exit_container(m);
2695 if (r < 0)
2696 return bus_log_parse_error(r);
2697
35d379b2 2698 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
2699 return 0;
2700}
2701
bd062910
ZJS
2702int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2703 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2704 _cleanup_free_ char *path = NULL;
2705 int r;
2706
2707 path = unit_dbus_path_from_name(name);
2708 if (!path)
2709 return log_oom();
2710
2711 /* This function warns on it's own, because otherwise it'd be awkward to pass
2712 * the dbus error message around. */
2713
2714 r = sd_bus_get_property_string(
2715 bus,
2716 "org.freedesktop.systemd1",
2717 path,
2718 "org.freedesktop.systemd1.Unit",
2719 "LoadState",
2720 &error,
2721 load_state);
2722 if (r < 0)
2723 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2724
2725 return 0;
2726}
4dcc0653
LP
2727
2728int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2729 int r;
2730
2731 /* First, order by machine */
2732 r = strcasecmp_ptr(a->machine, b->machine);
2733 if (r != 0)
2734 return r;
2735
2736 /* Second, order by unit type */
2737 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2738 if (r != 0)
2739 return r;
2740
2741 /* Third, order by name */
2742 return strcasecmp(a->id, b->id);
2743}