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