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