]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
linux: import if_ether.h from kernel-5.0
[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
c52db42b 412 if (STR_IN_SET(field, "MemoryMin", "DefaultMemoryLow", "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 748 if (STR_IN_SET(field,
f69567cb
LP
749 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
750 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
751 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
752 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
753 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
754 "ProtectHostname", "RestrictSUIDSGID"))
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",
afcfaa69 1317 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
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 1501
efebb613
LP
1502 if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
1503 "OnTimezoneChange", "OnClockChange"))
89ada3ba
YW
1504
1505 return bus_append_parse_boolean(m, field, eq);
1506
3d63c749
YW
1507 if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1508
1509 return bus_append_parse_sec_rename(m, field, eq);
1510
89ada3ba
YW
1511 if (STR_IN_SET(field,
1512 "OnActiveSec", "OnBootSec", "OnStartupSec",
3d63c749 1513 "OnUnitActiveSec","OnUnitInactiveSec")) {
89ada3ba 1514
3d63c749
YW
1515 if (isempty(eq))
1516 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1517 else {
1518 usec_t t;
1519 r = parse_sec(eq, &t);
1520 if (r < 0)
1521 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 1522
3d63c749
YW
1523 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1524 }
1525 if (r < 0)
1526 return bus_log_create_error(r);
89ada3ba 1527
3d63c749
YW
1528 return 1;
1529 }
1530
1531 if (streq(field, "OnCalendar")) {
1532
1533 if (isempty(eq))
1534 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1535 else
1536 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1537 if (r < 0)
1538 return bus_log_create_error(r);
1539
1540 return 1;
1541 }
89ada3ba
YW
1542
1543 return 0;
1544}
1545
1546static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
1547 ConditionType t = _CONDITION_TYPE_INVALID;
1548 bool is_condition = false;
1549 int r;
f6c66be1 1550
3d63c749
YW
1551 if (STR_IN_SET(field,
1552 "Description", "SourcePath", "OnFailureJobMode",
1553 "JobTimeoutAction", "JobTimeoutRebootArgument",
1554 "StartLimitAction", "FailureAction", "SuccessAction",
1555 "RebootArgument", "CollectMode"))
89ada3ba
YW
1556
1557 return bus_append_string(m, field, eq);
1558
3d63c749
YW
1559 if (STR_IN_SET(field,
1560 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1561 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
89ada3ba
YW
1562
1563 return bus_append_parse_boolean(m, field, eq);
1564
3d63c749
YW
1565 if (STR_IN_SET(field, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1566
1567 return bus_append_parse_sec_rename(m, field, eq);
1568
1569 if (streq(field, "StartLimitBurst"))
1570
1571 return bus_append_safe_atou(m, field, eq);
1572
7af67e9a
LP
1573 if (STR_IN_SET(field, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1574
1575 if (isempty(eq))
1576 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1577 else {
1578 uint8_t u;
1579
1580 r = safe_atou8(eq, &u);
1581 if (r < 0)
1582 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1583
1584 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1585 }
1586 if (r < 0)
1587 return bus_log_create_error(r);
1588
1589 return 1;
1590 }
1591
3d63c749
YW
1592 if (unit_dependency_from_string(field) >= 0 ||
1593 STR_IN_SET(field, "Documentation", "RequiresMountsFor"))
89ada3ba 1594
eae194a5 1595 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
89ada3ba 1596
3d63c749
YW
1597 t = condition_type_from_string(field);
1598 if (t >= 0)
1599 is_condition = true;
1600 else
1601 t = assert_type_from_string(field);
1602 if (t >= 0) {
1603 if (isempty(eq))
1604 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1605 else {
1606 const char *p = eq;
1607 int trigger, negate;
1608
1609 trigger = *p == '|';
1610 if (trigger)
1611 p++;
1612
1613 negate = *p == '!';
1614 if (negate)
1615 p++;
1616
1617 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1618 field, trigger, negate, p);
1619 }
1620 if (r < 0)
1621 return bus_log_create_error(r);
1622
1623 return 1;
1624 }
1625
89ada3ba
YW
1626 return 0;
1627}
1628
1629int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1630 const char *eq, *field;
1631 int r;
1632
1633 assert(m);
1634 assert(assignment);
1635
1636 eq = strchr(assignment, '=');
baaa35ad
ZJS
1637 if (!eq)
1638 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1639 "Not an assignment: %s", assignment);
89ada3ba
YW
1640
1641 field = strndupa(assignment, eq - assignment);
1642 eq++;
1643
1644 switch (t) {
1645 case UNIT_SERVICE:
1646 r = bus_append_cgroup_property(m, field, eq);
1647 if (r != 0)
f6c66be1
LP
1648 return r;
1649
89ada3ba
YW
1650 r = bus_append_execute_property(m, field, eq);
1651 if (r != 0)
1652 return r;
f6c66be1 1653
89ada3ba
YW
1654 r = bus_append_kill_property(m, field, eq);
1655 if (r != 0)
1656 return r;
f6c66be1 1657
89ada3ba
YW
1658 r = bus_append_service_property(m, field, eq);
1659 if (r != 0)
1660 return r;
1661 break;
f6c66be1 1662
89ada3ba
YW
1663 case UNIT_SOCKET:
1664 r = bus_append_cgroup_property(m, field, eq);
1665 if (r != 0)
1666 return r;
f6c66be1 1667
89ada3ba
YW
1668 r = bus_append_execute_property(m, field, eq);
1669 if (r != 0)
1670 return r;
f6c66be1 1671
89ada3ba
YW
1672 r = bus_append_kill_property(m, field, eq);
1673 if (r != 0)
1674 return r;
f6c66be1 1675
89ada3ba
YW
1676 r = bus_append_socket_property(m, field, eq);
1677 if (r != 0)
f6c66be1 1678 return r;
89ada3ba 1679 break;
f6c66be1 1680
89ada3ba
YW
1681 case UNIT_TIMER:
1682 r = bus_append_timer_property(m, field, eq);
1683 if (r != 0)
1684 return r;
1685 break;
f6c66be1 1686
89ada3ba
YW
1687 case UNIT_PATH:
1688 r = bus_append_path_property(m, field, eq);
1689 if (r != 0)
1690 return r;
1691 break;
268833ed 1692
89ada3ba
YW
1693 case UNIT_SLICE:
1694 r = bus_append_cgroup_property(m, field, eq);
1695 if (r != 0)
1696 return r;
1697 break;
268833ed 1698
89ada3ba 1699 case UNIT_SCOPE:
3d63c749
YW
1700
1701 if (streq(field, "TimeoutStopSec"))
1702 return bus_append_parse_sec_rename(m, field, eq);
1703
89ada3ba
YW
1704 r = bus_append_cgroup_property(m, field, eq);
1705 if (r != 0)
1706 return r;
268833ed 1707
89ada3ba
YW
1708 r = bus_append_kill_property(m, field, eq);
1709 if (r != 0)
1710 return r;
1711 break;
535e0d19 1712
89ada3ba 1713 case UNIT_MOUNT:
3d63c749
YW
1714 r = bus_append_cgroup_property(m, field, eq);
1715 if (r != 0)
1716 return r;
1717
1718 r = bus_append_execute_property(m, field, eq);
1719 if (r != 0)
1720 return r;
1721
1722 r = bus_append_kill_property(m, field, eq);
1723 if (r != 0)
1724 return r;
1725
1726 r = bus_append_mount_property(m, field, eq);
1727 if (r != 0)
1728 return r;
1729
1730 break;
1731
89ada3ba 1732 case UNIT_AUTOMOUNT:
3d63c749
YW
1733 r = bus_append_automount_property(m, field, eq);
1734 if (r != 0)
1735 return r;
1736
89ada3ba 1737 break;
535e0d19 1738
89ada3ba
YW
1739 case UNIT_TARGET:
1740 case UNIT_DEVICE:
1741 case UNIT_SWAP:
baaa35ad
ZJS
1742 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1743 "Not supported unit type");
535e0d19 1744
89ada3ba 1745 default:
baaa35ad
ZJS
1746 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1747 "Invalid unit type");
20b16441
LP
1748 }
1749
89ada3ba
YW
1750 r = bus_append_unit_property(m, field, eq);
1751 if (r != 0)
1752 return r;
20b16441 1753
baaa35ad
ZJS
1754 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1755 "Unknown assignment: %s", assignment);
20b16441
LP
1756}
1757
89ada3ba 1758int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
1759 char **i;
1760 int r;
1761
1762 assert(m);
1763
1764 STRV_FOREACH(i, l) {
89ada3ba 1765 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
1766 if (r < 0)
1767 return r;
1768 }
1769
1770 return 0;
1771}
1772
da6053d0 1773int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
1774 const char *type, *path, *source;
1775 int r;
1776
acc0269c
CH
1777 /* changes is dereferenced when calling unit_file_dump_changes() later,
1778 * so we have to make sure this is not NULL. */
1779 assert(changes);
1780 assert(n_changes);
1781
20b16441
LP
1782 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1783 if (r < 0)
1784 return bus_log_parse_error(r);
1785
1786 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1787 /* We expect only "success" changes to be sent over the bus.
1788 Hence, reject anything negative. */
1789 UnitFileChangeType ch = unit_file_change_type_from_string(type);
1790
1791 if (ch < 0) {
1792 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1793 continue;
1794 }
1795
1796 r = unit_file_changes_add(changes, n_changes, ch, path, source);
1797 if (r < 0)
1798 return r;
1799 }
1800 if (r < 0)
1801 return bus_log_parse_error(r);
1802
1803 r = sd_bus_message_exit_container(m);
1804 if (r < 0)
1805 return bus_log_parse_error(r);
1806
35d379b2 1807 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
1808 return 0;
1809}
1810
bd062910
ZJS
1811int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
1812 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1813 _cleanup_free_ char *path = NULL;
1814 int r;
1815
1816 path = unit_dbus_path_from_name(name);
1817 if (!path)
1818 return log_oom();
1819
1820 /* This function warns on it's own, because otherwise it'd be awkward to pass
1821 * the dbus error message around. */
1822
1823 r = sd_bus_get_property_string(
1824 bus,
1825 "org.freedesktop.systemd1",
1826 path,
1827 "org.freedesktop.systemd1.Unit",
1828 "LoadState",
1829 &error,
1830 load_state);
1831 if (r < 0)
1832 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
1833
1834 return 0;
1835}