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