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