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