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