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