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