• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

systemd / systemd / 15430420074

03 Jun 2025 10:29PM UTC coverage: 72.013% (-0.03%) from 72.041%
15430420074

push

github

yuwata
doc: fix integration tests guide reference

299598 of 416033 relevant lines covered (72.01%)

700977.9 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

60.63
/src/shared/bus-unit-util.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <paths.h>
4
#include <sys/mount.h>
5

6
#include "sd-bus.h"
7

8
#include "alloc-util.h"
9
#include "bus-common-errors.h"
10
#include "bus-error.h"
11
#include "bus-locator.h"
12
#include "bus-unit-util.h"
13
#include "bus-util.h"
14
#include "cap-list.h"
15
#include "cgroup-setup.h"
16
#include "cgroup-util.h"
17
#include "condition.h"
18
#include "constants.h"
19
#include "coredump-util.h"
20
#include "cpu-set-util.h"
21
#include "escape.h"
22
#include "exec-util.h"
23
#include "exit-status.h"
24
#include "extract-word.h"
25
#include "firewall-util.h"
26
#include "hexdecoct.h"
27
#include "hostname-util.h"
28
#include "in-addr-util.h"
29
#include "install.h"
30
#include "ioprio-util.h"
31
#include "ip-protocol-list.h"
32
#include "log.h"
33
#include "mountpoint-util.h"
34
#include "nsflags.h"
35
#include "numa-util.h"
36
#include "open-file.h"
37
#include "parse-helpers.h"
38
#include "parse-util.h"
39
#include "path-util.h"
40
#include "percent-util.h"
41
#include "pidref.h"
42
#include "process-util.h"
43
#include "rlimit-util.h"
44
#include "seccomp-util.h"
45
#include "securebits-util.h"
46
#include "signal-util.h"
47
#include "socket-util.h"
48
#include "string-util.h"
49
#include "syslog-util.h"
50
#include "time-util.h"
51
#include "unit-def.h"
52

53
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
11,589✔
54
        assert(message);
11,589✔
55
        assert(u);
11,589✔
56

57
        u->machine = NULL;
11,589✔
58

59
        return sd_bus_message_read(
11,589✔
60
                        message,
61
                        "(ssssssouso)",
62
                        &u->id,
63
                        &u->description,
64
                        &u->load_state,
65
                        &u->active_state,
66
                        &u->sub_state,
67
                        &u->following,
68
                        &u->unit_path,
69
                        &u->job_id,
70
                        &u->job_type,
71
                        &u->job_path);
72
}
73

74
static int warn_deprecated(const char *field, const char *eq) {
×
75
        log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq);
×
76
        return 1;
×
77
}
78

79
#define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
80
        static int bus_append_##parse_func(                             \
81
                        sd_bus_message *m,                              \
82
                        const char *field,                              \
83
                        const char *eq) {                               \
84
                type val;                                               \
85
                int r;                                                  \
86
                                                                        \
87
                r = parse_func(eq, &val);                               \
88
                if (r < 0)                                              \
89
                        return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq); \
90
                                                                        \
91
                r = sd_bus_message_append(m, "(sv)", field,             \
92
                                          bus_type, (cast_type) val);   \
93
                if (r < 0)                                              \
94
                        return bus_log_create_error(r);                 \
95
                                                                        \
96
                return 1;                                               \
97
        }
98

99
#define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func)                   \
100
        static int bus_append_##parse_func(                             \
101
                        sd_bus_message *m,                              \
102
                        const char *field,                              \
103
                        const char *eq) {                               \
104
                int r;                                                  \
105
                                                                        \
106
                r = parse_func(eq);                                     \
107
                if (r < 0)                                              \
108
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s: %s", field, eq);                                 \
109
                                                                        \
110
                r = sd_bus_message_append(m, "(sv)", field,             \
111
                                          bus_type, (int32_t) r);       \
112
                if (r < 0)                                              \
113
                        return bus_log_create_error(r);                 \
114
                                                                        \
115
                return 1;                                               \
116
        }
117

118
DEFINE_BUS_APPEND_PARSE("b", parse_boolean);
403✔
119
DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
×
120
DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
×
121
DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
×
122
DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
1✔
123
DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
×
124
DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
×
125
DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
×
126
DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
2✔
127
DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
×
128
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
×
129
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
×
130
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
1✔
131
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
×
132
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
×
133
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
×
134
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string);
1✔
135
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
2✔
136
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
22✔
137
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
2✔
138
DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
×
139
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
2✔
140

141
static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
610✔
142
        int r;
610✔
143

144
        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
610✔
145
        if (r < 0)
610✔
146
                return bus_log_create_error(r);
×
147

148
        return 1;
149
}
150

151
static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
404✔
152
        int r;
404✔
153

154
        assert(m);
404✔
155
        assert(field);
404✔
156

157
        r = sd_bus_message_open_container(m, 'r', "sv");
404✔
158
        if (r < 0)
404✔
159
                return bus_log_create_error(r);
×
160

161
        r = sd_bus_message_append_basic(m, 's', field);
404✔
162
        if (r < 0)
404✔
163
                return bus_log_create_error(r);
×
164

165
        r = sd_bus_message_open_container(m, 'v', "as");
404✔
166
        if (r < 0)
404✔
167
                return bus_log_create_error(r);
×
168

169
        r = sd_bus_message_open_container(m, 'a', "s");
404✔
170
        if (r < 0)
404✔
171
                return bus_log_create_error(r);
×
172

173
        for (const char *p = eq;;) {
404✔
174
                _cleanup_free_ char *word = NULL;
100✔
175

176
                r = extract_first_word(&p, &word, separator, flags);
504✔
177
                if (r == -ENOMEM)
504✔
178
                        return log_oom();
×
179
                if (r < 0)
504✔
180
                        return log_error_errno(r, "Invalid syntax: %s", eq);
×
181
                if (r == 0)
504✔
182
                        break;
183

184
                r = sd_bus_message_append_basic(m, 's', word);
100✔
185
                if (r < 0)
100✔
186
                        return bus_log_create_error(r);
×
187
        }
188

189
        r = sd_bus_message_close_container(m);
404✔
190
        if (r < 0)
404✔
191
                return bus_log_create_error(r);
×
192

193
        r = sd_bus_message_close_container(m);
404✔
194
        if (r < 0)
404✔
195
                return bus_log_create_error(r);
×
196

197
        r = sd_bus_message_close_container(m);
404✔
198
        if (r < 0)
404✔
199
                return bus_log_create_error(r);
×
200

201
        return 1;
202
}
203

204
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
18✔
205
        int r;
18✔
206

207
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
18✔
208
        if (r < 0)
18✔
209
                return bus_log_create_error(r);
×
210

211
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
18✔
212
        if (r < 0)
18✔
213
                return bus_log_create_error(r);
×
214

215
        r = sd_bus_message_open_container(m, 'v', "ay");
18✔
216
        if (r < 0)
18✔
217
                return bus_log_create_error(r);
×
218

219
        r = sd_bus_message_append_array(m, 'y', buf, n);
18✔
220
        if (r < 0)
18✔
221
                return bus_log_create_error(r);
×
222

223
        r = sd_bus_message_close_container(m);
18✔
224
        if (r < 0)
18✔
225
                return bus_log_create_error(r);
×
226

227
        r = sd_bus_message_close_container(m);
18✔
228
        if (r < 0)
18✔
229
                return bus_log_create_error(r);
×
230

231
        return 1;
232
}
233

234
static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
8✔
235
        char *n;
8✔
236
        usec_t t;
8✔
237
        size_t l;
8✔
238
        int r;
8✔
239

240
        r = parse_sec(eq, &t);
8✔
241
        if (r < 0)
8✔
242
                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
×
243

244
        l = strlen(field);
8✔
245
        n = newa(char, l + 2);
8✔
246
        /* Change suffix Sec → USec */
247
        strcpy(mempcpy(n, field, l - 3), "USec");
8✔
248

249
        r = sd_bus_message_append(m, "(sv)", n, "t", t);
8✔
250
        if (r < 0)
8✔
251
                return bus_log_create_error(r);
×
252

253
        return 1;
254
}
255

256
static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
8✔
257
        uint64_t v;
8✔
258
        int r;
8✔
259

260
        r = parse_size(eq, base, &v);
8✔
261
        if (r < 0)
8✔
262
                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
×
263

264
        r = sd_bus_message_append(m, "(sv)", field, "t", v);
8✔
265
        if (r < 0)
8✔
266
                return bus_log_create_error(r);
×
267

268
        return 1;
269
}
270

271
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
43✔
272
        bool explicit_path = false, done = false, ambient_hack = false;
43✔
273
        _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
43✔
274
        _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
43✔
275
        ExecCommandFlags flags = 0;
43✔
276
        bool is_ex_prop = endswith(field, "Ex");
43✔
277
        int r;
62✔
278

279
        do {
62✔
280
                switch (*eq) {
62✔
281

282
                case '-':
2✔
283
                        if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
2✔
284
                                done = true;
285
                        else {
286
                                flags |= EXEC_COMMAND_IGNORE_FAILURE;
2✔
287
                                eq++;
2✔
288
                        }
289
                        break;
290

291
                case '@':
1✔
292
                        if (explicit_path)
1✔
293
                                done = true;
294
                        else {
295
                                explicit_path = true;
1✔
296
                                eq++;
1✔
297
                        }
298
                        break;
299

300
                case ':':
14✔
301
                        if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
14✔
302
                                done = true;
303
                        else {
304
                                flags |= EXEC_COMMAND_NO_ENV_EXPAND;
14✔
305
                                eq++;
14✔
306
                        }
307
                        break;
308

309
                case '+':
×
310
                        if ((flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID)) != 0 || ambient_hack)
×
311
                                done = true;
312
                        else {
313
                                flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
×
314
                                eq++;
×
315
                        }
316
                        break;
317

318
                case '!':
×
319
                        if (FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED) || ambient_hack)
×
320
                                done = true;
321
                        else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
×
322
                                /* Compatibility with the old !! ambient caps hack (removed in v258). Since
323
                                 * we don't support that anymore and !! was a noop on non-supporting systems,
324
                                 * we'll just turn off the EXEC_COMMAND_NO_SETUID flag again and be done with
325
                                 * it. */
326
                                flags &= ~EXEC_COMMAND_NO_SETUID;
×
327
                                eq++;
×
328
                                ambient_hack = true;
×
329

330
                                log_notice("!! modifier for %s= fields is no longer supported and is now ignored.", field);
×
331
                        } else {
332
                                flags |= EXEC_COMMAND_NO_SETUID;
×
333
                                eq++;
×
334
                        }
335
                        break;
336

337
                case '|':
2✔
338
                        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL))
2✔
339
                                done = true;
340
                        else {
341
                                flags |= EXEC_COMMAND_VIA_SHELL;
2✔
342
                                eq++;
2✔
343
                        }
344
                        break;
345

346
                default:
347
                        done = true;
348
                }
349
        } while (!done);
62✔
350

351
        if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL))) {
43✔
352
                /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
353
                is_ex_prop = true;
9✔
354

355
                upgraded_name = strjoin(field, "Ex");
9✔
356
                if (!upgraded_name)
9✔
357
                        return log_oom();
×
358
                field = upgraded_name;
359
        }
360

361
        if (is_ex_prop) {
34✔
362
                r = exec_command_flags_to_strv(flags, &ex_opts);
16✔
363
                if (r < 0)
16✔
364
                        return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
×
365
        }
366

367
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
43✔
368
                path = strdup(_PATH_BSHELL);
2✔
369
                if (!path)
2✔
370
                        return log_oom();
×
371

372
        } else if (explicit_path) {
41✔
373
                r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
×
374
                if (r < 0)
×
375
                        return log_error_errno(r, "Failed to parse path: %m");
×
376
                if (r == 0)
×
377
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No executable path specified, refusing.");
×
378
                if (isempty(eq))
×
379
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got empty command line, refusing.");
×
380
        }
381

382
        r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
43✔
383
        if (r < 0)
43✔
384
                return log_error_errno(r, "Failed to parse command line: %m");
×
385

386
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
43✔
387
                r = strv_prepend(&l, explicit_path ? "-sh" : "sh");
3✔
388
                if (r < 0)
2✔
389
                        return log_oom();
×
390
        }
391

392
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
43✔
393
        if (r < 0)
43✔
394
                return bus_log_create_error(r);
×
395

396
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
43✔
397
        if (r < 0)
43✔
398
                return bus_log_create_error(r);
×
399

400
        r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
70✔
401
        if (r < 0)
43✔
402
                return bus_log_create_error(r);
×
403

404
        r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
70✔
405
        if (r < 0)
43✔
406
                return bus_log_create_error(r);
×
407

408
        if (!strv_isempty(l)) {
43✔
409

410
                r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
70✔
411
                if (r < 0)
43✔
412
                        return bus_log_create_error(r);
×
413

414
                r = sd_bus_message_append(m, "s", path ?: l[0]);
43✔
415
                if (r < 0)
43✔
416
                        return bus_log_create_error(r);
×
417

418
                r = sd_bus_message_append_strv(m, l);
43✔
419
                if (r < 0)
43✔
420
                        return bus_log_create_error(r);
×
421

422
                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));
43✔
423
                if (r < 0)
43✔
424
                        return bus_log_create_error(r);
×
425

426
                r = sd_bus_message_close_container(m);
43✔
427
                if (r < 0)
43✔
428
                        return bus_log_create_error(r);
×
429
        }
430

431
        r = sd_bus_message_close_container(m);
43✔
432
        if (r < 0)
43✔
433
                return bus_log_create_error(r);
×
434

435
        r = sd_bus_message_close_container(m);
