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