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