43✔
436
        if (r < 0)
43✔
437
                return bus_log_create_error(r);
×
438

439
        r = sd_bus_message_close_container(m);
43✔
440
        if (r < 0)
43✔
441
                return bus_log_create_error(r);
×
442

443
        return 1;
444
}
445

446
static int bus_append_open_file(sd_bus_message *m, const char *field, const char *eq) {
5✔
447
        _cleanup_(open_file_freep) OpenFile *of = NULL;
5✔
448
        int r;
5✔
449

450
        assert(m);
5✔
451

452
        r = open_file_parse(eq, &of);
5✔
453
        if (r < 0)
5✔
454
                return log_error_errno(r, "Failed to parse OpenFile= setting: %m");
×
455

456
        r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
5✔
457
        if (r < 0)
5✔
458
                return bus_log_create_error(r);
×
459

460
        return 1;
461
}
462

463
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
×
464
        int r;
×
465

466
        assert(m);
×
467
        assert(prefix);
×
468

469
        r = sd_bus_message_open_container(m, 'r', "iayu");
×
470
        if (r < 0)
×
471
                return r;
472

473
        r = sd_bus_message_append(m, "i", family);
×
474
        if (r < 0)
×
475
                return r;
476

477
        r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
×
478
        if (r < 0)
×
479
                return r;
480

481
        r = sd_bus_message_append(m, "u", prefixlen);
×
482
        if (r < 0)
×
483
                return r;
484

485
        return sd_bus_message_close_container(m);
×
486
}
487

488
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
2✔
489
        int r;
2✔
490

491
        assert(m);
2✔
492
        assert(field);
2✔
493
        assert(eq);
2✔
494

495
        if (isempty(eq)) {
2✔
496
                r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
×
497
                if (r < 0)
×
498
                        return bus_log_create_error(r);
×
499

500
                return 1;
501
        }
502

503
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
504
        if (r < 0)
2✔
505
                return bus_log_create_error(r);
×
506

507
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
508
        if (r < 0)
2✔
509
                return bus_log_create_error(r);
×
510

511
        r = sd_bus_message_open_container(m, 'v', "a(iiss)");
2✔
512
        if (r < 0)
2✔
513
                return bus_log_create_error(r);
×
514

515
        r = sd_bus_message_open_container(m, 'a', "(iiss)");
2✔
516
        if (r < 0)
2✔
517
                return bus_log_create_error(r);
×
518

519
        for (const char *p = eq;;) {
2✔
520
                _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
4✔
521
                const char *q = NULL;
6✔
522
                int source, nfproto;
6✔
523

524
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
6✔
525
                if (r == -ENOMEM)
6✔
526
                        return log_oom();
×
527
                if (r < 0)
6✔
528
                        return log_error_errno(r, "Failed to parse %s: %m", field);
×
529
                if (r == 0)
6✔
530
                        break;
531
                if (isempty(tuple))
4✔
532
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
533

534
                q = tuple;
4✔
535
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
4✔
536
                if (r == -ENOMEM)
4✔
537
                        return log_oom();
×
538
                if (r != 4 || !isempty(q))
4✔
539
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
540

541
                assert(source_str);
4✔
542
                assert(nfproto_str);
4✔
543
                assert(table);
4✔
544
                assert(set);
4✔
545

546
                source = nft_set_source_from_string(source_str);
4✔
547
                if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
4✔
548
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
549

550
                nfproto = nfproto_from_string(nfproto_str);
4✔
551
                if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set))
4✔
552
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
553

554
                r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
4✔
555
                if (r < 0)
4✔
556
                        return bus_log_create_error(r);
×
557
        }
558
        r = sd_bus_message_close_container(m);
2✔
559
        if (r < 0)
2✔
560
                return bus_log_create_error(r);
×
561

562
        r = sd_bus_message_close_container(m);
2✔
563
        if (r < 0)
2✔
564
                return bus_log_create_error(r);
×
565

566
        r = sd_bus_message_close_container(m);
2✔
567
        if (r < 0)
2✔
568
                return bus_log_create_error(r);
×
569

570
        return 1;
571
}
572

573
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
3,204✔
574
        int r;
3,204✔
575

576
        if (STR_IN_SET(field, "DevicePolicy",
3,204✔
577
                              "Slice",
578
                              "ManagedOOMSwap",
579
                              "ManagedOOMMemoryPressure",
580
                              "ManagedOOMPreference",
581
                              "MemoryPressureWatch",
582
                              "DelegateSubgroup"))
583
                return bus_append_string(m, field, eq);
17✔
584

585
        if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
3,187✔
586
                r = parse_permyriad(eq);
×
587
                if (r < 0)
×
588
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
589

590
                /* Pass around scaled to 2^32-1 == 100% */
591
                r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
592
                if (r < 0)
×
593
                        return bus_log_create_error(r);
×
594

595
                return 1;
596
        }
597

598
        if (STR_IN_SET(field, "MemoryAccounting",
3,187✔
599
                              "MemoryZSwapWriteback",
600
                              "IOAccounting",
601
                              "TasksAccounting",
602
                              "IPAccounting",
603
                              "CoredumpReceive"))
604
                return bus_append_parse_boolean(m, field, eq);
8✔
605

606
        if (STR_IN_SET(field, "CPUWeight",
3,179✔
607
                              "StartupCPUWeight"))
608
                return bus_append_cg_cpu_weight_parse(m, field, eq);
×
609

610
        if (STR_IN_SET(field, "IOWeight",
3,179✔
611
                              "StartupIOWeight"))
612
                return bus_append_cg_weight_parse(m, field, eq);
×
613

614
        if (STR_IN_SET(field, "AllowedCPUs",
3,179✔
615
                              "StartupAllowedCPUs",
616
                              "AllowedMemoryNodes",
617
                              "StartupAllowedMemoryNodes")) {
618
                _cleanup_(cpu_set_reset) CPUSet cpuset = {};
×
619
                _cleanup_free_ uint8_t *array = NULL;
×
620
                size_t allocated;
×
621

622
                r = parse_cpu_set(eq, &cpuset);
×
623
                if (r < 0)
×
624
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
625

626
                r = cpu_set_to_dbus(&cpuset, &array, &allocated);
×
627
                if (r < 0)
×
628
                        return log_error_errno(r, "Failed to serialize CPUSet: %m");
×
629

630
                return bus_append_byte_array(m, field, array, allocated);
×
631
        }
632

633
        if (streq(field, "DisableControllers"))
3,179✔
634
                return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
635

636
        if (streq(field, "Delegate")) {
3,179✔
637
                r = parse_boolean(eq);
345✔
638
                if (r < 0)
345✔
639
                        return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
9✔
640

641
                r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
336✔
642
                if (r < 0)
336✔
643
                        return bus_log_create_error(r);
×
644

645
                return 1;
646
        }
647

648
        if (STR_IN_SET(field, "MemoryMin",
2,834✔
649
                              "DefaultMemoryLow",
650
                              "DefaultMemoryMin",
651
                              "MemoryLow",
652
                              "MemoryHigh",
653
                              "MemoryMax",
654
                              "MemorySwapMax",
655
                              "MemoryZSwapMax",
656
                              "TasksMax")) {
657

658
                if (streq(eq, "infinity")) {
10✔
659
                        r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
×
660
                        if (r < 0)
×
661
                                return bus_log_create_error(r);
10✔
662
                        return 1;
663
                } else if (isempty(eq)) {
10✔
664
                        uint64_t empty_value = STR_IN_SET(field,
×
665
                                                          "DefaultMemoryLow",
666
                                                          "DefaultMemoryMin",
667
                                                          "MemoryLow",
668
                                                          "MemoryMin") ?
669
                                               CGROUP_LIMIT_MIN :
×
670
                                               CGROUP_LIMIT_MAX;
671

672
                        r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
×
673
                        if (r < 0)
×
674
                                return bus_log_create_error(r);
×
675
                        return 1;
676
                }
677

678
                r = parse_permyriad(eq);
10✔
679
                if (r >= 0) {
10✔
680
                        char *n;
×
681

682
                        /* When this is a percentage we'll convert this into a relative value in the range
683
                         * 0…UINT32_MAX and pass it in the MemoryLowScale property (and related ones). This
684
                         * way the physical memory size can be determined server-side. */
685

686
                        n = strjoina(field, "Scale");
×
687
                        r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
688
                        if (r < 0)
×
689
                                return bus_log_create_error(r);
×
690

691
                        return 1;
692
                }
693

694
                if (streq(field, "TasksMax"))
10✔
695
                        return bus_append_safe_atou64(m, field, eq);
2✔
696

697
                return bus_append_parse_size(m, field, eq, 1024);
8✔
698
        }
699

700
        if (streq(field, "CPUQuota")) {
2,824✔
701
                if (isempty(eq))
1✔
702
                        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
×
703
                else {
704
                        r = parse_permyriad_unbounded(eq);
1✔
705
                        if (r == 0)
1✔
706
                                return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small.");
×
707
                        if (r < 0)
1✔
708
                                return log_error_errno(r, "CPU quota '%s' invalid.", eq);
×
709

710
                        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
1✔
711
                }
712

713
                if (r < 0)
1✔
714
                        return bus_log_create_error(r);
×
715

716
                return 1;
717
        }
718

719
        if (streq(field, "CPUQuotaPeriodSec")) {
2,823✔
720
                usec_t u = USEC_INFINITY;
×
721

722
                r = parse_sec_def_infinity(eq, &u);
×
723
                if (r < 0)
×
724
                        return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
×
725

726
                r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
×
727
                if (r < 0)
×
728
                        return bus_log_create_error(r);
×
729

730
                return 1;
731
        }
732

733
        if (streq(field, "DeviceAllow")) {
2,823✔
734
                if (isempty(eq))
6✔
735
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
736
                else {
737
                        const char *path = eq, *rwm = NULL, *e;
6✔
738

739
                        e = strchr(eq, ' ');
6✔
740
                        if (e) {
6✔
741
                                path = strndupa_safe(eq, e - eq);
6✔
742
                                rwm = e+1;
6✔
743
                        }
744

745
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
6✔
746
                }
747

748
                if (r < 0)
6✔
749
                        return bus_log_create_error(r);
×
750

751
                return 1;
752
        }
753

754
        if (cgroup_io_limit_type_from_string(field) >= 0) {
2,817✔
755

756
                if (isempty(eq))
3✔
757
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
758
                else {
759
                        const char *path, *bandwidth, *e;
3✔
760
                        uint64_t bytes;
3✔
761

762
                        e = strchr(eq, ' ');
3✔
763
                        if (!e)
3✔
764
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
765
                                                       "Failed to parse %s value %s.",
766
                                                       field, eq);
767

768
                        path = strndupa_safe(eq, e - eq);
3✔
769
                        bandwidth = e+1;
3✔
770

771
                        if (streq(bandwidth, "infinity"))
3✔
772
                                bytes = CGROUP_LIMIT_MAX;
×
773
                        else {
774
                                r = parse_size(bandwidth, 1000, &bytes);
3✔
775
                                if (r < 0)
3✔
776
                                        return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
×
777
                        }
778

779
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
3✔
780
                }
781

782
                if (r < 0)
3✔
783
                        return bus_log_create_error(r);
×
784

785
                return 1;
786
        }
787

788
        if (streq(field, "IODeviceWeight")) {
2,814✔
789
                if (isempty(eq))
×
790
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
791
                else {
792
                        const char *path, *weight, *e;
×
793
                        uint64_t u;
×
794

795
                        e = strchr(eq, ' ');
×
796
                        if (!e)
×
797
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
798
                                                       "Failed to parse %s value %s.",
799
                                                       field, eq);
800

801
                        path = strndupa_safe(eq, e - eq);
×
802
                        weight = e+1;
×
803

804
                        r = safe_atou64(weight, &u);
×
805
                        if (r < 0)
×
806
                                return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
×
807

808
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
×
809
                }
810

811
                if (r < 0)
×
812
                        return bus_log_create_error(r);
×
813

814
                return 1;
815
        }
816

817
        if (streq(field, "IODeviceLatencyTargetSec")) {
2,814✔
818
                const char *field_usec = "IODeviceLatencyTargetUSec";
×
819

820
                if (isempty(eq))
×
821
                        r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
×
822
                else {
823
                        const char *path, *target, *e;
×
824
                        usec_t usec;
×
825

826
                        e = strchr(eq, ' ');
×
827
                        if (!e)
×
828
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
829
                                                       "Failed to parse %s value %s.",
830
                                                       field, eq);
831

832
                        path = strndupa_safe(eq, e - eq);
×
833
                        target = e+1;
×
834

835
                        r = parse_sec(target, &usec);
×
836
                        if (r < 0)
×
837
                                return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
×
838

839
                        r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
×
840
                }
841

842
                if (r < 0)
×
843
                        return bus_log_create_error(r);
×
844

845
                return 1;
846
        }
847

