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