]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
treewide: fix "an" before consonant U sounds
[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",
85614c6e 994 "MemoryKSM",
9c0c6701
DDM
995 "RestrictSUIDSGID",
996 "RootEphemeral"))
89ada3ba 997 return bus_append_parse_boolean(m, field, eq);
cffaed83 998
c57d2a76
ZJS
999 if (STR_IN_SET(field, "ReadWriteDirectories",
1000 "ReadOnlyDirectories",
1001 "InaccessibleDirectories",
1002 "ReadWritePaths",
1003 "ReadOnlyPaths",
1004 "InaccessiblePaths",
ddc155b2
TM
1005 "ExecPaths",
1006 "NoExecPaths",
8c35c10d 1007 "ExecSearchPath",
a07b9926 1008 "ExtensionDirectories",
c57d2a76
ZJS
1009 "ConfigurationDirectory",
1010 "SupplementaryGroups",
1011 "SystemCallArchitectures"))
4ec85141 1012 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
20b16441 1013
c57d2a76
ZJS
1014 if (STR_IN_SET(field, "SyslogLevel",
1015 "LogLevelMax"))
89ada3ba 1016 return bus_append_log_level_from_string(m, field, eq);
20b16441 1017
89ada3ba 1018 if (streq(field, "SyslogFacility"))
89ada3ba 1019 return bus_append_log_facility_unshifted_from_string(m, field, eq);
cffaed83 1020
89ada3ba 1021 if (streq(field, "SecureBits"))
89ada3ba 1022 return bus_append_secure_bits_from_string(m, field, eq);
cffaed83 1023
89ada3ba 1024 if (streq(field, "CPUSchedulingPolicy"))
89ada3ba 1025 return bus_append_sched_policy_from_string(m, field, eq);
cffaed83 1026
c57d2a76
ZJS
1027 if (STR_IN_SET(field, "CPUSchedulingPriority",
1028 "OOMScoreAdjust"))
89ada3ba 1029 return bus_append_safe_atoi(m, field, eq);
3f856a28 1030
ad21e542
ZJS
1031 if (streq(field, "CoredumpFilter"))
1032 return bus_append_coredump_filter_mask_from_string(m, field, eq);
1033
89ada3ba 1034 if (streq(field, "Nice"))
89ada3ba 1035 return bus_append_parse_nice(m, field, eq);
3f856a28 1036
89ada3ba 1037 if (streq(field, "SystemCallErrorNumber"))
005bfaf1 1038 return bus_append_seccomp_parse_errno_or_action(m, field, eq);
cffaed83 1039
89ada3ba 1040 if (streq(field, "IOSchedulingClass"))
89ada3ba 1041 return bus_append_ioprio_class_from_string(m, field, eq);
cffaed83 1042
89ada3ba 1043 if (streq(field, "IOSchedulingPriority"))
89ada3ba 1044 return bus_append_ioprio_parse_priority(m, field, eq);
cffaed83 1045
c57d2a76
ZJS
1046 if (STR_IN_SET(field, "RuntimeDirectoryMode",
1047 "StateDirectoryMode",
1048 "CacheDirectoryMode",
1049 "LogsDirectoryMode",
1050 "ConfigurationDirectoryMode",
1051 "UMask"))
89ada3ba 1052 return bus_append_parse_mode(m, field, eq);
cffaed83 1053
89ada3ba 1054 if (streq(field, "TimerSlackNSec"))
89ada3ba 1055 return bus_append_parse_nsec(m, field, eq);
cffaed83 1056
691d6f6d 1057 if (streq(field, "LogRateLimitIntervalSec"))
90fc172e
AZ
1058 return bus_append_parse_sec_rename(m, field, eq);
1059
51462135
DDM
1060 if (STR_IN_SET(field, "LogRateLimitBurst",
1061 "TTYRows",
1062 "TTYColumns"))
90fc172e
AZ
1063 return bus_append_safe_atou(m, field, eq);
1064
89ada3ba 1065 if (streq(field, "MountFlags"))
b205e59a 1066 return bus_append_mount_propagation_flag_from_string(m, field, eq);
cffaed83 1067
c57d2a76
ZJS
1068 if (STR_IN_SET(field, "Environment",
1069 "UnsetEnvironment",
1070 "PassEnvironment"))
4ec85141 1071 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
cffaed83 1072
89ada3ba 1073 if (streq(field, "EnvironmentFile")) {
89ada3ba
YW
1074 if (isempty(eq))
1075 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
1076 else
1077 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
1078 eq[0] == '-' ? eq + 1 : eq,
1079 eq[0] == '-');
1080 if (r < 0)
1081 return bus_log_create_error(r);
cffaed83 1082
89ada3ba
YW
1083 return 1;
1084 }
cffaed83 1085
43144be4 1086 if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
bb0c0d6f
LP
1087 r = sd_bus_message_open_container(m, 'r', "sv");
1088 if (r < 0)
1089 return bus_log_create_error(r);
1090
43144be4 1091 r = sd_bus_message_append_basic(m, 's', field);
bb0c0d6f
LP
1092 if (r < 0)
1093 return bus_log_create_error(r);
1094
1095 r = sd_bus_message_open_container(m, 'v', "a(say)");
1096 if (r < 0)
1097 return bus_log_create_error(r);
1098
1099 if (isempty(eq))
1100 r = sd_bus_message_append(m, "a(say)", 0);
1101 else {
43144be4 1102 _cleanup_free_ char *word = NULL;
bb0c0d6f 1103 const char *p = eq;
bb0c0d6f
LP
1104
1105 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1106 if (r == -ENOMEM)
1107 return log_oom();
1108 if (r < 0)
43144be4 1109 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
bb0c0d6f 1110 if (r == 0 || !p)
43144be4 1111 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f
LP
1112
1113 r = sd_bus_message_open_container(m, 'a', "(say)");
1114 if (r < 0)
1115 return bus_log_create_error(r);
1116
1117 r = sd_bus_message_open_container(m, 'r', "say");
1118 if (r < 0)
1119 return bus_log_create_error(r);
1120
1121 r = sd_bus_message_append(m, "s", word);
1122 if (r < 0)
1123 return bus_log_create_error(r);
1124
43144be4
LP
1125 if (streq(field, "SetCredentialEncrypted")) {
1126 _cleanup_free_ void *decoded = NULL;
1127 size_t decoded_size;
1128
1129 r = unbase64mem(p, SIZE_MAX, &decoded, &decoded_size);
1130 if (r < 0)
1131 return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
1132
1133 r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
1134 } else {
1135 _cleanup_free_ char *unescaped = NULL;
e437538f 1136 ssize_t l;
43144be4
LP
1137
1138 l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
1139 if (l < 0)
1140 return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
1141
1142 r = sd_bus_message_append_array(m, 'y', unescaped, l);
1143 }
bb0c0d6f
LP
1144 if (r < 0)
1145 return bus_log_create_error(r);
1146
1147 r = sd_bus_message_close_container(m);
1148 if (r < 0)
1149 return bus_log_create_error(r);
1150
1151 r = sd_bus_message_close_container(m);
1152 }
1153 if (r < 0)
1154 return bus_log_create_error(r);
1155
1156 r = sd_bus_message_close_container(m);
1157 if (r < 0)
1158 return bus_log_create_error(r);
1159
1160 r = sd_bus_message_close_container(m);
1161 if (r < 0)
1162 return bus_log_create_error(r);
1163
1164 return 1;
1165 }
1166
43144be4 1167 if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
bb0c0d6f
LP
1168 r = sd_bus_message_open_container(m, 'r', "sv");
1169 if (r < 0)
1170 return bus_log_create_error(r);
1171
43144be4 1172 r = sd_bus_message_append_basic(m, 's', field);
bb0c0d6f
LP
1173 if (r < 0)
1174 return bus_log_create_error(r);
1175
1176 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1177 if (r < 0)
1178 return bus_log_create_error(r);
1179
1180 if (isempty(eq))
1181 r = sd_bus_message_append(m, "a(ss)", 0);
1182 else {
1183 _cleanup_free_ char *word = NULL;
1184 const char *p = eq;
1185
1186 r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1187 if (r == -ENOMEM)
1188 return log_oom();
1189 if (r < 0)
43144be4 1190 return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
255689ae 1191 if (r == 0)
43144be4 1192 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
bb0c0d6f 1193
255689ae
LP
1194 if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
1195 p = eq;
1196
bb0c0d6f
LP
1197 r = sd_bus_message_append(m, "a(ss)", 1, word, p);
1198 }
1199 if (r < 0)
1200 return bus_log_create_error(r);
1201
1202 r = sd_bus_message_close_container(m);
1203 if (r < 0)
1204 return bus_log_create_error(r);
1205
1206 r = sd_bus_message_close_container(m);
1207 if (r < 0)
1208 return bus_log_create_error(r);
1209
1210 return 1;
1211 }
1212
bbfb25f4
DDM
1213 if (streq(field, "ImportCredential")) {
1214 if (isempty(eq))
1215 r = sd_bus_message_append(m, "(sv)", field, "as", 0);
1216 else
1217 r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
1218 if (r < 0)
1219 return bus_log_create_error(r);
1220
1221 return 1;
1222 }
1223
89ada3ba 1224 if (streq(field, "LogExtraFields")) {
89ada3ba 1225 r = sd_bus_message_open_container(m, 'r', "sv");
3f856a28
YW
1226 if (r < 0)
1227 return bus_log_create_error(r);
1228
89ada3ba 1229 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
3f856a28
YW
1230 if (r < 0)
1231 return bus_log_create_error(r);
1232
89ada3ba 1233 r = sd_bus_message_open_container(m, 'v', "aay");
3f856a28
YW
1234 if (r < 0)
1235 return bus_log_create_error(r);
1236
89ada3ba 1237 r = sd_bus_message_open_container(m, 'a', "ay");
cffaed83
YW
1238 if (r < 0)
1239 return bus_log_create_error(r);
1240
89ada3ba 1241 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
3f856a28
YW
1242 if (r < 0)
1243 return bus_log_create_error(r);
cffaed83 1244
3f856a28
YW
1245 r = sd_bus_message_close_container(m);
1246 if (r < 0)
1247 return bus_log_create_error(r);
9f617cd0 1248
89ada3ba
YW
1249 r = sd_bus_message_close_container(m);
1250 if (r < 0)
1251 return bus_log_create_error(r);
9efb9df9 1252
89ada3ba 1253 r = sd_bus_message_close_container(m);
9efb9df9 1254 if (r < 0)
89ada3ba
YW
1255 return bus_log_create_error(r);
1256
1257 return 1;
1258 }
9efb9df9 1259
523ea123
QD
1260 if (streq(field, "LogFilterPatterns")) {
1261 r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
1262 eq[0] != '~',
1263 eq[0] != '~' ? eq : eq + 1);
1264 if (r < 0)
1265 return bus_log_create_error(r);
1266
1267 return 1;
1268 }
1269
c57d2a76
ZJS
1270 if (STR_IN_SET(field, "StandardInput",
1271 "StandardOutput",
1272 "StandardError")) {
89ada3ba 1273 const char *n, *appended;
9efb9df9 1274
89ada3ba
YW
1275 if ((n = startswith(eq, "fd:"))) {
1276 appended = strjoina(field, "FileDescriptorName");
1277 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
1278 } else if ((n = startswith(eq, "file:"))) {
1279 appended = strjoina(field, "File");
1280 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d33232e
LP
1281 } else if ((n = startswith(eq, "append:"))) {
1282 appended = strjoina(field, "FileToAppend");
1283 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d7dab1f
LW
1284 } else if ((n = startswith(eq, "truncate:"))) {
1285 appended = strjoina(field, "FileToTruncate");
1286 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
89ada3ba
YW
1287 } else
1288 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
89ada3ba
YW
1289 if (r < 0)
1290 return bus_log_create_error(r);
7f452159 1291
89ada3ba
YW
1292 return 1;
1293 }
7f452159 1294
89ada3ba
YW
1295 if (streq(field, "StandardInputText")) {
1296 _cleanup_free_ char *unescaped = NULL;
e437538f 1297 ssize_t l;
7f452159 1298
e437538f
ZJS
1299 l = cunescape(eq, 0, &unescaped);
1300 if (l < 0)
1301 return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
7f452159 1302
c2bc710b 1303 if (!strextend(&unescaped, "\n"))
89ada3ba 1304 return log_oom();
7f452159 1305
e437538f
ZJS
1306 /* Note that we don't expand specifiers here, but that should be OK, as this is a
1307 * programmatic interface anyway */
20b16441 1308
e437538f 1309 return bus_append_byte_array(m, field, unescaped, l + 1);
89ada3ba 1310 }
20b16441 1311
89ada3ba
YW
1312 if (streq(field, "StandardInputData")) {
1313 _cleanup_free_ void *decoded = NULL;
1314 size_t sz;
1315
f5fbe71d 1316 r = unbase64mem(eq, SIZE_MAX, &decoded, &sz);
20b16441 1317 if (r < 0)
89ada3ba 1318 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
20b16441 1319
89ada3ba
YW
1320 return bus_append_byte_array(m, field, decoded, sz);
1321 }
20b16441 1322
6550c24c
LP
1323 if ((suffix = startswith(field, "Limit"))) {
1324 int rl;
20b16441 1325
6550c24c
LP
1326 rl = rlimit_from_string(suffix);
1327 if (rl >= 0) {
1328 const char *sn;
1329 struct rlimit l;
20b16441 1330
6550c24c
LP
1331 r = rlimit_parse(rl, eq, &l);
1332 if (r < 0)
1333 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
20b16441 1334
6550c24c
LP
1335 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
1336 if (r < 0)
1337 return bus_log_create_error(r);
20b16441 1338
6550c24c
LP
1339 sn = strjoina(field, "Soft");
1340 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
1341 if (r < 0)
1342 return bus_log_create_error(r);
1343
1344 return 1;
1345 }
89ada3ba 1346 }
20b16441 1347
c57d2a76
ZJS
1348 if (STR_IN_SET(field, "AppArmorProfile",
1349 "SmackProcessLabel")) {
89ada3ba
YW
1350 int ignore = 0;
1351 const char *s = eq;
20b16441 1352
89ada3ba
YW
1353 if (eq[0] == '-') {
1354 ignore = 1;
1355 s = eq + 1;
20b16441
LP
1356 }
1357
89ada3ba 1358 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
6bbfdc67 1359 if (r < 0)
89ada3ba 1360 return bus_log_create_error(r);
20b16441 1361
89ada3ba
YW
1362 return 1;
1363 }
20b16441 1364
c57d2a76
ZJS
1365 if (STR_IN_SET(field, "CapabilityBoundingSet",
1366 "AmbientCapabilities")) {
89ada3ba
YW
1367 uint64_t sum = 0;
1368 bool invert = false;
1369 const char *p = eq;
afcb1cd3 1370
89ada3ba
YW
1371 if (*p == '~') {
1372 invert = true;
1373 p++;
1374 }
20b16441 1375
89ada3ba 1376 r = capability_set_from_string(p, &sum);
20b16441 1377 if (r < 0)
89ada3ba 1378 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
20b16441 1379
89ada3ba
YW
1380 sum = invert ? ~sum : sum;
1381
1382 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
20b16441
LP
1383 if (r < 0)
1384 return bus_log_create_error(r);
1385
89ada3ba
YW
1386 return 1;
1387 }
20b16441 1388
89ada3ba 1389 if (streq(field, "CPUAffinity")) {
0985c7c4 1390 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
c367f996
MS
1391 _cleanup_free_ uint8_t *array = NULL;
1392 size_t allocated;
20b16441 1393
e2b2fb7f
MS
1394 if (eq && streq(eq, "numa")) {
1395 r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1396 if (r < 0)
1397 return bus_log_create_error(r);
1398 return r;
1399 }
1400
89ada3ba
YW
1401 r = parse_cpu_set(eq, &cpuset);
1402 if (r < 0)
1403 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
20b16441 1404
c367f996
MS
1405 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1406 if (r < 0)
1407 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1408
1409 return bus_append_byte_array(m, field, array, allocated);
89ada3ba 1410 }
20b7a007 1411
b070c7c0
MS
1412 if (streq(field, "NUMAPolicy")) {
1413 r = mpol_from_string(eq);
1414 if (r < 0)
1415 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1416
1417 r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
1418 if (r < 0)
1419 return bus_log_create_error(r);
1420
1421 return 1;
1422 }
1423
1424 if (streq(field, "NUMAMask")) {
1425 _cleanup_(cpu_set_reset) CPUSet nodes = {};
1426 _cleanup_free_ uint8_t *array = NULL;
1427 size_t allocated;
1428
332d387f
MS
1429 if (eq && streq(eq, "all")) {
1430 r = numa_mask_add_all(&nodes);
1431 if (r < 0)
1432 return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
1433 } else {
1434 r = parse_cpu_set(eq, &nodes);
1435 if (r < 0)
1436 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
1437 }
b070c7c0
MS
1438
1439 r = cpu_set_to_dbus(&nodes, &array, &allocated);
1440 if (r < 0)
1441 return log_error_errno(r, "Failed to serialize NUMAMask: %m");
1442
1443 return bus_append_byte_array(m, field, array, allocated);
1444 }
1445
c57d2a76 1446 if (STR_IN_SET(field, "RestrictAddressFamilies",
cc86a278 1447 "RestrictFileSystems",
9df2cdd8 1448 "SystemCallFilter",
a59cb62c
MV
1449 "SystemCallLog",
1450 "RestrictNetworkInterfaces")) {
6b000af4 1451 int allow_list = 1;
89ada3ba 1452 const char *p = eq;
20b16441 1453
89ada3ba 1454 if (*p == '~') {
6b000af4 1455 allow_list = 0;
89ada3ba 1456 p++;
20b16441
LP
1457 }
1458
89ada3ba 1459 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1460 if (r < 0)
1461 return bus_log_create_error(r);
1462
89ada3ba
YW
1463 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1464 if (r < 0)
1465 return bus_log_create_error(r);
1466
1467 r = sd_bus_message_open_container(m, 'v', "(bas)");
1468 if (r < 0)
1469 return bus_log_create_error(r);
20b16441 1470
89ada3ba
YW
1471 r = sd_bus_message_open_container(m, 'r', "bas");
1472 if (r < 0)
1473 return bus_log_create_error(r);
cffaed83 1474
6b000af4 1475 r = sd_bus_message_append_basic(m, 'b', &allow_list);
cffaed83
YW
1476 if (r < 0)
1477 return bus_log_create_error(r);
1478
1479 r = sd_bus_message_open_container(m, 'a', "s");
1480 if (r < 0)
1481 return bus_log_create_error(r);
1482
98008caa 1483 for (;;) {
cffaed83
YW
1484 _cleanup_free_ char *word = NULL;
1485
4ec85141 1486 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
cffaed83
YW
1487 if (r == 0)
1488 break;
89ada3ba
YW
1489 if (r == -ENOMEM)
1490 return log_oom();
1491 if (r < 0)
1492 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1493
1494 r = sd_bus_message_append_basic(m, 's', word);
1495 if (r < 0)
1496 return bus_log_create_error(r);
1497 }
1498
1499 r = sd_bus_message_close_container(m);
1500 if (r < 0)
1501 return bus_log_create_error(r);
1502
1503 r = sd_bus_message_close_container(m);
20b16441
LP
1504 if (r < 0)
1505 return bus_log_create_error(r);
1506
89ada3ba 1507 r = sd_bus_message_close_container(m);
20b16441
LP
1508 if (r < 0)
1509 return bus_log_create_error(r);
1510
20b16441
LP
1511 r = sd_bus_message_close_container(m);
1512 if (r < 0)
1513 return bus_log_create_error(r);
1514
89ada3ba
YW
1515 return 1;
1516 }
20b16441 1517
89ada3ba 1518 if (streq(field, "RestrictNamespaces")) {
add00535 1519 bool invert = false;
aa9d574d 1520 unsigned long flags;
add00535
LP
1521
1522 r = parse_boolean(eq);
1523 if (r > 0)
1524 flags = 0;
1525 else if (r == 0)
1526 flags = NAMESPACE_FLAGS_ALL;
1527 else {
aa9d574d
YW
1528 if (eq[0] == '~') {
1529 invert = true;
1530 eq++;
1531 }
1532
86c2a9f1 1533 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1534 if (r < 0)
1535 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1536 }
1537
1538 if (invert)
1539 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1540
89ada3ba
YW
1541 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1542 if (r < 0)
1543 return bus_log_create_error(r);
afcb1cd3 1544
89ada3ba
YW
1545 return 1;
1546 }
afcb1cd3 1547
c57d2a76
ZJS
1548 if (STR_IN_SET(field, "BindPaths",
1549 "BindReadOnlyPaths")) {
89ada3ba 1550 const char *p = eq;
83555251 1551
89ada3ba 1552 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1553 if (r < 0)
89ada3ba 1554 return bus_log_create_error(r);
afcb1cd3 1555
89ada3ba
YW
1556 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1557 if (r < 0)
1558 return bus_log_create_error(r);
d2d6c096
LP
1559
1560 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1561 if (r < 0)
89ada3ba 1562 return bus_log_create_error(r);
d2d6c096
LP
1563
1564 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1565 if (r < 0)
89ada3ba 1566 return bus_log_create_error(r);
d2d6c096
LP
1567
1568 for (;;) {
1569 _cleanup_free_ char *source = NULL, *destination = NULL;
1570 char *s = NULL, *d = NULL;
1571 bool ignore_enoent = false;
1572 uint64_t flags = MS_REC;
1573
4ec85141 1574 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1575 if (r < 0)
1576 return log_error_errno(r, "Failed to parse argument: %m");
1577 if (r == 0)
1578 break;
1579
1580 s = source;
1581 if (s[0] == '-') {
1582 ignore_enoent = true;
1583 s++;
1584 }
1585
1586 if (p && p[-1] == ':') {
4ec85141 1587 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
d2d6c096
LP
1588 if (r < 0)
1589 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1590 if (r == 0)
1591 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1592 "Missing argument after ':': %s",
1593 eq);
d2d6c096
LP
1594
1595 d = destination;
1596
1597 if (p && p[-1] == ':') {
1598 _cleanup_free_ char *options = NULL;
1599
4ec85141 1600 r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
d2d6c096
LP
1601 if (r < 0)
1602 return log_error_errno(r, "Failed to parse argument: %m");
1603
1604 if (isempty(options) || streq(options, "rbind"))
1605 flags = MS_REC;
1606 else if (streq(options, "norbind"))
1607 flags = 0;
baaa35ad
ZJS
1608 else
1609 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1610 "Unknown options: %s",
1611 eq);
d2d6c096
LP
1612 }
1613 } else
1614 d = s;
1615
d2d6c096
LP
1616 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1617 if (r < 0)
89ada3ba 1618 return bus_log_create_error(r);
d2d6c096
LP
1619 }
1620
1621 r = sd_bus_message_close_container(m);
1622 if (r < 0)
89ada3ba
YW
1623 return bus_log_create_error(r);
1624
1625 r = sd_bus_message_close_container(m);
1626 if (r < 0)
1627 return bus_log_create_error(r);
d2d6c096
LP
1628
1629 r = sd_bus_message_close_container(m);
89ada3ba
YW
1630 if (r < 0)
1631 return bus_log_create_error(r);
f6c66be1 1632
89ada3ba
YW
1633 return 1;
1634 }
f6c66be1 1635
784ad252
YW
1636 if (streq(field, "TemporaryFileSystem")) {
1637 const char *p = eq;
1638
1639 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1640 if (r < 0)
1641 return bus_log_create_error(r);
1642
1643 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1644 if (r < 0)
1645 return bus_log_create_error(r);
1646
1647 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1648 if (r < 0)
1649 return bus_log_create_error(r);
1650
1651 r = sd_bus_message_open_container(m, 'a', "(ss)");
1652 if (r < 0)
1653 return bus_log_create_error(r);
1654
1655 for (;;) {
1656 _cleanup_free_ char *word = NULL, *path = NULL;
1657 const char *w;
1658
4ec85141 1659 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
784ad252
YW
1660 if (r < 0)
1661 return log_error_errno(r, "Failed to parse argument: %m");
1662 if (r == 0)
1663 break;
1664
1665 w = word;
1666 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1667 if (r < 0)
1668 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1669 if (r == 0)
1670 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1671 "Failed to parse argument: %s",
1672 p);
784ad252
YW
1673
1674 r = sd_bus_message_append(m, "(ss)", path, w);
1675 if (r < 0)
1676 return bus_log_create_error(r);
1677 }
1678
1679 r = sd_bus_message_close_container(m);
1680 if (r < 0)
1681 return bus_log_create_error(r);
1682
1683 r = sd_bus_message_close_container(m);
1684 if (r < 0)
1685 return bus_log_create_error(r);
1686
1687 r = sd_bus_message_close_container(m);
1688 if (r < 0)
1689 return bus_log_create_error(r);
1690
1691 return 1;
1692 }
1693
0389f4fa
LB
1694 if (streq(field, "RootHash")) {
1695 _cleanup_free_ void *roothash_decoded = NULL;
1696 size_t roothash_decoded_size = 0;
1697
1698 /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1699 if (path_is_absolute(eq))
1700 return bus_append_string(m, "RootHashPath", eq);
1701
1702 /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1703 r = unhexmem(eq, strlen(eq), &roothash_decoded, &roothash_decoded_size);
1704 if (r < 0)
1705 return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
1706 if (roothash_decoded_size < sizeof(sd_id128_t))
1707 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short: %m", eq);
1708
1709 return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
1710 }
1711
d4d55b0d
LB
1712 if (streq(field, "RootHashSignature")) {
1713 _cleanup_free_ void *roothash_sig_decoded = NULL;
1714 char *value;
1715 size_t roothash_sig_decoded_size = 0;
1716
1717 /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1718 if (path_is_absolute(eq))
1719 return bus_append_string(m, "RootHashSignaturePath", eq);
1720
1721 if (!(value = startswith(eq, "base64:")))
1722 return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:': %m", eq);
1723
1724 /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1725 r = unbase64mem(value, strlen(value), &roothash_sig_decoded, &roothash_sig_decoded_size);
1726 if (r < 0)
1727 return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
1728
1729 return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1730 }
1731
18d73705 1732 if (streq(field, "RootImageOptions")) {
bc8d56d3 1733 _cleanup_strv_free_ char **l = NULL;
18d73705
LB
1734 const char *p = eq;
1735
1736 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1737 if (r < 0)
1738 return bus_log_create_error(r);
1739
1740 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1741 if (r < 0)
1742 return bus_log_create_error(r);
1743
9ece6444 1744 r = sd_bus_message_open_container(m, 'v', "a(ss)");
18d73705
LB
1745 if (r < 0)
1746 return bus_log_create_error(r);
1747
9ece6444 1748 r = sd_bus_message_open_container(m, 'a', "(ss)");
18d73705
LB
1749 if (r < 0)
1750 return bus_log_create_error(r);
1751
bc8d56d3
LB
1752 r = strv_split_colon_pairs(&l, p);
1753 if (r < 0)
1754 return log_error_errno(r, "Failed to parse argument: %m");
18d73705 1755
bc8d56d3 1756 STRV_FOREACH_PAIR(first, second, l) {
9ece6444
LB
1757 r = sd_bus_message_append(m, "(ss)",
1758 !isempty(*second) ? *first : "root",
1759 !isempty(*second) ? *second : *first);
18d73705
LB
1760 if (r < 0)
1761 return bus_log_create_error(r);
1762 }
1763
1764 r = sd_bus_message_close_container(m);
1765 if (r < 0)
b3d13314
LB
1766 return bus_log_create_error(r);
1767
1768 r = sd_bus_message_close_container(m);
1769 if (r < 0)
1770 return bus_log_create_error(r);
1771
1772 r = sd_bus_message_close_container(m);
1773 if (r < 0)
1774 return bus_log_create_error(r);
1775
1776 return 1;
1777 }
1778
1779 if (streq(field, "MountImages")) {
b3d13314
LB
1780 const char *p = eq;
1781
1782 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1783 if (r < 0)
1784 return bus_log_create_error(r);
1785
1786 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1787 if (r < 0)
1788 return bus_log_create_error(r);
1789
427353f6 1790 r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
b3d13314
LB
1791 if (r < 0)
1792 return bus_log_create_error(r);
1793
427353f6 1794 r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
b3d13314
LB
1795 if (r < 0)
1796 return bus_log_create_error(r);
1797
427353f6
LB
1798 for (;;) {
1799 _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
1800 const char *q = NULL, *source = NULL;
b3d13314
LB
1801 bool permissive = false;
1802
427353f6
LB
1803 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1804 if (r < 0)
de4abc3f 1805 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1806 if (r == 0)
1807 break;
1808
1809 q = tuple;
1810 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second, NULL);
1811 if (r < 0)
de4abc3f 1812 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
427353f6
LB
1813 if (r == 0)
1814 continue;
1815
1816 source = first;
1817 if (source[0] == '-') {
b3d13314 1818 permissive = true;
427353f6 1819 source++;
b3d13314
LB
1820 }
1821
427353f6 1822 if (isempty(second))
b3d13314
LB
1823 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1824 "Missing argument after ':': %s",
1825 eq);
1826
427353f6
LB
1827 r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
1828 if (r < 0)
1829 return bus_log_create_error(r);
1830
1831 r = sd_bus_message_append(m, "ssb", source, second, permissive);
1832 if (r < 0)
1833 return bus_log_create_error(r);
1834
1835 r = sd_bus_message_open_container(m, 'a', "(ss)");
1836 if (r < 0)
1837 return bus_log_create_error(r);
1838
1839 for (;;) {
1840 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1841
1842 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1843 if (r < 0)
de4abc3f 1844 return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
93f59701
LB
1845 if (r == 0)
1846 break;
1847 /* Single set of options, applying to the root partition/single filesystem */
1848 if (r == 1) {
1849 r = sd_bus_message_append(m, "(ss)", "root", partition);
1850 if (r < 0)
1851 return bus_log_create_error(r);
1852
1853 break;
1854 }
1855
93f59701
LB
1856 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1857 if (r < 0)
1858 return bus_log_create_error(r);
1859 }
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
1870 r = sd_bus_message_close_container(m);
1871 if (r < 0)
1872 return bus_log_create_error(r);
1873
1874 r = sd_bus_message_close_container(m);
1875 if (r < 0)
1876 return bus_log_create_error(r);
1877
1878 r = sd_bus_message_close_container(m);
1879 if (r < 0)
1880 return bus_log_create_error(r);
1881
1882 return 1;
1883 }
1884
1885 if (streq(field, "ExtensionImages")) {
1886 const char *p = eq;
1887
1888 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1889 if (r < 0)
1890 return bus_log_create_error(r);
1891
1892 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1893 if (r < 0)
1894 return bus_log_create_error(r);
1895
1896 r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
1897 if (r < 0)
1898 return bus_log_create_error(r);
1899
1900 r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
1901 if (r < 0)
1902 return bus_log_create_error(r);
1903
1904 for (;;) {
1905 _cleanup_free_ char *source = NULL, *tuple = NULL;
1906 const char *q = NULL, *s = NULL;
1907 bool permissive = false;
1908
1909 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
1910 if (r < 0)
de4abc3f 1911 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1912 if (r == 0)
1913 break;
1914
1915 q = tuple;
1916 r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
1917 if (r < 0)
de4abc3f 1918 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
93f59701
LB
1919 if (r == 0)
1920 continue;
1921
1922 s = source;
1923 if (s[0] == '-') {
1924 permissive = true;
1925 s++;
1926 }
1927
1928 r = sd_bus_message_open_container(m, 'r', "sba(ss)");
1929 if (r < 0)
1930 return bus_log_create_error(r);
1931
1932 r = sd_bus_message_append(m, "sb", s, permissive);
1933 if (r < 0)
1934 return bus_log_create_error(r);
1935
1936 r = sd_bus_message_open_container(m, 'a', "(ss)");
1937 if (r < 0)
1938 return bus_log_create_error(r);
1939
1940 for (;;) {
1941 _cleanup_free_ char *partition = NULL, *mount_options = NULL;
1942
1943 r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options, NULL);
1944 if (r < 0)
de4abc3f 1945 return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
427353f6
LB
1946 if (r == 0)
1947 break;
1948 /* Single set of options, applying to the root partition/single filesystem */
1949 if (r == 1) {
1950 r = sd_bus_message_append(m, "(ss)", "root", partition);
1951 if (r < 0)
1952 return bus_log_create_error(r);
1953
1954 break;
1955 }
1956
427353f6
LB
1957 r = sd_bus_message_append(m, "(ss)", partition, mount_options);
1958 if (r < 0)
1959 return bus_log_create_error(r);
1960 }
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);
b3d13314
LB
1967 if (r < 0)
1968 return bus_log_create_error(r);
1969 }
1970
1971 r = sd_bus_message_close_container(m);
1972 if (r < 0)
18d73705
LB
1973 return bus_log_create_error(r);
1974
1975 r = sd_bus_message_close_container(m);
1976 if (r < 0)
1977 return bus_log_create_error(r);
1978
1979 r = sd_bus_message_close_container(m);
1980 if (r < 0)
1981 return bus_log_create_error(r);
1982
1983 return 1;
1984 }
1985
211a3d87
LB
1986 if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
1987 _cleanup_strv_free_ char **symlinks = NULL, **sources = NULL;
1988 const char *p = eq;
1989
1990 /* Adding new directories is supported from both *DirectorySymlink methods and the
1991 * older ones, so first parse the input, and if we are given a new-style src:dst
1992 * tuple use the new method, else use the old one. */
1993
1994 for (;;) {
1995 _cleanup_free_ char *tuple = NULL, *source = NULL, *destination = NULL;
1996
1997 r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
1998 if (r < 0)
1999 return log_error_errno(r, "Failed to parse argument: %m");
2000 if (r == 0)
2001 break;
2002
2003 const char *t = tuple;
2004 r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &destination, NULL);
2005 if (r <= 0)
2006 return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
2007
2008 path_simplify(source);
2009
2010 if (isempty(destination)) {
2aaf6d40 2011 r = strv_consume(&sources, TAKE_PTR(source));
211a3d87
LB
2012 if (r < 0)
2013 return bus_log_create_error(r);
2014 } else {
2015 path_simplify(destination);
2016
2017 r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(destination));
2018 if (r < 0)
2019 return log_oom();
2020 }
2021 }
2022
2023 if (!strv_isempty(sources)) {
2024 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2025 if (r < 0)
2026 return bus_log_create_error(r);
2027
2028 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2029 if (r < 0)
2030 return bus_log_create_error(r);
2031
2032 r = sd_bus_message_open_container(m, 'v', "as");
2033 if (r < 0)
2034 return bus_log_create_error(r);
2035
2036 r = sd_bus_message_append_strv(m, sources);
2037 if (r < 0)
2038 return bus_log_create_error(r);
2039
2040 r = sd_bus_message_close_container(m);
2041 if (r < 0)
2042 return bus_log_create_error(r);
2043
2044 r = sd_bus_message_close_container(m);
2045 if (r < 0)
2046 return bus_log_create_error(r);
2047 }
2048
2049 /* For State and Runtime directories we support an optional destination parameter, which
2050 * will be used to create a symlink to the source. But it is new so we cannot change the
2051 * old DBUS signatures, so append a new message type. */
2052 if (!strv_isempty(symlinks)) {
2053 const char *symlink_field;
2054
2055 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2056 if (r < 0)
2057 return bus_log_create_error(r);
2058
2059 if (streq(field, "StateDirectory"))
2060 symlink_field = "StateDirectorySymlink";
2061 else if (streq(field, "RuntimeDirectory"))
2062 symlink_field = "RuntimeDirectorySymlink";
2063 else if (streq(field, "CacheDirectory"))
2064 symlink_field = "CacheDirectorySymlink";
2065 else if (streq(field, "LogsDirectory"))
2066 symlink_field = "LogsDirectorySymlink";
2067 else
2068 assert_not_reached();
2069
2070 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
2071 if (r < 0)
2072 return bus_log_create_error(r);
2073
2074 r = sd_bus_message_open_container(m, 'v', "a(sst)");
2075 if (r < 0)
2076 return bus_log_create_error(r);
2077
2078 r = sd_bus_message_open_container(m, 'a', "(sst)");
2079 if (r < 0)
2080 return bus_log_create_error(r);
2081
211a3d87
LB
2082 STRV_FOREACH_PAIR(source, destination, symlinks) {
2083 r = sd_bus_message_append(m, "(sst)", *source, *destination, 0);
2084 if (r < 0)
2085 return bus_log_create_error(r);
2086 }
2087
2088 r = sd_bus_message_close_container(m);
2089 if (r < 0)
2090 return bus_log_create_error(r);
2091
2092 r = sd_bus_message_close_container(m);
2093 if (r < 0)
2094 return bus_log_create_error(r);
2095
2096 r = sd_bus_message_close_container(m);
2097 if (r < 0)
2098 return bus_log_create_error(r);
2099 }
2100
2101 return 1;
2102 }
2103
89ada3ba
YW
2104 return 0;
2105}
f6c66be1 2106
89ada3ba 2107static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2108 if (streq(field, "KillMode"))
89ada3ba 2109 return bus_append_string(m, field, eq);
f6c66be1 2110
c57d2a76
ZJS
2111 if (STR_IN_SET(field, "SendSIGHUP",
2112 "SendSIGKILL"))
89ada3ba 2113 return bus_append_parse_boolean(m, field, eq);
f6c66be1 2114
c57d2a76
ZJS
2115 if (STR_IN_SET(field, "KillSignal",
2116 "RestartKillSignal",
2117 "FinalKillSignal",
3bd28bf7
LP
2118 "WatchdogSignal",
2119 "ReloadSignal"))
29a3db75 2120 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
2121
2122 return 0;
2123}
2124
3d63c749 2125static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 2126
c57d2a76
ZJS
2127 if (STR_IN_SET(field, "What",
2128 "Where",
2129 "Options",
2130 "Type"))
89ada3ba
YW
2131 return bus_append_string(m, field, eq);
2132
3d63c749 2133 if (streq(field, "TimeoutSec"))
3d63c749
YW
2134 return bus_append_parse_sec_rename(m, field, eq);
2135
2136 if (streq(field, "DirectoryMode"))
3d63c749
YW
2137 return bus_append_parse_mode(m, field, eq);
2138
c57d2a76
ZJS
2139 if (STR_IN_SET(field, "SloppyOptions",
2140 "LazyUnmount",
c600357b
MH
2141 "ForceUnmount",
2142 "ReadwriteOnly"))
3d63c749
YW
2143 return bus_append_parse_boolean(m, field, eq);
2144
2145 return 0;
2146}
2147
2148static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
2149 int r;
2150
89ada3ba 2151 if (streq(field, "MakeDirectory"))
89ada3ba
YW
2152 return bus_append_parse_boolean(m, field, eq);
2153
2154 if (streq(field, "DirectoryMode"))
89ada3ba
YW
2155 return bus_append_parse_mode(m, field, eq);
2156
c57d2a76
ZJS
2157 if (STR_IN_SET(field, "PathExists",
2158 "PathExistsGlob",
2159 "PathChanged",
2160 "PathModified",
2161 "DirectoryNotEmpty")) {
3d63c749
YW
2162 if (isempty(eq))
2163 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
2164 else
2165 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
2166 if (r < 0)
2167 return bus_log_create_error(r);
2168
2169 return 1;
2170 }
2171
47dba9fb
LB
2172 if (streq(field, "TriggerLimitBurst"))
2173 return bus_append_safe_atou(m, field, eq);
2174
2175 if (streq(field, "TriggerLimitIntervalSec"))
2176 return bus_append_parse_sec_rename(m, field, eq);
2177
89ada3ba
YW
2178 return 0;
2179}
2180
5a70a68f 2181static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
9ed7de60 2182 if (streq(field, "RuntimeMaxSec"))
9ed7de60
PW
2183 return bus_append_parse_sec_rename(m, field, eq);
2184
5918a933
AB
2185 if (streq(field, "RuntimeRandomizedExtraSec"))
2186 return bus_append_parse_sec_rename(m, field, eq);
2187
5a70a68f 2188 if (streq(field, "TimeoutStopSec"))
5a70a68f
PW
2189 return bus_append_parse_sec_rename(m, field, eq);
2190
03860190
MS
2191 /* Scope units don't have execution context but we still want to allow setting these two,
2192 * so let's handle them separately. */
2193 if (STR_IN_SET(field, "User", "Group"))
2194 return bus_append_string(m, field, eq);
2195
5fa09835
ML
2196 if (streq(field, "OOMPolicy"))
2197 return bus_append_string(m, field, eq);
2198
5a70a68f
PW
2199 return 0;
2200}
2201
89ada3ba 2202static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2203 int r;
89ada3ba 2204
c57d2a76
ZJS
2205 if (STR_IN_SET(field, "PIDFile",
2206 "Type",
596e4470 2207 "ExitType",
c57d2a76
ZJS
2208 "Restart",
2209 "BusName",
2210 "NotifyAccess",
2211 "USBFunctionDescriptors",
2212 "USBFunctionStrings",
bf760801
JK
2213 "OOMPolicy",
2214 "TimeoutStartFailureMode",
b9c1883a
LP
2215 "TimeoutStopFailureMode",
2216 "FileDescriptorStorePreserve"))
89ada3ba 2217 return bus_append_string(m, field, eq);
f6c66be1 2218
c57d2a76
ZJS
2219 if (STR_IN_SET(field, "PermissionsStartOnly",
2220 "RootDirectoryStartOnly",
2221 "RemainAfterExit",
2222 "GuessMainPID"))
89ada3ba
YW
2223 return bus_append_parse_boolean(m, field, eq);
2224
c57d2a76 2225 if (STR_IN_SET(field, "RestartSec",
a559ea15 2226 "RestartMaxDelaySec",
c57d2a76
ZJS
2227 "TimeoutStartSec",
2228 "TimeoutStopSec",
e737017b 2229 "TimeoutAbortSec",
c57d2a76 2230 "RuntimeMaxSec",
5918a933 2231 "RuntimeRandomizedExtraSec",
c57d2a76 2232 "WatchdogSec"))
89ada3ba
YW
2233 return bus_append_parse_sec_rename(m, field, eq);
2234
3d63c749 2235 if (streq(field, "TimeoutSec")) {
3d63c749
YW
2236 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
2237 if (r < 0)
2238 return r;
2239
2240 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
2241 }
2242
a559ea15
MY
2243 if (STR_IN_SET(field, "FileDescriptorStoreMax",
2244 "RestartSteps"))
89ada3ba
YW
2245 return bus_append_safe_atou(m, field, eq);
2246
c57d2a76
ZJS
2247 if (STR_IN_SET(field, "ExecCondition",
2248 "ExecStartPre",
2249 "ExecStart",
2250 "ExecStartPost",
2251 "ExecConditionEx",
2252 "ExecStartPreEx",
2253 "ExecStartEx",
2254 "ExecStartPostEx",
2255 "ExecReload",
2256 "ExecStop",
2257 "ExecStopPost",
2258 "ExecReloadEx",
2259 "ExecStopEx",
2260 "ExecStopPostEx"))
89ada3ba
YW
2261 return bus_append_exec_command(m, field, eq);
2262
c57d2a76
ZJS
2263 if (STR_IN_SET(field, "RestartPreventExitStatus",
2264 "RestartForceExitStatus",
2265 "SuccessExitStatus")) {
3d63c749 2266 _cleanup_free_ int *status = NULL, *signal = NULL;
62b21e2e 2267 size_t n_status = 0, n_signal = 0;
3d63c749
YW
2268 const char *p;
2269
2270 for (p = eq;;) {
2271 _cleanup_free_ char *word = NULL;
3d63c749 2272
4ec85141 2273 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3d63c749
YW
2274 if (r == 0)
2275 break;
2276 if (r == -ENOMEM)
2277 return log_oom();
2278 if (r < 0)
2279 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
2280
2e2ed880
ZJS
2281 /* We need to call exit_status_from_string() first, because we want
2282 * to parse numbers as exit statuses, not signals. */
3d63c749 2283
2e2ed880
ZJS
2284 r = exit_status_from_string(word);
2285 if (r >= 0) {
2286 assert(r >= 0 && r < 256);
3d63c749 2287
62b21e2e 2288 status = reallocarray(status, n_status + 1, sizeof(int));
3d63c749
YW
2289 if (!status)
2290 return log_oom();
2291
2e2ed880
ZJS
2292 status[n_status++] = r;
2293
2294 } else if ((r = signal_from_string(word)) >= 0) {
2295 signal = reallocarray(signal, n_signal + 1, sizeof(int));
2296 if (!signal)
2297 return log_oom();
2298
2299 signal[n_signal++] = r;
2300
2301 } else
2302 /* original r from exit_status_to_string() */
2303 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
2304 word, field);
3d63c749
YW
2305 }
2306
2307 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2308 if (r < 0)
2309 return bus_log_create_error(r);
2310
2311 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2312 if (r < 0)
2313 return bus_log_create_error(r);
2314
2315 r = sd_bus_message_open_container(m, 'v', "(aiai)");
2316 if (r < 0)
2317 return bus_log_create_error(r);
2318
2319 r = sd_bus_message_open_container(m, 'r', "aiai");
2320 if (r < 0)
2321 return bus_log_create_error(r);
2322
62b21e2e 2323 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
3d63c749
YW
2324 if (r < 0)
2325 return bus_log_create_error(r);
2326
62b21e2e 2327 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
3d63c749
YW
2328 if (r < 0)
2329 return bus_log_create_error(r);
2330
2331 r = sd_bus_message_close_container(m);
2332 if (r < 0)
2333 return bus_log_create_error(r);
2334
2335 r = sd_bus_message_close_container(m);
2336 if (r < 0)
2337 return bus_log_create_error(r);
2338
2339 r = sd_bus_message_close_container(m);
2340 if (r < 0)
2341 return bus_log_create_error(r);
2342
2343 return 1;
2344 }
2345
cd48e23f
RP
2346 if (streq(field, "OpenFile"))
2347 return bus_append_open_file(m, field, eq);
2348
89ada3ba
YW
2349 return 0;
2350}
2351
2352static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
2353 int r;
2354
c57d2a76 2355 if (STR_IN_SET(field, "Accept",
3e5f04bf 2356 "FlushPending",
c57d2a76
ZJS
2357 "Writable",
2358 "KeepAlive",
2359 "NoDelay",
2360 "FreeBind",
2361 "Transparent",
2362 "Broadcast",
2363 "PassCredentials",
2364 "PassSecurity",
a3d19f5d 2365 "PassPacketInfo",
c57d2a76
ZJS
2366 "ReusePort",
2367 "RemoveOnStop",
2368 "SELinuxContextFromNet"))
89ada3ba
YW
2369 return bus_append_parse_boolean(m, field, eq);
2370
c57d2a76
ZJS
2371 if (STR_IN_SET(field, "Priority",
2372 "IPTTL",
2373 "Mark"))
89ada3ba
YW
2374 return bus_append_safe_atoi(m, field, eq);
2375
2376 if (streq(field, "IPTOS"))
89ada3ba
YW
2377 return bus_append_ip_tos_from_string(m, field, eq);
2378
c57d2a76
ZJS
2379 if (STR_IN_SET(field, "Backlog",
2380 "MaxConnections",
2381 "MaxConnectionsPerSource",
2382 "KeepAliveProbes",
2383 "TriggerLimitBurst"))
89ada3ba
YW
2384 return bus_append_safe_atou(m, field, eq);
2385
c57d2a76
ZJS
2386 if (STR_IN_SET(field, "SocketMode",
2387 "DirectoryMode"))
89ada3ba
YW
2388 return bus_append_parse_mode(m, field, eq);
2389
c57d2a76
ZJS
2390 if (STR_IN_SET(field, "MessageQueueMaxMessages",
2391 "MessageQueueMessageSize"))
89ada3ba
YW
2392 return bus_append_safe_atoi64(m, field, eq);
2393
c57d2a76
ZJS
2394 if (STR_IN_SET(field, "TimeoutSec",
2395 "KeepAliveTimeSec",
2396 "KeepAliveIntervalSec",
2397 "DeferAcceptSec",
2398 "TriggerLimitIntervalSec"))
89ada3ba
YW
2399 return bus_append_parse_sec_rename(m, field, eq);
2400
c57d2a76
ZJS
2401 if (STR_IN_SET(field, "ReceiveBuffer",
2402 "SendBuffer",
2403 "PipeSize"))
b48e508d 2404 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 2405
c57d2a76
ZJS
2406 if (STR_IN_SET(field, "ExecStartPre",
2407 "ExecStartPost",
2408 "ExecReload",
2409 "ExecStopPost"))
89ada3ba
YW
2410 return bus_append_exec_command(m, field, eq);
2411
c57d2a76
ZJS
2412 if (STR_IN_SET(field, "SmackLabel",
2413 "SmackLabelIPIn",
2414 "SmackLabelIPOut",
2415 "TCPCongestion",
2416 "BindToDevice",
2417 "BindIPv6Only",
2418 "FileDescriptorName",
2419 "SocketUser",
9b191525
LP
2420 "SocketGroup",
2421 "Timestamping"))
89ada3ba
YW
2422 return bus_append_string(m, field, eq);
2423
2424 if (streq(field, "Symlinks"))
4ec85141 2425 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2426
e045e325 2427 if (streq(field, "SocketProtocol"))
d2b42d63 2428 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba 2429
c57d2a76
ZJS
2430 if (STR_IN_SET(field, "ListenStream",
2431 "ListenDatagram",
2432 "ListenSequentialPacket",
2433 "ListenNetlink",
2434 "ListenSpecial",
2435 "ListenMessageQueue",
2436 "ListenFIFO",
2437 "ListenUSBFunction")) {
3d63c749
YW
2438 if (isempty(eq))
2439 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
2440 else
81b1dc27 2441 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 2442 if (r < 0)
89ada3ba
YW
2443 return bus_log_create_error(r);
2444
2445 return 1;
2446 }
2447
2448 return 0;
2449}
2450static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 2451 int r;
89ada3ba 2452
c57d2a76
ZJS
2453 if (STR_IN_SET(field, "WakeSystem",
2454 "RemainAfterElapse",
2455 "Persistent",
2456 "OnTimezoneChange",
acf24a1a
KG
2457 "OnClockChange",
2458 "FixedRandomDelay"))
89ada3ba
YW
2459 return bus_append_parse_boolean(m, field, eq);
2460
c57d2a76
ZJS
2461 if (STR_IN_SET(field, "AccuracySec",
2462 "RandomizedDelaySec"))
3d63c749
YW
2463 return bus_append_parse_sec_rename(m, field, eq);
2464
c57d2a76
ZJS
2465 if (STR_IN_SET(field, "OnActiveSec",
2466 "OnBootSec",
2467 "OnStartupSec",
2468 "OnUnitActiveSec",
2469 "OnUnitInactiveSec")) {
3d63c749
YW
2470 if (isempty(eq))
2471 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
2472 else {
2473 usec_t t;
2474 r = parse_sec(eq, &t);
2475 if (r < 0)
2476 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 2477
3d63c749
YW
2478 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
2479 }
2480 if (r < 0)
2481 return bus_log_create_error(r);
89ada3ba 2482
3d63c749
YW
2483 return 1;
2484 }
2485
2486 if (streq(field, "OnCalendar")) {
3d63c749
YW
2487 if (isempty(eq))
2488 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
2489 else
2490 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2491 if (r < 0)
2492 return bus_log_create_error(r);
2493
2494 return 1;
2495 }
89ada3ba
YW
2496
2497 return 0;
2498}
2499
2500static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
2501 ConditionType t = _CONDITION_TYPE_INVALID;
2502 bool is_condition = false;
2503 int r;
f6c66be1 2504
c57d2a76
ZJS
2505 if (STR_IN_SET(field, "Description",
2506 "SourcePath",
2507 "OnFailureJobMode",
2508 "JobTimeoutAction",
2509 "JobTimeoutRebootArgument",
2510 "StartLimitAction",
2511 "FailureAction",
2512 "SuccessAction",
2513 "RebootArgument",
2514 "CollectMode"))
89ada3ba
YW
2515 return bus_append_string(m, field, eq);
2516
c57d2a76
ZJS
2517 if (STR_IN_SET(field, "StopWhenUnneeded",
2518 "RefuseManualStart",
2519 "RefuseManualStop",
2520 "AllowIsolate",
2521 "IgnoreOnIsolate",
2522 "DefaultDependencies"))
89ada3ba
YW
2523 return bus_append_parse_boolean(m, field, eq);
2524
c57d2a76
ZJS
2525 if (STR_IN_SET(field, "JobTimeoutSec",
2526 "JobRunningTimeoutSec",
2527 "StartLimitIntervalSec"))
3d63c749
YW
2528 return bus_append_parse_sec_rename(m, field, eq);
2529
2530 if (streq(field, "StartLimitBurst"))
3d63c749
YW
2531 return bus_append_safe_atou(m, field, eq);
2532
c57d2a76
ZJS
2533 if (STR_IN_SET(field, "SuccessActionExitStatus",
2534 "FailureActionExitStatus")) {
7af67e9a
LP
2535 if (isempty(eq))
2536 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2537 else {
2538 uint8_t u;
2539
2540 r = safe_atou8(eq, &u);
2541 if (r < 0)
2542 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
2543
2544 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2545 }
2546 if (r < 0)
2547 return bus_log_create_error(r);
2548
2549 return 1;
2550 }
2551
3d63c749 2552 if (unit_dependency_from_string(field) >= 0 ||
c57d2a76 2553 STR_IN_SET(field, "Documentation",
0dd3c090
ZJS
2554 "RequiresMountsFor",
2555 "Markers"))
4ec85141 2556 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 2557
3d63c749
YW
2558 t = condition_type_from_string(field);
2559 if (t >= 0)
2560 is_condition = true;
2561 else
2562 t = assert_type_from_string(field);
2563 if (t >= 0) {
2564 if (isempty(eq))
2565 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
2566 else {
2567 const char *p = eq;
2568 int trigger, negate;
2569
2570 trigger = *p == '|';
2571 if (trigger)
2572 p++;
2573
2574 negate = *p == '!';
2575 if (negate)
2576 p++;
2577
2578 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
2579 field, trigger, negate, p);
2580 }
2581 if (r < 0)
2582 return bus_log_create_error(r);
2583
2584 return 1;
2585 }
2586
89ada3ba
YW
2587 return 0;
2588}
2589
2590int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2591 const char *eq, *field;
2592 int r;
2593
2594 assert(m);
2595 assert(assignment);
2596
2597 eq = strchr(assignment, '=');
baaa35ad
ZJS
2598 if (!eq)
2599 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2600 "Not an assignment: %s", assignment);
89ada3ba 2601
2f82562b 2602 field = strndupa_safe(assignment, eq - assignment);
89ada3ba
YW
2603 eq++;
2604
2605 switch (t) {
2606 case UNIT_SERVICE:
2607 r = bus_append_cgroup_property(m, field, eq);
2608 if (r != 0)
f6c66be1
LP
2609 return r;
2610
89ada3ba
YW
2611 r = bus_append_execute_property(m, field, eq);
2612 if (r != 0)
2613 return r;
f6c66be1 2614
89ada3ba
YW
2615 r = bus_append_kill_property(m, field, eq);
2616 if (r != 0)
2617 return r;
f6c66be1 2618
89ada3ba
YW
2619 r = bus_append_service_property(m, field, eq);
2620 if (r != 0)
2621 return r;
2622 break;
f6c66be1 2623
89ada3ba
YW
2624 case UNIT_SOCKET:
2625 r = bus_append_cgroup_property(m, field, eq);
2626 if (r != 0)
2627 return r;
f6c66be1 2628
89ada3ba
YW
2629 r = bus_append_execute_property(m, field, eq);
2630 if (r != 0)
2631 return r;
f6c66be1 2632
89ada3ba
YW
2633 r = bus_append_kill_property(m, field, eq);
2634 if (r != 0)
2635 return r;
f6c66be1 2636
89ada3ba
YW
2637 r = bus_append_socket_property(m, field, eq);
2638 if (r != 0)
f6c66be1 2639 return r;
89ada3ba 2640 break;
f6c66be1 2641
89ada3ba
YW
2642 case UNIT_TIMER:
2643 r = bus_append_timer_property(m, field, eq);
2644 if (r != 0)
2645 return r;
2646 break;
f6c66be1 2647
89ada3ba
YW
2648 case UNIT_PATH:
2649 r = bus_append_path_property(m, field, eq);
2650 if (r != 0)
2651 return r;
2652 break;
268833ed 2653
89ada3ba
YW
2654 case UNIT_SLICE:
2655 r = bus_append_cgroup_property(m, field, eq);
2656 if (r != 0)
2657 return r;
2658 break;
268833ed 2659
89ada3ba
YW
2660 case UNIT_SCOPE:
2661 r = bus_append_cgroup_property(m, field, eq);
2662 if (r != 0)
2663 return r;
268833ed 2664
89ada3ba 2665 r = bus_append_kill_property(m, field, eq);
5a70a68f
PW
2666 if (r != 0)
2667 return r;
2668
2669 r = bus_append_scope_property(m, field, eq);
89ada3ba
YW
2670 if (r != 0)
2671 return r;
2672 break;
535e0d19 2673
89ada3ba 2674 case UNIT_MOUNT:
3d63c749
YW
2675 r = bus_append_cgroup_property(m, field, eq);
2676 if (r != 0)
2677 return r;
2678
2679 r = bus_append_execute_property(m, field, eq);
2680 if (r != 0)
2681 return r;
2682
2683 r = bus_append_kill_property(m, field, eq);
2684 if (r != 0)
2685 return r;
2686
2687 r = bus_append_mount_property(m, field, eq);
2688 if (r != 0)
2689 return r;
2690
2691 break;
2692
89ada3ba 2693 case UNIT_AUTOMOUNT:
3d63c749
YW
2694 r = bus_append_automount_property(m, field, eq);
2695 if (r != 0)
2696 return r;
2697
89ada3ba 2698 break;
535e0d19 2699
89ada3ba
YW
2700 case UNIT_TARGET:
2701 case UNIT_DEVICE:
2702 case UNIT_SWAP:
eab62c01 2703 break;
535e0d19 2704
89ada3ba 2705 default:
eab62c01 2706 assert_not_reached();
20b16441
LP
2707 }
2708
89ada3ba
YW
2709 r = bus_append_unit_property(m, field, eq);
2710 if (r != 0)
2711 return r;
20b16441 2712
baaa35ad
ZJS
2713 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2714 "Unknown assignment: %s", assignment);
20b16441
LP
2715}
2716
89ada3ba 2717int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
2718 int r;
2719
2720 assert(m);
2721
2722 STRV_FOREACH(i, l) {
89ada3ba 2723 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
2724 if (r < 0)
2725 return r;
2726 }
2727
2728 return 0;
2729}
2730
5e891cbb 2731int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
20b16441 2732 const char *type, *path, *source;
5e891cbb
DT
2733 InstallChange *changes = NULL;
2734 size_t n_changes = 0;
20b16441
LP
2735 int r;
2736
5e891cbb 2737 CLEANUP_ARRAY(changes, n_changes, install_changes_free);
acc0269c 2738
20b16441
LP
2739 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2740 if (r < 0)
2741 return bus_log_parse_error(r);
2742
2743 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
f8662fee
LP
2744 InstallChangeType t;
2745
2746 /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2747 * negative. */
2748 t = install_change_type_from_string(type);
2749 if (t < 0) {
2750 log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
c1b48a7f 2751 type, path);
20b16441
LP
2752 continue;
2753 }
2754
5e891cbb 2755 r = install_changes_add(&changes, &n_changes, t, path, source);
20b16441
LP
2756 if (r < 0)
2757 return r;
2758 }
2759 if (r < 0)
2760 return bus_log_parse_error(r);
2761
2762 r = sd_bus_message_exit_container(m);
2763 if (r < 0)
2764 return bus_log_parse_error(r);
2765
5e891cbb
DT
2766 install_changes_dump(0, NULL, changes, n_changes, quiet);
2767
20b16441
LP
2768 return 0;
2769}
2770
bd062910
ZJS
2771int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2772 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2773 _cleanup_free_ char *path = NULL;
2774 int r;
2775
2776 path = unit_dbus_path_from_name(name);
2777 if (!path)
2778 return log_oom();
2779
18fe76eb 2780 /* This function warns on its own, because otherwise it'd be awkward to pass
bd062910
ZJS
2781 * the dbus error message around. */
2782
2783 r = sd_bus_get_property_string(
2784 bus,
2785 "org.freedesktop.systemd1",
2786 path,
2787 "org.freedesktop.systemd1.Unit",
2788 "LoadState",
2789 &error,
2790 load_state);
2791 if (r < 0)
2792 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2793
2794 return 0;
2795}
4dcc0653
LP
2796
2797int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
2798 int r;
2799
2800 /* First, order by machine */
2801 r = strcasecmp_ptr(a->machine, b->machine);
2802 if (r != 0)
2803 return r;
2804
2805 /* Second, order by unit type */
2806 r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
2807 if (r != 0)
2808 return r;
2809
2810 /* Third, order by name */
2811 return strcasecmp(a->id, b->id);
2812}