848
        if (STR_IN_SET(field, "IPAddressAllow",
2,814✔
849
                              "IPAddressDeny")) {
850
                unsigned char prefixlen;
×
851
                union in_addr_union prefix = {};
×
852
                int family;
×
853

854
                if (isempty(eq)) {
×
855
                        r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
×
856
                        if (r < 0)
×
857
                                return bus_log_create_error(r);
×
858

859
                        return 1;
860
                }
861

862
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
863
                if (r < 0)
×
864
                        return bus_log_create_error(r);
×
865

866
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
867
                if (r < 0)
×
868
                        return bus_log_create_error(r);
×
869

870
                r = sd_bus_message_open_container(m, 'v', "a(iayu)");
×
871
                if (r < 0)
×
872
                        return bus_log_create_error(r);
×
873

874
                r = sd_bus_message_open_container(m, 'a', "(iayu)");
×
875
                if (r < 0)
×
876
                        return bus_log_create_error(r);
×
877

878
                if (streq(eq, "any")) {
×
879
                        /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
880

881
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
×
882
                        if (r < 0)
×
883
                                return bus_log_create_error(r);
×
884

885
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
×
886
                        if (r < 0)
×
887
                                return bus_log_create_error(r);
×
888

889
                } else if (is_localhost(eq)) {
×
890
                        /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
891

892
                        prefix.in.s_addr = htobe32(0x7f000000);
×
893
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
×
894
                        if (r < 0)
×
895
                                return bus_log_create_error(r);
×
896

897
                        prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
×
898
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
×
899
                        if (r < 0)
×
900
                                return r;
901

902
                } else if (streq(eq, "link-local")) {
×
903
                        /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
904

905
                        prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
×
906
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
×
907
                        if (r < 0)
×
908
                                return bus_log_create_error(r);
×
909

910
                        prefix.in6 = (struct in6_addr) {
×
911
                                .s6_addr32[0] = htobe32(0xfe800000)
×
912
                        };
913
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
×
914
                        if (r < 0)
×
915
                                return bus_log_create_error(r);
×
916

917
                } else if (streq(eq, "multicast")) {
×
918
                        /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
919

920
                        prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
×
921
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
×
922
                        if (r < 0)
×
923
                                return bus_log_create_error(r);
×
924

925
                        prefix.in6 = (struct in6_addr) {
×
926
                                .s6_addr32[0] = htobe32(0xff000000)
×
927
                        };
928
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
×
929
                        if (r < 0)
×
930
                                return bus_log_create_error(r);
×
931

932
                } else {
933
                        for (;;) {
×
934
                                _cleanup_free_ char *word = NULL;
×
935

936
                                r = extract_first_word(&eq, &word, NULL, 0);
×
937
                                if (r == 0)
×
938
                                        break;
939
                                if (r == -ENOMEM)
×
940
                                        return log_oom();
×
941
                                if (r < 0)
×
942
                                        return log_error_errno(r, "Failed to parse %s: %s", field, eq);
×
943

944
                                r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
×
945
                                if (r < 0)
×
946
                                        return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
×
947

948
                                r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
×
949
                                if (r < 0)
×
950
                                        return bus_log_create_error(r);
×
951
                        }
952
                }
953

954
                r = sd_bus_message_close_container(m);
×
955
                if (r < 0)
×
956
                        return bus_log_create_error(r);
×
957

958
                r = sd_bus_message_close_container(m);
×
959
                if (r < 0)
×
960
                        return bus_log_create_error(r);
×
961

962
                r = sd_bus_message_close_container(m);
×
963
                if (r < 0)
×
964
                        return bus_log_create_error(r);
×
965

966
                return 1;
967
        }
968

969
        if (STR_IN_SET(field, "IPIngressFilterPath",
2,814✔
970
                              "IPEgressFilterPath")) {
971
                if (isempty(eq))
×
972
                        r = sd_bus_message_append(m, "(sv)", field, "as", 0);
×
973
                else
974
                        r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
×
975

976
                if (r < 0)
×
977
                        return bus_log_create_error(r);
×
978

979
                return 1;
980
        }
981

982
        if (streq(field, "BPFProgram")) {
2,814✔
983
                if (isempty(eq))
×
984
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
985
                else {
986
                        _cleanup_free_ char *word = NULL;
×
987

988
                        r = extract_first_word(&eq, &word, ":", 0);
×
989
                        if (r == -ENOMEM)
×
990
                                return log_oom();
×
991
                        if (r < 0)
×
992
                                return log_error_errno(r, "Failed to parse %s: %m", field);
×
993

994
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
×
995
                }
996
                if (r < 0)
×
997
                        return bus_log_create_error(r);
×
998

999
                return 1;
1000
        }
1001

1002
        if (STR_IN_SET(field, "SocketBindAllow",
2,814✔
1003
                              "SocketBindDeny")) {
1004
                if (isempty(eq))
×
1005
                        r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
×
1006
                else {
1007
                        int32_t family, ip_protocol;
×
1008
                        uint16_t nr_ports, port_min;
×
1009

1010
                        r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
×
1011
                        if (r == -ENOMEM)
×
1012
                                return log_oom();
×
1013
                        if (r < 0)
×
1014
                                return log_error_errno(r, "Failed to parse %s", field);
×
1015

1016
                        r = sd_bus_message_append(
×
1017
                                        m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
1018
                }
1019
                if (r < 0)
×
1020
                        return bus_log_create_error(r);
×
1021

1022
                return 1;
1023
        }
1024

1025
        if (streq(field, "MemoryPressureThresholdSec"))
2,814✔
1026
                return bus_append_parse_sec_rename(m, field, eq);
1✔
1027

1028
        if (streq(field, "NFTSet"))
2,813✔
1029
                return bus_append_nft_set(m, field, eq);
2✔
1030

1031
        if (streq(field, "ManagedOOMMemoryPressureDurationSec"))
2,811✔
1032
                /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
1033
                 * means use the default memory pressure duration from oomd.conf. */
1034
                return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
×
1035

1036
        if (STR_IN_SET(field,
2,811✔
1037
                       "MemoryLimit",
1038
                       "CPUShares",
1039
                       "StartupCPUShares",
1040
                       "BlockIOAccounting",
1041
                       "BlockIOWeight",
1042
                       "StartupBlockIOWeight",
1043
                       "BlockIODeviceWeight",
1044
                       "BlockIOReadBandwidth",
1045
                       "BlockIOWriteBandwidth",
1046
                       "CPUAccounting"))
1047
                return warn_deprecated(field, eq);
×
1048

1049
        return 0;
2,811✔
1050
}
1051

1052
static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
1✔
1053
        if (STR_IN_SET(field, "Where",
1✔
1054
                              "ExtraOptions"))
1055
                return bus_append_string(m, field, eq);
×
1056

1057
        if (streq(field, "DirectoryMode"))
1✔
1058
                return bus_append_parse_mode(m, field, eq);
×
1059

1060
        if (streq(field, "TimeoutIdleSec"))
1✔
1061
                return bus_append_parse_sec_rename(m, field, eq);
×
1062

1063
        return 0;
1064
}
1065

1066
static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
2,803✔
1067
        const char *suffix;
2,803✔
1068
        int r;
2,803✔
1069

1070
        if (STR_IN_SET(field, "User",
2,803✔
1071
                              "Group",
1072
                              "UtmpIdentifier",
1073
                              "UtmpMode",
1074
                              "PAMName",
1075
                              "TTYPath",
1076
                              "WorkingDirectory",
1077
                              "RootDirectory",
1078
                              "SyslogIdentifier",
1079
                              "ProtectSystem",
1080
                              "ProtectHome",
1081
                              "PrivateTmpEx",
1082
                              "PrivateUsersEx",
1083
                              "ProtectControlGroupsEx",
1084
                              "SELinuxContext",
1085
                              "RootImage",
1086
                              "RootVerity",
1087
                              "RuntimeDirectoryPreserve",
1088
                              "Personality",
1089
                              "KeyringMode",
1090
                              "ProtectProc",
1091
                              "ProcSubset",
1092
                              "NetworkNamespacePath",
1093
                              "IPCNamespacePath",
1094
                              "LogNamespace",
1095
                              "RootImagePolicy",
1096
                              "MountImagePolicy",
1097
                              "ExtensionImagePolicy",
1098
                              "PrivatePIDs"))
1099
                return bus_append_string(m, field, eq);
461✔
1100

1101
        if (STR_IN_SET(field, "IgnoreSIGPIPE",
2,342✔
1102
                              "TTYVHangup",
1103
                              "TTYReset",
1104
                              "TTYVTDisallocate",
1105
                              "PrivateTmp",
1106
                              "PrivateDevices",
1107
                              "PrivateNetwork",
1108
                              "PrivateUsers",
1109
                              "PrivateMounts",
1110
                              "PrivateIPC",
1111
                              "NoNewPrivileges",
1112
                              "SyslogLevelPrefix",
1113
                              "MemoryDenyWriteExecute",
1114
                              "RestrictRealtime",
1115
                              "DynamicUser",
1116
                              "RemoveIPC",
1117
                              "ProtectKernelTunables",
1118
                              "ProtectKernelModules",
1119
                              "ProtectKernelLogs",
1120
                              "ProtectClock",
1121
                              "ProtectControlGroups",
1122
                              "MountAPIVFS",
1123
                              "BindLogSockets",
1124
                              "CPUSchedulingResetOnFork",
1125
                              "LockPersonality",
1126
                              "ProtectHostname",
1127
                              "MemoryKSM",
1128
                              "RestrictSUIDSGID",
1129
                              "RootEphemeral",
1130
                              "SetLoginEnvironment"))
1131
                return bus_append_parse_boolean(m, field, eq);
387✔
1132

1133
        if (STR_IN_SET(field, "ReadWriteDirectories",
1,955✔
1134
                              "ReadOnlyDirectories",
1135
                              "InaccessibleDirectories",
1136
                              "ReadWritePaths",
1137
                              "ReadOnlyPaths",
1138
                              "InaccessiblePaths",
1139
                              "ExecPaths",
1140
                              "NoExecPaths",
1141
                              "ExecSearchPath",
1142
                              "ExtensionDirectories",
1143
                              "ConfigurationDirectory",
1144
                              "SupplementaryGroups",
1145
                              "SystemCallArchitectures"))
1146
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
30✔
1147

1148
        if (STR_IN_SET(field, "SyslogLevel",
1,925✔
1149
                              "LogLevelMax"))
1150
                return bus_append_log_level_from_string(m, field, eq);
1✔
1151

1152
        if (streq(field, "SyslogFacility"))
1,924✔
1153
                return bus_append_log_facility_unshifted_from_string(m, field, eq);
×
1154

1155
        if (streq(field, "SecureBits"))
1,924✔
1156
                return bus_append_secure_bits_from_string(m, field, eq);
×
1157

1158
        if (streq(field, "CPUSchedulingPolicy"))
1,924✔
1159
                return bus_append_sched_policy_from_string(m, field, eq);
×
1160

1161
        if (STR_IN_SET(field, "CPUSchedulingPriority",
1,924✔
1162
                              "OOMScoreAdjust"))
1163
                return bus_append_safe_atoi(m, field, eq);
1✔
1164

1165
        if (streq(field, "CoredumpFilter"))
1,923✔
1166
                return bus_append_coredump_filter_mask_from_string(m, field, eq);
2✔
1167

1168
        if (streq(field, "Nice"))
1,921✔
1169
                return bus_append_parse_nice(m, field, eq);
×
1170

1171
        if (streq(field, "SystemCallErrorNumber"))
1,921✔
1172
                return bus_append_seccomp_parse_errno_or_action(m, field, eq);
×
1173

1174
        if (streq(field, "IOSchedulingClass"))
1,921✔
1175
                return bus_append_ioprio_class_from_string(m, field, eq);
×
1176

1177
        if (streq(field, "IOSchedulingPriority"))
1,921✔
1178
                return bus_append_ioprio_parse_priority(m, field, eq);
×
1179

1180
        if (STR_IN_SET(field, "RuntimeDirectoryMode",
1,921✔
1181
                              "StateDirectoryMode",
1182
                              "CacheDirectoryMode",
1183
                              "LogsDirectoryMode",
1184
                              "ConfigurationDirectoryMode",
1185
                              "UMask"))
1186
                return bus_append_parse_mode(m, field, eq);
20✔
1187

1188
        if (streq(field, "TimerSlackNSec"))
1,901✔
1189
                return bus_append_parse_nsec(m, field, eq);
×
1190

1191
        if (streq(field, "LogRateLimitIntervalSec"))
1,901✔
1192
                return bus_append_parse_sec_rename(m, field, eq);
×
1193

1194
        if (STR_IN_SET(field, "LogRateLimitBurst",
1,901✔
1195
                              "TTYRows",
1196
                              "TTYColumns"))
1197
                return bus_append_safe_atou(m, field, eq);
×
1198

1199
        if (streq(field, "MountFlags"))
1,901✔
1200
                return bus_append_mount_propagation_flag_from_string(m, field, eq);
1✔
1201

1202
        if (STR_IN_SET(field, "Environment",
1,900✔
1203
                              "UnsetEnvironment",
1204
                              "PassEnvironment"))
1205
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
354✔
1206

1207
        if (streq(field, "EnvironmentFile")) {
1,546✔
1208
                if (isempty(eq))
340✔
1209
                        r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
×
1210
                else
1211
                        r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
340✔
1212
                                                  eq[0] == '-' ? eq + 1 : eq,
1213
                                                  eq[0] == '-');
1214
                if (r < 0)
340✔
1215
                        return bus_log_create_error(r);
×
1216

1217
                return 1;
1218
        }
1219

1220
        if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
1,206✔
1221
                r = sd_bus_message_open_container(m, 'r', "sv");
90✔
1222
                if (r < 0)
90✔
1223
                        return bus_log_create_error(r);
90✔
1224

1225
                r = sd_bus_message_append_basic(m, 's', field);
90✔
1226
                if (r < 0)
90✔
1227
                        return bus_log_create_error(r);
×
1228

1229
                r = sd_bus_message_open_container(m, 'v', "a(say)");
90✔
1230
                if (r < 0)
90✔
1231
                        return bus_log_create_error(r);
×
1232

1233
                if (isempty(eq))
90✔
1234
                        r = sd_bus_message_append(m, "a(say)", 0);
