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