]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
Merge pull request #20303 from andir/sysconfig-example
[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 1386 "SystemCallFilter",
a59cb62c
MV
1387 "SystemCallLog",
1388 "RestrictNetworkInterfaces")) {
6b000af4 1389 int allow_list = 1;
89ada3ba 1390 const char *p = eq;
20b16441 1391
89ada3ba 1392 if (*p == '~') {
6b000af4 1393 allow_list = 0;
89ada3ba 1394 p++;
20b16441
LP
1395 }
1396
89ada3ba 1397 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1398 if (r < 0)
1399 return bus_log_create_error(r);
1400
89ada3ba
YW
1401 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1402 if (r < 0)
1403 return bus_log_create_error(r);
1404
1405 r = sd_bus_message_open_container(m, 'v', "(bas)");
1406 if (r < 0)
1407 return bus_log_create_error(r);
20b16441 1408
89ada3ba
YW
1409 r = sd_bus_message_open_container(m, 'r', "bas");
1410 if (r < 0)
1411 return bus_log_create_error(r);
cffaed83 1412
6b000af4 1413 r = sd_bus_message_append_basic(m, 'b', &allow_list);
cffaed83
YW
1414 if (r < 0)
1415 return bus_log_create_error(r);
1416
1417 r = sd_bus_message_open_container(m, 'a', "s");
1418 if (r < 0)
1419 return bus_log_create_error(r);
1420
98008caa 1421 for (;;) {
cffaed83
YW
1422 _cleanup_free_ char *word = NULL;
1423
4ec85141 1424 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
cffaed83
YW
1425 if (r == 0)
1426 break;
89ada3ba
YW
1427 if (r == -ENOMEM)
1428 return log_oom();
1429 if (r < 0)
1430 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1431
1432 r = sd_bus_message_append_basic(m, 's', word);
1433 if (r < 0)
1434 return bus_log_create_error(r);
1435 }
1436
1437 r = sd_bus_message_close_container(m);
1438 if (r < 0)
1439 return bus_log_create_error(r);
1440
1441 r = sd_bus_message_close_container(m);
20b16441
LP
1442 if (r < 0)
1443 return bus_log_create_error(r);
1444
89ada3ba 1445 r = sd_bus_message_close_container(m);
20b16441
LP
1446 if (r < 0)
1447 return bus_log_create_error(r);
1448
20b16441
LP
1449 r = sd_bus_message_close_container(m);
1450 if (r < 0)
1451 return bus_log_create_error(r);
1452
89ada3ba
YW
1453 return 1;
1454 }
20b16441 1455
89ada3ba 1456 if (streq(field, "RestrictNamespaces")) {
add00535 1457 bool invert = false;
aa9d574d 1458 unsigned long flags;
add00535
LP
1459
1460 r = parse_boolean(eq);
1461 if (r > 0)
1462 flags = 0;
1463 else if (r == 0)
1464 flags = NAMESPACE_FLAGS_ALL;
1465 else {
aa9d574d
YW
1466 if (eq[0] == '~') {
1467 invert = true;
1468 eq++;
1469 }
1470
86c2a9f1 1471 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1472 if (r < 0)
1473 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1474 }
1475
1476 if (invert)
1477 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1478
89ada3ba
YW
1479 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1480 if (r < 0)
1481 return bus_log_create_error(r);
afcb1cd3 1482
89ada3ba
YW
1483 return 1;
1484 }
afcb1cd3 1485
c57d2a76
ZJS
1486 if (STR_IN_SET(field, "BindPaths",
1487 "BindReadOnlyPaths")) {
89ada3ba 1488 const char *p = eq;
83555251 1489
89ada3ba 1490 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1491 if (r < 0)
89ada3ba 1492 return bus_log_create_error(r);
afcb1cd3 1493
89ada3ba
YW
1494 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1495 if (r < 0)
1496 return bus_log_create_error(r);
d2d6c096
LP
1497
1498 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1499 if (r < 0)
89ada3ba 1500 return bus_log_create_error(r);
d2d6c096
LP
1501
1502 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1503 if (r < 0)
89ada3ba 1504 return bus_log_create_error(r);
d2d6c096
LP
1505
1506 for (;;) {
1507 _cleanup_free_ char *source = NULL, *destination = NULL;
1508 char *s = NULL, *d = NULL;
1509 bool ignore_enoent = false;
1510 uint64_t flags = MS_REC;
1511
4ec85141 1512 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1513 if (r < 0)
1514 return log_error_errno(r, "Failed to parse argument: %m");
1515 if (r == 0)
1516 break;
1517
1518 s = source;
1519 if (s[0] == '-') {
1520 ignore_enoent = true;
1521 s++;
1522 }
1523
1524 if (p && p[-1] == ':') {
4ec85141 1525 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1526 if (r < 0)
1527 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1528 if (r == 0)
1529 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1530 "Missing argument after ':': %s",
1531 eq);
d2d6c096
LP
1532
1533 d = destination;
1534
1535 if (p && p[-1] == ':') {
1536 _cleanup_free_ char *options = NULL;
1537
4ec85141 1538 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
d2d6c096
LP
1539 if (r < 0)
1540 return log_error_errno(r, "Failed to parse argument: %m");
1541
1542 if (isempty(options) || streq(options, "rbind"))
1543 flags = MS_REC;
1544 else if (streq(options, "norbind"))
1545 flags = 0;
baaa35ad
ZJS
1546 else
1547 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1548 "Unknown options: %s",
1549 eq);
d2d6c096
LP
1550 }
1551 } else
1552 d = s;
1553
d2d6c096
LP
1554 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1555 if (r < 0)
89ada3ba 1556 return bus_log_create_error(r);
d2d6c096
LP
1557 }
1558
1559 r = sd_bus_message_close_container(m);
1560 if (r < 0)
89ada3ba
YW
1561 return bus_log_create_error(r);
1562
1563 r = sd_bus_message_close_container(m);
1564 if (r < 0)
1565 return bus_log_create_error(r);
d2d6c096
LP
1566
1567 r = sd_bus_message_close_container(m);
89ada3ba
YW
1568 if (r < 0)
1569 return bus_log_create_error(r);
f6c66be1 1570
89ada3ba
YW
1571 return 1;
1572 }
f6c66be1 1573
784ad252
YW
1574 if (streq(field, "TemporaryFileSystem")) {
1575 const char *p = eq;
1576
1577 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1578 if (r < 0)
1579 return bus_log_create_error(r);
1580
1581 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1582 if (r < 0)
1583 return bus_log_create_error(r);
1584
1585 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1586 if (r < 0)
1587 return bus_log_create_error(r);
1588
1589 r = sd_bus_message_open_container(m, 'a', "(ss)");
1590 if (r < 0)
1591 return bus_log_create_error(r);
1592
1593 for (;;) {
1594 _cleanup_free_ char *word = NULL, *path = NULL;
1595 const char *w;
1596
4ec85141 1597 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
784ad252
YW
1598 if (r < 0)
1599 return log_error_errno(r, "Failed to parse argument: %m");
1600 if (r == 0)
1601 break;
1602
1603 w = word;
1604 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1605 if (r < 0)
1606 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1607 if (r == 0)
1608 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1609 "Failed to parse argument: %s",
1610 p);
784ad252
YW
1611
1612 r = sd_bus_message_append(m, "(ss)", path, w);
1613 if (r < 0)
1614 return bus_log_create_error(r);
1615 }
1616
1617 r = sd_bus_message_close_container(m);
1618 if (r < 0)
1619 return bus_log_create_error(r);
1620
1621 r = sd_bus_message_close_container(m);
1622 if (r < 0)
1623 return bus_log_create_error(r);
1624
1625 r = sd_bus_message_close_container(m);
1626 if (r < 0)
1627 return bus_log_create_error(r);
1628
1629 return 1;
1630 }
1631
0389f4fa
LB
1632 if (streq(field, "RootHash")) {
1633 _cleanup_free_ void *roothash_decoded = NULL;
1634 size_t roothash_decoded_size = 0;
1635
1636 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1637 if (path_is_absolute(eq))
1638 return bus_append_string(m, "RootHashPath", eq);
1639
1640 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1641 r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
1642 if (r < 0)
1643 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1644 if (roothash_decoded_size < sizeof(sd_id128_t))
1645 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
1646
1647 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1648 }
1649
d4d55b0d
LB
1650 if (streq(field, "RootHashSignature")) {
1651 _cleanup_free_ void *roothash_sig_decoded = NULL;
1652 char *value;
1653 size_t roothash_sig_decoded_size = 0;
1654
1655 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1656 if (path_is_absolute(eq))
1657 return bus_append_string(m, "RootHashSignaturePath", eq);
1658
1659 if (!(value = startswith(eq, "base64:")))
1660 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
1661
1662 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1663 r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
1664 if (r < 0)
1665 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1666
1667 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1668 }
1669
18d73705 1670 if (streq(field, "RootImageOptions")) {
bc8d56d3
LB
1671 _cleanup_strv_free_ char **l = NULL;
1672 char **first = NULL, **second = NULL;
18d73705
LB
1673 const char *p = eq;
1674
1675 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1676 if (r < 0)
1677 return bus_log_create_error(r);
1678
1679 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1680 if (r < 0)
1681 return bus_log_create_error(r);
1682
9ece6444 1683 r = sd_bus_message_open_container(m, 'v', "a(ss)");
18d73705
LB
1684 if (r < 0)
1685 return bus_log_create_error(r);
1686
9ece6444 1687 r = sd_bus_message_open_container(m, 'a', "(ss)");
18d73705
LB
1688 if (r < 0)
1689 return bus_log_create_error(r);
1690
bc8d56d3
LB
1691 r = strv_split_colon_pairs(&l, p);
1692 if (r < 0)
1693 return log_error_errno(r, "Failed to parse argument: %m");
18d73705 1694
bc8d56d3 1695 STRV_FOREACH_PAIR(first, second, l) {
9ece6444
LB
1696 r = sd_bus_message_append(m, "(ss)",
1697 !isempty(*second) ? *first : "root",
1698 !isempty(*second) ? *second : *first);
18d73705
LB
1699 if (r < 0)
1700 return bus_log_create_error(r);
1701 }
1702
1703 r = sd_bus_message_close_container(m);
1704 if (r < 0)
b3d13314
LB
1705 return bus_log_create_error(r);
1706
1707 r = sd_bus_message_close_container(m);
1708 if (r < 0)
1709 return bus_log_create_error(r);
1710
1711 r = sd_bus_message_close_container(m);
1712 if (r < 0)
1713 return bus_log_create_error(r);
1714
1715 return 1;
1716 }
1717
1718 if (streq(field, "MountImages")) {
b3d13314
LB
1719 const char *p = eq;
1720
1721 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1722 if (r < 0)
1723 return bus_log_create_error(r);
1724
1725 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1726 if (r < 0)
1727 return bus_log_create_error(r);
1728
427353f6 1729 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
b3d13314
LB
1730 if (r < 0)
1731 return bus_log_create_error(r);
1732
427353f6 1733 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
b3d13314
LB
1734 if (r < 0)
1735 return bus_log_create_error(r);
1736
427353f6
LB
1737 for (;;) {
1738 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1739 const char *q = NULL, *source = NULL;
b3d13314
LB
1740 bool permissive = false;
1741
427353f6
LB
1742 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1743 if (r < 0)
de4abc3f 1744 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1745 if (r == 0)
1746 break;
1747
1748 q = tuple;
1749 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
1750 if (r < 0)
de4abc3f 1751 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1752 if (r == 0)
1753 continue;
1754
1755 source = first;
1756 if (source[0] == '-') {
b3d13314 1757 permissive = true;
427353f6 1758 source++;
b3d13314
LB
1759 }
1760
427353f6 1761 if (isempty(second))
b3d13314
LB
1762 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1763 "Missing argument after ':': %s",
1764 eq);
1765
427353f6
LB
1766 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
1767 if (r < 0)
1768 return bus_log_create_error(r);
1769
1770 r = sd_bus_message_append(m, "ssb", source, second, permissive);
1771 if (r < 0)
1772 return bus_log_create_error(r);
1773
1774 r = sd_bus_message_open_container(m, 'a', "(ss)");
1775 if (r < 0)
1776 return bus_log_create_error(r);
1777
1778 for (;;) {
1779 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1780
1781 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1782 if (r < 0)
de4abc3f 1783 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
93f59701
LB
1784 if (r == 0)
1785 break;
1786 /* Single set of options, applying to the root partition/single filesystem */
1787 if (r == 1) {
1788 r = sd_bus_message_append(m, "(ss)", "root", partition);
1789 if (r < 0)
1790 return bus_log_create_error(r);
1791
1792 break;
1793 }
1794
93f59701
LB
1795 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1796 if (r < 0)
1797 return bus_log_create_error(r);
1798 }
1799
1800 r = sd_bus_message_close_container(m);
1801 if (r < 0)
1802 return bus_log_create_error(r);
1803
1804 r = sd_bus_message_close_container(m);
1805 if (r < 0)
1806 return bus_log_create_error(r);
1807 }
1808
1809 r = sd_bus_message_close_container(m);
1810 if (r < 0)
1811 return bus_log_create_error(r);
1812
1813 r = sd_bus_message_close_container(m);
1814 if (r < 0)
1815 return bus_log_create_error(r);
1816
1817 r = sd_bus_message_close_container(m);
1818 if (r < 0)
1819 return bus_log_create_error(r);
1820
1821 return 1;
1822 }
1823
1824 if (streq(field, "ExtensionImages")) {
1825 const char *p = eq;
1826
1827 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1828 if (r < 0)
1829 return bus_log_create_error(r);
1830
1831 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1832 if (r < 0)
1833 return bus_log_create_error(r);
1834
1835 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
1836 if (r < 0)
1837 return bus_log_create_error(r);
1838
1839 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
1840 if (r < 0)
1841 return bus_log_create_error(r);
1842
1843 for (;;) {
1844 _cleanup_free_ char *source = NULL, *tuple = NULL;
1845 const char *q = NULL, *s = NULL;
1846 bool permissive = false;
1847
1848 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1849 if (r < 0)
de4abc3f 1850 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1851 if (r == 0)
1852 break;
1853
1854 q = tuple;
1855 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
1856 if (r < 0)
de4abc3f 1857 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1858 if (r == 0)
1859 continue;
1860
1861 s = source;
1862 if (s[0] == '-') {
1863 permissive = true;
1864 s++;
1865 }
1866
1867 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
1868 if (r < 0)
1869 return bus_log_create_error(r);
1870
1871 r = sd_bus_message_append(m, "sb", s, permissive);
1872 if (r < 0)
1873 return bus_log_create_error(r);
1874
1875 r = sd_bus_message_open_container(m, 'a', "(ss)");
1876 if (r < 0)
1877 return bus_log_create_error(r);
1878
1879 for (;;) {
1880 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1881
1882 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1883 if (r < 0)
de4abc3f 1884 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
427353f6
LB
1885 if (r == 0)
1886 break;
1887 /* Single set of options, applying to the root partition/single filesystem */
1888 if (r == 1) {
1889 r = sd_bus_message_append(m, "(ss)", "root", partition);
1890 if (r < 0)
1891 return bus_log_create_error(r);
1892
1893 break;
1894 }
1895
427353f6
LB
1896 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1897 if (r < 0)
1898 return bus_log_create_error(r);
1899 }
1900
1901 r = sd_bus_message_close_container(m);
1902 if (r < 0)
1903 return bus_log_create_error(r);
1904
1905 r = sd_bus_message_close_container(m);
b3d13314
LB
1906 if (r < 0)
1907 return bus_log_create_error(r);
1908 }
1909
1910 r = sd_bus_message_close_container(m);
1911 if (r < 0)
18d73705
LB
1912 return bus_log_create_error(r);
1913
1914 r = sd_bus_message_close_container(m);
1915 if (r < 0)
1916 return bus_log_create_error(r);
1917
1918 r = sd_bus_message_close_container(m);
1919 if (r < 0)
1920 return bus_log_create_error(r);
1921
1922 return 1;
1923 }
1924
89ada3ba
YW
1925 return 0;
1926}
f6c66be1 1927
89ada3ba 1928static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 1929 if (streq(field, "KillMode"))
89ada3ba 1930 return bus_append_string(m, field, eq);
f6c66be1 1931
c57d2a76
ZJS
1932 if (STR_IN_SET(field, "SendSIGHUP",
1933 "SendSIGKILL"))
89ada3ba 1934 return bus_append_parse_boolean(m, field, eq);
f6c66be1 1935
c57d2a76
ZJS
1936 if (STR_IN_SET(field, "KillSignal",
1937 "RestartKillSignal",
1938 "FinalKillSignal",
1939 "WatchdogSignal"))
29a3db75 1940 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
1941
1942 return 0;
1943}
1944
3d63c749 1945static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 1946
c57d2a76
ZJS
1947 if (STR_IN_SET(field, "What",
1948 "Where",
1949 "Options",
1950 "Type"))
89ada3ba
YW
1951 return bus_append_string(m, field, eq);
1952
3d63c749 1953 if (streq(field, "TimeoutSec"))
3d63c749
YW
1954 return bus_append_parse_sec_rename(m, field, eq);
1955
1956 if (streq(field, "DirectoryMode"))
3d63c749
YW
1957 return bus_append_parse_mode(m, field, eq);
1958
c57d2a76
ZJS
1959 if (STR_IN_SET(field, "SloppyOptions",
1960 "LazyUnmount",
c600357b
MH
1961 "ForceUnmount",
1962 "ReadwriteOnly"))
3d63c749
YW
1963 return bus_append_parse_boolean(m, field, eq);
1964
1965 return 0;
1966}
1967
1968static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1969 int r;
1970
89ada3ba 1971 if (streq(field, "MakeDirectory"))
89ada3ba
YW
1972 return bus_append_parse_boolean(m, field, eq);
1973
1974 if (streq(field, "DirectoryMode"))
89ada3ba
YW
1975 return bus_append_parse_mode(m, field, eq);
1976
c57d2a76
ZJS
1977 if (STR_IN_SET(field, "PathExists",
1978 "PathExistsGlob",
1979 "PathChanged",
1980 "PathModified",
1981 "DirectoryNotEmpty")) {
3d63c749
YW
1982 if (isempty(eq))
1983 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1984 else
1985 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1986 if (r < 0)
1987 return bus_log_create_error(r);
1988
1989 return 1;
1990 }
1991
89ada3ba
YW
1992 return 0;
1993}
1994
5a70a68f 1995static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
9ed7de60 1996 if (streq(field, "RuntimeMaxSec"))
9ed7de60
PW
1997 return bus_append_parse_sec_rename(m, field, eq);
1998
5a70a68f 1999 if (streq(field, "TimeoutStopSec"))
5a70a68f
PW
2000 return bus_append_parse_sec_rename(m, field, eq);
2001
2002 return 0;
2003}
2004
89ada3ba 2005static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2006 int r;
89ada3ba 2007
c57d2a76
ZJS
2008 if (STR_IN_SET(field, "PIDFile",
2009 "Type",
2010 "Restart",
2011 "BusName",
2012 "NotifyAccess",
2013 "USBFunctionDescriptors",
2014 "USBFunctionStrings",
bf760801
JK
2015 "OOMPolicy",
2016 "TimeoutStartFailureMode",
2017 "TimeoutStopFailureMode"))
89ada3ba 2018 return bus_append_string(m, field, eq);
f6c66be1 2019
c57d2a76
ZJS
2020 if (STR_IN_SET(field, "PermissionsStartOnly",
2021 "RootDirectoryStartOnly",
2022 "RemainAfterExit",
2023 "GuessMainPID"))
89ada3ba
YW
2024 return bus_append_parse_boolean(m, field, eq);
2025
c57d2a76
ZJS
2026 if (STR_IN_SET(field, "RestartSec",
2027 "TimeoutStartSec",
2028 "TimeoutStopSec",
e737017b 2029 "TimeoutAbortSec",
c57d2a76
ZJS
2030 "RuntimeMaxSec",
2031 "WatchdogSec"))
89ada3ba
YW
2032 return bus_append_parse_sec_rename(m, field, eq);
2033
3d63c749 2034 if (streq(field, "TimeoutSec")) {
3d63c749
YW
2035 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2036 if (r < 0)
2037 return r;
2038
2039 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2040 }
2041
89ada3ba 2042 if (streq(field, "FileDescriptorStoreMax"))
89ada3ba
YW
2043 return bus_append_safe_atou(m, field, eq);
2044
c57d2a76
ZJS
2045 if (STR_IN_SET(field, "ExecCondition",
2046 "ExecStartPre",
2047 "ExecStart",
2048 "ExecStartPost",
2049 "ExecConditionEx",
2050 "ExecStartPreEx",
2051 "ExecStartEx",
2052 "ExecStartPostEx",
2053 "ExecReload",
2054 "ExecStop",
2055 "ExecStopPost",
2056 "ExecReloadEx",
2057 "ExecStopEx",
2058 "ExecStopPostEx"))
89ada3ba
YW
2059 return bus_append_exec_command(m, field, eq);
2060
c57d2a76
ZJS
2061 if (STR_IN_SET(field, "RestartPreventExitStatus",
2062 "RestartForceExitStatus",
2063 "SuccessExitStatus")) {
3d63c749 2064 _cleanup_free_ int *status = NULL, *signal = NULL;
62b21e2e 2065 size_t n_status = 0, n_signal = 0;
3d63c749
YW
2066 const char *p;
2067
2068 for (p = eq;;) {
2069 _cleanup_free_ char *word = NULL;
3d63c749 2070
4ec85141 2071 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3d63c749
YW
2072 if (r == 0)
2073 break;
2074 if (r == -ENOMEM)
2075 return log_oom();
2076 if (r < 0)
2077 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2078
2e2ed880
ZJS
2079 /* We need to call exit_status_from_string() first, because we want
2080 * to parse numbers as exit statuses, not signals. */
3d63c749 2081
2e2ed880
ZJS
2082 r = exit_status_from_string(word);
2083 if (r >= 0) {
2084 assert(r >= 0 && r < 256);
3d63c749 2085
62b21e2e 2086 status = reallocarray(status, n_status + 1, sizeof(int));
3d63c749
YW
2087 if (!status)
2088 return log_oom();
2089
2e2ed880
ZJS
2090 status[n_status++] = r;
2091
2092 } else if ((r = signal_from_string(word)) >= 0) {
2093 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2094 if (!signal)
2095 return log_oom();
2096
2097 signal[n_signal++] = r;
2098
2099 } else
2100 /* original r from exit_status_to_string() */
2101 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2102 word, field);
3d63c749
YW
2103 }
2104
2105 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2106 if (r < 0)
2107 return bus_log_create_error(r);
2108
2109 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2110 if (r < 0)
2111 return bus_log_create_error(r);
2112
2113 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2114 if (r < 0)
2115 return bus_log_create_error(r);
2116
2117 r = sd_bus_message_open_container(m, 'r', "aiai");
2118 if (r < 0)
2119 return bus_log_create_error(r);
2120
62b21e2e 2121 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
3d63c749
YW
2122 if (r < 0)
2123 return bus_log_create_error(r);
2124
62b21e2e 2125 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
3d63c749
YW
2126 if (r < 0)
2127 return bus_log_create_error(r);
2128
2129 r = sd_bus_message_close_container(m);
2130 if (r < 0)
2131 return bus_log_create_error(r);
2132
2133 r = sd_bus_message_close_container(m);
2134 if (r < 0)
2135 return bus_log_create_error(r);
2136
2137 r = sd_bus_message_close_container(m);
2138 if (r < 0)
2139 return bus_log_create_error(r);
2140
2141 return 1;
2142 }
2143
89ada3ba
YW
2144 return 0;
2145}
2146
2147static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2148 int r;
2149
c57d2a76 2150 if (STR_IN_SET(field, "Accept",
3e5f04bf 2151 "FlushPending",
c57d2a76
ZJS
2152 "Writable",
2153 "KeepAlive",
2154 "NoDelay",
2155 "FreeBind",
2156 "Transparent",
2157 "Broadcast",
2158 "PassCredentials",
2159 "PassSecurity",
a3d19f5d 2160 "PassPacketInfo",
c57d2a76
ZJS
2161 "ReusePort",
2162 "RemoveOnStop",
2163 "SELinuxContextFromNet"))
89ada3ba
YW
2164 return bus_append_parse_boolean(m, field, eq);
2165
c57d2a76
ZJS
2166 if (STR_IN_SET(field, "Priority",
2167 "IPTTL",
2168 "Mark"))
89ada3ba
YW
2169 return bus_append_safe_atoi(m, field, eq);
2170
2171 if (streq(field, "IPTOS"))
89ada3ba
YW
2172 return bus_append_ip_tos_from_string(m, field, eq);
2173
c57d2a76
ZJS
2174 if (STR_IN_SET(field, "Backlog",
2175 "MaxConnections",
2176 "MaxConnectionsPerSource",
2177 "KeepAliveProbes",
2178 "TriggerLimitBurst"))
89ada3ba
YW
2179 return bus_append_safe_atou(m, field, eq);
2180
c57d2a76
ZJS
2181 if (STR_IN_SET(field, "SocketMode",
2182 "DirectoryMode"))
89ada3ba
YW
2183 return bus_append_parse_mode(m, field, eq);
2184
c57d2a76
ZJS
2185 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2186 "MessageQueueMessageSize"))
89ada3ba
YW
2187 return bus_append_safe_atoi64(m, field, eq);
2188
c57d2a76
ZJS
2189 if (STR_IN_SET(field, "TimeoutSec",
2190 "KeepAliveTimeSec",
2191 "KeepAliveIntervalSec",
2192 "DeferAcceptSec",
2193 "TriggerLimitIntervalSec"))
89ada3ba
YW
2194 return bus_append_parse_sec_rename(m, field, eq);
2195
c57d2a76
ZJS
2196 if (STR_IN_SET(field, "ReceiveBuffer",
2197 "SendBuffer",
2198 "PipeSize"))
b48e508d 2199 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 2200
c57d2a76
ZJS
2201 if (STR_IN_SET(field, "ExecStartPre",
2202 "ExecStartPost",
2203 "ExecReload",
2204 "ExecStopPost"))
89ada3ba
YW
2205 return bus_append_exec_command(m, field, eq);
2206
c57d2a76
ZJS
2207 if (STR_IN_SET(field, "SmackLabel",
2208 "SmackLabelIPIn",
2209 "SmackLabelIPOut",
2210 "TCPCongestion",
2211 "BindToDevice",
2212 "BindIPv6Only",
2213 "FileDescriptorName",
2214 "SocketUser",
9b191525
LP
2215 "SocketGroup",
2216 "Timestamping"))
89ada3ba
YW
2217 return bus_append_string(m, field, eq);
2218
2219 if (streq(field, "Symlinks"))
4ec85141 2220 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2221
e045e325 2222 if (streq(field, "SocketProtocol"))
d2b42d63 2223 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba 2224
c57d2a76
ZJS
2225 if (STR_IN_SET(field, "ListenStream",
2226 "ListenDatagram",
2227 "ListenSequentialPacket",
2228 "ListenNetlink",
2229 "ListenSpecial",
2230 "ListenMessageQueue",
2231 "ListenFIFO",
2232 "ListenUSBFunction")) {
3d63c749
YW
2233 if (isempty(eq))
2234 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2235 else
81b1dc27 2236 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 2237 if (r < 0)
89ada3ba
YW
2238 return bus_log_create_error(r);
2239
2240 return 1;
2241 }
2242
2243 return 0;
2244}
2245static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2246 int r;
89ada3ba 2247
c57d2a76
ZJS
2248 if (STR_IN_SET(field, "WakeSystem",
2249 "RemainAfterElapse",
2250 "Persistent",
2251 "OnTimezoneChange",
acf24a1a
KG
2252 "OnClockChange",
2253 "FixedRandomDelay"))
89ada3ba
YW
2254 return bus_append_parse_boolean(m, field, eq);
2255
c57d2a76
ZJS
2256 if (STR_IN_SET(field, "AccuracySec",
2257 "RandomizedDelaySec"))
3d63c749
YW
2258 return bus_append_parse_sec_rename(m, field, eq);
2259
c57d2a76
ZJS
2260 if (STR_IN_SET(field, "OnActiveSec",
2261 "OnBootSec",
2262 "OnStartupSec",
2263 "OnUnitActiveSec",
2264 "OnUnitInactiveSec")) {
3d63c749
YW
2265 if (isempty(eq))
2266 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2267 else {
2268 usec_t t;
2269 r = parse_sec(eq, &t);
2270 if (r < 0)
2271 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 2272
3d63c749
YW
2273 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2274 }
2275 if (r < 0)
2276 return bus_log_create_error(r);
89ada3ba 2277
3d63c749
YW
2278 return 1;
2279 }
2280
2281 if (streq(field, "OnCalendar")) {
3d63c749
YW
2282 if (isempty(eq))
2283 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2284 else
2285 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2286 if (r < 0)
2287 return bus_log_create_error(r);
2288
2289 return 1;
2290 }
89ada3ba
YW
2291
2292 return 0;
2293}
2294
2295static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
2296 ConditionType t = _CONDITION_TYPE_INVALID;
2297 bool is_condition = false;
2298 int r;
f6c66be1 2299
c57d2a76
ZJS
2300 if (STR_IN_SET(field, "Description",
2301 "SourcePath",
2302 "OnFailureJobMode",
2303 "JobTimeoutAction",
2304 "JobTimeoutRebootArgument",
2305 "StartLimitAction",
2306 "FailureAction",
2307 "SuccessAction",
2308 "RebootArgument",
2309 "CollectMode"))
89ada3ba
YW
2310 return bus_append_string(m, field, eq);
2311
c57d2a76
ZJS
2312 if (STR_IN_SET(field, "StopWhenUnneeded",
2313 "RefuseManualStart",
2314 "RefuseManualStop",
2315 "AllowIsolate",
2316 "IgnoreOnIsolate",
2317 "DefaultDependencies"))
89ada3ba
YW
2318 return bus_append_parse_boolean(m, field, eq);
2319
c57d2a76
ZJS
2320 if (STR_IN_SET(field, "JobTimeoutSec",
2321 "JobRunningTimeoutSec",
2322 "StartLimitIntervalSec"))
3d63c749
YW
2323 return bus_append_parse_sec_rename(m, field, eq);
2324
2325 if (streq(field, "StartLimitBurst"))
3d63c749
YW
2326 return bus_append_safe_atou(m, field, eq);
2327
c57d2a76
ZJS
2328 if (STR_IN_SET(field, "SuccessActionExitStatus",
2329 "FailureActionExitStatus")) {
7af67e9a
LP
2330 if (isempty(eq))
2331 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2332 else {
2333 uint8_t u;
2334
2335 r = safe_atou8(eq, &u);
2336 if (r < 0)
2337 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2338
2339 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2340 }
2341 if (r < 0)
2342 return bus_log_create_error(r);
2343
2344 return 1;
2345 }
2346
3d63c749 2347 if (unit_dependency_from_string(field) >= 0 ||
c57d2a76 2348 STR_IN_SET(field, "Documentation",
0dd3c090
ZJS
2349 "RequiresMountsFor",
2350 "Markers"))
4ec85141 2351 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2352
3d63c749
YW
2353 t = condition_type_from_string(field);
2354 if (t >= 0)
2355 is_condition = true;
2356 else
2357 t = assert_type_from_string(field);
2358 if (t >= 0) {
2359 if (isempty(eq))
2360 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2361 else {
2362 const char *p = eq;
2363 int trigger, negate;
2364
2365 trigger = *p == '|';
2366 if (trigger)
2367 p++;
2368
2369 negate = *p == '!';
2370 if (negate)
2371 p++;
2372
2373 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2374 field, trigger, negate, p);
2375 }
2376 if (r < 0)
2377 return bus_log_create_error(r);
2378
2379 return 1;
2380 }
2381
89ada3ba
YW
2382 return 0;
2383}
2384
2385int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2386 const char *eq, *field;
2387 int r;
2388
2389 assert(m);
2390 assert(assignment);
2391
2392 eq = strchr(assignment, '=');
baaa35ad
ZJS
2393 if (!eq)
2394 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2395 "Not an assignment: %s", assignment);
89ada3ba
YW
2396
2397 field = strndupa(assignment, eq - assignment);
2398 eq++;
2399
2400 switch (t) {
2401 case UNIT_SERVICE:
2402 r = bus_append_cgroup_property(m, field, eq);
2403 if (r != 0)
f6c66be1
LP
2404 return r;
2405
89ada3ba
YW
2406 r = bus_append_execute_property(m, field, eq);
2407 if (r != 0)
2408 return r;
f6c66be1 2409
89ada3ba
YW
2410 r = bus_append_kill_property(m, field, eq);
2411 if (r != 0)
2412 return r;
f6c66be1 2413
89ada3ba
YW
2414 r = bus_append_service_property(m, field, eq);
2415 if (r != 0)
2416 return r;
2417 break;
f6c66be1 2418
89ada3ba
YW
2419 case UNIT_SOCKET:
2420 r = bus_append_cgroup_property(m, field, eq);
2421 if (r != 0)
2422 return r;
f6c66be1 2423
89ada3ba
YW
2424 r = bus_append_execute_property(m, field, eq);
2425 if (r != 0)
2426 return r;
f6c66be1 2427
89ada3ba
YW
2428 r = bus_append_kill_property(m, field, eq);
2429 if (r != 0)
2430 return r;
f6c66be1 2431
89ada3ba
YW
2432 r = bus_append_socket_property(m, field, eq);
2433 if (r != 0)
f6c66be1 2434 return r;
89ada3ba 2435 break;
f6c66be1 2436
89ada3ba
YW
2437 case UNIT_TIMER:
2438 r = bus_append_timer_property(m, field, eq);
2439 if (r != 0)
2440 return r;
2441 break;
f6c66be1 2442
89ada3ba
YW
2443 case UNIT_PATH:
2444 r = bus_append_path_property(m, field, eq);
2445 if (r != 0)
2446 return r;
2447 break;
268833ed 2448
89ada3ba
YW
2449 case UNIT_SLICE:
2450 r = bus_append_cgroup_property(m, field, eq);
2451 if (r != 0)
2452 return r;
2453 break;
268833ed 2454
89ada3ba
YW
2455 case UNIT_SCOPE:
2456 r = bus_append_cgroup_property(m, field, eq);
2457 if (r != 0)
2458 return r;
268833ed 2459
89ada3ba 2460 r = bus_append_kill_property(m, field, eq);
5a70a68f
PW
2461 if (r != 0)
2462 return r;
2463
2464 r = bus_append_scope_property(m, field, eq);
89ada3ba
YW
2465 if (r != 0)
2466 return r;
2467 break;
535e0d19 2468
89ada3ba 2469 case UNIT_MOUNT:
3d63c749
YW
2470 r = bus_append_cgroup_property(m, field, eq);
2471 if (r != 0)
2472 return r;
2473
2474 r = bus_append_execute_property(m, field, eq);
2475 if (r != 0)
2476 return r;
2477
2478 r = bus_append_kill_property(m, field, eq);
2479 if (r != 0)
2480 return r;
2481
2482 r = bus_append_mount_property(m, field, eq);
2483 if (r != 0)
2484 return r;
2485
2486 break;
2487
89ada3ba 2488 case UNIT_AUTOMOUNT:
3d63c749
YW
2489 r = bus_append_automount_property(m, field, eq);
2490 if (r != 0)
2491 return r;
2492
89ada3ba 2493 break;
535e0d19 2494
89ada3ba
YW
2495 case UNIT_TARGET:
2496 case UNIT_DEVICE:
2497 case UNIT_SWAP:
baaa35ad
ZJS
2498 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2499 "Not supported unit type");
535e0d19 2500
89ada3ba 2501 default:
baaa35ad
ZJS
2502 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2503 "Invalid unit type");
20b16441
LP
2504 }
2505
89ada3ba
YW
2506 r = bus_append_unit_property(m, field, eq);
2507 if (r != 0)
2508 return r;
20b16441 2509
baaa35ad
ZJS
2510 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2511 "Unknown assignment: %s", assignment);
20b16441
LP
2512}
2513
89ada3ba 2514int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
2515 char **i;
2516 int r;
2517
2518 assert(m);
2519
2520 STRV_FOREACH(i, l) {
89ada3ba 2521 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
2522 if (r < 0)
2523 return r;
2524 }
2525
2526 return 0;
2527}
2528
da6053d0 2529int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
2530 const char *type, *path, *source;
2531 int r;
2532
acc0269c
CH
2533 /* changes is dereferenced when calling unit_file_dump_changes() later,
2534 * so we have to make sure this is not NULL. */
2535 assert(changes);
2536 assert(n_changes);
2537
20b16441
LP
2538 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2539 if (r < 0)
2540 return bus_log_parse_error(r);
2541
2542 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2543 /* We expect only "success" changes to be sent over the bus.
2544 Hence, reject anything negative. */
93419a96 2545 int ch = unit_file_change_type_from_string(type);
20b16441 2546 if (ch < 0) {
c1b48a7f
BR
2547 log_notice_errno(ch, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
2548 type, path);
20b16441
LP
2549 continue;
2550 }
2551
2552 r = unit_file_changes_add(changes, n_changes, ch, path, source);
2553 if (r < 0)
2554 return r;
2555 }
2556 if (r < 0)
2557 return bus_log_parse_error(r);
2558
2559 r = sd_bus_message_exit_container(m);
2560 if (r < 0)
2561 return bus_log_parse_error(r);
2562
35d379b2 2563 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
2564 return 0;
2565}
2566
bd062910
ZJS
2567int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2568 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2569 _cleanup_free_ char *path = NULL;
2570 int r;
2571
2572 path = unit_dbus_path_from_name(name);
2573 if (!path)
2574 return log_oom();
2575
2576 /* This function warns on it's own, because otherwise it'd be awkward to pass
2577 * the dbus error message around. */
2578
2579 r = sd_bus_get_property_string(
2580 bus,
2581 "org.freedesktop.systemd1",
2582 path,
2583 "org.freedesktop.systemd1.Unit",
2584 "LoadState",
2585 &error,
2586 load_state);
2587 if (r < 0)
2588 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2589
2590 return 0;
2591}
4dcc0653
LP
2592
2593int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2594 int r;
2595
2596 /* First, order by machine */
2597 r = strcasecmp_ptr(a->machine, b->machine);
2598 if (r != 0)
2599 return r;
2600
2601 /* Second, order by unit type */
2602 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2603 if (r != 0)
2604 return r;
2605
2606 /* Third, order by name */
2607 return strcasecmp(a->id, b->id);
2608}