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