×
1235
                else {
1236
                        _cleanup_free_ char *word = NULL;
90✔
1237
                        const char *p = eq;
90✔
1238

1239
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
90✔
1240
                        if (r == -ENOMEM)
90✔
1241
                                return log_oom();
×
1242
                        if (r < 0)
90✔
1243
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1244
                        if (r == 0 || !p)
90✔
1245
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1246

1247
                        r = sd_bus_message_open_container(m, 'a', "(say)");
90✔
1248
                        if (r < 0)
90✔
1249
                                return bus_log_create_error(r);
×
1250

1251
                        r = sd_bus_message_open_container(m, 'r', "say");
90✔
1252
                        if (r < 0)
90✔
1253
                                return bus_log_create_error(r);
×
1254

1255
                        r = sd_bus_message_append(m, "s", word);
90✔
1256
                        if (r < 0)
90✔
1257
                                return bus_log_create_error(r);
×
1258

1259
                        if (streq(field, "SetCredentialEncrypted")) {
90✔
1260
                                _cleanup_free_ void *decoded = NULL;
2✔
1261
                                size_t decoded_size;
2✔
1262

1263
                                r = unbase64mem(p, &decoded, &decoded_size);
2✔
1264
                                if (r < 0)
2✔
1265
                                        return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
×
1266

1267
                                r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
2✔
1268
                        } else {
1269
                                _cleanup_free_ char *unescaped = NULL;
88✔
1270
                                ssize_t l;
88✔
1271

1272
                                l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
88✔
1273
                                if (l < 0)
88✔
1274
                                        return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
×
1275

1276
                                r = sd_bus_message_append_array(m, 'y', unescaped, l);
88✔
1277
                        }
1278
                        if (r < 0)
90✔
1279
                                return bus_log_create_error(r);
×
1280

1281
                        r = sd_bus_message_close_container(m);
90✔
1282
                        if (r < 0)
90✔
1283
                                return bus_log_create_error(r);
×
1284

1285
                        r = sd_bus_message_close_container(m);
90✔
1286
                }
1287
                if (r < 0)
90✔
1288
                        return bus_log_create_error(r);
×
1289

1290
                r = sd_bus_message_close_container(m);
90✔
1291
                if (r < 0)
90✔
1292
                        return bus_log_create_error(r);
×
1293

1294
                r = sd_bus_message_close_container(m);
90✔
1295
                if (r < 0)
90✔
1296
                        return bus_log_create_error(r);
×
1297

1298
                return 1;
1299
        }
1300

1301
        if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
1,116✔
1302
                r = sd_bus_message_open_container(m, 'r', "sv");
18✔
1303
                if (r < 0)
18✔
1304
                        return bus_log_create_error(r);
18✔
1305

1306
                r = sd_bus_message_append_basic(m, 's', field);
18✔
1307
                if (r < 0)
18✔
1308
                        return bus_log_create_error(r);
×
1309

1310
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
18✔
1311
                if (r < 0)
18✔
1312
                        return bus_log_create_error(r);
×
1313

1314
                if (isempty(eq))
18✔
1315
                        r = sd_bus_message_append(m, "a(ss)", 0);
×
1316
                else {
1317
                        _cleanup_free_ char *word = NULL;
18✔
1318
                        const char *p = eq;
18✔
1319

1320
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
18✔
1321
                        if (r == -ENOMEM)
18✔
1322
                                return log_oom();
×
1323
                        if (r < 0)
18✔
1324
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1325
                        if (r == 0)
18✔
1326
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1327

1328
                        if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
18✔
1329
                                p = eq;
2✔
1330

1331
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
18✔
1332
                }
1333
                if (r < 0)
18✔
1334
                        return bus_log_create_error(r);
×
1335

1336
                r = sd_bus_message_close_container(m);
18✔
1337
                if (r < 0)
18✔
1338
                        return bus_log_create_error(r);
×
1339

1340
                r = sd_bus_message_close_container(m);
18✔
1341
                if (r < 0)
18✔
1342
                        return bus_log_create_error(r);
×
1343

1344
                return 1;
1345
        }
1346

1347
        if (streq(field, "ImportCredential")) {
1,098✔
1348
                if (isempty(eq))
3✔
1349
                        r = sd_bus_message_append(m, "(sv)", field, "as", 0);
×
1350
                else
1351
                        r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
3✔
1352
                if (r < 0)
3✔
1353
                        return bus_log_create_error(r);
×
1354

1355
                return 1;
1356
        }
1357

1358
        if (streq(field, "ImportCredentialEx")) {
1,095✔
1359
                r = sd_bus_message_open_container(m, 'r', "sv");
9✔
1360
                if (r < 0)
9✔
1361
                        return bus_log_create_error(r);
×
1362

1363
                r = sd_bus_message_append_basic(m, 's', field);
9✔
1364
                if (r < 0)
9✔
1365
                        return bus_log_create_error(r);
×
1366

1367
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
9✔
1368
                if (r < 0)
9✔
1369
                        return bus_log_create_error(r);
×
1370

1371
                if (isempty(eq))
9✔
1372
                        r = sd_bus_message_append(m, "a(ss)", 0);
×
1373
                else {
1374
                         _cleanup_free_ char *word = NULL;
9✔
1375
                        const char *p = eq;
9✔
1376

1377
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
9✔
1378
                        if (r == -ENOMEM)
9✔
1379
                                return log_oom();
×
1380
                        if (r < 0)
9✔
1381
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1382
                        if (r == 0)
9✔
1383
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1384

1385
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
9✔
1386
                }
1387
                if (r < 0)
9✔
1388
                        return bus_log_create_error(r);
×
1389

1390
                r = sd_bus_message_close_container(m);
9✔
1391
                if (r < 0)
9✔
1392
                        return bus_log_create_error(r);
×
1393

1394
                r = sd_bus_message_close_container(m);
9✔
1395
                if (r < 0)
9✔
1396
                        return bus_log_create_error(r);
×
1397

1398
                return 1;
1399
        }
1400

1401
        if (streq(field, "LogExtraFields")) {
1,086✔
1402
                r = sd_bus_message_open_container(m, 'r', "sv");
474✔
1403
                if (r < 0)
474✔
1404
                        return bus_log_create_error(r);
×
1405

1406
                r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
474✔
1407
                if (r < 0)
474✔
1408
                        return bus_log_create_error(r);
×
1409

1410
                r = sd_bus_message_open_container(m, 'v', "aay");
474✔
1411
                if (r < 0)
474✔
1412
                        return bus_log_create_error(r);
×
1413

1414
                r = sd_bus_message_open_container(m, 'a', "ay");
474✔
1415
                if (r < 0)
474✔
1416
                        return bus_log_create_error(r);
×
1417

1418
                r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
474✔
1419
                if (r < 0)
474✔
1420
                        return bus_log_create_error(r);
×
1421

1422
                r = sd_bus_message_close_container(m);
474✔
1423
                if (r < 0)
474✔
1424
                        return bus_log_create_error(r);
×
1425

1426
                r = sd_bus_message_close_container(m);
474✔
1427
                if (r < 0)
474✔
1428
                        return bus_log_create_error(r);
×
1429

1430
                r = sd_bus_message_close_container(m);
474✔
1431
                if (r < 0)
474✔
1432
                        return bus_log_create_error(r);
×
1433

1434
                return 1;
1435
        }
1436

1437
        if (streq(field, "LogFilterPatterns")) {
612✔
1438
                r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
×
1439
                                          eq[0] != '~',
1440
                                          eq[0] != '~' ? eq : eq + 1);
×
1441
                if (r < 0)
×
1442
                        return bus_log_create_error(r);
×
1443

1444
                return 1;
1445
        }
1446

1447
        if (STR_IN_SET(field, "StandardInput",
612✔
1448
                              "StandardOutput",
1449
                              "StandardError")) {
1450
                const char *n, *appended;
46✔
1451

1452
                if ((n = startswith(eq, "fd:"))) {
46✔
1453
                        appended = strjoina(field, "FileDescriptorName");
×
1454
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
×
1455
                } else if ((n = startswith(eq, "file:"))) {
46✔
1456
                        appended = strjoina(field, "File");
20✔
1457
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
4✔
1458
                } else if ((n = startswith(eq, "append:"))) {
42✔
1459
                        appended = strjoina(field, "FileToAppend");
10✔
1460
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
2✔
1461
                } else if ((n = startswith(eq, "truncate:"))) {
40✔
1462
                        appended = strjoina(field, "FileToTruncate");
15✔
1463
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
3✔
1464
                } else
1465
                        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
37✔
1466
                if (r < 0)
46✔
1467
                        return bus_log_create_error(r);
46✔
1468

1469
                return 1;
1470
        }
1471

1472
        if (streq(field, "StandardInputText")) {
566✔
1473
                _cleanup_free_ char *unescaped = NULL;
×
1474
                ssize_t l;
×
1475

1476
                l = cunescape(eq, 0, &unescaped);
×
1477
                if (l < 0)
×
1478
                        return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
×
1479

1480
                if (!strextend(&unescaped, "\n"))
×
1481
                        return log_oom();
×
1482

1483
                /* Note that we don't expand specifiers here, but that should be OK, as this is a
1484
                 * programmatic interface anyway */
1485

1486
                return bus_append_byte_array(m, field, unescaped, l + 1);
×
1487
        }
1488

1489
        if (streq(field, "StandardInputData")) {
566✔
1490
                _cleanup_free_ void *decoded = NULL;
1✔
1491
                size_t sz;
1✔
1492

1493
                r = unbase64mem(eq, &decoded, &sz);
1✔
1494
                if (r < 0)
1✔
1495
                        return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
×
1496

1497
                return bus_append_byte_array(m, field, decoded, sz);
1✔
1498
        }
1499

1500
        if ((suffix = startswith(field, "Limit"))) {
565✔
1501
                int rl;
24✔
1502

1503
                rl = rlimit_from_string(suffix);
24✔
1504
                if (rl >= 0) {
24✔
1505
                        const char *sn;
24✔
1506
                        struct rlimit l;
24✔
1507

1508
                        r = rlimit_parse(rl, eq, &l);
24✔
1509
                        if (r < 0)
24✔
1510
                                return log_error_errno(r, "Failed to parse resource limit: %s", eq);
24✔
1511

1512
                        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
24✔
1513
                        if (r < 0)
24✔
1514
                                return bus_log_create_error(r);
×
1515

1516
                        sn = strjoina(field, "Soft");
120✔
1517
                        r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
24✔
1518
                        if (r < 0)
24✔
1519
                                return bus_log_create_error(r);
×
1520

1521
                        return 1;
1522
                }
1523
        }
1524

1525
        if (STR_IN_SET(field, "AppArmorProfile",
541✔
1526
                              "SmackProcessLabel")) {
1527
                int ignore = 0;
×
1528
                const char *s = eq;
×
1529

1530
                if (eq[0] == '-') {
×
1531
                        ignore = 1;
×
1532
                        s = eq + 1;
×
1533
                }
1534

1535
                r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
×
1536
                if (r < 0)
×
1537
                        return bus_log_create_error(r);
×
1538

1539
                return 1;
1540
        }
1541

1542
        if (STR_IN_SET(field, "CapabilityBoundingSet",
541✔
1543
                              "AmbientCapabilities")) {
1544
                uint64_t sum = 0;
6✔
1545
                bool invert = false;
6✔
1546
                const char *p = eq;
6✔
1547

1548
                if (*p == '~') {
6✔
1549
                        invert = true;
3✔
1550
                        p++;
3✔
1551
                }
1552

1553
                r = capability_set_from_string(p, &sum);
6✔
1554
                if (r < 0)
6✔
1555
                        return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
6✔
1556

1557
                sum = invert ? ~sum : sum;
6✔
1558

1559
                r = sd_bus_message_append(m, "(sv)", field, "t", sum);
6✔
1560
                if (r < 0)
6✔
1561
                        return bus_log_create_error(r);
×
1562

1563
                return 1;
1564
        }
1565

1566
        if (streq(field, "CPUAffinity")) {
535✔
1567
                _cleanup_(cpu_set_reset) CPUSet cpuset = {};
×
1568
                _cleanup_free_ uint8_t *array = NULL;
1✔
1569
                size_t allocated;
1✔
1570

1571
                if (eq && streq(eq, "numa")) {
1✔
1572
                        r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1✔
1573
                        if (r < 0)
1✔
1574
                                return bus_log_create_error(r);
×
1575
                        return r;
1576
                }
1577

1578
                r = parse_cpu_set(eq, &cpuset);
×
1579
                if (r < 0)
×
1580
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1581

1582
                r = cpu_set_to_dbus(&cpuset, &array, &allocated);
×
1583
                if (r < 0)
×
1584
                        return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
×
1585

1586
                return bus_append_byte_array(m, field, array, allocated);
×
1587
        }
1588

1589
        if (streq(field, "NUMAPolicy")) {
534✔
1590
                r = mpol_from_string(eq);
8✔
1591
                if (r < 0)
8✔
1592
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1593

1594
                r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
8✔
1595
                if (r < 0)
8✔
1596
                        return bus_log_create_error(r);
×
1597

1598
                return 1;
1599
        }
1600

1601
        if (streq(field, "NUMAMask")) {
526✔
1602
                _cleanup_(cpu_set_reset) CPUSet nodes = {};
×
1603
                _cleanup_free_ uint8_t *array = NULL;
6✔
1604
                size_t allocated;
6✔
1605

1606
                if (eq && streq(eq, "all")) {
6✔
1607
                        r = numa_mask_add_all(&nodes);
×
1608
                        if (r < 0)
×
1609
                                return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
×
1610
                } else {
1611
                        r = parse_cpu_set(eq, &nodes);
6✔
1612
                        if (r < 0)
6✔
1613
                                return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1614
                }
1615

1616
                r = cpu_set_to_dbus(&nodes, &array, &allocated);
6✔
1617
                if (r < 0)
6✔
1618
                        return log_error_errno(r, "Failed to serialize NUMAMask: %m");
×
1619

1620
                return bus_append_byte_array(m, field, array, allocated);
6✔
1621
        }
