]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/bus-unit-util.c
core: add ExecStartXYZEx= with dbus support for executable prefixes
[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;
316 upgraded_name = strappend(field, "Ex");
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
YW
327 if (explicit_path) {
328 r = extract_first_word(&eq, &path, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
329 if (r < 0)
330 return log_error_errno(r, "Failed to parse path: %m");
331 }
2038c3f5 332
89ada3ba
YW
333 r = strv_split_extract(&l, eq, NULL, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
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
443 return bus_append_strv(m, "DisableControllers", eq, EXTRACT_QUOTES);
444
89ada3ba 445 if (streq(field, "Delegate")) {
08f3be7a 446
89ada3ba 447 r = parse_boolean(eq);
08f3be7a 448 if (r < 0)
89ada3ba 449 return bus_append_strv(m, "DelegateControllers", eq, EXTRACT_QUOTES);
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);
cffaed83 757
89ada3ba
YW
758 return 1;
759 }
cffaed83 760
89ada3ba
YW
761 return 0;
762}
cffaed83 763
3d63c749
YW
764static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
765
766 if (streq(field, "Where"))
767
768 return bus_append_string(m, field, eq);
769
770 if (streq(field, "DirectoryMode"))
771
772 return bus_append_parse_mode(m, field, eq);
773
774 if (streq(field, "TimeoutIdleSec"))
775
776 return bus_append_parse_sec_rename(m, field, eq);
777
778 return 0;
779}
780
89ada3ba 781static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
6550c24c
LP
782 const char *suffix;
783 int r;
cffaed83 784
89ada3ba
YW
785 if (STR_IN_SET(field,
786 "User", "Group",
787 "UtmpIdentifier", "UtmpMode", "PAMName", "TTYPath",
788 "WorkingDirectory", "RootDirectory", "SyslogIdentifier",
789 "ProtectSystem", "ProtectHome", "SELinuxContext", "RootImage",
4ad9fb38 790 "RuntimeDirectoryPreserve", "Personality", "KeyringMode", "NetworkNamespacePath"))
cffaed83 791
89ada3ba 792 return bus_append_string(m, field, eq);
cffaed83 793
89ada3ba 794 if (STR_IN_SET(field,
f69567cb
LP
795 "IgnoreSIGPIPE", "TTYVHangup", "TTYReset", "TTYVTDisallocate", "PrivateTmp",
796 "PrivateDevices", "PrivateNetwork", "PrivateUsers", "PrivateMounts",
797 "NoNewPrivileges", "SyslogLevelPrefix", "MemoryDenyWriteExecute", "RestrictRealtime",
798 "DynamicUser", "RemoveIPC", "ProtectKernelTunables", "ProtectKernelModules",
799 "ProtectControlGroups", "MountAPIVFS", "CPUSchedulingResetOnFork", "LockPersonality",
800 "ProtectHostname", "RestrictSUIDSGID"))
cffaed83 801
89ada3ba 802 return bus_append_parse_boolean(m, field, eq);
cffaed83 803
89ada3ba
YW
804 if (STR_IN_SET(field,
805 "ReadWriteDirectories", "ReadOnlyDirectories", "InaccessibleDirectories",
806 "ReadWritePaths", "ReadOnlyPaths", "InaccessiblePaths",
807 "RuntimeDirectory", "StateDirectory", "CacheDirectory", "LogsDirectory", "ConfigurationDirectory",
808 "SupplementaryGroups", "SystemCallArchitectures"))
cffaed83 809
89ada3ba 810 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
20b16441 811
89ada3ba 812 if (STR_IN_SET(field, "SyslogLevel", "LogLevelMax"))
20b16441 813
89ada3ba 814 return bus_append_log_level_from_string(m, field, eq);
20b16441 815
89ada3ba 816 if (streq(field, "SyslogFacility"))
cffaed83 817
89ada3ba 818 return bus_append_log_facility_unshifted_from_string(m, field, eq);
cffaed83 819
89ada3ba 820 if (streq(field, "SecureBits"))
cffaed83 821
89ada3ba 822 return bus_append_secure_bits_from_string(m, field, eq);
cffaed83 823
89ada3ba 824 if (streq(field, "CPUSchedulingPolicy"))
cffaed83 825
89ada3ba 826 return bus_append_sched_policy_from_string(m, field, eq);
cffaed83 827
89ada3ba 828 if (STR_IN_SET(field, "CPUSchedulingPriority", "OOMScoreAdjust"))
3f856a28 829
89ada3ba 830 return bus_append_safe_atoi(m, field, eq);
3f856a28 831
89ada3ba 832 if (streq(field, "Nice"))
3f856a28 833
89ada3ba 834 return bus_append_parse_nice(m, field, eq);
3f856a28 835
89ada3ba 836 if (streq(field, "SystemCallErrorNumber"))
cffaed83 837
89ada3ba 838 return bus_append_parse_errno(m, field, eq);
cffaed83 839
89ada3ba 840 if (streq(field, "IOSchedulingClass"))
cffaed83 841
89ada3ba 842 return bus_append_ioprio_class_from_string(m, field, eq);
cffaed83 843
89ada3ba 844 if (streq(field, "IOSchedulingPriority"))
cffaed83 845
89ada3ba 846 return bus_append_ioprio_parse_priority(m, field, eq);
cffaed83 847
89ada3ba
YW
848 if (STR_IN_SET(field,
849 "RuntimeDirectoryMode", "StateDirectoryMode", "CacheDirectoryMode",
850 "LogsDirectoryMode", "ConfigurationDirectoryMode", "UMask"))
cffaed83 851
89ada3ba 852 return bus_append_parse_mode(m, field, eq);
cffaed83 853
89ada3ba 854 if (streq(field, "TimerSlackNSec"))
cffaed83 855
89ada3ba 856 return bus_append_parse_nsec(m, field, eq);
cffaed83 857
691d6f6d 858 if (streq(field, "LogRateLimitIntervalSec"))
90fc172e
AZ
859
860 return bus_append_parse_sec_rename(m, field, eq);
861
862 if (streq(field, "LogRateLimitBurst"))
863
864 return bus_append_safe_atou(m, field, eq);
865
89ada3ba 866 if (streq(field, "MountFlags"))
cffaed83 867
89ada3ba 868 return bus_append_mount_propagation_flags_from_string(m, field, eq);
cffaed83 869
89ada3ba 870 if (STR_IN_SET(field, "Environment", "UnsetEnvironment", "PassEnvironment"))
cffaed83 871
89ada3ba 872 return bus_append_strv(m, field, eq, EXTRACT_QUOTES|EXTRACT_CUNESCAPE);
cffaed83 873
89ada3ba 874 if (streq(field, "EnvironmentFile")) {
cffaed83 875
89ada3ba
YW
876 if (isempty(eq))
877 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
878 else
879 r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
880 eq[0] == '-' ? eq + 1 : eq,
881 eq[0] == '-');
882 if (r < 0)
883 return bus_log_create_error(r);
cffaed83 884
89ada3ba
YW
885 return 1;
886 }
cffaed83 887
89ada3ba 888 if (streq(field, "LogExtraFields")) {
cffaed83 889
89ada3ba 890 r = sd_bus_message_open_container(m, 'r', "sv");
3f856a28
YW
891 if (r < 0)
892 return bus_log_create_error(r);
893
89ada3ba 894 r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
3f856a28
YW
895 if (r < 0)
896 return bus_log_create_error(r);
897
89ada3ba 898 r = sd_bus_message_open_container(m, 'v', "aay");
3f856a28
YW
899 if (r < 0)
900 return bus_log_create_error(r);
901
89ada3ba 902 r = sd_bus_message_open_container(m, 'a', "ay");
cffaed83
YW
903 if (r < 0)
904 return bus_log_create_error(r);
905
89ada3ba 906 r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
3f856a28
YW
907 if (r < 0)
908 return bus_log_create_error(r);
cffaed83 909
3f856a28
YW
910 r = sd_bus_message_close_container(m);
911 if (r < 0)
912 return bus_log_create_error(r);
9f617cd0 913
89ada3ba
YW
914 r = sd_bus_message_close_container(m);
915 if (r < 0)
916 return bus_log_create_error(r);
9efb9df9 917
89ada3ba 918 r = sd_bus_message_close_container(m);
9efb9df9 919 if (r < 0)
89ada3ba
YW
920 return bus_log_create_error(r);
921
922 return 1;
923 }
9efb9df9 924
89ada3ba
YW
925 if (STR_IN_SET(field, "StandardInput", "StandardOutput", "StandardError")) {
926 const char *n, *appended;
9efb9df9 927
89ada3ba
YW
928 if ((n = startswith(eq, "fd:"))) {
929 appended = strjoina(field, "FileDescriptorName");
930 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
931 } else if ((n = startswith(eq, "file:"))) {
932 appended = strjoina(field, "File");
933 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
8d33232e
LP
934 } else if ((n = startswith(eq, "append:"))) {
935 appended = strjoina(field, "FileToAppend");
936 r = sd_bus_message_append(m, "(sv)", appended, "s", n);
89ada3ba
YW
937 } else
938 r = sd_bus_message_append(m, "(sv)", field, "s", eq);
89ada3ba
YW
939 if (r < 0)
940 return bus_log_create_error(r);
7f452159 941
89ada3ba
YW
942 return 1;
943 }
7f452159 944
89ada3ba
YW
945 if (streq(field, "StandardInputText")) {
946 _cleanup_free_ char *unescaped = NULL;
7f452159 947
89ada3ba 948 r = cunescape(eq, 0, &unescaped);
7f452159 949 if (r < 0)
89ada3ba 950 return log_error_errno(r, "Failed to unescape text '%s': %m", eq);
7f452159 951
89ada3ba
YW
952 if (!strextend(&unescaped, "\n", NULL))
953 return log_oom();
7f452159 954
89ada3ba
YW
955 /* Note that we don't expand specifiers here, but that should be OK, as this is a programmatic
956 * interface anyway */
20b16441 957
89ada3ba
YW
958 return bus_append_byte_array(m, field, unescaped, strlen(unescaped));
959 }
20b16441 960
89ada3ba
YW
961 if (streq(field, "StandardInputData")) {
962 _cleanup_free_ void *decoded = NULL;
963 size_t sz;
964
965 r = unbase64mem(eq, (size_t) -1, &decoded, &sz);
20b16441 966 if (r < 0)
89ada3ba 967 return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
20b16441 968
89ada3ba
YW
969 return bus_append_byte_array(m, field, decoded, sz);
970 }
20b16441 971
6550c24c
LP
972 if ((suffix = startswith(field, "Limit"))) {
973 int rl;
20b16441 974
6550c24c
LP
975 rl = rlimit_from_string(suffix);
976 if (rl >= 0) {
977 const char *sn;
978 struct rlimit l;
20b16441 979
6550c24c
LP
980 r = rlimit_parse(rl, eq, &l);
981 if (r < 0)
982 return log_error_errno(r, "Failed to parse resource limit: %s", eq);
20b16441 983
6550c24c
LP
984 r = sd_bus_message_append(m, "(sv)", field, "t", l.rlim_max);
985 if (r < 0)
986 return bus_log_create_error(r);
20b16441 987
6550c24c
LP
988 sn = strjoina(field, "Soft");
989 r = sd_bus_message_append(m, "(sv)", sn, "t", l.rlim_cur);
990 if (r < 0)
991 return bus_log_create_error(r);
992
993 return 1;
994 }
89ada3ba 995 }
20b16441 996
89ada3ba
YW
997 if (STR_IN_SET(field, "AppArmorProfile", "SmackProcessLabel")) {
998 int ignore = 0;
999 const char *s = eq;
20b16441 1000
89ada3ba
YW
1001 if (eq[0] == '-') {
1002 ignore = 1;
1003 s = eq + 1;
20b16441
LP
1004 }
1005
89ada3ba 1006 r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
6bbfdc67 1007 if (r < 0)
89ada3ba 1008 return bus_log_create_error(r);
20b16441 1009
89ada3ba
YW
1010 return 1;
1011 }
20b16441 1012
89ada3ba
YW
1013 if (STR_IN_SET(field, "CapabilityBoundingSet", "AmbientCapabilities")) {
1014 uint64_t sum = 0;
1015 bool invert = false;
1016 const char *p = eq;
afcb1cd3 1017
89ada3ba
YW
1018 if (*p == '~') {
1019 invert = true;
1020 p++;
1021 }
20b16441 1022
89ada3ba 1023 r = capability_set_from_string(p, &sum);
20b16441 1024 if (r < 0)
89ada3ba 1025 return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
20b16441 1026
89ada3ba
YW
1027 sum = invert ? ~sum : sum;
1028
1029 r = sd_bus_message_append(m, "(sv)", field, "t", sum);
20b16441
LP
1030 if (r < 0)
1031 return bus_log_create_error(r);
1032
89ada3ba
YW
1033 return 1;
1034 }
20b16441 1035
89ada3ba 1036 if (streq(field, "CPUAffinity")) {
0985c7c4 1037 _cleanup_(cpu_set_reset) CPUSet cpuset = {};
c367f996
MS
1038 _cleanup_free_ uint8_t *array = NULL;
1039 size_t allocated;
20b16441 1040
89ada3ba
YW
1041 r = parse_cpu_set(eq, &cpuset);
1042 if (r < 0)
1043 return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
20b16441 1044
c367f996
MS
1045 r = cpu_set_to_dbus(&cpuset, &array, &allocated);
1046 if (r < 0)
1047 return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
1048
1049 return bus_append_byte_array(m, field, array, allocated);
89ada3ba 1050 }
20b7a007 1051
89ada3ba
YW
1052 if (STR_IN_SET(field, "RestrictAddressFamilies", "SystemCallFilter")) {
1053 int whitelist = 1;
1054 const char *p = eq;
20b16441 1055
89ada3ba
YW
1056 if (*p == '~') {
1057 whitelist = 0;
1058 p++;
20b16441
LP
1059 }
1060
89ada3ba 1061 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20b16441
LP
1062 if (r < 0)
1063 return bus_log_create_error(r);
1064
89ada3ba
YW
1065 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1066 if (r < 0)
1067 return bus_log_create_error(r);
1068
1069 r = sd_bus_message_open_container(m, 'v', "(bas)");
1070 if (r < 0)
1071 return bus_log_create_error(r);
20b16441 1072
89ada3ba
YW
1073 r = sd_bus_message_open_container(m, 'r', "bas");
1074 if (r < 0)
1075 return bus_log_create_error(r);
cffaed83 1076
89ada3ba 1077 r = sd_bus_message_append_basic(m, 'b', &whitelist);
cffaed83
YW
1078 if (r < 0)
1079 return bus_log_create_error(r);
1080
1081 r = sd_bus_message_open_container(m, 'a', "s");
1082 if (r < 0)
1083 return bus_log_create_error(r);
1084
98008caa 1085 for (;;) {
cffaed83
YW
1086 _cleanup_free_ char *word = NULL;
1087
1088 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
cffaed83
YW
1089 if (r == 0)
1090 break;
89ada3ba
YW
1091 if (r == -ENOMEM)
1092 return log_oom();
1093 if (r < 0)
1094 return log_error_errno(r, "Invalid syntax: %s", eq);
cffaed83
YW
1095
1096 r = sd_bus_message_append_basic(m, 's', word);
1097 if (r < 0)
1098 return bus_log_create_error(r);
1099 }
1100
1101 r = sd_bus_message_close_container(m);
1102 if (r < 0)
1103 return bus_log_create_error(r);
1104
1105 r = sd_bus_message_close_container(m);
20b16441
LP
1106 if (r < 0)
1107 return bus_log_create_error(r);
1108
89ada3ba 1109 r = sd_bus_message_close_container(m);
20b16441
LP
1110 if (r < 0)
1111 return bus_log_create_error(r);
1112
20b16441
LP
1113 r = sd_bus_message_close_container(m);
1114 if (r < 0)
1115 return bus_log_create_error(r);
1116
89ada3ba
YW
1117 return 1;
1118 }
20b16441 1119
89ada3ba 1120 if (streq(field, "RestrictNamespaces")) {
add00535 1121 bool invert = false;
aa9d574d 1122 unsigned long flags;
add00535
LP
1123
1124 r = parse_boolean(eq);
1125 if (r > 0)
1126 flags = 0;
1127 else if (r == 0)
1128 flags = NAMESPACE_FLAGS_ALL;
1129 else {
aa9d574d
YW
1130 if (eq[0] == '~') {
1131 invert = true;
1132 eq++;
1133 }
1134
86c2a9f1 1135 r = namespace_flags_from_string(eq, &flags);
add00535
LP
1136 if (r < 0)
1137 return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
1138 }
1139
1140 if (invert)
1141 flags = (~flags) & NAMESPACE_FLAGS_ALL;
1142
89ada3ba
YW
1143 r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
1144 if (r < 0)
1145 return bus_log_create_error(r);
afcb1cd3 1146
89ada3ba
YW
1147 return 1;
1148 }
afcb1cd3 1149
89ada3ba
YW
1150 if (STR_IN_SET(field, "BindPaths", "BindReadOnlyPaths")) {
1151 const char *p = eq;
83555251 1152
89ada3ba 1153 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
c7383828 1154 if (r < 0)
89ada3ba 1155 return bus_log_create_error(r);
afcb1cd3 1156
89ada3ba
YW
1157 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1158 if (r < 0)
1159 return bus_log_create_error(r);
d2d6c096
LP
1160
1161 r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
1162 if (r < 0)
89ada3ba 1163 return bus_log_create_error(r);
d2d6c096
LP
1164
1165 r = sd_bus_message_open_container(m, 'a', "(ssbt)");
1166 if (r < 0)
89ada3ba 1167 return bus_log_create_error(r);
d2d6c096
LP
1168
1169 for (;;) {
1170 _cleanup_free_ char *source = NULL, *destination = NULL;
1171 char *s = NULL, *d = NULL;
1172 bool ignore_enoent = false;
1173 uint64_t flags = MS_REC;
1174
1175 r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1176 if (r < 0)
1177 return log_error_errno(r, "Failed to parse argument: %m");
1178 if (r == 0)
1179 break;
1180
1181 s = source;
1182 if (s[0] == '-') {
1183 ignore_enoent = true;
1184 s++;
1185 }
1186
1187 if (p && p[-1] == ':') {
1188 r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_QUOTES|EXTRACT_DONT_COALESCE_SEPARATORS);
1189 if (r < 0)
1190 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1191 if (r == 0)
1192 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1193 "Missing argument after ':': %s",
1194 eq);
d2d6c096
LP
1195
1196 d = destination;
1197
1198 if (p && p[-1] == ':') {
1199 _cleanup_free_ char *options = NULL;
1200
1201 r = extract_first_word(&p, &options, NULL, EXTRACT_QUOTES);
1202 if (r < 0)
1203 return log_error_errno(r, "Failed to parse argument: %m");
1204
1205 if (isempty(options) || streq(options, "rbind"))
1206 flags = MS_REC;
1207 else if (streq(options, "norbind"))
1208 flags = 0;
baaa35ad
ZJS
1209 else
1210 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1211 "Unknown options: %s",
1212 eq);
d2d6c096
LP
1213 }
1214 } else
1215 d = s;
1216
d2d6c096
LP
1217 r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
1218 if (r < 0)
89ada3ba 1219 return bus_log_create_error(r);
d2d6c096
LP
1220 }
1221
1222 r = sd_bus_message_close_container(m);
1223 if (r < 0)
89ada3ba
YW
1224 return bus_log_create_error(r);
1225
1226 r = sd_bus_message_close_container(m);
1227 if (r < 0)
1228 return bus_log_create_error(r);
d2d6c096
LP
1229
1230 r = sd_bus_message_close_container(m);
89ada3ba
YW
1231 if (r < 0)
1232 return bus_log_create_error(r);
f6c66be1 1233
89ada3ba
YW
1234 return 1;
1235 }
f6c66be1 1236
784ad252
YW
1237 if (streq(field, "TemporaryFileSystem")) {
1238 const char *p = eq;
1239
1240 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1241 if (r < 0)
1242 return bus_log_create_error(r);
1243
1244 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1245 if (r < 0)
1246 return bus_log_create_error(r);
1247
1248 r = sd_bus_message_open_container(m, 'v', "a(ss)");
1249 if (r < 0)
1250 return bus_log_create_error(r);
1251
1252 r = sd_bus_message_open_container(m, 'a', "(ss)");
1253 if (r < 0)
1254 return bus_log_create_error(r);
1255
1256 for (;;) {
1257 _cleanup_free_ char *word = NULL, *path = NULL;
1258 const char *w;
1259
1260 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1261 if (r < 0)
1262 return log_error_errno(r, "Failed to parse argument: %m");
1263 if (r == 0)
1264 break;
1265
1266 w = word;
1267 r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
1268 if (r < 0)
1269 return log_error_errno(r, "Failed to parse argument: %m");
baaa35ad
ZJS
1270 if (r == 0)
1271 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1272 "Failed to parse argument: %s",
1273 p);
784ad252
YW
1274
1275 r = sd_bus_message_append(m, "(ss)", path, w);
1276 if (r < 0)
1277 return bus_log_create_error(r);
1278 }
1279
1280 r = sd_bus_message_close_container(m);
1281 if (r < 0)
1282 return bus_log_create_error(r);
1283
1284 r = sd_bus_message_close_container(m);
1285 if (r < 0)
1286 return bus_log_create_error(r);
1287
1288 r = sd_bus_message_close_container(m);
1289 if (r < 0)
1290 return bus_log_create_error(r);
1291
1292 return 1;
1293 }
1294
89ada3ba
YW
1295 return 0;
1296}
f6c66be1 1297
89ada3ba 1298static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
f6c66be1 1299
89ada3ba 1300 if (streq(field, "KillMode"))
f6c66be1 1301
89ada3ba 1302 return bus_append_string(m, field, eq);
f6c66be1 1303
89ada3ba 1304 if (STR_IN_SET(field, "SendSIGHUP", "SendSIGKILL"))
f6c66be1 1305
89ada3ba 1306 return bus_append_parse_boolean(m, field, eq);
f6c66be1 1307
c87700a1 1308 if (STR_IN_SET(field, "KillSignal", "FinalKillSignal", "WatchdogSignal"))
89ada3ba 1309
29a3db75 1310 return bus_append_signal_from_string(m, field, eq);
89ada3ba
YW
1311
1312 return 0;
1313}
1314
3d63c749 1315static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
89ada3ba 1316
3d63c749 1317 if (STR_IN_SET(field, "What", "Where", "Options", "Type"))
89ada3ba
YW
1318
1319 return bus_append_string(m, field, eq);
1320
3d63c749
YW
1321 if (streq(field, "TimeoutSec"))
1322
1323 return bus_append_parse_sec_rename(m, field, eq);
1324
1325 if (streq(field, "DirectoryMode"))
1326
1327 return bus_append_parse_mode(m, field, eq);
1328
1329 if (STR_IN_SET(field, "SloppyOptions", "LazyUnmount", "ForceUnmount"))
1330
1331 return bus_append_parse_boolean(m, field, eq);
1332
1333 return 0;
1334}
1335
1336static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
1337 int r;
1338
89ada3ba
YW
1339 if (streq(field, "MakeDirectory"))
1340
1341 return bus_append_parse_boolean(m, field, eq);
1342
1343 if (streq(field, "DirectoryMode"))
1344
1345 return bus_append_parse_mode(m, field, eq);
1346
3d63c749
YW
1347 if (STR_IN_SET(field,
1348 "PathExists", "PathExistsGlob", "PathChanged",
1349 "PathModified", "DirectoryNotEmpty")) {
1350
1351 if (isempty(eq))
1352 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
1353 else
1354 r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
1355 if (r < 0)
1356 return bus_log_create_error(r);
1357
1358 return 1;
1359 }
1360
89ada3ba
YW
1361 return 0;
1362}
1363
1364static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 1365 int r;
89ada3ba 1366
3d63c749
YW
1367 if (STR_IN_SET(field,
1368 "PIDFile", "Type", "Restart", "BusName", "NotifyAccess",
afcfaa69 1369 "USBFunctionDescriptors", "USBFunctionStrings", "OOMPolicy"))
89ada3ba
YW
1370
1371 return bus_append_string(m, field, eq);
f6c66be1 1372
3d63c749 1373 if (STR_IN_SET(field, "PermissionsStartOnly", "RootDirectoryStartOnly", "RemainAfterExit", "GuessMainPID"))
89ada3ba
YW
1374
1375 return bus_append_parse_boolean(m, field, eq);
1376
3d63c749 1377 if (STR_IN_SET(field, "RestartSec", "TimeoutStartSec", "TimeoutStopSec", "RuntimeMaxSec", "WatchdogSec"))
89ada3ba
YW
1378
1379 return bus_append_parse_sec_rename(m, field, eq);
1380
3d63c749
YW
1381 if (streq(field, "TimeoutSec")) {
1382
1383 r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1384 if (r < 0)
1385 return r;
1386
1387 return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1388 }
1389
89ada3ba
YW
1390 if (streq(field, "FileDescriptorStoreMax"))
1391
1392 return bus_append_safe_atou(m, field, eq);
1393
1394 if (STR_IN_SET(field,
1395 "ExecStartPre", "ExecStart", "ExecStartPost",
b3d59367 1396 "ExecStartPreEx", "ExecStartEx", "ExecStartPostEx",
89ada3ba 1397 "ExecReload", "ExecStop", "ExecStopPost"))
89ada3ba
YW
1398 return bus_append_exec_command(m, field, eq);
1399
3d63c749
YW
1400 if (STR_IN_SET(field, "RestartPreventExitStatus", "RestartForceExitStatus", "SuccessExitStatus")) {
1401 _cleanup_free_ int *status = NULL, *signal = NULL;
1402 size_t sz_status = 0, sz_signal = 0;
1403 const char *p;
1404
1405 for (p = eq;;) {
1406 _cleanup_free_ char *word = NULL;
1407 int val;
1408
1409 r = extract_first_word(&p, &word, NULL, EXTRACT_QUOTES);
1410 if (r == 0)
1411 break;
1412 if (r == -ENOMEM)
1413 return log_oom();
1414 if (r < 0)
1415 return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
1416
1417 r = safe_atoi(word, &val);
1418 if (r < 0) {
29a3db75 1419 val = signal_from_string(word);
3d63c749
YW
1420 if (val < 0)
1421 return log_error_errno(r, "Invalid status or signal %s in %s: %m", word, field);
1422
aa484f35 1423 signal = reallocarray(signal, sz_signal + 1, sizeof(int));
3d63c749
YW
1424 if (!signal)
1425 return log_oom();
1426
1427 signal[sz_signal++] = val;
1428 } else {
aa484f35 1429 status = reallocarray(status, sz_status + 1, sizeof(int));
3d63c749
YW
1430 if (!status)
1431 return log_oom();
1432
1433 status[sz_status++] = val;
1434 }
1435 }
1436
1437 r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
1438 if (r < 0)
1439 return bus_log_create_error(r);
1440
1441 r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
1442 if (r < 0)
1443 return bus_log_create_error(r);
1444
1445 r = sd_bus_message_open_container(m, 'v', "(aiai)");
1446 if (r < 0)
1447 return bus_log_create_error(r);
1448
1449 r = sd_bus_message_open_container(m, 'r', "aiai");
1450 if (r < 0)
1451 return bus_log_create_error(r);
1452
1453 r = sd_bus_message_append_array(m, 'i', status, sz_status);
1454 if (r < 0)
1455 return bus_log_create_error(r);
1456
1457 r = sd_bus_message_append_array(m, 'i', signal, sz_signal);
1458 if (r < 0)
1459 return bus_log_create_error(r);
1460
1461 r = sd_bus_message_close_container(m);
1462 if (r < 0)
1463 return bus_log_create_error(r);
1464
1465 r = sd_bus_message_close_container(m);
1466 if (r < 0)
1467 return bus_log_create_error(r);
1468
1469 r = sd_bus_message_close_container(m);
1470 if (r < 0)
1471 return bus_log_create_error(r);
1472
1473 return 1;
1474 }
1475
89ada3ba
YW
1476 return 0;
1477}
1478
1479static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
1480 int r;
1481
1482 if (STR_IN_SET(field,
1483 "Accept", "Writable", "KeepAlive", "NoDelay", "FreeBind", "Transparent", "Broadcast",
1484 "PassCredentials", "PassSecurity", "ReusePort", "RemoveOnStop", "SELinuxContextFromNet"))
1485
1486 return bus_append_parse_boolean(m, field, eq);
1487
1488 if (STR_IN_SET(field, "Priority", "IPTTL", "Mark"))
1489
1490 return bus_append_safe_atoi(m, field, eq);
1491
1492 if (streq(field, "IPTOS"))
1493
1494 return bus_append_ip_tos_from_string(m, field, eq);
1495
1496 if (STR_IN_SET(field, "Backlog", "MaxConnections", "MaxConnectionsPerSource", "KeepAliveProbes", "TriggerLimitBurst"))
1497
1498 return bus_append_safe_atou(m, field, eq);
1499
1500 if (STR_IN_SET(field, "SocketMode", "DirectoryMode"))
1501
1502 return bus_append_parse_mode(m, field, eq);
1503
1504 if (STR_IN_SET(field, "MessageQueueMaxMessages", "MessageQueueMessageSize"))
1505
1506 return bus_append_safe_atoi64(m, field, eq);
1507
1508 if (STR_IN_SET(field, "TimeoutSec", "KeepAliveTimeSec", "KeepAliveIntervalSec", "DeferAcceptSec", "TriggerLimitIntervalSec"))
1509
1510 return bus_append_parse_sec_rename(m, field, eq);
1511
1512 if (STR_IN_SET(field, "ReceiveBuffer", "SendBuffer", "PipeSize"))
1513
b48e508d 1514 return bus_append_parse_size(m, field, eq, 1024);
89ada3ba
YW
1515
1516 if (STR_IN_SET(field, "ExecStartPre", "ExecStartPost", "ExecReload", "ExecStopPost"))
1517
1518 return bus_append_exec_command(m, field, eq);
1519
1520 if (STR_IN_SET(field,
1521 "SmackLabel", "SmackLabelIPIn", "SmackLabelIPOut", "TCPCongestion",
1522 "BindToDevice", "BindIPv6Only", "FileDescriptorName",
1523 "SocketUser", "SocketGroup"))
1524
1525 return bus_append_string(m, field, eq);
1526
1527 if (streq(field, "Symlinks"))
1528
1529 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
1530
e045e325 1531 if (streq(field, "SocketProtocol"))
89ada3ba 1532
d2b42d63 1533 return bus_append_parse_ip_protocol(m, field, eq);
89ada3ba
YW
1534
1535 if (STR_IN_SET(field,
1536 "ListenStream", "ListenDatagram", "ListenSequentialPacket", "ListenNetlink",
1537 "ListenSpecial", "ListenMessageQueue", "ListenFIFO", "ListenUSBFunction")) {
1538
3d63c749
YW
1539 if (isempty(eq))
1540 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
1541 else
81b1dc27 1542 r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
f6c66be1 1543 if (r < 0)
89ada3ba
YW
1544 return bus_log_create_error(r);
1545
1546 return 1;
1547 }
1548
1549 return 0;
1550}
1551static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749 1552 int r;
89ada3ba 1553
efebb613
LP
1554 if (STR_IN_SET(field, "WakeSystem", "RemainAfterElapse", "Persistent",
1555 "OnTimezoneChange", "OnClockChange"))
89ada3ba
YW
1556
1557 return bus_append_parse_boolean(m, field, eq);
1558
3d63c749
YW
1559 if (STR_IN_SET(field, "AccuracySec", "RandomizedDelaySec"))
1560
1561 return bus_append_parse_sec_rename(m, field, eq);
1562
89ada3ba
YW
1563 if (STR_IN_SET(field,
1564 "OnActiveSec", "OnBootSec", "OnStartupSec",
3d63c749 1565 "OnUnitActiveSec","OnUnitInactiveSec")) {
89ada3ba 1566
3d63c749
YW
1567 if (isempty(eq))
1568 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
1569 else {
1570 usec_t t;
1571 r = parse_sec(eq, &t);
1572 if (r < 0)
1573 return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
89ada3ba 1574
3d63c749
YW
1575 r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
1576 }
1577 if (r < 0)
1578 return bus_log_create_error(r);
89ada3ba 1579
3d63c749
YW
1580 return 1;
1581 }
1582
1583 if (streq(field, "OnCalendar")) {
1584
1585 if (isempty(eq))
1586 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
1587 else
1588 r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
1589 if (r < 0)
1590 return bus_log_create_error(r);
1591
1592 return 1;
1593 }
89ada3ba
YW
1594
1595 return 0;
1596}
1597
1598static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
3d63c749
YW
1599 ConditionType t = _CONDITION_TYPE_INVALID;
1600 bool is_condition = false;
1601 int r;
f6c66be1 1602
3d63c749
YW
1603 if (STR_IN_SET(field,
1604 "Description", "SourcePath", "OnFailureJobMode",
1605 "JobTimeoutAction", "JobTimeoutRebootArgument",
1606 "StartLimitAction", "FailureAction", "SuccessAction",
1607 "RebootArgument", "CollectMode"))
89ada3ba
YW
1608
1609 return bus_append_string(m, field, eq);
1610
3d63c749
YW
1611 if (STR_IN_SET(field,
1612 "StopWhenUnneeded", "RefuseManualStart", "RefuseManualStop",
1613 "AllowIsolate", "IgnoreOnIsolate", "DefaultDependencies"))
89ada3ba
YW
1614
1615 return bus_append_parse_boolean(m, field, eq);
1616
3d63c749
YW
1617 if (STR_IN_SET(field, "JobTimeoutSec", "JobRunningTimeoutSec", "StartLimitIntervalSec"))
1618
1619 return bus_append_parse_sec_rename(m, field, eq);
1620
1621 if (streq(field, "StartLimitBurst"))
1622
1623 return bus_append_safe_atou(m, field, eq);
1624
7af67e9a
LP
1625 if (STR_IN_SET(field, "SuccessActionExitStatus", "FailureActionExitStatus")) {
1626
1627 if (isempty(eq))
1628 r = sd_bus_message_append(m, "(sv)", field, "i", -1);
1629 else {
1630 uint8_t u;
1631
1632 r = safe_atou8(eq, &u);
1633 if (r < 0)
1634 return log_error_errno(r, "Failed to parse %s=%s", field, eq);
1635
1636 r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
1637 }
1638 if (r < 0)
1639 return bus_log_create_error(r);
1640
1641 return 1;
1642 }
1643
3d63c749
YW
1644 if (unit_dependency_from_string(field) >= 0 ||
1645 STR_IN_SET(field, "Documentation", "RequiresMountsFor"))
89ada3ba 1646
eae194a5 1647 return bus_append_strv(m, field, eq, EXTRACT_QUOTES);
89ada3ba 1648
3d63c749
YW
1649 t = condition_type_from_string(field);
1650 if (t >= 0)
1651 is_condition = true;
1652 else
1653 t = assert_type_from_string(field);
1654 if (t >= 0) {
1655 if (isempty(eq))
1656 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
1657 else {
1658 const char *p = eq;
1659 int trigger, negate;
1660
1661 trigger = *p == '|';
1662 if (trigger)
1663 p++;
1664
1665 negate = *p == '!';
1666 if (negate)
1667 p++;
1668
1669 r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
1670 field, trigger, negate, p);
1671 }
1672 if (r < 0)
1673 return bus_log_create_error(r);
1674
1675 return 1;
1676 }
1677
89ada3ba
YW
1678 return 0;
1679}
1680
1681int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
1682 const char *eq, *field;
1683 int r;
1684
1685 assert(m);
1686 assert(assignment);
1687
1688 eq = strchr(assignment, '=');
baaa35ad
ZJS
1689 if (!eq)
1690 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1691 "Not an assignment: %s", assignment);
89ada3ba
YW
1692
1693 field = strndupa(assignment, eq - assignment);
1694 eq++;
1695
1696 switch (t) {
1697 case UNIT_SERVICE:
1698 r = bus_append_cgroup_property(m, field, eq);
1699 if (r != 0)
f6c66be1
LP
1700 return r;
1701
89ada3ba
YW
1702 r = bus_append_execute_property(m, field, eq);
1703 if (r != 0)
1704 return r;
f6c66be1 1705
89ada3ba
YW
1706 r = bus_append_kill_property(m, field, eq);
1707 if (r != 0)
1708 return r;
f6c66be1 1709
89ada3ba
YW
1710 r = bus_append_service_property(m, field, eq);
1711 if (r != 0)
1712 return r;
1713 break;
f6c66be1 1714
89ada3ba
YW
1715 case UNIT_SOCKET:
1716 r = bus_append_cgroup_property(m, field, eq);
1717 if (r != 0)
1718 return r;
f6c66be1 1719
89ada3ba
YW
1720 r = bus_append_execute_property(m, field, eq);
1721 if (r != 0)
1722 return r;
f6c66be1 1723
89ada3ba
YW
1724 r = bus_append_kill_property(m, field, eq);
1725 if (r != 0)
1726 return r;
f6c66be1 1727
89ada3ba
YW
1728 r = bus_append_socket_property(m, field, eq);
1729 if (r != 0)
f6c66be1 1730 return r;
89ada3ba 1731 break;
f6c66be1 1732
89ada3ba
YW
1733 case UNIT_TIMER:
1734 r = bus_append_timer_property(m, field, eq);
1735 if (r != 0)
1736 return r;
1737 break;
f6c66be1 1738
89ada3ba
YW
1739 case UNIT_PATH:
1740 r = bus_append_path_property(m, field, eq);
1741 if (r != 0)
1742 return r;
1743 break;
268833ed 1744
89ada3ba
YW
1745 case UNIT_SLICE:
1746 r = bus_append_cgroup_property(m, field, eq);
1747 if (r != 0)
1748 return r;
1749 break;
268833ed 1750
89ada3ba 1751 case UNIT_SCOPE:
3d63c749
YW
1752
1753 if (streq(field, "TimeoutStopSec"))
1754 return bus_append_parse_sec_rename(m, field, eq);
1755
89ada3ba
YW
1756 r = bus_append_cgroup_property(m, field, eq);
1757 if (r != 0)
1758 return r;
268833ed 1759
89ada3ba
YW
1760 r = bus_append_kill_property(m, field, eq);
1761 if (r != 0)
1762 return r;
1763 break;
535e0d19 1764
89ada3ba 1765 case UNIT_MOUNT:
3d63c749
YW
1766 r = bus_append_cgroup_property(m, field, eq);
1767 if (r != 0)
1768 return r;
1769
1770 r = bus_append_execute_property(m, field, eq);
1771 if (r != 0)
1772 return r;
1773
1774 r = bus_append_kill_property(m, field, eq);
1775 if (r != 0)
1776 return r;
1777
1778 r = bus_append_mount_property(m, field, eq);
1779 if (r != 0)
1780 return r;
1781
1782 break;
1783
89ada3ba 1784 case UNIT_AUTOMOUNT:
3d63c749
YW
1785 r = bus_append_automount_property(m, field, eq);
1786 if (r != 0)
1787 return r;
1788
89ada3ba 1789 break;
535e0d19 1790
89ada3ba
YW
1791 case UNIT_TARGET:
1792 case UNIT_DEVICE:
1793 case UNIT_SWAP:
baaa35ad
ZJS
1794 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1795 "Not supported unit type");
535e0d19 1796
89ada3ba 1797 default:
baaa35ad
ZJS
1798 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1799 "Invalid unit type");
20b16441
LP
1800 }
1801
89ada3ba
YW
1802 r = bus_append_unit_property(m, field, eq);
1803 if (r != 0)
1804 return r;
20b16441 1805
baaa35ad
ZJS
1806 return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
1807 "Unknown assignment: %s", assignment);
20b16441
LP
1808}
1809
89ada3ba 1810int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
8673cf13
LP
1811 char **i;
1812 int r;
1813
1814 assert(m);
1815
1816 STRV_FOREACH(i, l) {
89ada3ba 1817 r = bus_append_unit_property_assignment(m, t, *i);
8673cf13
LP
1818 if (r < 0)
1819 return r;
1820 }
1821
1822 return 0;
1823}
1824
da6053d0 1825int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet, UnitFileChange **changes, size_t *n_changes) {
20b16441
LP
1826 const char *type, *path, *source;
1827 int r;
1828
acc0269c
CH
1829 /* changes is dereferenced when calling unit_file_dump_changes() later,
1830 * so we have to make sure this is not NULL. */
1831 assert(changes);
1832 assert(n_changes);
1833
20b16441
LP
1834 r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
1835 if (r < 0)
1836 return bus_log_parse_error(r);
1837
1838 while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
1839 /* We expect only "success" changes to be sent over the bus.
1840 Hence, reject anything negative. */
1841 UnitFileChangeType ch = unit_file_change_type_from_string(type);
1842
1843 if (ch < 0) {
1844 log_notice("Manager reported unknown change type \"%s\" for path \"%s\", ignoring.", type, path);
1845 continue;
1846 }
1847
1848 r = unit_file_changes_add(changes, n_changes, ch, path, source);
1849 if (r < 0)
1850 return r;
1851 }
1852 if (r < 0)
1853 return bus_log_parse_error(r);
1854
1855 r = sd_bus_message_exit_container(m);
1856 if (r < 0)
1857 return bus_log_parse_error(r);
1858
35d379b2 1859 unit_file_dump_changes(0, NULL, *changes, *n_changes, quiet);
20b16441
LP
1860 return 0;
1861}
1862
bd062910
ZJS
1863int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
1864 _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
1865 _cleanup_free_ char *path = NULL;
1866 int r;
1867
1868 path = unit_dbus_path_from_name(name);
1869 if (!path)
1870 return log_oom();
1871
1872 /* This function warns on it's own, because otherwise it'd be awkward to pass
1873 * the dbus error message around. */
1874
1875 r = sd_bus_get_property_string(
1876 bus,
1877 "org.freedesktop.systemd1",
1878 path,
1879 "org.freedesktop.systemd1.Unit",
1880 "LoadState",
1881 &error,
1882 load_state);
1883 if (r < 0)
1884 return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
1885
1886 return 0;
1887}