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