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