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