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