]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
Rework cpu affinity parsing
[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
25cc30c4
AZ
399 if (streq(field, "DisableControllers"))
400
401 return bus_append_strv(m, "DisableControllers", eq, EXTRACT_QUOTES);
402
89ada3ba 403 if (streq(field, "Delegate")) {
08f3be7a 404
89ada3ba 405 r = parse_boolean(eq);
08f3be7a 406 if (r < 0)
89ada3ba 407 return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_QUOTES);
08f3be7a 408
89ada3ba 409 r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
08f3be7a
LP
410 if (r < 0)
411 return bus_log_create_error(r);
412
89ada3ba
YW
413 return 1;
414 }
08f3be7a 415
7e7223b3 416 if (STR_IN_SET(field, "MemoryMin", "DefaultMemoryLow", "DefaultMemoryMin", "MemoryLow", "MemoryHigh", "MemoryMax", "MemorySwapMax", "MemoryLimit", "TasksMax")) {
cffaed83 417
89ada3ba
YW
418 if (isempty(eq) || streq(eq, "infinity")) {
419 r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
420 if (r < 0)
421 return bus_log_create_error(r);
422 return 1;
cffaed83
YW
423 }
424
f806dfd3 425 r = parse_permille(eq);
89ada3ba
YW
426 if (r >= 0) {
427 char *n;
20b16441 428
f806dfd3
LP
429 /* When this is a percentage we'll convert this into a relative value in the range 0…UINT32_MAX
430 * and pass it in the MemoryLowScale property (and related ones). This way the physical memory
431 * size can be determined server-side. */
20b16441 432
89ada3ba 433 n = strjoina(field, "Scale");
f806dfd3 434 r = sd_bus_message_append(m, "(sv)", n, "u", (uint32_t) (((uint64_t) r * UINT32_MAX) / 1000U));
89ada3ba
YW
435 if (r < 0)
436 return bus_log_create_error(r);
20b16441 437
89ada3ba 438 return 1;
20b16441
LP
439 }
440
89ada3ba 441 if (streq(field, "TasksMax"))
62b749a9 442 return bus_append_safe_atou64(m, field, eq);
20b16441 443
62b749a9 444 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba 445 }
cffaed83 446
89ada3ba 447 if (streq(field, "CPUQuota")) {
cffaed83 448
89ada3ba
YW
449 if (isempty(eq))
450 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
451 else {
f806dfd3 452 r = parse_permille_unbounded(eq);
baaa35ad
ZJS
453 if (r == 0)
454 return log_error_errno(SYNTHETIC_ERRNO(ERANGE),
455 "CPU quota too small.");
f806dfd3
LP
456 if (r < 0)
457 return log_error_errno(r, "CPU quota '%s' invalid.", eq);
89ada3ba 458
f806dfd3 459 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 1000U));
cffaed83
YW
460 }
461
6bbfdc67 462 if (r < 0)
89ada3ba 463 return bus_log_create_error(r);
cffaed83 464
89ada3ba
YW
465 return 1;
466 }
cffaed83 467
10f28641
FB
468 if (streq(field, "CPUQuotaPeriodSec")) {
469 usec_t u = USEC_INFINITY;
470
471 r = parse_sec_def_infinity(eq, &u);
472 if (r < 0)
473 return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
474
475 r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
476 if (r < 0)
477 return bus_log_create_error(r);
478
479 return 1;
480 }
481
89ada3ba 482 if (streq(field, "DeviceAllow")) {
20b16441
LP
483
484 if (isempty(eq))
89ada3ba 485 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
20b16441 486 else {
d9f7305f 487 const char *path = eq, *rwm = NULL, *e;
20b16441
LP
488
489 e = strchr(eq, ' ');
490 if (e) {
491 path = strndupa(eq, e - eq);
492 rwm = e+1;
20b16441
LP
493 }
494
d9f7305f 495 r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
20b16441
LP
496 }
497
89ada3ba
YW
498 if (r < 0)
499 return bus_log_create_error(r);
500
501 return 1;
502 }
503
504 if (cgroup_io_limit_type_from_string(field) >= 0 || STR_IN_SET(field, "BlockIOReadBandwidth", "BlockIOWriteBandwidth")) {
20b16441
LP
505
506 if (isempty(eq))
89ada3ba 507 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
20b16441
LP
508 else {
509 const char *path, *bandwidth, *e;
510 uint64_t bytes;
511
512 e = strchr(eq, ' ');
baaa35ad
ZJS
513 if (!e)
514 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
515 "Failed to parse %s value %s.",
516 field, eq);
20b16441 517
d9f7305f
YW
518 path = strndupa(eq, e - eq);
519 bandwidth = e+1;
20b16441 520
79d53eb8 521 if (streq(bandwidth, "infinity"))
13c31542 522 bytes = CGROUP_LIMIT_MAX;
79d53eb8 523 else {
13c31542 524 r = parse_size(bandwidth, 1000, &bytes);
6bbfdc67
LP
525 if (r < 0)
526 return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
20b16441
LP
527 }
528
89ada3ba 529 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
20b16441
LP
530 }
531
89ada3ba
YW
532 if (r < 0)
533 return bus_log_create_error(r);
534
535 return 1;
536 }
537
538 if (STR_IN_SET(field, "IODeviceWeight", "BlockIODeviceWeight")) {
20b16441
LP
539
540 if (isempty(eq))
89ada3ba 541 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
20b16441
LP
542 else {
543 const char *path, *weight, *e;
544 uint64_t u;
545
546 e = strchr(eq, ' ');
baaa35ad
ZJS
547 if (!e)
548 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
549 "Failed to parse %s value %s.",
550 field, eq);
20b16441 551
d9f7305f
YW
552 path = strndupa(eq, e - eq);
553 weight = e+1;
20b16441
LP
554
555 r = safe_atou64(weight, &u);
6bbfdc67
LP
556 if (r < 0)
557 return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
558
89ada3ba 559 r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
20b16441
LP
560 }
561
89ada3ba
YW
562 if (r < 0)
563 return bus_log_create_error(r);
3dc5ca97 564
89ada3ba
YW
565 return 1;
566 }
3dc5ca97 567
6ae4283c
TH
568 if (streq(field, "IODeviceLatencyTargetSec")) {
569 const char *field_usec = "IODeviceLatencyTargetUSec";
570
571 if (isempty(eq))
572 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
573 else {
574 const char *path, *target, *e;
575 usec_t usec;
576
577 e = strchr(eq, ' ');
baaa35ad
ZJS
578 if (!e)
579 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
580 "Failed to parse %s value %s.",
581 field, eq);
6ae4283c
TH
582
583 path = strndupa(eq, e - eq);
584 target = e+1;
585
586 r = parse_sec(target, &usec);
587 if (r < 0)
588 return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
589
590 r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
591 }
592
593 if (r < 0)
594 return bus_log_create_error(r);
595
596 return 1;
597 }
598
89ada3ba
YW
599 if (STR_IN_SET(field, "IPAddressAllow", "IPAddressDeny")) {
600 unsigned char prefixlen;
601 union in_addr_union prefix = {};
602 int family;
3dc5ca97 603
89ada3ba
YW
604 if (isempty(eq)) {
605 r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
3dc5ca97
LP
606 if (r < 0)
607 return bus_log_create_error(r);
608
89ada3ba
YW
609 return 1;
610 }
3dc5ca97 611
89ada3ba
YW
612 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
613 if (r < 0)
614 return bus_log_create_error(r);
3dc5ca97 615
89ada3ba
YW
616 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
617 if (r < 0)
618 return bus_log_create_error(r);
3dc5ca97 619
89ada3ba
YW
620 r = sd_bus_message_open_container(m, 'v', "a(iayu)");
621 if (r < 0)
622 return bus_log_create_error(r);
3dc5ca97 623
89ada3ba
YW
624 r = sd_bus_message_open_container(m, 'a', "(iayu)");
625 if (r < 0)
626 return bus_log_create_error(r);
3dc5ca97 627
89ada3ba
YW
628 if (streq(eq, "any")) {
629 /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
3dc5ca97 630
89ada3ba
YW
631 r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
632 if (r < 0)
633 return bus_log_create_error(r);
3dc5ca97 634
89ada3ba
YW
635 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
636 if (r < 0)
637 return bus_log_create_error(r);
3dc5ca97 638
89ada3ba
YW
639 } else if (is_localhost(eq)) {
640 /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
3dc5ca97 641
89ada3ba
YW
642 prefix.in.s_addr = htobe32(0x7f000000);
643 r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
644 if (r < 0)
645 return bus_log_create_error(r);
3dc5ca97 646
89ada3ba
YW
647 prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
648 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
649 if (r < 0)
650 return r;
3dc5ca97 651
89ada3ba
YW
652 } else if (streq(eq, "link-local")) {
653 /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
3dc5ca97 654
89ada3ba
YW
655 prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
656 r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
657 if (r < 0)
658 return bus_log_create_error(r);
3dc5ca97 659
89ada3ba
YW
660 prefix.in6 = (struct in6_addr) {
661 .s6_addr32[0] = htobe32(0xfe800000)
662 };
663 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
664 if (r < 0)
665 return bus_log_create_error(r);
3dc5ca97 666
89ada3ba
YW
667 } else if (streq(eq, "multicast")) {
668 /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
3dc5ca97 669
89ada3ba
YW
670 prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
671 r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
672 if (r < 0)
673 return bus_log_create_error(r);
3dc5ca97 674
89ada3ba
YW
675 prefix.in6 = (struct in6_addr) {
676 .s6_addr32[0] = htobe32(0xff000000)
677 };
678 r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
3dc5ca97
LP
679 if (r < 0)
680 return bus_log_create_error(r);
681
89ada3ba 682 } else {
afc1feae
RC
683 for (;;) {
684 _cleanup_free_ char *word = NULL;
685
686 r = extract_first_word(&eq, &word, NULL, 0);
687 if (r == 0)
688 break;
689 if (r == -ENOMEM)
690 return log_oom();
691 if (r < 0)
692 return log_error_errno(r, "Failed to parse %s: %s", field, eq);
89ada3ba 693
afc1feae
RC
694 r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
695 if (r < 0)
696 return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
697
698 r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
699 if (r < 0)
700 return bus_log_create_error(r);
701 }
3dc5ca97
LP
702 }
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 r = sd_bus_message_close_container(m);
713 if (r < 0)
714 return bus_log_create_error(r);
cffaed83 715
89ada3ba
YW
716 return 1;
717 }
cffaed83 718
89ada3ba
YW
719 return 0;
720}
cffaed83 721
3d63c749
YW
722static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
723
724 if (streq(field, "Where"))
725
726 return bus_append_string(m, field, eq);
727
728 if (streq(field, "DirectoryMode"))
729
730 return bus_append_parse_mode(m, field, eq);
731
732 if (streq(field, "TimeoutIdleSec"))
733
734 return bus_append_parse_sec_rename(m, field, eq);
735
736 return 0;
737}
738
89ada3ba 739static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
6550c24c
LP
740 const char *suffix;
741 int r;
cffaed83 742
89ada3ba
YW
743 if (STR_IN_SET(field,
744 "User", "Group",
745 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
746 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
747 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
4ad9fb38 748 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
cffaed83 749
89ada3ba 750 return bus_append_string(m, field, eq);
cffaed83 751
89ada3ba 752 if (STR_IN_SET(field,
f69567cb
LP
753 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
754 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
755 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
756 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
757 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
758 "ProtectHostname", "RestrictSUIDSGID"))
cffaed83 759
89ada3ba 760 return bus_append_parse_boolean(m, field, eq);
cffaed83 761
89ada3ba
YW
762 if (STR_IN_SET(field,
763 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
764 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
765 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
766 "SupplementaryGroups", "SystemCallArchitectures"))
cffaed83 767
89ada3ba 768 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
20b16441 769
89ada3ba 770 if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax"))
20b16441 771
89ada3ba 772 return bus_append_log_level_from_string(m, field, eq);
20b16441 773
89ada3ba 774 if (streq(field, "SyslogFacility"))
cffaed83 775
89ada3ba 776 return bus_append_log_facility_unshifted_from_string(m, field, eq);
cffaed83 777
89ada3ba 778 if (streq(field, "SecureBits"))
cffaed83 779
89ada3ba 780 return bus_append_secure_bits_from_string(m, field, eq);
cffaed83 781
89ada3ba 782 if (streq(field, "CPUSchedulingPolicy"))
cffaed83 783
89ada3ba 784 return bus_append_sched_policy_from_string(m, field, eq);
cffaed83 785
89ada3ba 786 if (STR_IN_SET(field, "CPUSchedulingPriority", "OOMScoreAdjust"))
3f856a28 787
89ada3ba 788 return bus_append_safe_atoi(m, field, eq);
3f856a28 789
89ada3ba 790 if (streq(field, "Nice"))
3f856a28 791
89ada3ba 792 return bus_append_parse_nice(m, field, eq);
3f856a28 793
89ada3ba 794 if (streq(field, "SystemCallErrorNumber"))
cffaed83 795
89ada3ba 796 return bus_append_parse_errno(m, field, eq);
cffaed83 797
89ada3ba 798 if (streq(field, "IOSchedulingClass"))
cffaed83 799
89ada3ba 800 return bus_append_ioprio_class_from_string(m, field, eq);
cffaed83 801
89ada3ba 802 if (streq(field, "IOSchedulingPriority"))
cffaed83 803
89ada3ba 804 return bus_append_ioprio_parse_priority(m, field, eq);
cffaed83 805
89ada3ba
YW
806 if (STR_IN_SET(field,
807 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
808 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
cffaed83 809
89ada3ba 810 return bus_append_parse_mode(m, field, eq);
cffaed83 811
89ada3ba 812 if (streq(field, "TimerSlackNSec"))
cffaed83 813
89ada3ba 814 return bus_append_parse_nsec(m, field, eq);
cffaed83 815
691d6f6d 816 if (streq(field, "LogRateLimitIntervalSec"))
90fc172e
AZ
817
818 return bus_append_parse_sec_rename(m, field, eq);
819
820 if (streq(field, "LogRateLimitBurst"))
821
822 return bus_append_safe_atou(m, field, eq);
823
89ada3ba 824 if (streq(field, "MountFlags"))
cffaed83 825
89ada3ba 826 return bus_append_mount_propagation_flags_from_string(m, field, eq);
cffaed83 827
89ada3ba 828 if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment"))
cffaed83 829
89ada3ba 830 return bus_append_strv(m, field, eq, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
cffaed83 831
89ada3ba 832 if (streq(field, "EnvironmentFile")) {
cffaed83 833
89ada3ba
YW
834 if (isempty(eq))
835 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
836 else
837 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
838 eq[0] == '-' ? eq + 1 : eq,
839 eq[0] == '-');
840 if (r < 0)
841 return bus_log_create_error(r);
cffaed83 842
89ada3ba
YW
843 return 1;
844 }
cffaed83 845
89ada3ba 846 if (streq(field, "LogExtraFields")) {
cffaed83 847
89ada3ba 848 r = sd_bus_message_open_container(m, 'r', "sv");
3f856a28
YW
849 if (r < 0)
850 return bus_log_create_error(r);
851
89ada3ba 852 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
3f856a28
YW
853 if (r < 0)
854 return bus_log_create_error(r);
855
89ada3ba 856 r = sd_bus_message_open_container(m, 'v', "aay");
3f856a28
YW
857 if (r < 0)
858 return bus_log_create_error(r);
859
89ada3ba 860 r = sd_bus_message_open_container(m, 'a', "ay");
cffaed83
YW
861 if (r < 0)
862 return bus_log_create_error(r);
863
89ada3ba 864 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
3f856a28
YW
865 if (r < 0)
866 return bus_log_create_error(r);
cffaed83 867
3f856a28
YW
868 r = sd_bus_message_close_container(m);
869 if (r < 0)
870 return bus_log_create_error(r);
9f617cd0 871
89ada3ba
YW
872 r = sd_bus_message_close_container(m);
873 if (r < 0)
874 return bus_log_create_error(r);
9efb9df9 875
89ada3ba 876 r = sd_bus_message_close_container(m);
9efb9df9 877 if (r < 0)
89ada3ba
YW
878 return bus_log_create_error(r);
879
880 return 1;
881 }
9efb9df9 882
89ada3ba
YW
883 if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) {
884 const char *n, *appended;
9efb9df9 885
89ada3ba
YW
886 if ((n = startswith(eq, "fd:"))) {
887 appended = strjoina(field, "FileDescriptorName");
888 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
889 } else if ((n = startswith(eq, "file:"))) {
890 appended = strjoina(field, "File");
891 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d33232e
LP
892 } else if ((n = startswith(eq, "append:"))) {
893 appended = strjoina(field, "FileToAppend");
894 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
89ada3ba
YW
895 } else
896 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
89ada3ba
YW
897 if (r < 0)
898 return bus_log_create_error(r);
7f452159 899
89ada3ba
YW
900 return 1;
901 }
7f452159 902
89ada3ba
YW
903 if (streq(field, "StandardInputText")) {
904 _cleanup_free_ char *unescaped = NULL;
7f452159 905
89ada3ba 906 r = cunescape(eq, 0, &unescaped);
7f452159 907 if (r < 0)
89ada3ba 908 return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
7f452159 909
89ada3ba
YW
910 if (!strextend(&unescaped, "\n", NULL))
911 return log_oom();
7f452159 912
89ada3ba
YW
913 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
914 * interface anyway */
20b16441 915
89ada3ba
YW
916 return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
917 }
20b16441 918
89ada3ba
YW
919 if (streq(field, "StandardInputData")) {
920 _cleanup_free_ void *decoded = NULL;
921 size_t sz;
922
923 r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
20b16441 924 if (r < 0)
89ada3ba 925 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
20b16441 926
89ada3ba
YW
927 return bus_append_byte_array(m, field, decoded, sz);
928 }
20b16441 929
6550c24c
LP
930 if ((suffix = startswith(field, "Limit"))) {
931 int rl;
20b16441 932
6550c24c
LP
933 rl = rlimit_from_string(suffix);
934 if (rl >= 0) {
935 const char *sn;
936 struct rlimit l;
20b16441 937
6550c24c
LP
938 r = rlimit_parse(rl, eq, &l);
939 if (r < 0)
940 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
20b16441 941
6550c24c
LP
942 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
943 if (r < 0)
944 return bus_log_create_error(r);
20b16441 945
6550c24c
LP
946 sn = strjoina(field, "Soft");
947 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
948 if (r < 0)
949 return bus_log_create_error(r);
950
951 return 1;
952 }
89ada3ba 953 }
20b16441 954
89ada3ba
YW
955 if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
956 int ignore = 0;
957 const char *s = eq;
20b16441 958
89ada3ba
YW
959 if (eq[0] == '-') {
960 ignore = 1;
961 s = eq + 1;
20b16441
LP
962 }
963
89ada3ba 964 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
6bbfdc67 965 if (r < 0)
89ada3ba 966 return bus_log_create_error(r);
20b16441 967
89ada3ba
YW
968 return 1;
969 }
20b16441 970
89ada3ba
YW
971 if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) {
972 uint64_t sum = 0;
973 bool invert = false;
974 const char *p = eq;
afcb1cd3 975
89ada3ba
YW
976 if (*p == '~') {
977 invert = true;
978 p++;
979 }
20b16441 980
89ada3ba 981 r = capability_set_from_string(p, &sum);
20b16441 982 if (r < 0)
89ada3ba 983 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
20b16441 984
89ada3ba
YW
985 sum = invert ? ~sum : sum;
986
987 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
20b16441
LP
988 if (r < 0)
989 return bus_log_create_error(r);
990
89ada3ba
YW
991 return 1;
992 }
20b16441 993
89ada3ba 994 if (streq(field, "CPUAffinity")) {
0985c7c4 995 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
20b16441 996
89ada3ba
YW
997 r = parse_cpu_set(eq, &cpuset);
998 if (r < 0)
999 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
20b16441 1000
0985c7c4 1001 return bus_append_byte_array(m, field, cpuset.set, cpuset.allocated);
89ada3ba 1002 }
20b7a007 1003
89ada3ba
YW
1004 if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
1005 int whitelist = 1;
1006 const char *p = eq;
20b16441 1007
89ada3ba
YW
1008 if (*p == '~') {
1009 whitelist = 0;
1010 p++;
20b16441
LP
1011 }
1012
89ada3ba 1013 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1014 if (r < 0)
1015 return bus_log_create_error(r);
1016
89ada3ba
YW
1017 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1018 if (r < 0)
1019 return bus_log_create_error(r);
1020
1021 r = sd_bus_message_open_container(m, 'v', "(bas)");
1022 if (r < 0)
1023 return bus_log_create_error(r);
20b16441 1024
89ada3ba
YW
1025 r = sd_bus_message_open_container(m, 'r', "bas");
1026 if (r < 0)
1027 return bus_log_create_error(r);
cffaed83 1028
89ada3ba 1029 r = sd_bus_message_append_basic(m, 'b', &whitelist);
cffaed83
YW
1030 if (r < 0)
1031 return bus_log_create_error(r);
1032
1033 r = sd_bus_message_open_container(m, 'a', "s");
1034 if (r < 0)
1035 return bus_log_create_error(r);
1036
98008caa 1037 for (;;) {
cffaed83
YW
1038 _cleanup_free_ char *word = NULL;
1039
1040 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
cffaed83
YW
1041 if (r == 0)
1042 break;
89ada3ba
YW
1043 if (r == -ENOMEM)
1044 return log_oom();
1045 if (r < 0)
1046 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1047
1048 r = sd_bus_message_append_basic(m, 's', word);
1049 if (r < 0)
1050 return bus_log_create_error(r);
1051 }
1052
1053 r = sd_bus_message_close_container(m);
1054 if (r < 0)
1055 return bus_log_create_error(r);
1056
1057 r = sd_bus_message_close_container(m);
20b16441
LP
1058 if (r < 0)
1059 return bus_log_create_error(r);
1060
89ada3ba 1061 r = sd_bus_message_close_container(m);
20b16441
LP
1062 if (r < 0)
1063 return bus_log_create_error(r);
1064
20b16441
LP
1065 r = sd_bus_message_close_container(m);
1066 if (r < 0)
1067 return bus_log_create_error(r);
1068
89ada3ba
YW
1069 return 1;
1070 }
20b16441 1071
89ada3ba 1072 if (streq(field, "RestrictNamespaces")) {
add00535 1073 bool invert = false;
aa9d574d 1074 unsigned long flags;
add00535
LP
1075
1076 r = parse_boolean(eq);
1077 if (r > 0)
1078 flags = 0;
1079 else if (r == 0)
1080 flags = NAMESPACE_FLAGS_ALL;
1081 else {
aa9d574d
YW
1082 if (eq[0] == '~') {
1083 invert = true;
1084 eq++;
1085 }
1086
86c2a9f1 1087 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1088 if (r < 0)
1089 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1090 }
1091
1092 if (invert)
1093 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1094
89ada3ba
YW
1095 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1096 if (r < 0)
1097 return bus_log_create_error(r);
afcb1cd3 1098
89ada3ba
YW
1099 return 1;
1100 }
afcb1cd3 1101
89ada3ba
YW
1102 if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
1103 const char *p = eq;
83555251 1104
89ada3ba 1105 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1106 if (r < 0)
89ada3ba 1107 return bus_log_create_error(r);
afcb1cd3 1108
89ada3ba
YW
1109 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1110 if (r < 0)
1111 return bus_log_create_error(r);
d2d6c096
LP
1112
1113 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1114 if (r < 0)
89ada3ba 1115 return bus_log_create_error(r);
d2d6c096
LP
1116
1117 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1118 if (r < 0)
89ada3ba 1119 return bus_log_create_error(r);
d2d6c096
LP
1120
1121 for (;;) {
1122 _cleanup_free_ char *source = NULL, *destination = NULL;
1123 char *s = NULL, *d = NULL;
1124 bool ignore_enoent = false;
1125 uint64_t flags = MS_REC;
1126
1127 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1128 if (r < 0)
1129 return log_error_errno(r, "Failed to parse argument: %m");
1130 if (r == 0)
1131 break;
1132
1133 s = source;
1134 if (s[0] == '-') {
1135 ignore_enoent = true;
1136 s++;
1137 }
1138
1139 if (p && p[-1] == ':') {
1140 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1141 if (r < 0)
1142 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1143 if (r == 0)
1144 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1145 "Missing argument after ':': %s",
1146 eq);
d2d6c096
LP
1147
1148 d = destination;
1149
1150 if (p && p[-1] == ':') {
1151 _cleanup_free_ char *options = NULL;
1152
1153 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
1154 if (r < 0)
1155 return log_error_errno(r, "Failed to parse argument: %m");
1156
1157 if (isempty(options) || streq(options, "rbind"))
1158 flags = MS_REC;
1159 else if (streq(options, "norbind"))
1160 flags = 0;
baaa35ad
ZJS
1161 else
1162 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1163 "Unknown options: %s",
1164 eq);
d2d6c096
LP
1165 }
1166 } else
1167 d = s;
1168
d2d6c096
LP
1169 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1170 if (r < 0)
89ada3ba 1171 return bus_log_create_error(r);
d2d6c096
LP
1172 }
1173
1174 r = sd_bus_message_close_container(m);
1175 if (r < 0)
89ada3ba
YW
1176 return bus_log_create_error(r);
1177
1178 r = sd_bus_message_close_container(m);
1179 if (r < 0)
1180 return bus_log_create_error(r);
d2d6c096
LP
1181
1182 r = sd_bus_message_close_container(m);
89ada3ba
YW
1183 if (r < 0)
1184 return bus_log_create_error(r);
f6c66be1 1185
89ada3ba
YW
1186 return 1;
1187 }
f6c66be1 1188
784ad252
YW
1189 if (streq(field, "TemporaryFileSystem")) {
1190 const char *p = eq;
1191
1192 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1193 if (r < 0)
1194 return bus_log_create_error(r);
1195
1196 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1197 if (r < 0)
1198 return bus_log_create_error(r);
1199
1200 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1201 if (r < 0)
1202 return bus_log_create_error(r);
1203
1204 r = sd_bus_message_open_container(m, 'a', "(ss)");
1205 if (r < 0)
1206 return bus_log_create_error(r);
1207
1208 for (;;) {
1209 _cleanup_free_ char *word = NULL, *path = NULL;
1210 const char *w;
1211
1212 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1213 if (r < 0)
1214 return log_error_errno(r, "Failed to parse argument: %m");
1215 if (r == 0)
1216 break;
1217
1218 w = word;
1219 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1220 if (r < 0)
1221 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1222 if (r == 0)
1223 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1224 "Failed to parse argument: %s",
1225 p);
784ad252
YW
1226
1227 r = sd_bus_message_append(m, "(ss)", path, w);
1228 if (r < 0)
1229 return bus_log_create_error(r);
1230 }
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 r = sd_bus_message_close_container(m);
1241 if (r < 0)
1242 return bus_log_create_error(r);
1243
1244 return 1;
1245 }
1246
89ada3ba
YW
1247 return 0;
1248}
f6c66be1 1249
89ada3ba 1250static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
f6c66be1 1251
89ada3ba 1252 if (streq(field, "KillMode"))
f6c66be1 1253
89ada3ba 1254 return bus_append_string(m, field, eq);
f6c66be1 1255
89ada3ba 1256 if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
f6c66be1 1257
89ada3ba 1258 return bus_append_parse_boolean(m, field, eq);
f6c66be1 1259
c87700a1 1260 if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
89ada3ba 1261
29a3db75 1262 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
1263
1264 return 0;
1265}
1266
3d63c749 1267static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 1268
3d63c749 1269 if (STR_IN_SET(field, "What", "Where", "Options", "Type"))
89ada3ba
YW
1270
1271 return bus_append_string(m, field, eq);
1272
3d63c749
YW
1273 if (streq(field, "TimeoutSec"))
1274
1275 return bus_append_parse_sec_rename(m, field, eq);
1276
1277 if (streq(field, "DirectoryMode"))
1278
1279 return bus_append_parse_mode(m, field, eq);
1280
1281 if (STR_IN_SET(field, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1282
1283 return bus_append_parse_boolean(m, field, eq);
1284
1285 return 0;
1286}
1287
1288static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1289 int r;
1290
89ada3ba
YW
1291 if (streq(field, "MakeDirectory"))
1292
1293 return bus_append_parse_boolean(m, field, eq);
1294
1295 if (streq(field, "DirectoryMode"))
1296
1297 return bus_append_parse_mode(m, field, eq);
1298
3d63c749
YW
1299 if (STR_IN_SET(field,
1300 "PathExists", "PathExistsGlob", "PathChanged",
1301 "PathModified", "DirectoryNotEmpty")) {
1302
1303 if (isempty(eq))
1304 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1305 else
1306 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1307 if (r < 0)
1308 return bus_log_create_error(r);
1309
1310 return 1;
1311 }
1312
89ada3ba
YW
1313 return 0;
1314}
1315
1316static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 1317 int r;
89ada3ba 1318
3d63c749
YW
1319 if (STR_IN_SET(field,
1320 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
afcfaa69 1321 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
89ada3ba
YW
1322
1323 return bus_append_string(m, field, eq);
f6c66be1 1324
3d63c749 1325 if (STR_IN_SET(field, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
89ada3ba
YW
1326
1327 return bus_append_parse_boolean(m, field, eq);
1328
3d63c749 1329 if (STR_IN_SET(field, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
89ada3ba
YW
1330
1331 return bus_append_parse_sec_rename(m, field, eq);
1332
3d63c749
YW
1333 if (streq(field, "TimeoutSec")) {
1334
1335 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1336 if (r < 0)
1337 return r;
1338
1339 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1340 }
1341
89ada3ba
YW
1342 if (streq(field, "FileDescriptorStoreMax"))
1343
1344 return bus_append_safe_atou(m, field, eq);
1345
1346 if (STR_IN_SET(field,
1347 "ExecStartPre", "ExecStart", "ExecStartPost",
1348 "ExecReload", "ExecStop", "ExecStopPost"))
1349
1350 return bus_append_exec_command(m, field, eq);
1351
3d63c749
YW
1352 if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1353 _cleanup_free_ int *status = NULL, *signal = NULL;
1354 size_t sz_status = 0, sz_signal = 0;
1355 const char *p;
1356
1357 for (p = eq;;) {
1358 _cleanup_free_ char *word = NULL;
1359 int val;
1360
1361 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1362 if (r == 0)
1363 break;
1364 if (r == -ENOMEM)
1365 return log_oom();
1366 if (r < 0)
1367 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1368
1369 r = safe_atoi(word, &val);
1370 if (r < 0) {
29a3db75 1371 val = signal_from_string(word);
3d63c749
YW
1372 if (val < 0)
1373 return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field);
1374
aa484f35 1375 signal = reallocarray(signal, sz_signal + 1, sizeof(int));
3d63c749
YW
1376 if (!signal)
1377 return log_oom();
1378
1379 signal[sz_signal++] = val;
1380 } else {
aa484f35 1381 status = reallocarray(status, sz_status + 1, sizeof(int));
3d63c749
YW
1382 if (!status)
1383 return log_oom();
1384
1385 status[sz_status++] = val;
1386 }
1387 }
1388
1389 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1390 if (r < 0)
1391 return bus_log_create_error(r);
1392
1393 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1394 if (r < 0)
1395 return bus_log_create_error(r);
1396
1397 r = sd_bus_message_open_container(m, 'v', "(aiai)");
1398 if (r < 0)
1399 return bus_log_create_error(r);
1400
1401 r = sd_bus_message_open_container(m, 'r', "aiai");
1402 if (r < 0)
1403 return bus_log_create_error(r);
1404
1405 r = sd_bus_message_append_array(m, 'i', status, sz_status);
1406 if (r < 0)
1407 return bus_log_create_error(r);
1408
1409 r = sd_bus_message_append_array(m, 'i', signal, sz_signal);
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 r = sd_bus_message_close_container(m);
1422 if (r < 0)
1423 return bus_log_create_error(r);
1424
1425 return 1;
1426 }
1427
89ada3ba
YW
1428 return 0;
1429}
1430
1431static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1432 int r;
1433
1434 if (STR_IN_SET(field,
1435 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1436 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1437
1438 return bus_append_parse_boolean(m, field, eq);
1439
1440 if (STR_IN_SET(field, "Priority", "IPTTL", "Mark"))
1441
1442 return bus_append_safe_atoi(m, field, eq);
1443
1444 if (streq(field, "IPTOS"))
1445
1446 return bus_append_ip_tos_from_string(m, field, eq);
1447
1448 if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1449
1450 return bus_append_safe_atou(m, field, eq);
1451
1452 if (STR_IN_SET(field, "SocketMode", "DirectoryMode"))
1453
1454 return bus_append_parse_mode(m, field, eq);
1455
1456 if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1457
1458 return bus_append_safe_atoi64(m, field, eq);
1459
1460 if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1461
1462 return bus_append_parse_sec_rename(m, field, eq);
1463
1464 if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1465
b48e508d 1466 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba
YW
1467
1468 if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1469
1470 return bus_append_exec_command(m, field, eq);
1471
1472 if (STR_IN_SET(field,
1473 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1474 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1475 "SocketUser", "SocketGroup"))
1476
1477 return bus_append_string(m, field, eq);
1478
1479 if (streq(field, "Symlinks"))
1480
1481 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1482
e045e325 1483 if (streq(field, "SocketProtocol"))
89ada3ba 1484
d2b42d63 1485 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba
YW
1486
1487 if (STR_IN_SET(field,
1488 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1489 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1490
3d63c749
YW
1491 if (isempty(eq))
1492 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1493 else
81b1dc27 1494 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 1495 if (r < 0)
89ada3ba
YW
1496 return bus_log_create_error(r);
1497
1498 return 1;
1499 }
1500
1501 return 0;
1502}
1503static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 1504 int r;
89ada3ba 1505
efebb613
LP
1506 if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
1507 "OnTimezoneChange", "OnClockChange"))
89ada3ba
YW
1508
1509 return bus_append_parse_boolean(m, field, eq);
1510
3d63c749
YW
1511 if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1512
1513 return bus_append_parse_sec_rename(m, field, eq);
1514
89ada3ba
YW
1515 if (STR_IN_SET(field,
1516 "OnActiveSec", "OnBootSec", "OnStartupSec",
3d63c749 1517 "OnUnitActiveSec","OnUnitInactiveSec")) {
89ada3ba 1518
3d63c749
YW
1519 if (isempty(eq))
1520 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1521 else {
1522 usec_t t;
1523 r = parse_sec(eq, &t);
1524 if (r < 0)
1525 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 1526
3d63c749
YW
1527 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1528 }
1529 if (r < 0)
1530 return bus_log_create_error(r);
89ada3ba 1531
3d63c749
YW
1532 return 1;
1533 }
1534
1535 if (streq(field, "OnCalendar")) {
1536
1537 if (isempty(eq))
1538 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1539 else
1540 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1541 if (r < 0)
1542 return bus_log_create_error(r);
1543
1544 return 1;
1545 }
89ada3ba
YW
1546
1547 return 0;
1548}
1549
1550static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
1551 ConditionType t = _CONDITION_TYPE_INVALID;
1552 bool is_condition = false;
1553 int r;
f6c66be1 1554
3d63c749
YW
1555 if (STR_IN_SET(field,
1556 "Description", "SourcePath", "OnFailureJobMode",
1557 "JobTimeoutAction", "JobTimeoutRebootArgument",
1558 "StartLimitAction", "FailureAction", "SuccessAction",
1559 "RebootArgument", "CollectMode"))
89ada3ba
YW
1560
1561 return bus_append_string(m, field, eq);
1562
3d63c749
YW
1563 if (STR_IN_SET(field,
1564 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1565 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
89ada3ba
YW
1566
1567 return bus_append_parse_boolean(m, field, eq);
1568
3d63c749
YW
1569 if (STR_IN_SET(field, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1570
1571 return bus_append_parse_sec_rename(m, field, eq);
1572
1573 if (streq(field, "StartLimitBurst"))
1574
1575 return bus_append_safe_atou(m, field, eq);
1576
7af67e9a
LP
1577 if (STR_IN_SET(field, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1578
1579 if (isempty(eq))
1580 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1581 else {
1582 uint8_t u;
1583
1584 r = safe_atou8(eq, &u);
1585 if (r < 0)
1586 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1587
1588 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1589 }
1590 if (r < 0)
1591 return bus_log_create_error(r);
1592
1593 return 1;
1594 }
1595
3d63c749
YW
1596 if (unit_dependency_from_string(field) >= 0 ||
1597 STR_IN_SET(field, "Documentation", "RequiresMountsFor"))
89ada3ba 1598
eae194a5 1599 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
89ada3ba 1600
3d63c749
YW
1601 t = condition_type_from_string(field);
1602 if (t >= 0)
1603 is_condition = true;
1604 else
1605 t = assert_type_from_string(field);
1606 if (t >= 0) {
1607 if (isempty(eq))
1608 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1609 else {
1610 const char *p = eq;
1611 int trigger, negate;
1612
1613 trigger = *p == '|';
1614 if (trigger)
1615 p++;
1616
1617 negate = *p == '!';
1618 if (negate)
1619 p++;
1620
1621 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1622 field, trigger, negate, p);
1623 }
1624 if (r < 0)
1625 return bus_log_create_error(r);
1626
1627 return 1;
1628 }
1629
89ada3ba
YW
1630 return 0;
1631}
1632
1633int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1634 const char *eq, *field;
1635 int r;
1636
1637 assert(m);
1638 assert(assignment);
1639
1640 eq = strchr(assignment, '=');
baaa35ad
ZJS
1641 if (!eq)
1642 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1643 "Not an assignment: %s", assignment);
89ada3ba
YW
1644
1645 field = strndupa(assignment, eq - assignment);
1646 eq++;
1647
1648 switch (t) {
1649 case UNIT_SERVICE:
1650 r = bus_append_cgroup_property(m, field, eq);
1651 if (r != 0)
f6c66be1
LP
1652 return r;
1653
89ada3ba
YW
1654 r = bus_append_execute_property(m, field, eq);
1655 if (r != 0)
1656 return r;
f6c66be1 1657
89ada3ba
YW
1658 r = bus_append_kill_property(m, field, eq);
1659 if (r != 0)
1660 return r;
f6c66be1 1661
89ada3ba
YW
1662 r = bus_append_service_property(m, field, eq);
1663 if (r != 0)
1664 return r;
1665 break;
f6c66be1 1666
89ada3ba
YW
1667 case UNIT_SOCKET:
1668 r = bus_append_cgroup_property(m, field, eq);
1669 if (r != 0)
1670 return r;
f6c66be1 1671
89ada3ba
YW
1672 r = bus_append_execute_property(m, field, eq);
1673 if (r != 0)
1674 return r;
f6c66be1 1675
89ada3ba
YW
1676 r = bus_append_kill_property(m, field, eq);
1677 if (r != 0)
1678 return r;
f6c66be1 1679
89ada3ba
YW
1680 r = bus_append_socket_property(m, field, eq);
1681 if (r != 0)
f6c66be1 1682 return r;
89ada3ba 1683 break;
f6c66be1 1684
89ada3ba
YW
1685 case UNIT_TIMER:
1686 r = bus_append_timer_property(m, field, eq);
1687 if (r != 0)
1688 return r;
1689 break;
f6c66be1 1690
89ada3ba
YW
1691 case UNIT_PATH:
1692 r = bus_append_path_property(m, field, eq);
1693 if (r != 0)
1694 return r;
1695 break;
268833ed 1696
89ada3ba
YW
1697 case UNIT_SLICE:
1698 r = bus_append_cgroup_property(m, field, eq);
1699 if (r != 0)
1700 return r;
1701 break;
268833ed 1702
89ada3ba 1703 case UNIT_SCOPE:
3d63c749
YW
1704
1705 if (streq(field, "TimeoutStopSec"))
1706 return bus_append_parse_sec_rename(m, field, eq);
1707
89ada3ba
YW
1708 r = bus_append_cgroup_property(m, field, eq);
1709 if (r != 0)
1710 return r;
268833ed 1711
89ada3ba
YW
1712 r = bus_append_kill_property(m, field, eq);
1713 if (r != 0)
1714 return r;
1715 break;
535e0d19 1716
89ada3ba 1717 case UNIT_MOUNT:
3d63c749
YW
1718 r = bus_append_cgroup_property(m, field, eq);
1719 if (r != 0)
1720 return r;
1721
1722 r = bus_append_execute_property(m, field, eq);
1723 if (r != 0)
1724 return r;
1725
1726 r = bus_append_kill_property(m, field, eq);
1727 if (r != 0)
1728 return r;
1729
1730 r = bus_append_mount_property(m, field, eq);
1731 if (r != 0)
1732 return r;
1733
1734 break;
1735
89ada3ba 1736 case UNIT_AUTOMOUNT:
3d63c749
YW
1737 r = bus_append_automount_property(m, field, eq);
1738 if (r != 0)
1739 return r;
1740
89ada3ba 1741 break;
535e0d19 1742
89ada3ba
YW
1743 case UNIT_TARGET:
1744 case UNIT_DEVICE:
1745 case UNIT_SWAP:
baaa35ad
ZJS
1746 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1747 "Not supported unit type");
535e0d19 1748
89ada3ba 1749 default:
baaa35ad
ZJS
1750 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1751 "Invalid unit type");
20b16441
LP
1752 }
1753
89ada3ba
YW
1754 r = bus_append_unit_property(m, field, eq);
1755 if (r != 0)
1756 return r;
20b16441 1757
baaa35ad
ZJS
1758 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1759 "Unknown assignment: %s", assignment);
20b16441
LP
1760}
1761
89ada3ba 1762int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
1763 char **i;
1764 int r;
1765
1766 assert(m);
1767
1768 STRV_FOREACH(i, l) {
89ada3ba 1769 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
1770 if (r < 0)
1771 return r;
1772 }
1773
1774 return 0;
1775}
1776
da6053d0 1777int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
1778 const char *type, *path, *source;
1779 int r;
1780
acc0269c
CH
1781 /* changes is dereferenced when calling unit_file_dump_changes() later,
1782 * so we have to make sure this is not NULL. */
1783 assert(changes);
1784 assert(n_changes);
1785
20b16441
LP
1786 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1787 if (r < 0)
1788 return bus_log_parse_error(r);
1789
1790 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1791 /* We expect only "success" changes to be sent over the bus.
1792 Hence, reject anything negative. */
1793 UnitFileChangeType ch = unit_file_change_type_from_string(type);
1794
1795 if (ch < 0) {
1796 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1797 continue;
1798 }
1799
1800 r = unit_file_changes_add(changes, n_changes, ch, path, source);
1801 if (r < 0)
1802 return r;
1803 }
1804 if (r < 0)
1805 return bus_log_parse_error(r);
1806
1807 r = sd_bus_message_exit_container(m);
1808 if (r < 0)
1809 return bus_log_parse_error(r);
1810
35d379b2 1811 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
1812 return 0;
1813}
1814
bd062910
ZJS
1815int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
1816 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1817 _cleanup_free_ char *path = NULL;
1818 int r;
1819
1820 path = unit_dbus_path_from_name(name);
1821 if (!path)
1822 return log_oom();
1823
1824 /* This function warns on it's own, because otherwise it'd be awkward to pass
1825 * the dbus error message around. */
1826
1827 r = sd_bus_get_property_string(
1828 bus,
1829 "org.freedesktop.systemd1",
1830 path,
1831 "org.freedesktop.systemd1.Unit",
1832 "LoadState",
1833 &error,
1834 load_state);
1835 if (r < 0)
1836 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
1837
1838 return 0;
1839}