1622

1623
        if (STR_IN_SET(field, "RestrictAddressFamilies",
520✔
1624
                              "RestrictFileSystems",
1625
                              "SystemCallFilter",
1626
                              "SystemCallLog",
1627
                              "RestrictNetworkInterfaces")) {
1628
                int allow_list = 1;
7✔
1629
                const char *p = eq;
7✔
1630

1631
                if (*p == '~') {
7✔
1632
                        allow_list = 0;
3✔
1633
                        p++;
3✔
1634
                }
1635

1636
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
7✔
1637
                if (r < 0)
7✔
1638
                        return bus_log_create_error(r);
7✔
1639

1640
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
7✔
1641
                if (r < 0)
7✔
1642
                        return bus_log_create_error(r);
×
1643

1644
                r = sd_bus_message_open_container(m, 'v', "(bas)");
7✔
1645
                if (r < 0)
7✔
1646
                        return bus_log_create_error(r);
×
1647

1648
                r = sd_bus_message_open_container(m, 'r', "bas");
7✔
1649
                if (r < 0)
7✔
1650
                        return bus_log_create_error(r);
×
1651

1652
                r = sd_bus_message_append_basic(m, 'b', &allow_list);
7✔
1653
                if (r < 0)
7✔
1654
                        return bus_log_create_error(r);
×
1655

1656
                r = sd_bus_message_open_container(m, 'a', "s");
7✔
1657
                if (r < 0)
7✔
1658
                        return bus_log_create_error(r);
×
1659

1660
                for (;;) {
25✔
1661
                        _cleanup_free_ char *word = NULL;
9✔
1662

1663
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
16✔
1664
                        if (r == 0)
16✔
1665
                                break;
1666
                        if (r == -ENOMEM)
9✔
1667
                                return log_oom();
×
1668
                        if (r < 0)
9✔
1669
                                return log_error_errno(r, "Invalid syntax: %s", eq);
×
1670

1671
                        r = sd_bus_message_append_basic(m, 's', word);
9✔
1672
                        if (r < 0)
9✔
1673
                                return bus_log_create_error(r);
×
1674
                }
1675

1676
                r = sd_bus_message_close_container(m);
7✔
1677
                if (r < 0)
7✔
1678
                        return bus_log_create_error(r);
×
1679

1680
                r = sd_bus_message_close_container(m);
7✔
1681
                if (r < 0)
7✔
1682
                        return bus_log_create_error(r);
×
1683

1684
                r = sd_bus_message_close_container(m);
7✔
1685
                if (r < 0)
7✔
1686
                        return bus_log_create_error(r);
×
1687

1688
                r = sd_bus_message_close_container(m);
7✔
1689
                if (r < 0)
7✔
1690
                        return bus_log_create_error(r);
×
1691

1692
                return 1;
1693
        }
1694

1695
        if (STR_IN_SET(field, "RestrictNamespaces",
513✔
1696
                              "DelegateNamespaces")) {
1697
                bool invert = false;
11✔
1698
                unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
11✔
1699
                unsigned long flags;
11✔
1700

1701
                r = parse_boolean(eq);
11✔
1702
                if (r > 0)
11✔
1703
                        /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1704
                         * namespaces which are retained), so RestrictNamespaces=true means we retain no
1705
                         * access to any namespaces and vice-versa. */
1706
                        flags = streq(field, "RestrictNamespaces") ? 0 : all;
2✔
1707
                else if (r == 0)
9✔
1708
                        flags = streq(field, "RestrictNamespaces") ? all : 0;
2✔
1709
                else {
1710
                        if (eq[0] == '~') {
7✔
1711
                                invert = true;
1✔
1712
                                eq++;
1✔
1713
                        }
1714

1715
                        r = namespace_flags_from_string(eq, &flags);
7✔
1716
                        if (r < 0)
7✔
1717
                                return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
11✔
1718
                }
1719

1720
                if (invert)
11✔
1721
                        flags = (~flags) & all;
1✔
1722

1723
                r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
11✔
1724
                if (r < 0)
11✔
1725
                        return bus_log_create_error(r);
×
1726

1727
                return 1;
1728
        }
1729

1730
        if (STR_IN_SET(field, "BindPaths",
502✔
1731
                              "BindReadOnlyPaths")) {
1732
                const char *p = eq;
10✔
1733

1734
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
10✔
1735
                if (r < 0)
10✔
1736
                        return bus_log_create_error(r);
10✔
1737

1738
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
10✔
1739
                if (r < 0)
10✔
1740
                        return bus_log_create_error(r);
×
1741

1742
                r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
10✔
1743
                if (r < 0)
10✔
1744
                        return bus_log_create_error(r);
×
1745

1746
                r = sd_bus_message_open_container(m, 'a', "(ssbt)");
10✔
1747
                if (r < 0)
10✔
1748
                        return bus_log_create_error(r);
×
1749

1750
                for (;;) {
46✔
1751
                        _cleanup_free_ char *source = NULL, *destination = NULL;
18✔
1752
                        char *s = NULL, *d = NULL;
28✔
1753
                        bool ignore_enoent = false;
28✔
1754
                        uint64_t flags = MS_REC;
28✔
1755

1756
                        r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
28✔
1757
                        if (r < 0)
28✔
1758
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1759
                        if (r == 0)
28✔
1760
                                break;
1761

1762
                        s = source;
18✔
1763
                        if (s[0] == '-') {
18✔
1764
                                ignore_enoent = true;
2✔
1765
                                s++;
2✔
1766
                        }
1767

1768
                        if (p && p[-1] == ':') {
18✔
1769
                                r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
10✔
1770
                                if (r < 0)
10✔
1771
                                        return log_error_errno(r, "Failed to parse argument: %m");
×
1772
                                if (r == 0)
10✔
1773
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1774
                                                               "Missing argument after ':': %s",
1775
                                                               eq);
1776

1777
                                d = destination;
10✔
1778

1779
                                if (p && p[-1] == ':') {
10✔
1780
                                        _cleanup_free_ char *options = NULL;
6✔
1781

1782
                                        r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
6✔
1783
                                        if (r < 0)
6✔
1784
                                                return log_error_errno(r, "Failed to parse argument: %m");
×
1785

1786
                                        if (isempty(options) || streq(options, "rbind"))
16✔
1787
                                                flags = MS_REC;
1788
                                        else if (streq(options, "norbind"))
4✔
1789
                                                flags = 0;
1790
                                        else
1791
                                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1792
                                                                       "Unknown options: %s",
1793
                                                                       eq);
1794
                                }
1795
                        } else
1796
                                d = s;
1797

1798
                        r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
18✔
1799
                        if (r < 0)
18✔
1800
                                return bus_log_create_error(r);
×
1801
                }
1802

1803
                r = sd_bus_message_close_container(m);
10✔
1804
                if (r < 0)
10✔
1805
                        return bus_log_create_error(r);
×
1806

1807
                r = sd_bus_message_close_container(m);
10✔
1808
                if (r < 0)
10✔
1809
                        return bus_log_create_error(r);
×
1810

1811
                r = sd_bus_message_close_container(m);
10✔
1812
                if (r < 0)
10✔
1813
                        return bus_log_create_error(r);
×
1814

1815
                return 1;
1816
        }
1817

1818
        if (streq(field, "TemporaryFileSystem")) {
492✔
1819
                const char *p = eq;
48✔
1820

1821
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
48✔
1822
                if (r < 0)
48✔
1823
                        return bus_log_create_error(r);
48✔
1824

1825
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
48✔
1826
                if (r < 0)
48✔
1827
                        return bus_log_create_error(r);
×
1828

1829
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
48✔
1830
                if (r < 0)
48✔
1831
                        return bus_log_create_error(r);
×
1832

1833
                r = sd_bus_message_open_container(m, 'a', "(ss)");
48✔
1834
                if (r < 0)
48✔
1835
                        return bus_log_create_error(r);
×
1836

1837
                for (;;) {
144✔
1838
                        _cleanup_free_ char *word = NULL, *path = NULL;
48✔
1839
                        const char *w;
96✔
1840

1841
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
96✔
1842
                        if (r < 0)
96✔
1843
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1844
                        if (r == 0)
96✔
1845
                                break;
1846

1847
                        w = word;
48✔
1848
                        r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
48✔
1849
                        if (r < 0)
48✔
1850
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1851
                        if (r == 0)
48✔
1852
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1853
                                                       "Failed to parse argument: %s",
1854
                                                       p);
1855

1856
                        r = sd_bus_message_append(m, "(ss)", path, w);
48✔
1857
                        if (r < 0)
48✔
1858
                                return bus_log_create_error(r);
×
1859
                }
1860

1861
                r = sd_bus_message_close_container(m);
48✔
1862
                if (r < 0)
48✔
1863
                        return bus_log_create_error(r);
×
1864

1865
                r = sd_bus_message_close_container(m);
48✔
1866
                if (r < 0)
48✔
1867
                        return bus_log_create_error(r);
×
1868

1869
                r = sd_bus_message_close_container(m);
48✔
1870
                if (r < 0)
48✔
1871
                        return bus_log_create_error(r);
×
1872

1873
                return 1;
1874
        }
1875

1876
        if (streq(field, "RootHash")) {
444✔
1877
                _cleanup_free_ void *roothash_decoded = NULL;
12✔
1878
                size_t roothash_decoded_size = 0;
12✔
1879

1880
                /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1881
                if (path_is_absolute(eq))
12✔
1882
                        return bus_append_string(m, "RootHashPath", eq);
1✔
1883

1884
                /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1885
                r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
11✔
1886
                if (r < 0)
11✔
1887
                        return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
×
1888
                if (roothash_decoded_size < sizeof(sd_id128_t))
11✔
1889
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
×
1890

1891
                return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
11✔
1892
        }
1893

1894
        if (streq(field, "RootHashSignature")) {
432✔
1895
                _cleanup_free_ void *roothash_sig_decoded = NULL;
×
1896
                char *value;
×
1897
                size_t roothash_sig_decoded_size = 0;
×
1898

1899
                /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1900
                if (path_is_absolute(eq))
×
1901
                        return bus_append_string(m, "RootHashSignaturePath", eq);
×
1902

1903
                if (!(value = startswith(eq, "base64:")))
×
1904
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to decode RootHashSignature= '%s', not a path but doesn't start with 'base64:'.", eq);
×
1905

1906
                /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1907
                r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
×
1908
                if (r < 0)
×
1909
                        return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
×
1910

1911
                return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
×
1912
        }
1913

1914
        if (streq(field, "RootImageOptions")) {
432✔
1915
                _cleanup_strv_free_ char **l = NULL;
2✔
1916
                const char *p = eq;
2✔
1917

1918
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
1919
                if (r < 0)
2✔
1920
                        return bus_log_create_error(r);
×
1921

1922
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
1923
                if (r < 0)
2✔
1924
                        return bus_log_create_error(r);
×
1925

1926
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
2✔
1927
                if (r < 0)
2✔
1928
                        return bus_log_create_error(r);
×
1929

1930
                r = sd_bus_message_open_container(m, 'a', "(ss)");
2✔
1931
                if (r < 0)
2✔
1932
                        return bus_log_create_error(r);
×
1933

1934
                r = strv_split_colon_pairs(&l, p);
2✔
1935
                if (r < 0)
2✔
1936
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1937

1938
                STRV_FOREACH_PAIR(first, second, l) {
7✔
1939
                        r = sd_bus_message_append(m, "(ss)",
15✔
1940
                                                  !isempty(*second) ? *first : "root",
5✔
1941
                                                  !isempty(*second) ? *second : *first);
5✔
1942
                        if (r < 0)
5✔
1943
                                return bus_log_create_error(r);
×
1944
                }
1945

1946
                r = sd_bus_message_close_container(m);
2✔
1947
                if (r < 0)
2✔
1948
                        return bus_log_create_error(r);
×
1949

1950
                r = sd_bus_message_close_container(m);
2✔
1951
                if (r < 0)
2✔
1952
                        return bus_log_create_error(r);
×
1953

1954
                r = sd_bus_message_close_container(m);
2✔
1955
                if (r < 0)
2✔
1956
                        return bus_log_create_error(r);
×
1957

1958
                return 1;
1959
        }
1960

