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