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