1961
        if (streq(field, "MountImages")) {
430✔
1962
                const char *p = eq;
11✔
1963

1964
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
11✔
1965
                if (r < 0)
11✔
1966
                        return bus_log_create_error(r);
11✔
1967

1968
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
11✔
1969
                if (r < 0)
11✔
1970
                        return bus_log_create_error(r);
×
1971

1972
                r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
11✔
1973
                if (r < 0)
11✔
1974
                        return bus_log_create_error(r);
×
1975

1976
                r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
11✔
1977
                if (r < 0)
11✔
1978
                        return bus_log_create_error(r);
×
1979

1980
                for (;;) {
29✔
1981
                        _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
18✔
1982
                        const char *q = NULL, *source = NULL;
29✔
1983
                        bool permissive = false;
29✔
1984

1985
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
29✔
1986
                        if (r < 0)
29✔
1987
                                return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1988
                        if (r == 0)
29✔
1989
                                break;
1990

1991
                        q = tuple;
18✔
1992
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
18✔
1993
                        if (r < 0)
18✔
1994
                                return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1995
                        if (r == 0)
18✔
1996
                                continue;
×
1997

1998
                        source = first;
18✔
1999
                        if (source[0] == '-') {
18✔
2000
                                permissive = true;
×
2001
                                source++;
×
2002
                        }
2003

2004
                        if (isempty(second))
18✔
2005
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2006
                                                        "Missing argument after ':': %s",
2007
                                                        eq);
2008

2009
                        r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
18✔
2010
                        if (r < 0)
18✔
2011
                                return bus_log_create_error(r);
×
2012

2013
                        r = sd_bus_message_append(m, "ssb", source, second, permissive);
18✔
2014
                        if (r < 0)
18✔
2015
                                return bus_log_create_error(r);
×
2016

2017
                        r = sd_bus_message_open_container(m, 'a', "(ss)");
18✔
2018
                        if (r < 0)
18✔
2019
                                return bus_log_create_error(r);
×
2020

2021
                        for (;;) {
22✔
2022
                                _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2✔
2023

2024
                                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
20✔
2025
                                if (r < 0)
20✔
2026
                                        return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
2027
                                if (r == 0)
20✔
2028
                                        break;
2029
                                /* Single set of options, applying to the root partition/single filesystem */
2030
                                if (r == 1) {
5✔
2031
                                        r = sd_bus_message_append(m, "(ss)", "root", partition);
3✔
2032
                                        if (r < 0)
3✔
2033
                                                return bus_log_create_error(r);
×
2034

2035
                                        break;
2036
                                }
2037

2038
                                r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2✔
2039
                                if (r < 0)
2✔
2040
                                        return bus_log_create_error(r);
×
2041
                        }
2042

2043
                        r = sd_bus_message_close_container(m);
18✔
2044
                        if (r < 0)
18✔
2045
                                return bus_log_create_error(r);
×
2046

2047
                        r = sd_bus_message_close_container(m);
18✔
2048
                        if (r < 0)
18✔
2049
                                return bus_log_create_error(r);
×
2050
                }
2051

2052
                r = sd_bus_message_close_container(m);
11✔
2053
                if (r < 0)
11✔
2054
                        return bus_log_create_error(r);
×
2055

2056
                r = sd_bus_message_close_container(m);
11✔
2057
                if (r < 0)
11✔
2058
                        return bus_log_create_error(r);
×
2059

2060
                r = sd_bus_message_close_container(m);
11✔
2061
                if (r < 0)
11✔
2062
                        return bus_log_create_error(r);
×
2063

2064
                return 1;
2065
        }
2066

2067
        if (streq(field, "ExtensionImages")) {
419✔
2068
                const char *p = eq;
20✔
2069

2070
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20✔
2071
                if (r < 0)
20✔
2072
                        return bus_log_create_error(r);
20✔
2073

2074
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
20✔
2075
                if (r < 0)
20✔
2076
                        return bus_log_create_error(r);
×
2077

2078
                r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
20✔
2079
                if (r < 0)
20✔
2080
                        return bus_log_create_error(r);
×
2081

2082
                r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
20✔
2083
                if (r < 0)
20✔
2084
                        return bus_log_create_error(r);
×
2085

2086
                for (;;) {
48✔
2087
                        _cleanup_free_ char *source = NULL, *tuple = NULL;
28✔
2088
                        const char *q = NULL, *s = NULL;
48✔
2089
                        bool permissive = false;
48✔
2090

2091
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
48✔
2092
                        if (r < 0)
48✔
2093
                                return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2094
                        if (r == 0)
48✔
2095
                                break;
2096

2097
                        q = tuple;
28✔
2098
                        r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
28✔
2099
                        if (r < 0)
28✔
2100
                                return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2101
                        if (r == 0)
28✔
2102
                                continue;
×
2103

2104
                        s = source;
28✔
2105
                        if (s[0] == '-') {
28✔
2106
                                permissive = true;
2✔
2107
                                s++;
2✔
2108
                        }
2109

2110
                        r = sd_bus_message_open_container(m, 'r', "sba(ss)");
28✔
2111
                        if (r < 0)
28✔
2112
                                return bus_log_create_error(r);
×
2113

2114
                        r = sd_bus_message_append(m, "sb", s, permissive);
28✔
2115
                        if (r < 0)
28✔
2116
                                return bus_log_create_error(r);
×
2117

2118
                        r = sd_bus_message_open_container(m, 'a', "(ss)");
28✔
2119
                        if (r < 0)
28✔
2120
                                return bus_log_create_error(r);
×
2121

2122
                        for (;;) {
28✔
2123
                                _cleanup_free_ char *partition = NULL, *mount_options = NULL;
×
2124

2125
                                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
28✔
2126
                                if (r < 0)
28✔
2127
                                        return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2128
                                if (r == 0)
28✔
2129
                                        break;
2130
                                /* Single set of options, applying to the root partition/single filesystem */
2131
                                if (r == 1) {
×
2132
                                        r = sd_bus_message_append(m, "(ss)", "root", partition);
×
2133
                                        if (r < 0)
×
2134
                                                return bus_log_create_error(r);
×
2135

2136
                                        break;
2137
                                }
2138

2139
                                r = sd_bus_message_append(m, "(ss)", partition, mount_options);
×
2140
                                if (r < 0)
×
2141
                                        return bus_log_create_error(r);
×
2142
                        }
2143

2144
                        r = sd_bus_message_close_container(m);
28✔
2145
                        if (r < 0)
28✔
2146
                                return bus_log_create_error(r);
×
2147

2148
                        r = sd_bus_message_close_container(m);
28✔
2149
                        if (r < 0)
28✔
2150
                                return bus_log_create_error(r);
×
2151
                }
2152

2153
                r = sd_bus_message_close_container(m);
20✔
2154
                if (r < 0)
20✔
2155
                        return bus_log_create_error(r);
×
2156

2157
                r = sd_bus_message_close_container(m);
20✔
2158
                if (r < 0)
20✔
2159
                        return bus_log_create_error(r);
×
2160

2161
                r = sd_bus_message_close_container(m);
20✔
2162
                if (r < 0)
20✔
2163
                        return bus_log_create_error(r);
×
2164

2165
                return 1;
2166
        }
2167

2168
        if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
399✔
2169
                _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
183✔
2170
                const char *p = eq;
183✔
2171

2172
                /* Adding new directories is supported from both *DirectorySymlink methods and the
2173
                 * older ones, so first parse the input, and if we are given a new-style src:dst
2174
                 * tuple use the new method, else use the old one. */
2175

2176
                for (;;) {
665✔
2177
                        _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
241✔
2178

2179
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
424✔
2180
                        if (r < 0)
424✔
2181
                                return log_error_errno(r, "Failed to parse argument: %m");
×
2182
                        if (r == 0)
424✔
2183
                                break;
2184

2185
                        const char *t = tuple;
241✔
2186
                        r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
241✔
2187
                        if (r <= 0)
241✔
2188
                                return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
×
2189

2190
                        path_simplify(source);
241✔
2191

2192
                        if (isempty(dest) && isempty(flags)) {
278✔
2193
                                r = strv_consume(&sources, TAKE_PTR(source));
110✔
2194
                                if (r < 0)
110✔
2195
                                        return bus_log_create_error(r);
×
2196
                        } else if (isempty(flags)) {
131✔
2197
                                path_simplify(dest);
57✔
2198
                                r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
57✔
2199
                                if (r < 0)
57✔
2200
                                        return log_oom();
×
2201
                        } else {
2202
                                ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
74✔
2203
                                if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
74✔
2204
                                        return log_error_errno(r, "Failed to parse flags: %s", flags);
×
2205

2206
                                if (!isempty(dest)) {
74✔
2207
                                        path_simplify(dest);
37✔
2208
                                        r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
37✔
2209
                                } else
2210
                                        r = strv_consume(&sources_ro, TAKE_PTR(source));
37✔
2211
                                if (r < 0)
74✔
2212
                                        return log_oom();
×
2213
                        }
2214
                }
2215

2216
                if (!strv_isempty(sources)) {
183✔
2217
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
95✔
2218
                        if (r < 0)
95✔
2219
                                return bus_log_create_error(r);
×
2220

2221
                        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
95✔
2222
                        if (r < 0)
95✔
2223
                                return bus_log_create_error(r);
×
2224

2225
                        r = sd_bus_message_open_container(m, 'v', "as");
95✔
2226
                        if (r < 0)
95✔
2227
                                return bus_log_create_error(r);
×
2228

2229
                        r = sd_bus_message_append_strv(m, sources);
95✔
2230
                        if (r < 0)
95✔
2231
                                return bus_log_create_error(r);
×
2232

2233
                        r = sd_bus_message_close_container(m);
95✔
2234
                        if (r < 0)
95✔
2235
                                return bus_log_create_error(r);
×
2236

2237
                        r = sd_bus_message_close_container(m);
95✔
2238
                        if (r < 0)
95✔
2239
                                return bus_log_create_error(r);
×
2240
                }
2241

2242
                /* For State and Runtime directories we support an optional destination parameter, which
2243
                 * will be used to create a symlink to the source. But it is new so we cannot change the
2244
                 * old DBUS signatures, so append a new message type. */
2245
                if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) {
183✔
2246
                        const char *symlink_field;
83✔
2247

2248
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
83✔
2249
                        if (r < 0)
83✔
2250
                                return bus_log_create_error(r);
×
2251

2252
                        if (streq(field, "StateDirectory"))
83✔
2253
                                symlink_field = "StateDirectorySymlink";
2254
                        else if (streq(field, "RuntimeDirectory"))
62✔
2255
                                symlink_field = "RuntimeDirectorySymlink";
2256
                        else if (streq(field, "CacheDirectory"))
38✔
2257
                                symlink_field = "CacheDirectorySymlink";
2258
                        else if (streq(field, "LogsDirectory"))
19✔
2259
                                symlink_field = "LogsDirectorySymlink";
2260
                        else
2261
                                assert_not_reached();
×
2262

2263
                        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
83✔
2264
                        if (r < 0)
83✔
2265
                                return bus_log_create_error(r);
×
2266

2267
                        r = sd_bus_message_open_container(m, 'v', "a(sst)");
83✔
2268
                        if (r < 0)
83✔
2269
                                return bus_log_create_error(r);
×
2270

2271
                        r = sd_bus_message_open_container(m, 'a', "(sst)");
83✔
2272
                        if (r < 0)
83✔
2273
                                return bus_log_create_error(r);
×
2274

2275
                        STRV_FOREACH_PAIR(source, destination, symlinks) {
140✔
2276
                                r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
57✔
2277
                                if (r < 0)
57✔
2278
                                        return bus_log_create_error(r);
×
2279
                        }
2280

2281
                        STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
120✔
2282
                                r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2283
                                if (r < 0)
37✔
2284
                                        return bus_log_create_error(r);
×
2285
                        }
2286

2287
                        STRV_FOREACH(source, sources_ro) {
120✔
2288
                                r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2289
                                if (r < 0)
37✔
2290
                                        return bus_log_create_error(r);
×
2291
                        }
2292

2293
                        r = sd_bus_message_close_container(m);
83✔
2294
                        if (r < 0)
83✔
2295
                                return bus_log_create_error(r);
×
2296

2297
                        r = sd_bus_message_close_container(m);
83✔
2298
                        if (r < 0)
83✔
2299
                                return bus_log_create_error(r);
×
2300

2301
                        r = sd_bus_message_close_container(m);
83✔
2302
                        if (r < 0)
83✔
2303
                                return bus_log_create_error(r);
×
2304
                }
2305

2306
                return 1;
183✔
2307
        }
2308

2309
        if (streq(field, "ProtectHostnameEx")) {
216✔
2310
                const char *colon = strchr(eq, ':');
16✔
2311
                if (colon) {
16✔
2312
                        if (isempty(colon + 1))
11✔
2313
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
2,803✔
2314

2315
                        _cleanup_free_ char *p = strndup(eq, colon - eq);
9✔
2316
                        if (!p)
9✔
2317
                                return -ENOMEM;
×
2318

2319
                        r = sd_bus_message_append(m, "(sv)", field, "(ss)", p, colon + 1);
9✔
2320
                } else
2321
                        r = sd_bus_message_append(m, "(sv)", field, "(ss)", eq, NULL);
5✔
2322
                if (r < 0)
14✔
2323
                        return bus_log_create_error(r);
×
2324

2325
                return 1;
2326
        }
2327
        return 0;
2328
}
2329

2330
static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
208✔
2331
        if (streq(field, "KillMode"))
208✔
2332
                return bus_append_string(m, field, eq);
1✔
2333

2334
        if (STR_IN_SET(field, "SendSIGHUP",
207✔
2335
                              "SendSIGKILL"))
2336
                return bus_append_parse_boolean(m, field, eq);
×
2337

2338
        if (STR_IN_SET(field, "KillSignal",
207✔
2339
                              "RestartKillSignal",
2340
                              "FinalKillSignal",
2341
                              "WatchdogSignal",
2342
                              "ReloadSignal"))
2343
                return bus_append_signal_from_string(m, field, eq);
2✔
2344

2345
        return 0;
205✔
2346
}
2347

2348
static int bus_append_mount_property(sd_bus_message *m, const char *field, const char *eq) {
1✔
2349

2350
        if (STR_IN_SET(field, "What",
1✔
2351
                              "Where",
2352
                              "Options",
2353
                              "Type"))
2354
                return bus_append_string(m, field, eq);
×
2355

2356
        if (streq(field, "TimeoutSec"))
1✔
2357
                return bus_append_parse_sec_rename(m, field, eq);
×
2358

2359
        if (streq(field, "DirectoryMode"))
1✔
2360
                return bus_append_parse_mode(m, field, eq);
×
2361

2362
        if (STR_IN_SET(field, "SloppyOptions",
1✔
2363
                              "LazyUnmount",
2364
                              "ForceUnmount",
2365
                              "ReadwriteOnly"))
2366
                return bus_append_parse_boolean(m, field, eq);
×
2367

2368
        return 0;
1✔
2369
}
2370

