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