]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
strv: add strv_split_colon_pairs function
[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
18d73705
LB
1457 if (streq(field, "RootImageOptions")) {
1458 const char *p = eq;
1459
1460 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1461 if (r < 0)
1462 return bus_log_create_error(r);
1463
1464 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1465 if (r < 0)
1466 return bus_log_create_error(r);
1467
1468 r = sd_bus_message_open_container(m, 'v', "a(us)");
1469 if (r < 0)
1470 return bus_log_create_error(r);
1471
1472 r = sd_bus_message_open_container(m, 'a', "(us)");
1473 if (r < 0)
1474 return bus_log_create_error(r);
1475
1476 for (;;) {
1477 _cleanup_free_ char *first = NULL, *tuple = NULL;
1478 const char *mount_options = NULL, *second = NULL;
1479 unsigned partition_number = 0;
1480
1481 r = extract_first_word(&p, &tuple, WHITESPACE, EXTRACT_UNQUOTE);
1482 if (r == 0)
1483 break;
1484 if (r < 0)
1485 return log_error_errno(r, "Failed to parse argument: %m");
1486
1487 second = tuple;
1488 r = extract_first_word(&second, &first, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
1489 if (r == 0)
1490 continue;
1491 if (r < 0)
1492 return log_error_errno(r, "Failed to parse argument: %m");
1493
1494 /* Format is either '0:foo' or 'foo' (0 is implied) */
1495 if (!isempty(second) && second[-1] == ':') {
1496 mount_options = second;
1497 r = safe_atou(first, &partition_number);
1498 if (r < 0) {
1499 log_error_errno(r, "Failed to parse partition number from %s: %m", first);
1500 continue;
1501 }
1502 } else
1503 mount_options = first;
1504
1505 r = sd_bus_message_append(m, "(us)", partition_number, mount_options);
1506 if (r < 0)
1507 return bus_log_create_error(r);
1508 }
1509
1510 r = sd_bus_message_close_container(m);
1511 if (r < 0)
1512 return bus_log_create_error(r);
1513
1514 r = sd_bus_message_close_container(m);
1515 if (r < 0)
1516 return bus_log_create_error(r);
1517
1518 r = sd_bus_message_close_container(m);
1519 if (r < 0)
1520 return bus_log_create_error(r);
1521
1522 return 1;
1523 }
1524
89ada3ba
YW
1525 return 0;
1526}
f6c66be1 1527
89ada3ba 1528static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 1529 if (streq(field, "KillMode"))
89ada3ba 1530 return bus_append_string(m, field, eq);
f6c66be1 1531
c57d2a76
ZJS
1532 if (STR_IN_SET(field, "SendSIGHUP",
1533 "SendSIGKILL"))
89ada3ba 1534 return bus_append_parse_boolean(m, field, eq);
f6c66be1 1535
c57d2a76
ZJS
1536 if (STR_IN_SET(field, "KillSignal",
1537 "RestartKillSignal",
1538 "FinalKillSignal",
1539 "WatchdogSignal"))
29a3db75 1540 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
1541
1542 return 0;
1543}
1544
3d63c749 1545static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 1546
c57d2a76
ZJS
1547 if (STR_IN_SET(field, "What",
1548 "Where",
1549 "Options",
1550 "Type"))
89ada3ba
YW
1551 return bus_append_string(m, field, eq);
1552
3d63c749 1553 if (streq(field, "TimeoutSec"))
3d63c749
YW
1554 return bus_append_parse_sec_rename(m, field, eq);
1555
1556 if (streq(field, "DirectoryMode"))
3d63c749
YW
1557 return bus_append_parse_mode(m, field, eq);
1558
c57d2a76
ZJS
1559 if (STR_IN_SET(field, "SloppyOptions",
1560 "LazyUnmount",
c600357b
MH
1561 "ForceUnmount",
1562 "ReadwriteOnly"))
3d63c749
YW
1563 return bus_append_parse_boolean(m, field, eq);
1564
1565 return 0;
1566}
1567
1568static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1569 int r;
1570
89ada3ba 1571 if (streq(field, "MakeDirectory"))
89ada3ba
YW
1572 return bus_append_parse_boolean(m, field, eq);
1573
1574 if (streq(field, "DirectoryMode"))
89ada3ba
YW
1575 return bus_append_parse_mode(m, field, eq);
1576
c57d2a76
ZJS
1577 if (STR_IN_SET(field, "PathExists",
1578 "PathExistsGlob",
1579 "PathChanged",
1580 "PathModified",
1581 "DirectoryNotEmpty")) {
3d63c749
YW
1582 if (isempty(eq))
1583 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1584 else
1585 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1586 if (r < 0)
1587 return bus_log_create_error(r);
1588
1589 return 1;
1590 }
1591
89ada3ba
YW
1592 return 0;
1593}
1594
5a70a68f 1595static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
9ed7de60 1596 if (streq(field, "RuntimeMaxSec"))
9ed7de60
PW
1597 return bus_append_parse_sec_rename(m, field, eq);
1598
5a70a68f 1599 if (streq(field, "TimeoutStopSec"))
5a70a68f
PW
1600 return bus_append_parse_sec_rename(m, field, eq);
1601
1602 return 0;
1603}
1604
89ada3ba 1605static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 1606 int r;
89ada3ba 1607
c57d2a76
ZJS
1608 if (STR_IN_SET(field, "PIDFile",
1609 "Type",
1610 "Restart",
1611 "BusName",
1612 "NotifyAccess",
1613 "USBFunctionDescriptors",
1614 "USBFunctionStrings",
bf760801
JK
1615 "OOMPolicy",
1616 "TimeoutStartFailureMode",
1617 "TimeoutStopFailureMode"))
89ada3ba 1618 return bus_append_string(m, field, eq);
f6c66be1 1619
c57d2a76
ZJS
1620 if (STR_IN_SET(field, "PermissionsStartOnly",
1621 "RootDirectoryStartOnly",
1622 "RemainAfterExit",
1623 "GuessMainPID"))
89ada3ba
YW
1624 return bus_append_parse_boolean(m, field, eq);
1625
c57d2a76
ZJS
1626 if (STR_IN_SET(field, "RestartSec",
1627 "TimeoutStartSec",
1628 "TimeoutStopSec",
e737017b 1629 "TimeoutAbortSec",
c57d2a76
ZJS
1630 "RuntimeMaxSec",
1631 "WatchdogSec"))
89ada3ba
YW
1632 return bus_append_parse_sec_rename(m, field, eq);
1633
3d63c749 1634 if (streq(field, "TimeoutSec")) {
3d63c749
YW
1635 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1636 if (r < 0)
1637 return r;
1638
1639 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1640 }
1641
89ada3ba 1642 if (streq(field, "FileDescriptorStoreMax"))
89ada3ba
YW
1643 return bus_append_safe_atou(m, field, eq);
1644
c57d2a76
ZJS
1645 if (STR_IN_SET(field, "ExecCondition",
1646 "ExecStartPre",
1647 "ExecStart",
1648 "ExecStartPost",
1649 "ExecConditionEx",
1650 "ExecStartPreEx",
1651 "ExecStartEx",
1652 "ExecStartPostEx",
1653 "ExecReload",
1654 "ExecStop",
1655 "ExecStopPost",
1656 "ExecReloadEx",
1657 "ExecStopEx",
1658 "ExecStopPostEx"))
89ada3ba
YW
1659 return bus_append_exec_command(m, field, eq);
1660
c57d2a76
ZJS
1661 if (STR_IN_SET(field, "RestartPreventExitStatus",
1662 "RestartForceExitStatus",
1663 "SuccessExitStatus")) {
3d63c749 1664 _cleanup_free_ int *status = NULL, *signal = NULL;
62b21e2e 1665 size_t n_status = 0, n_signal = 0;
3d63c749
YW
1666 const char *p;
1667
1668 for (p = eq;;) {
1669 _cleanup_free_ char *word = NULL;
3d63c749 1670
4ec85141 1671 r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
3d63c749
YW
1672 if (r == 0)
1673 break;
1674 if (r == -ENOMEM)
1675 return log_oom();
1676 if (r < 0)
1677 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1678
2e2ed880
ZJS
1679 /* We need to call exit_status_from_string() first, because we want
1680 * to parse numbers as exit statuses, not signals. */
3d63c749 1681
2e2ed880
ZJS
1682 r = exit_status_from_string(word);
1683 if (r >= 0) {
1684 assert(r >= 0 && r < 256);
3d63c749 1685
62b21e2e 1686 status = reallocarray(status, n_status + 1, sizeof(int));
3d63c749
YW
1687 if (!status)
1688 return log_oom();
1689
2e2ed880
ZJS
1690 status[n_status++] = r;
1691
1692 } else if ((r = signal_from_string(word)) >= 0) {
1693 signal = reallocarray(signal, n_signal + 1, sizeof(int));
1694 if (!signal)
1695 return log_oom();
1696
1697 signal[n_signal++] = r;
1698
1699 } else
1700 /* original r from exit_status_to_string() */
1701 return log_error_errno(r, "Invalid status or signal %s in %s: %m",
1702 word, field);
3d63c749
YW
1703 }
1704
1705 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1706 if (r < 0)
1707 return bus_log_create_error(r);
1708
1709 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1710 if (r < 0)
1711 return bus_log_create_error(r);
1712
1713 r = sd_bus_message_open_container(m, 'v', "(aiai)");
1714 if (r < 0)
1715 return bus_log_create_error(r);
1716
1717 r = sd_bus_message_open_container(m, 'r', "aiai");
1718 if (r < 0)
1719 return bus_log_create_error(r);
1720
62b21e2e 1721 r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
3d63c749
YW
1722 if (r < 0)
1723 return bus_log_create_error(r);
1724
62b21e2e 1725 r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
3d63c749
YW
1726 if (r < 0)
1727 return bus_log_create_error(r);
1728
1729 r = sd_bus_message_close_container(m);
1730 if (r < 0)
1731 return bus_log_create_error(r);
1732
1733 r = sd_bus_message_close_container(m);
1734 if (r < 0)
1735 return bus_log_create_error(r);
1736
1737 r = sd_bus_message_close_container(m);
1738 if (r < 0)
1739 return bus_log_create_error(r);
1740
1741 return 1;
1742 }
1743
89ada3ba
YW
1744 return 0;
1745}
1746
1747static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1748 int r;
1749
c57d2a76
ZJS
1750 if (STR_IN_SET(field, "Accept",
1751 "Writable",
1752 "KeepAlive",
1753 "NoDelay",
1754 "FreeBind",
1755 "Transparent",
1756 "Broadcast",
1757 "PassCredentials",
1758 "PassSecurity",
a3d19f5d 1759 "PassPacketInfo",
c57d2a76
ZJS
1760 "ReusePort",
1761 "RemoveOnStop",
1762 "SELinuxContextFromNet"))
89ada3ba
YW
1763 return bus_append_parse_boolean(m, field, eq);
1764
c57d2a76
ZJS
1765 if (STR_IN_SET(field, "Priority",
1766 "IPTTL",
1767 "Mark"))
89ada3ba
YW
1768 return bus_append_safe_atoi(m, field, eq);
1769
1770 if (streq(field, "IPTOS"))
89ada3ba
YW
1771 return bus_append_ip_tos_from_string(m, field, eq);
1772
c57d2a76
ZJS
1773 if (STR_IN_SET(field, "Backlog",
1774 "MaxConnections",
1775 "MaxConnectionsPerSource",
1776 "KeepAliveProbes",
1777 "TriggerLimitBurst"))
89ada3ba
YW
1778 return bus_append_safe_atou(m, field, eq);
1779
c57d2a76
ZJS
1780 if (STR_IN_SET(field, "SocketMode",
1781 "DirectoryMode"))
89ada3ba
YW
1782 return bus_append_parse_mode(m, field, eq);
1783
c57d2a76
ZJS
1784 if (STR_IN_SET(field, "MessageQueueMaxMessages",
1785 "MessageQueueMessageSize"))
89ada3ba
YW
1786 return bus_append_safe_atoi64(m, field, eq);
1787
c57d2a76
ZJS
1788 if (STR_IN_SET(field, "TimeoutSec",
1789 "KeepAliveTimeSec",
1790 "KeepAliveIntervalSec",
1791 "DeferAcceptSec",
1792 "TriggerLimitIntervalSec"))
89ada3ba
YW
1793 return bus_append_parse_sec_rename(m, field, eq);
1794
c57d2a76
ZJS
1795 if (STR_IN_SET(field, "ReceiveBuffer",
1796 "SendBuffer",
1797 "PipeSize"))
b48e508d 1798 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 1799
c57d2a76
ZJS
1800 if (STR_IN_SET(field, "ExecStartPre",
1801 "ExecStartPost",
1802 "ExecReload",
1803 "ExecStopPost"))
89ada3ba
YW
1804 return bus_append_exec_command(m, field, eq);
1805
c57d2a76
ZJS
1806 if (STR_IN_SET(field, "SmackLabel",
1807 "SmackLabelIPIn",
1808 "SmackLabelIPOut",
1809 "TCPCongestion",
1810 "BindToDevice",
1811 "BindIPv6Only",
1812 "FileDescriptorName",
1813 "SocketUser",
1814 "SocketGroup"))
89ada3ba
YW
1815 return bus_append_string(m, field, eq);
1816
1817 if (streq(field, "Symlinks"))
4ec85141 1818 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 1819
e045e325 1820 if (streq(field, "SocketProtocol"))
d2b42d63 1821 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba 1822
c57d2a76
ZJS
1823 if (STR_IN_SET(field, "ListenStream",
1824 "ListenDatagram",
1825 "ListenSequentialPacket",
1826 "ListenNetlink",
1827 "ListenSpecial",
1828 "ListenMessageQueue",
1829 "ListenFIFO",
1830 "ListenUSBFunction")) {
3d63c749
YW
1831 if (isempty(eq))
1832 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1833 else
81b1dc27 1834 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 1835 if (r < 0)
89ada3ba
YW
1836 return bus_log_create_error(r);
1837
1838 return 1;
1839 }
1840
1841 return 0;
1842}
1843static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 1844 int r;
89ada3ba 1845
c57d2a76
ZJS
1846 if (STR_IN_SET(field, "WakeSystem",
1847 "RemainAfterElapse",
1848 "Persistent",
1849 "OnTimezoneChange",
1850 "OnClockChange"))
89ada3ba
YW
1851 return bus_append_parse_boolean(m, field, eq);
1852
c57d2a76
ZJS
1853 if (STR_IN_SET(field, "AccuracySec",
1854 "RandomizedDelaySec"))
3d63c749
YW
1855 return bus_append_parse_sec_rename(m, field, eq);
1856
c57d2a76
ZJS
1857 if (STR_IN_SET(field, "OnActiveSec",
1858 "OnBootSec",
1859 "OnStartupSec",
1860 "OnUnitActiveSec",
1861 "OnUnitInactiveSec")) {
3d63c749
YW
1862 if (isempty(eq))
1863 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1864 else {
1865 usec_t t;
1866 r = parse_sec(eq, &t);
1867 if (r < 0)
1868 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 1869
3d63c749
YW
1870 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1871 }
1872 if (r < 0)
1873 return bus_log_create_error(r);
89ada3ba 1874
3d63c749
YW
1875 return 1;
1876 }
1877
1878 if (streq(field, "OnCalendar")) {
3d63c749
YW
1879 if (isempty(eq))
1880 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1881 else
1882 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1883 if (r < 0)
1884 return bus_log_create_error(r);
1885
1886 return 1;
1887 }
89ada3ba
YW
1888
1889 return 0;
1890}
1891
1892static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
1893 ConditionType t = _CONDITION_TYPE_INVALID;
1894 bool is_condition = false;
1895 int r;
f6c66be1 1896
c57d2a76
ZJS
1897 if (STR_IN_SET(field, "Description",
1898 "SourcePath",
1899 "OnFailureJobMode",
1900 "JobTimeoutAction",
1901 "JobTimeoutRebootArgument",
1902 "StartLimitAction",
1903 "FailureAction",
1904 "SuccessAction",
1905 "RebootArgument",
1906 "CollectMode"))
89ada3ba
YW
1907 return bus_append_string(m, field, eq);
1908
c57d2a76
ZJS
1909 if (STR_IN_SET(field, "StopWhenUnneeded",
1910 "RefuseManualStart",
1911 "RefuseManualStop",
1912 "AllowIsolate",
1913 "IgnoreOnIsolate",
1914 "DefaultDependencies"))
89ada3ba
YW
1915 return bus_append_parse_boolean(m, field, eq);
1916
c57d2a76
ZJS
1917 if (STR_IN_SET(field, "JobTimeoutSec",
1918 "JobRunningTimeoutSec",
1919 "StartLimitIntervalSec"))
3d63c749
YW
1920 return bus_append_parse_sec_rename(m, field, eq);
1921
1922 if (streq(field, "StartLimitBurst"))
3d63c749
YW
1923 return bus_append_safe_atou(m, field, eq);
1924
c57d2a76
ZJS
1925 if (STR_IN_SET(field, "SuccessActionExitStatus",
1926 "FailureActionExitStatus")) {
7af67e9a
LP
1927 if (isempty(eq))
1928 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1929 else {
1930 uint8_t u;
1931
1932 r = safe_atou8(eq, &u);
1933 if (r < 0)
1934 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1935
1936 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1937 }
1938 if (r < 0)
1939 return bus_log_create_error(r);
1940
1941 return 1;
1942 }
1943
3d63c749 1944 if (unit_dependency_from_string(field) >= 0 ||
c57d2a76
ZJS
1945 STR_IN_SET(field, "Documentation",
1946 "RequiresMountsFor"))
4ec85141 1947 return bus_append_strv(m, field, eq, EXTRACT_UNQUOTE);
89ada3ba 1948
3d63c749
YW
1949 t = condition_type_from_string(field);
1950 if (t >= 0)
1951 is_condition = true;
1952 else
1953 t = assert_type_from_string(field);
1954 if (t >= 0) {
1955 if (isempty(eq))
1956 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1957 else {
1958 const char *p = eq;
1959 int trigger, negate;
1960
1961 trigger = *p == '|';
1962 if (trigger)
1963 p++;
1964
1965 negate = *p == '!';
1966 if (negate)
1967 p++;
1968
1969 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1970 field, trigger, negate, p);
1971 }
1972 if (r < 0)
1973 return bus_log_create_error(r);
1974
1975 return 1;
1976 }
1977
89ada3ba
YW
1978 return 0;
1979}
1980
1981int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1982 const char *eq, *field;
1983 int r;
1984
1985 assert(m);
1986 assert(assignment);
1987
1988 eq = strchr(assignment, '=');
baaa35ad
ZJS
1989 if (!eq)
1990 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1991 "Not an assignment: %s", assignment);
89ada3ba
YW
1992
1993 field = strndupa(assignment, eq - assignment);
1994 eq++;
1995
1996 switch (t) {
1997 case UNIT_SERVICE:
1998 r = bus_append_cgroup_property(m, field, eq);
1999 if (r != 0)
f6c66be1
LP
2000 return r;
2001
89ada3ba
YW
2002 r = bus_append_execute_property(m, field, eq);
2003 if (r != 0)
2004 return r;
f6c66be1 2005
89ada3ba
YW
2006 r = bus_append_kill_property(m, field, eq);
2007 if (r != 0)
2008 return r;
f6c66be1 2009
89ada3ba
YW
2010 r = bus_append_service_property(m, field, eq);
2011 if (r != 0)
2012 return r;
2013 break;
f6c66be1 2014
89ada3ba
YW
2015 case UNIT_SOCKET:
2016 r = bus_append_cgroup_property(m, field, eq);
2017 if (r != 0)
2018 return r;
f6c66be1 2019
89ada3ba
YW
2020 r = bus_append_execute_property(m, field, eq);
2021 if (r != 0)
2022 return r;
f6c66be1 2023
89ada3ba
YW
2024 r = bus_append_kill_property(m, field, eq);
2025 if (r != 0)
2026 return r;
f6c66be1 2027
89ada3ba
YW
2028 r = bus_append_socket_property(m, field, eq);
2029 if (r != 0)
f6c66be1 2030 return r;
89ada3ba 2031 break;
f6c66be1 2032
89ada3ba
YW
2033 case UNIT_TIMER:
2034 r = bus_append_timer_property(m, field, eq);
2035 if (r != 0)
2036 return r;
2037 break;
f6c66be1 2038
89ada3ba
YW
2039 case UNIT_PATH:
2040 r = bus_append_path_property(m, field, eq);
2041 if (r != 0)
2042 return r;
2043 break;
268833ed 2044
89ada3ba
YW
2045 case UNIT_SLICE:
2046 r = bus_append_cgroup_property(m, field, eq);
2047 if (r != 0)
2048 return r;
2049 break;
268833ed 2050
89ada3ba
YW
2051 case UNIT_SCOPE:
2052 r = bus_append_cgroup_property(m, field, eq);
2053 if (r != 0)
2054 return r;
268833ed 2055
89ada3ba 2056 r = bus_append_kill_property(m, field, eq);
5a70a68f
PW
2057 if (r != 0)
2058 return r;
2059
2060 r = bus_append_scope_property(m, field, eq);
89ada3ba
YW
2061 if (r != 0)
2062 return r;
2063 break;
535e0d19 2064
89ada3ba 2065 case UNIT_MOUNT:
3d63c749
YW
2066 r = bus_append_cgroup_property(m, field, eq);
2067 if (r != 0)
2068 return r;
2069
2070 r = bus_append_execute_property(m, field, eq);
2071 if (r != 0)
2072 return r;
2073
2074 r = bus_append_kill_property(m, field, eq);
2075 if (r != 0)
2076 return r;
2077
2078 r = bus_append_mount_property(m, field, eq);
2079 if (r != 0)
2080 return r;
2081
2082 break;
2083
89ada3ba 2084 case UNIT_AUTOMOUNT:
3d63c749
YW
2085 r = bus_append_automount_property(m, field, eq);
2086 if (r != 0)
2087 return r;
2088
89ada3ba 2089 break;
535e0d19 2090
89ada3ba
YW
2091 case UNIT_TARGET:
2092 case UNIT_DEVICE:
2093 case UNIT_SWAP:
baaa35ad
ZJS
2094 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2095 "Not supported unit type");
535e0d19 2096
89ada3ba 2097 default:
baaa35ad
ZJS
2098 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2099 "Invalid unit type");
20b16441
LP
2100 }
2101
89ada3ba
YW
2102 r = bus_append_unit_property(m, field, eq);
2103 if (r != 0)
2104 return r;
20b16441 2105
baaa35ad
ZJS
2106 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2107 "Unknown assignment: %s", assignment);
20b16441
LP
2108}
2109
89ada3ba 2110int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
2111 char **i;
2112 int r;
2113
2114 assert(m);
2115
2116 STRV_FOREACH(i, l) {
89ada3ba 2117 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
2118 if (r < 0)
2119 return r;
2120 }
2121
2122 return 0;
2123}
2124
da6053d0 2125int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
2126 const char *type, *path, *source;
2127 int r;
2128
acc0269c
CH
2129 /* changes is dereferenced when calling unit_file_dump_changes() later,
2130 * so we have to make sure this is not NULL. */
2131 assert(changes);
2132 assert(n_changes);
2133
20b16441
LP
2134 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
2135 if (r < 0)
2136 return bus_log_parse_error(r);
2137
2138 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
2139 /* We expect only "success" changes to be sent over the bus.
2140 Hence, reject anything negative. */
2141 UnitFileChangeType ch = unit_file_change_type_from_string(type);
2142
2143 if (ch < 0) {
2144 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
2145 continue;
2146 }
2147
2148 r = unit_file_changes_add(changes, n_changes, ch, path, source);
2149 if (r < 0)
2150 return r;
2151 }
2152 if (r < 0)
2153 return bus_log_parse_error(r);
2154
2155 r = sd_bus_message_exit_container(m);
2156 if (r < 0)
2157 return bus_log_parse_error(r);
2158
35d379b2 2159 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
2160 return 0;
2161}
2162
bd062910
ZJS
2163int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
2164 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
2165 _cleanup_free_ char *path = NULL;
2166 int r;
2167
2168 path = unit_dbus_path_from_name(name);
2169 if (!path)
2170 return log_oom();
2171
2172 /* This function warns on it's own, because otherwise it'd be awkward to pass
2173 * the dbus error message around. */
2174
2175 r = sd_bus_get_property_string(
2176 bus,
2177 "org.freedesktop.systemd1",
2178 path,
2179 "org.freedesktop.systemd1.Unit",
2180 "LoadState",
2181 &error,
2182 load_state);
2183 if (r < 0)
2184 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
2185
2186 return 0;
2187}