2371
static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
3✔
2372
        int r;
3✔
2373

2374
        if (streq(field, "MakeDirectory"))
3✔
2375
                return bus_append_parse_boolean(m, field, eq);
×
2376

2377
        if (streq(field, "DirectoryMode"))
3✔
2378
                return bus_append_parse_mode(m, field, eq);
×
2379

2380
        if (STR_IN_SET(field, "PathExists",
3✔
2381
                              "PathExistsGlob",
2382
                              "PathChanged",
2383
                              "PathModified",
2384
                              "DirectoryNotEmpty")) {
2385
                if (isempty(eq))
3✔
2386
                        r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
×
2387
                else
2388
                        r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
3✔
2389
                if (r < 0)
3✔
2390
                        return bus_log_create_error(r);
3✔
2391

2392
                return 1;
2393
        }
2394

2395
        if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
×
2396
                return bus_append_safe_atou(m, field, eq);
×
2397

2398
        if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
×
2399
                return bus_append_parse_sec_rename(m, field, eq);
×
2400

2401
        return 0;
×
2402
}
2403

2404
static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
8✔
2405
        if (streq(field, "RuntimeMaxSec"))
8✔
2406
                return bus_append_parse_sec_rename(m, field, eq);
4✔
2407

2408
        if (streq(field, "RuntimeRandomizedExtraSec"))
4✔
2409
                return bus_append_parse_sec_rename(m, field, eq);
×
2410

2411
        if (streq(field, "TimeoutStopSec"))
4✔
2412
                return bus_append_parse_sec_rename(m, field, eq);
×
2413

2414
        /* Scope units don't have execution context but we still want to allow setting these two,
2415
         * so let's handle them separately. */
2416
        if (STR_IN_SET(field, "User", "Group"))
4✔
2417
                return bus_append_string(m, field, eq);
1✔
2418

2419
        if (streq(field, "OOMPolicy"))
3✔
2420
                return bus_append_string(m, field, eq);
×
2421

2422
        return 0;
2423
}
2424

2425
static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
192✔
2426
        int r;
192✔
2427

2428
        if (STR_IN_SET(field, "PIDFile",
192✔
2429
                              "Type",
2430
                              "ExitType",
2431
                              "Restart",
2432
                              "RestartMode",
2433
                              "BusName",
2434
                              "NotifyAccess",
2435
                              "USBFunctionDescriptors",
2436
                              "USBFunctionStrings",
2437
                              "OOMPolicy",
2438
                              "TimeoutStartFailureMode",
2439
                              "TimeoutStopFailureMode",
2440
                              "FileDescriptorStorePreserve"))
2441
                return bus_append_string(m, field, eq);
117✔
2442

2443
        if (STR_IN_SET(field, "PermissionsStartOnly",
75✔
2444
                              "RootDirectoryStartOnly",
2445
                              "RemainAfterExit",
2446
                              "GuessMainPID"))
2447
                return bus_append_parse_boolean(m, field, eq);
1✔
2448

2449
        if (STR_IN_SET(field, "RestartSec",
74✔
2450
                              "RestartMaxDelaySec",
2451
                              "TimeoutStartSec",
2452
                              "TimeoutStopSec",
2453
                              "TimeoutAbortSec",
2454
                              "RuntimeMaxSec",
2455
                              "RuntimeRandomizedExtraSec",
2456
                              "WatchdogSec"))
2457
                return bus_append_parse_sec_rename(m, field, eq);
2✔
2458

2459
        if (streq(field, "TimeoutSec")) {
72✔
2460
                r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
×
2461
                if (r < 0)
×
2462
                        return r;
2463

2464
                return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
×
2465
        }
2466

2467
        if (STR_IN_SET(field, "FileDescriptorStoreMax",
72✔
2468
                              "RestartSteps"))
2469
                return bus_append_safe_atou(m, field, eq);
1✔
2470

2471
        if (STR_IN_SET(field, "ExecCondition",
71✔
2472
                              "ExecStartPre",
2473
                              "ExecStart",
2474
                              "ExecStartPost",
2475
                              "ExecConditionEx",
2476
                              "ExecStartPreEx",
2477
                              "ExecStartEx",
2478
                              "ExecStartPostEx",
2479
                              "ExecReload",
2480
                              "ExecStop",
2481
                              "ExecStopPost",
2482
                              "ExecReloadEx",
2483
                              "ExecStopEx",
2484
                              "ExecStopPostEx"))
2485
                return bus_append_exec_command(m, field, eq);
43✔
2486

2487
        if (STR_IN_SET(field, "RestartPreventExitStatus",
28✔
2488
                              "RestartForceExitStatus",
2489
                              "SuccessExitStatus")) {
2490
                _cleanup_free_ int *status = NULL, *signal = NULL;
×
2491
                size_t n_status = 0, n_signal = 0;
×
2492
                const char *p;
×
2493

2494
                for (p = eq;;) {
×
2495
                        _cleanup_free_ char *word = NULL;
×
2496

2497
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
×
2498
                        if (r == 0)
×
2499
                                break;
2500
                        if (r == -ENOMEM)
×
2501
                                return log_oom();
×
2502
                        if (r < 0)
×
2503
                                return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
×
2504

2505
                        /* We need to call exit_status_from_string() first, because we want
2506
                         * to parse numbers as exit statuses, not signals. */
2507

2508
                        r = exit_status_from_string(word);
×
2509
                        if (r >= 0) {
×
2510
                                assert(r >= 0 && r < 256);
×
2511

2512
                                if (!GREEDY_REALLOC(status, n_status + 1))
×
2513
                                        return log_oom();
×
2514

2515
                                status[n_status++] = r;
×
2516

2517
                        } else if ((r = signal_from_string(word)) >= 0) {
×
2518
                                if (!GREEDY_REALLOC(signal, n_signal + 1))
×
2519
                                        return log_oom();
×
2520

2521
                                signal[n_signal++] = r;
×
2522

2523
                        } else
2524
                                /* original r from exit_status_to_string() */
2525
                                return log_error_errno(r, "Invalid status or signal %s in %s: %m",
×
2526
                                                       word, field);
2527
                }
2528

2529
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
2530
                if (r < 0)
×
2531
                        return bus_log_create_error(r);
×
2532

2533
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
2534
                if (r < 0)
×
2535
                        return bus_log_create_error(r);
×
2536

2537
                r = sd_bus_message_open_container(m, 'v', "(aiai)");
×
2538
                if (r < 0)
×
2539
                        return bus_log_create_error(r);
×
2540

2541
                r = sd_bus_message_open_container(m, 'r', "aiai");
×
2542
                if (r < 0)
×
2543
                        return bus_log_create_error(r);
×
2544

2545
                r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
×
2546
                if (r < 0)
×
2547
                        return bus_log_create_error(r);
×
2548

2549
                r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
×
2550
                if (r < 0)
×
2551
                        return bus_log_create_error(r);
×
2552

2553
                r = sd_bus_message_close_container(m);
×
2554
                if (r < 0)
×
2555
                        return bus_log_create_error(r);
×
2556

2557
                r = sd_bus_message_close_container(m);
×
2558
                if (r < 0)
×
2559
                        return bus_log_create_error(r);
×
2560

2561
                r = sd_bus_message_close_container(m);
×
2562
                if (r < 0)
×
2563
                        return bus_log_create_error(r);
×
2564

2565
                return 1;
2566
        }
2567

2568
        if (streq(field, "OpenFile"))
28✔
2569
                return bus_append_open_file(m, field, eq);
5✔
2570

2571
        return 0;
2572
}
2573

2574
static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
4✔
2575
        int r;
4✔
2576

2577
        if (STR_IN_SET(field, "Accept",
4✔
2578
                              "FlushPending",
2579
                              "Writable",
2580
                              "KeepAlive",
2581
                              "NoDelay",
2582
                              "FreeBind",
2583
                              "Transparent",
2584
                              "Broadcast",
2585
                              "PassCredentials",
2586
                              "PassFileDescriptorsToExec",
2587
                              "PassSecurity",
2588
                              "PassPacketInfo",
2589
                              "ReusePort",
2590
                              "RemoveOnStop",
2591
                              "SELinuxContextFromNet"))
2592
                return bus_append_parse_boolean(m, field, eq);
×
2593

2594
        if (STR_IN_SET(field, "Priority",
4✔
2595
                              "IPTTL",
2596
                              "Mark"))
2597
                return bus_append_safe_atoi(m, field, eq);
×
2598

2599
        if (streq(field, "IPTOS"))
4✔
2600
                return bus_append_ip_tos_from_string(m, field, eq);
×
2601

2602
        if (STR_IN_SET(field, "Backlog",
4✔
2603
                              "MaxConnections",
2604
                              "MaxConnectionsPerSource",
2605
                              "KeepAliveProbes",
2606
                              "TriggerLimitBurst",
2607
                              "PollLimitBurst"))
2608
                return bus_append_safe_atou(m, field, eq);
×
2609

2610
        if (STR_IN_SET(field, "SocketMode",
4✔
2611
                              "DirectoryMode"))
2612
                return bus_append_parse_mode(m, field, eq);
2✔
2613

2614
        if (STR_IN_SET(field, "MessageQueueMaxMessages",
2✔
2615
                              "MessageQueueMessageSize"))
2616
                return bus_append_safe_atoi64(m, field, eq);
×
2617

2618
        if (STR_IN_SET(field, "TimeoutSec",
2✔
2619
                              "KeepAliveTimeSec",
2620
                              "KeepAliveIntervalSec",
2621
                              "DeferAcceptSec",
2622
                              "TriggerLimitIntervalSec",
2623
                              "PollLimitIntervalSec"))
2624
                return bus_append_parse_sec_rename(m, field, eq);
×
2625

2626
        if (STR_IN_SET(field, "ReceiveBuffer",
2✔
2627
                              "SendBuffer",
2628
                              "PipeSize"))
2629
                return bus_append_parse_size(m, field, eq, 1024);
×
2630

2631
        if (STR_IN_SET(field, "ExecStartPre",
2✔
2632
                              "ExecStartPost",
2633
                              "ExecReload",
2634
                              "ExecStopPost"))
2635
                return bus_append_exec_command(m, field, eq);
×
2636

2637
        if (STR_IN_SET(field, "SmackLabel",
2✔
2638
                              "SmackLabelIPIn",
2639
                              "SmackLabelIPOut",
2640
                              "TCPCongestion",
2641
                              "BindToDevice",
2642
                              "BindIPv6Only",
2643
                              "FileDescriptorName",
2644
                              "SocketUser",
2645
                              "SocketGroup",
2646
                              "Timestamping"))
2647
                return bus_append_string(m, field, eq);
×
2648

2649
        if (streq(field, "Symlinks"))
2✔
2650
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
2651

2652
        if (streq(field, "SocketProtocol"))
2✔
2653
                return bus_append_parse_ip_protocol(m, field, eq);
×
2654

2655
        if (STR_IN_SET(field, "ListenStream",
2✔
2656
                              "ListenDatagram",
2657
                              "ListenSequentialPacket",
2658
                              "ListenNetlink",
2659
                              "ListenSpecial",
2660
                              "ListenMessageQueue",
2661
                              "ListenFIFO",
2662
                              "ListenUSBFunction")) {
2663
                if (isempty(eq))
2✔
2664
                        r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
×
2665
                else
2666
                        r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2✔
2667
                if (r < 0)
2✔
2668
                        return bus_log_create_error(r);
2✔
2669

2670
                return 1;
2671
        }
2672

2673
        return 0;
×
2674
}
2675
static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
25✔
2676
        int r;
25✔
2677

2678
        if (STR_IN_SET(field, "WakeSystem",
25✔
2679
                              "RemainAfterElapse",
2680
                              "Persistent",
2681
                              "OnTimezoneChange",
2682
                              "OnClockChange",
2683
                              "FixedRandomDelay",
2684
                              "DeferReactivation"))
2685
                return bus_append_parse_boolean(m, field, eq);
5✔
2686

2687
        if (STR_IN_SET(field, "AccuracySec",
20✔
2688
                              "RandomizedDelaySec"))
2689
                return bus_append_parse_sec_rename(m, field, eq);
×
2690

2691
        if (STR_IN_SET(field, "OnActiveSec",
20✔
2692
                              "OnBootSec",
2693
                              "OnStartupSec",
2694
                              "OnUnitActiveSec",
2695
                              "OnUnitInactiveSec")) {
2696
                if (isempty(eq))
17✔
2697
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
5✔
2698
                else {
2699
                        usec_t t;
12✔
2700
                        r = parse_sec(eq, &t);
12✔
2701
                        if (r < 0)
12✔
2702
                                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
5✔
2703

2704
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
7✔
2705
                }
2706
                if (r < 0)
12✔
2707
                        return bus_log_create_error(r);
×
2708

2709
                return 1;
2710
        }
2711

2712
        if (streq(field, "OnCalendar")) {
3✔
2713
                if (isempty(eq))
2✔
2714
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
×
2715
                else
2716
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2✔
2717
                if (r < 0)
2✔
2718
                        return bus_log_create_error(r);
×
2719

2720
                return 1;
2721
        }
2722

2723
        return 0;
2724
}
2725

2726
static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
29✔
2727
        ConditionType t = _CONDITION_TYPE_INVALID;
29✔
2728
        bool is_condition = false;
29✔
2729
        int r;
29✔
2730

