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