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