2731
        if (STR_IN_SET(field, "Description",
29✔
2732
                              "SourcePath",
2733
                              "OnFailureJobMode",
2734
                              "JobTimeoutAction",
2735
                              "JobTimeoutRebootArgument",
2736
                              "StartLimitAction",
2737
                              "FailureAction",
2738
                              "SuccessAction",
2739
                              "RebootArgument",
2740
                              "CollectMode"))
2741
                return bus_append_string(m, field, eq);
12✔
2742

2743
        if (STR_IN_SET(field, "StopWhenUnneeded",
17✔
2744
                              "RefuseManualStart",
2745
                              "RefuseManualStop",
2746
                              "AllowIsolate",
2747
                              "IgnoreOnIsolate",
2748
                              "SurviveFinalKillSignal",
2749
                              "DefaultDependencies"))
2750
                return bus_append_parse_boolean(m, field, eq);
2✔
2751

2752
        if (STR_IN_SET(field, "JobTimeoutSec",
15✔
2753
                              "JobRunningTimeoutSec",
2754
                              "StartLimitIntervalSec"))
2755
                return bus_append_parse_sec_rename(m, field, eq);
1✔
2756

2757
        if (streq(field, "StartLimitBurst"))
14✔
2758
                return bus_append_safe_atou(m, field, eq);
1✔
2759

2760
        if (STR_IN_SET(field, "SuccessActionExitStatus",
13✔
2761
                              "FailureActionExitStatus")) {
2762
                if (isempty(eq))
×
2763
                        r = sd_bus_message_append(m, "(sv)", field, "i", -1);
×
2764
                else {
2765
                        uint8_t u;
×
2766

2767
                        r = safe_atou8(eq, &u);
×
2768
                        if (r < 0)
×
2769
                                return log_error_errno(r, "Failed to parse %s=%s", field, eq);
×
2770

2771
                        r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
×
2772
                }
2773
                if (r < 0)
×
2774
                        return bus_log_create_error(r);
×
2775

2776
                return 1;
2777
        }
2778

2779
        if (unit_dependency_from_string(field) >= 0 ||
16✔
2780
            STR_IN_SET(field, "Documentation",
3✔
2781
                              "RequiresMountsFor",
2782
                              "WantsMountsFor",
2783
                              "Markers"))
2784
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
11✔
2785

2786
        t = condition_type_from_string(field);
2✔
2787
        if (t >= 0)
2✔
2788
                is_condition = true;
2789
        else
2790
                t = assert_type_from_string(field);
2✔
2791
        if (t >= 0) {
2✔
2792
                if (isempty(eq))
2✔
2793
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
×
2794
                else {
2795
                        const char *p = eq;
2✔
2796
                        int trigger, negate;
2✔
2797

2798
                        trigger = *p == '|';
2✔
2799
                        if (trigger)
2✔
2800
                                p++;
×
2801

2802
                        negate = *p == '!';
2✔
2803
                        if (negate)
2✔
2804
                                p++;
×
2805

2806
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
4✔
2807
                                                  field, trigger, negate, p);
2808
                }
2809
                if (r < 0)
2✔
2810
                        return bus_log_create_error(r);
×
2811

2812
                return 1;
2813
        }
2814

2815
        return 0;
2816
}
2817

2818
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
3,235✔
2819
        const char *eq, *field;
3,235✔
2820
        int r;
3,235✔
2821

2822
        assert(m);
3,235✔
2823
        assert(assignment);
3,235✔
2824

2825
        eq = strchr(assignment, '=');
3,235✔
2826
        if (!eq)
3,235✔
2827
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2828
                                       "Not an assignment: %s", assignment);
2829

2830
        field = strndupa_safe(assignment, eq - assignment);
3,233✔
2831
        eq++;
3,233✔
2832

2833
        switch (t) {
3,233✔
2834
        case UNIT_SERVICE:
3,184✔
2835
                r = bus_append_cgroup_property(m, field, eq);
3,184✔
2836
                if (r != 0)
3,184✔
2837
                        return r;
2838

2839
                r = bus_append_execute_property(m, field, eq);
2,796✔
2840
                if (r != 0)
2,796✔
2841
                        return r;
2842

2843
                r = bus_append_kill_property(m, field, eq);
195✔
2844
                if (r != 0)
195✔
2845
                        return r;
2846

2847
                r = bus_append_service_property(m, field, eq);
192✔
2848
                if (r != 0)
192✔
2849
                        return r;
2850
                break;
2851

2852
        case UNIT_SOCKET:
4✔
2853
                r = bus_append_cgroup_property(m, field, eq);
4✔
2854
                if (r != 0)
4✔
2855
                        return r;
2856

2857
                r = bus_append_execute_property(m, field, eq);
4✔
2858
                if (r != 0)
4✔
2859
                        return r;
2860

2861
                r = bus_append_kill_property(m, field, eq);
4✔
2862
                if (r != 0)
4✔
2863
                        return r;
2864

2865
                r = bus_append_socket_property(m, field, eq);
4✔
2866
                if (r != 0)
4✔
2867
                        return r;
2868
                break;
2869

2870
        case UNIT_TIMER:
25✔
2871
                r = bus_append_timer_property(m, field, eq);
25✔
2872
                if (r != 0)
25✔
2873
                        return r;
2874
                break;
2875

2876
        case UNIT_PATH:
3✔
2877
                r = bus_append_path_property(m, field, eq);
3✔
2878
                if (r != 0)
3✔
2879
                        return r;
2880
                break;
2881

2882
        case UNIT_SLICE:
3✔
2883
                r = bus_append_cgroup_property(m, field, eq);
3✔
2884
                if (r != 0)
3✔
2885
                        return r;
2886
                break;
2887

2888
        case UNIT_SCOPE:
10✔
2889
                r = bus_append_cgroup_property(m, field, eq);
10✔
2890
                if (r != 0)
10✔
2891
                        return r;
2892

2893
                r = bus_append_kill_property(m, field, eq);
8✔
2894
                if (r != 0)
8✔
2895
                        return r;
2896

2897
                r = bus_append_scope_property(m, field, eq);
8✔
2898
                if (r != 0)
8✔
2899
                        return r;
2900
                break;
2901

2902
        case UNIT_MOUNT:
3✔
2903
                r = bus_append_cgroup_property(m, field, eq);
3✔
2904
                if (r != 0)
3✔
2905
                        return r;
2906

2907
                r = bus_append_execute_property(m, field, eq);
3✔
2908
                if (r != 0)
3✔
2909
                        return r;
2910

2911
                r = bus_append_kill_property(m, field, eq);
1✔
2912
                if (r != 0)
1✔
2913
                        return r;
2914

2915
                r = bus_append_mount_property(m, field, eq);
1✔
2916
                if (r != 0)
1✔
2917
                        return r;
2918

2919
                break;
2920

2921
        case UNIT_AUTOMOUNT:
1✔
2922
                r = bus_append_automount_property(m, field, eq);
1✔
2923
                if (r != 0)
1✔
2924
                        return r;
2925

2926
                break;
2927

2928
        case UNIT_TARGET:
2929
        case UNIT_DEVICE:
2930
        case UNIT_SWAP:
2931
                break;
2932

2933
        default:
×
2934
                assert_not_reached();
×
2935
        }
2936

2937
        r = bus_append_unit_property(m, field, eq);
29✔
2938
        if (r != 0)
29✔
2939
                return r;
2940

2941
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2942
                               "Unknown assignment: %s", assignment);
2943
}
2944

2945
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1,339✔
2946
        int r;
1,339✔
2947

2948
        assert(m);
1,339✔
2949

2950
        STRV_FOREACH(i, l) {
4,565✔
2951
                r = bus_append_unit_property_assignment(m, t, *i);
3,235✔
2952
                if (r < 0)
3,235✔
2953
                        return r;
2954
        }
2955

2956
        return 0;
2957
}
2958

2959
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
428✔
2960
        assert(m);
428✔
2961

2962
        if (!pidref_is_set(pidref))
428✔
2963
                return -ESRCH;
2964

2965
        if (pidref->fd >= 0 && allow_pidfd)
428✔
2966
                return sd_bus_message_append(
428✔
2967
                                m, "(sv)",
2968
                                "PIDFDs", "ah", 1, pidref->fd);
2969

2970
        return sd_bus_message_append(
×
2971
                        m, "(sv)",
2972
                        "PIDs", "au", 1, pidref->pid);
2973
}
2974

2975
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
58✔
2976
        const char *type, *path, *source;
58✔
2977
        InstallChange *changes = NULL;
58✔
2978
        size_t n_changes = 0;
58✔
2979
        int r;
58✔
2980

2981
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
58✔
2982

2983
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
58✔
2984
        if (r < 0)
58✔
2985
                return bus_log_parse_error(r);
×
2986

2987
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
115✔
2988
                InstallChangeType t;
57✔
2989

2990
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2991
                 * negative. */
2992
                t = install_change_type_from_string(type);
57✔
2993
                if (t < 0) {
57✔
2994
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
2995
                                         type, path);
2996
                        continue;
×
2997
                }
2998

2999
                r = install_changes_add(&changes, &n_changes, t, path, source);
57✔
3000
                if (r < 0)
57✔
3001
                        return r;
3002
        }
3003
        if (r < 0)
58✔
3004
                return bus_log_parse_error(r);
×
3005

3006
        r = sd_bus_message_exit_container(m);
58✔
3007
        if (r < 0)
58✔
3008
                return bus_log_parse_error(r);
×
3009

3010
        install_changes_dump(0, NULL, changes, n_changes, quiet);
58✔
3011

3012
        return 0;
3013
}
3014

3015
int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
3,564✔
3016
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3017
        _cleanup_free_ char *path = NULL;
3,564✔
3018
        int r;
3,564✔
3019

3020
        path = unit_dbus_path_from_name(name);
3,564✔
3021
        if (!path)
3,564✔
3022
                return log_oom();
×
3023

3024
        /* This function warns on its own, because otherwise it'd be awkward to pass
3025
         * the dbus error message around. */
3026

3027
        r = sd_bus_get_property_string(
3,564✔
3028
                        bus,
3029
                        "org.freedesktop.systemd1",
3030
                        path,
3031
                        "org.freedesktop.systemd1.Unit",
3032
                        "LoadState",
3033
                        &error,
3034
                        load_state);
3035
        if (r < 0)
3,564✔
3036
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
3037

3038
        return 0;
3039
}
3040

3041
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
31,603✔
3042
        int r;
31,603✔
3043

3044
        /* First, order by machine */
3045
        r = strcasecmp_ptr(a->machine, b->machine);
31,603✔
3046
        if (r != 0)
31,603✔
3047
                return r;
3048

3049
        /* Second, order by unit type */
3050
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
31,603✔
3051
        if (r != 0)
31,603✔
3052
                return r;
3053

3054
        /* Third, order by name */
3055
        return strcasecmp(a->id, b->id);
29,286✔
3056
}
3057

3058
int bus_service_manager_reload(sd_bus *bus) {
62✔
3059
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3060
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
62✔
3061
        int r;
62✔
3062

3063
        assert(bus);
62✔
3064

3065
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
62✔
3066
        if (r < 0)
62✔
3067
                return bus_log_create_error(r);
×
3068

3069
        /* Reloading the daemon may take long, hence set a longer timeout here */
3070
        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
62✔
3071
        if (r < 0)
62✔
3072
                return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
×
3073

3074
        return 0;
3075
}
3076

3077
typedef struct UnitFreezer {
3078
        char *name;
3079
        sd_bus *bus;
3080
} UnitFreezer;
3081

3082
/* Wait for 60 seconds at maximum for freezer operation */
3083
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3084

3085
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
3086
        if (!f)
×
3087
                return NULL;
3088

3089
        free(f->name);
×
3090
        sd_bus_flush_close_unref(f->bus);
×
3091

3092
        return mfree(f);
×
3093
}
3094

3095
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
3096
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
3097
        int r;
×
3098

3099
        assert(name);
×
3100
        assert(ret);
×
3101

3102
        f = new(UnitFreezer, 1);
×
3103
        if (!f)
×
3104
                return log_oom();
×
3105

3106
        *f = (UnitFreezer) {
×
3107
                .name = strdup(name),
×
3108
        };
3109
        if (!f->name)
×
3110
                return log_oom();
×
3111

3112
        r = bus_connect_system_systemd(&f->bus);
×
3113
        if (r < 0)
×
3114
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3115

3116
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3117

3118
        *ret = TAKE_PTR(f);
×
3119
        return 0;
×
3120
}
3121

3122
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
3123
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3124
        int r;
×
3125

3126
        assert(f);
×
3127
        assert(f->name);
×
3128
        assert(f->bus);
×
3129

3130
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3131
                            freeze ? "FreezeUnit" : "ThawUnit",
3132
                            &error,
3133
                            /* reply = */ NULL,
3134
                            "s",
3135
                            f->name);
3136
        if (r < 0) {
×
3137
                if (sd_bus_error_has_names(&error,
×
3138
                                           BUS_ERROR_NO_SUCH_UNIT,
3139
                                           BUS_ERROR_UNIT_INACTIVE,
3140
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3141

3142
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
3143
                        return 0;
×
3144
                }
3145

3146
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3147
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3148
        }
3149

3150
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3151
        return 1;
3152
}
3153

3154
int unit_freezer_freeze(UnitFreezer *f) {
×
3155
        return unit_freezer_action(f, true);
×
3156
}
3157

3158
int unit_freezer_thaw(UnitFreezer *f) {
×
3159
        return unit_freezer_action(f, false);
×
3160
}
3161

3162
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,788✔
3163
        if (isempty(s))
1,788✔
3164
                return 0;
3165

3166
        if (streq(s, "ro"))
74✔
3167
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3168

3169
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3170
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2026 Coveralls, Inc