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