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