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