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

systemd / systemd / 16038438970

03 Jul 2025 12:06AM UTC coverage: 72.096% (+0.1%) from 71.988%
16038438970

push

github

web-flow
test-xattr-util.c: migrate to new assertion macros (#38025)

We recently added a new set of assertion macros such as ASSERT_GE,
ASSERT_OK, ASSERT_EQ, ... which show not only the expression that failed
but also the values of the arguments of the expression. Let's use them.

12 of 13 new or added lines in 1 file covered. (92.31%)

3080 existing lines in 44 files now uncovered.

300788 of 417204 relevant lines covered (72.1%)

711634.61 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,852✔
54
        assert(message);
11,852✔
55
        assert(u);
11,852✔
56

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

59
        return sd_bus_message_read(
11,852✔
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);
420✔
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) {
619✔
142
        int r;
619✔
143

144
        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
619✔
145
        if (r < 0)
619✔
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) {
416✔
152
        int r;
416✔
153

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

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

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

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

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

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

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

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

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

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

197
        r = sd_bus_message_close_container(m);
416✔
198
        if (r < 0)
416✔
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) {
45✔
272
        bool explicit_path = false, done = false, ambient_hack = false;
45✔
273
        _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
45✔
274
        _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
45✔
275
        ExecCommandFlags flags = 0;
45✔
276
        bool is_ex_prop = endswith(field, "Ex");
45✔
277
        int r;
64✔
278

279
        do {
64✔
280
                switch (*eq) {
64✔
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);
64✔
350

351
        if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL))) {
45✔
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) {
36✔
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)) {
45✔
368
                path = strdup(_PATH_BSHELL);
2✔
369
                if (!path)
2✔
370
                        return log_oom();
×
371

372
        } else if (explicit_path) {
43✔
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);
45✔
383
        if (r < 0)
45✔
384
                return log_error_errno(r, "Failed to parse command line: %m");
×
385

386
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
45✔
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");
45✔
393
        if (r < 0)
45✔
394
                return bus_log_create_error(r);
×
395

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

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

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

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

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

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

418
                r = sd_bus_message_append_strv(m, l);
45✔
419
                if (r < 0)
45✔
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));
45✔
423
                if (r < 0)
45✔
424
                        return bus_log_create_error(r);
×
425

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

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

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

439
        r = sd_bus_message_close_container(m);
45✔
440
        if (r < 0)
45✔
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,251✔
574
        int r;
3,251✔
575

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

585
        if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
3,231✔
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,231✔
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,223✔
607
                              "StartupCPUWeight"))
608
                return bus_append_cg_cpu_weight_parse(m, field, eq);
×
609

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

614
        if (STR_IN_SET(field, "AllowedCPUs",
3,223✔
615
                              "StartupAllowedCPUs",
616
                              "AllowedMemoryNodes",
617
                              "StartupAllowedMemoryNodes")) {
618

619
                _cleanup_(cpu_set_done) CPUSet cpuset = {};
×
620
                _cleanup_free_ uint8_t *array = NULL;
×
621
                size_t allocated;
×
622

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

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

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

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

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

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

646
                return 1;
647
        }
648

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

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

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

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

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

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

692
                        return 1;
693
                }
694

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

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

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

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

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

717
                return 1;
718
        }
719

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

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

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

731
                return 1;
732
        }
733

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

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

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

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

752
                return 1;
753
        }
754

755
        if (cgroup_io_limit_type_from_string(field) >= 0) {
2,857✔
756

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

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

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

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

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

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

786
                return 1;
787
        }
788

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

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

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

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

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

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

815
                return 1;
816
        }
817

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

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

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

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

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

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

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

846
                return 1;
847
        }
848

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

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

860
                        return 1;
861
                }
862

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

967
                return 1;
968
        }
969

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

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

980
                return 1;
981
        }
982

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

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

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

1000
                return 1;
1001
        }
1002

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

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

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

1023
                return 1;
1024
        }
1025

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

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

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

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

1050
        return 0;
2,851✔
1051
}
1052

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

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

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

1064
        return 0;
1065
}
1066

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1218
                return 1;
1219
        }
1220

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1299
                return 1;
1300
        }
1301

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

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

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

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

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

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

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

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

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

1345
                return 1;
1346
        }
1347

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

1356
                return 1;
1357
        }
1358

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

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

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

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

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

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

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

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

1399
                return 1;
1400
        }
1401

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

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

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

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

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

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

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

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

1435
                return 1;
1436
        }
1437

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

1445
                return 1;
1446
        }
1447

1448
        if (STR_IN_SET(field, "StandardInput",
638✔
1449
                              "StandardOutput",
1450
                              "StandardError")) {
1451
                const char *n, *appended;
47✔
1452

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

1470
                return 1;
1471
        }
1472

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

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

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

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

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

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

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

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

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

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

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

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

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

1522
                        return 1;
1523
                }
1524
        }
1525

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

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

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

1540
                return 1;
1541
        }
1542

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

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

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

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

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

1564
                return 1;
1565
        }
1566

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

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

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

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

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

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

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

1599
                return 1;
1600
        }
1601

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1693
                return 1;
1694
        }
1695

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

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

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

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

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

1728
                return 1;
1729
        }
1730

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

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

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

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

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

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

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

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

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

1778
                                d = destination;
10✔
1779

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

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

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

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

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

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

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

1816
                return 1;
1817
        }
1818

1819
        if (streq(field, "TemporaryFileSystem")) {
517✔
1820
                const char *p = eq;
49✔
1821

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

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

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

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

1838
                for (;;) {
151✔
1839
                        _cleanup_free_ char *word = NULL, *path = NULL;
51✔
1840
                        const char *w;
100✔
1841

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

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

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

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

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

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

1874
                return 1;
1875
        }
1876

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

1959
                return 1;
1960
        }
1961

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2036
                                        break;
2037
                                }
2038

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

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

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

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

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

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

2065
                return 1;
2066
        }
2067

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2137
                                        break;
2138
                                }
2139

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

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

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

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

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

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

2166
                return 1;
2167
        }
2168

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

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

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

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

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

2191
                        path_simplify(source);
241✔
2192

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2307
                return 1;
183✔
2308
        }
2309

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

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

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

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

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

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

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

2346
        return 0;
229✔
2347
}
2348

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

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

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

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

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

2369
        return 0;
1✔
2370
}
2371

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

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

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

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

2393
                return 1;
2394
        }
2395

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

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

2402
        return 0;
×
2403
}
2404

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

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

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

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

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

2423
        return 0;
2424
}
2425

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

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

2444
        if (STR_IN_SET(field, "PermissionsStartOnly",
99✔
2445
                              "RootDirectoryStartOnly",
2446
                              "RemainAfterExit",
2447
                              "GuessMainPID"))
2448
                return bus_append_parse_boolean(m, field, eq);
2✔
2449

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

2566
                return 1;
2567
        }
2568

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

2572
        return 0;
2573
}
2574

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

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

2597
        if (STR_IN_SET(field, "Priority",
4✔
2598
                              "IPTTL",
2599
                              "Mark"))
2600
                return bus_append_safe_atoi(m, field, eq);
×
2601

2602
        if (streq(field, "IPTOS"))
4✔
2603
                return bus_append_ip_tos_from_string(m, field, eq);
×
2604

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

2613
        if (STR_IN_SET(field, "SocketMode",
4✔
2614
                              "DirectoryMode"))
2615
                return bus_append_parse_mode(m, field, eq);
2✔
2616

2617
        if (STR_IN_SET(field, "MessageQueueMaxMessages",
2✔
2618
                              "MessageQueueMessageSize"))
2619
                return bus_append_safe_atoi64(m, field, eq);
×
2620

2621
        if (STR_IN_SET(field, "TimeoutSec",
2✔
2622
                              "KeepAliveTimeSec",
2623
                              "KeepAliveIntervalSec",
2624
                              "DeferAcceptSec",
2625
                              "TriggerLimitIntervalSec",
2626
                              "PollLimitIntervalSec",
2627
                              "DeferTriggerMaxSec"))
UNCOV
2628
                return bus_append_parse_sec_rename(m, field, eq);
×
2629

2630
        if (STR_IN_SET(field, "ReceiveBuffer",
2✔
2631
                              "SendBuffer",
2632
                              "PipeSize"))
UNCOV
2633
                return bus_append_parse_size(m, field, eq, 1024);
×
2634

2635
        if (STR_IN_SET(field, "ExecStartPre",
2✔
2636
                              "ExecStartPost",
2637
                              "ExecReload",
2638
                              "ExecStopPost"))
UNCOV
2639
                return bus_append_exec_command(m, field, eq);
×
2640

2641
        if (STR_IN_SET(field, "SmackLabel",
2✔
2642
                              "SmackLabelIPIn",
2643
                              "SmackLabelIPOut",
2644
                              "TCPCongestion",
2645
                              "BindToDevice",
2646
                              "BindIPv6Only",
2647
                              "FileDescriptorName",
2648
                              "SocketUser",
2649
                              "SocketGroup",
2650
                              "Timestamping",
2651
                              "DeferTrigger"))
UNCOV
2652
                return bus_append_string(m, field, eq);
×
2653

2654
        if (streq(field, "Symlinks"))
2✔
UNCOV
2655
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
2656

2657
        if (streq(field, "SocketProtocol"))
2✔
UNCOV
2658
                return bus_append_parse_ip_protocol(m, field, eq);
×
2659

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

2675
                return 1;
2676
        }
2677

UNCOV
2678
        return 0;
×
2679
}
2680
static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
27✔
2681
        int r;
27✔
2682

2683
        if (STR_IN_SET(field, "WakeSystem",
27✔
2684
                              "RemainAfterElapse",
2685
                              "Persistent",
2686
                              "OnTimezoneChange",
2687
                              "OnClockChange",
2688
                              "FixedRandomDelay",
2689
                              "DeferReactivation"))
2690
                return bus_append_parse_boolean(m, field, eq);
7✔
2691

2692
        if (STR_IN_SET(field, "AccuracySec",
20✔
2693
                              "RandomizedDelaySec",
2694
                              "RandomizedOffsetSec"))
UNCOV
2695
                return bus_append_parse_sec_rename(m, field, eq);
×
2696

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

2710
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
7✔
2711
                }
2712
                if (r < 0)
12✔
UNCOV
2713
                        return bus_log_create_error(r);
×
2714

2715
                return 1;
2716
        }
2717

2718
        if (streq(field, "OnCalendar")) {
3✔
2719
                if (isempty(eq))
2✔
UNCOV
2720
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
×
2721
                else
2722
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2✔
2723
                if (r < 0)
2✔
UNCOV
2724
                        return bus_log_create_error(r);
×
2725

2726
                return 1;
2727
        }
2728

2729
        return 0;
2730
}
2731

2732
static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
50✔
2733
        ConditionType t = _CONDITION_TYPE_INVALID;
50✔
2734
        bool is_condition = false;
50✔
2735
        int r;
50✔
2736

2737
        if (STR_IN_SET(field, "Description",
50✔
2738
                              "SourcePath",
2739
                              "OnFailureJobMode",
2740
                              "JobTimeoutAction",
2741
                              "JobTimeoutRebootArgument",
2742
                              "StartLimitAction",
2743
                              "FailureAction",
2744
                              "SuccessAction",
2745
                              "RebootArgument",
2746
                              "CollectMode"))
2747
                return bus_append_string(m, field, eq);
12✔
2748

2749
        if (STR_IN_SET(field, "StopWhenUnneeded",
38✔
2750
                              "RefuseManualStart",
2751
                              "RefuseManualStop",
2752
                              "AllowIsolate",
2753
                              "IgnoreOnIsolate",
2754
                              "SurviveFinalKillSignal",
2755
                              "DefaultDependencies"))
2756
                return bus_append_parse_boolean(m, field, eq);
13✔
2757

2758
        if (STR_IN_SET(field, "JobTimeoutSec",
25✔
2759
                              "JobRunningTimeoutSec",
2760
                              "StartLimitIntervalSec"))
2761
                return bus_append_parse_sec_rename(m, field, eq);
1✔
2762

2763
        if (streq(field, "StartLimitBurst"))
24✔
2764
                return bus_append_safe_atou(m, field, eq);
1✔
2765

2766
        if (STR_IN_SET(field, "SuccessActionExitStatus",
23✔
2767
                              "FailureActionExitStatus")) {
UNCOV
2768
                if (isempty(eq))
×
2769
                        r = sd_bus_message_append(m, "(sv)", field, "i", -1);
×
2770
                else {
2771
                        uint8_t u;
×
2772

2773
                        r = safe_atou8(eq, &u);
×
UNCOV
2774
                        if (r < 0)
×
2775
                                return log_error_errno(r, "Failed to parse %s=%s", field, eq);
×
2776

2777
                        r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
×
2778
                }
UNCOV
2779
                if (r < 0)
×
UNCOV
2780
                        return bus_log_create_error(r);
×
2781

2782
                return 1;
2783
        }
2784

2785
        if (unit_dependency_from_string(field) >= 0 ||
26✔
2786
            STR_IN_SET(field, "Documentation",
3✔
2787
                              "RequiresMountsFor",
2788
                              "WantsMountsFor",
2789
                              "Markers"))
2790
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
21✔
2791

2792
        t = condition_type_from_string(field);
2✔
2793
        if (t >= 0)
2✔
2794
                is_condition = true;
2795
        else
2796
                t = assert_type_from_string(field);
2✔
2797
        if (t >= 0) {
2✔
2798
                if (isempty(eq))
2✔
UNCOV
2799
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
×
2800
                else {
2801
                        const char *p = eq;
2✔
2802
                        int trigger, negate;
2✔
2803

2804
                        trigger = *p == '|';
2✔
2805
                        if (trigger)
2✔
UNCOV
2806
                                p++;
×
2807

2808
                        negate = *p == '!';
2✔
2809
                        if (negate)
2✔
UNCOV
2810
                                p++;
×
2811

2812
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
4✔
2813
                                                  field, trigger, negate, p);
2814
                }
2815
                if (r < 0)
2✔
UNCOV
2816
                        return bus_log_create_error(r);
×
2817

2818
                return 1;
2819
        }
2820

2821
        return 0;
2822
}
2823

2824
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
3,284✔
2825
        const char *eq, *field;
3,284✔
2826
        int r;
3,284✔
2827

2828
        assert(m);
3,284✔
2829
        assert(assignment);
3,284✔
2830

2831
        eq = strchr(assignment, '=');
3,284✔
2832
        if (!eq)
3,284✔
2833
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2834
                                       "Not an assignment: %s", assignment);
2835

2836
        field = strndupa_safe(assignment, eq - assignment);
3,282✔
2837
        eq++;
3,282✔
2838

2839
        switch (t) {
3,282✔
2840
        case UNIT_SERVICE:
3,231✔
2841
                r = bus_append_cgroup_property(m, field, eq);
3,231✔
2842
                if (r != 0)
3,231✔
2843
                        return r;
2844

2845
                r = bus_append_execute_property(m, field, eq);
2,836✔
2846
                if (r != 0)
2,836✔
2847
                        return r;
2848

2849
                r = bus_append_kill_property(m, field, eq);
219✔
2850
                if (r != 0)
219✔
2851
                        return r;
2852

2853
                r = bus_append_service_property(m, field, eq);
216✔
2854
                if (r != 0)
216✔
2855
                        return r;
2856
                break;
2857

2858
        case UNIT_SOCKET:
4✔
2859
                r = bus_append_cgroup_property(m, field, eq);
4✔
2860
                if (r != 0)
4✔
2861
                        return r;
2862

2863
                r = bus_append_execute_property(m, field, eq);
4✔
2864
                if (r != 0)
4✔
2865
                        return r;
2866

2867
                r = bus_append_kill_property(m, field, eq);
4✔
2868
                if (r != 0)
4✔
2869
                        return r;
2870

2871
                r = bus_append_socket_property(m, field, eq);
4✔
2872
                if (r != 0)
4✔
2873
                        return r;
2874
                break;
2875

2876
        case UNIT_TIMER:
27✔
2877
                r = bus_append_timer_property(m, field, eq);
27✔
2878
                if (r != 0)
27✔
2879
                        return r;
2880
                break;
2881

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

2888
        case UNIT_SLICE:
3✔
2889
                r = bus_append_cgroup_property(m, field, eq);
3✔
2890
                if (r != 0)
3✔
2891
                        return r;
2892
                break;
2893

2894
        case UNIT_SCOPE:
10✔
2895
                r = bus_append_cgroup_property(m, field, eq);
10✔
2896
                if (r != 0)
10✔
2897
                        return r;
2898

2899
                r = bus_append_kill_property(m, field, eq);
8✔
2900
                if (r != 0)
8✔
2901
                        return r;
2902

2903
                r = bus_append_scope_property(m, field, eq);
8✔
2904
                if (r != 0)
8✔
2905
                        return r;
2906
                break;
2907

2908
        case UNIT_MOUNT:
3✔
2909
                r = bus_append_cgroup_property(m, field, eq);
3✔
2910
                if (r != 0)
3✔
2911
                        return r;
2912

2913
                r = bus_append_execute_property(m, field, eq);
3✔
2914
                if (r != 0)
3✔
2915
                        return r;
2916

2917
                r = bus_append_kill_property(m, field, eq);
1✔
2918
                if (r != 0)
1✔
2919
                        return r;
2920

2921
                r = bus_append_mount_property(m, field, eq);
1✔
2922
                if (r != 0)
1✔
2923
                        return r;
2924

2925
                break;
2926

2927
        case UNIT_AUTOMOUNT:
1✔
2928
                r = bus_append_automount_property(m, field, eq);
1✔
2929
                if (r != 0)
1✔
2930
                        return r;
2931

2932
                break;
2933

2934
        case UNIT_TARGET:
2935
        case UNIT_DEVICE:
2936
        case UNIT_SWAP:
2937
                break;
2938

UNCOV
2939
        default:
×
UNCOV
2940
                assert_not_reached();
×
2941
        }
2942

2943
        r = bus_append_unit_property(m, field, eq);
50✔
2944
        if (r != 0)
50✔
2945
                return r;
2946

UNCOV
2947
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2948
                               "Unknown assignment: %s", assignment);
2949
}
2950

2951
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char * const *l) {
1,394✔
2952
        int r;
1,394✔
2953

2954
        assert(m);
1,394✔
2955

2956
        STRV_FOREACH(i, l) {
4,669✔
2957
                r = bus_append_unit_property_assignment(m, t, *i);
3,284✔
2958
                if (r < 0)
3,284✔
2959
                        return r;
2960
        }
2961

2962
        return 0;
2963
}
2964

2965
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
445✔
2966
        assert(m);
445✔
2967

2968
        if (!pidref_is_set(pidref))
445✔
2969
                return -ESRCH;
2970

2971
        if (pidref->fd >= 0 && allow_pidfd)
445✔
2972
                return sd_bus_message_append(
445✔
2973
                                m, "(sv)",
2974
                                "PIDFDs", "ah", 1, pidref->fd);
2975

UNCOV
2976
        return sd_bus_message_append(
×
2977
                        m, "(sv)",
2978
                        "PIDs", "au", 1, pidref->pid);
2979
}
2980

2981
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
58✔
2982
        const char *type, *path, *source;
58✔
2983
        InstallChange *changes = NULL;
58✔
2984
        size_t n_changes = 0;
58✔
2985
        int r;
58✔
2986

2987
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
58✔
2988

2989
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
58✔
2990
        if (r < 0)
58✔
UNCOV
2991
                return bus_log_parse_error(r);
×
2992

2993
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
115✔
2994
                InstallChangeType t;
57✔
2995

2996
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2997
                 * negative. */
2998
                t = install_change_type_from_string(type);
57✔
2999
                if (t < 0) {
57✔
3000
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
3001
                                         type, path);
UNCOV
3002
                        continue;
×
3003
                }
3004

3005
                r = install_changes_add(&changes, &n_changes, t, path, source);
57✔
3006
                if (r < 0)
57✔
3007
                        return r;
3008
        }
3009
        if (r < 0)
58✔
UNCOV
3010
                return bus_log_parse_error(r);
×
3011

3012
        r = sd_bus_message_exit_container(m);
58✔
3013
        if (r < 0)
58✔
UNCOV
3014
                return bus_log_parse_error(r);
×
3015

3016
        install_changes_dump(0, NULL, changes, n_changes, quiet);
58✔
3017

3018
        return 0;
3019
}
3020

3021
int unit_load_state(sd_bus *bus, const char *name, char **ret) {
3,819✔
UNCOV
3022
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3023
        _cleanup_free_ char *path = NULL;
3,819✔
3024
        int r;
3,819✔
3025

3026
        path = unit_dbus_path_from_name(name);
3,819✔
3027
        if (!path)
3,819✔
UNCOV
3028
                return log_oom();
×
3029

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

3033
        r = sd_bus_get_property_string(
3,819✔
3034
                        bus,
3035
                        "org.freedesktop.systemd1",
3036
                        path,
3037
                        "org.freedesktop.systemd1.Unit",
3038
                        "LoadState",
3039
                        &error,
3040
                        ret);
3041
        if (r < 0)
3,819✔
UNCOV
3042
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
3043

3044
        return 0;
3045
}
3046

3047
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
31,534✔
3048
        int r;
31,534✔
3049

3050
        /* First, order by machine */
3051
        r = strcasecmp_ptr(a->machine, b->machine);
31,534✔
3052
        if (r != 0)
31,534✔
3053
                return r;
3054

3055
        /* Second, order by unit type */
3056
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
31,534✔
3057
        if (r != 0)
31,534✔
3058
                return r;
3059

3060
        /* Third, order by name */
3061
        return strcasecmp(a->id, b->id);
29,270✔
3062
}
3063

3064
int bus_service_manager_reload(sd_bus *bus) {
63✔
UNCOV
3065
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3066
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
63✔
3067
        int r;
63✔
3068

3069
        assert(bus);
63✔
3070

3071
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
63✔
3072
        if (r < 0)
63✔
UNCOV
3073
                return bus_log_create_error(r);
×
3074

3075
        /* Reloading the daemon may take long, hence set a longer timeout here */
3076
        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
63✔
3077
        if (r < 0)
63✔
UNCOV
3078
                return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
×
3079

3080
        return 0;
3081
}
3082

3083
typedef struct UnitFreezer {
3084
        char *name;
3085
        sd_bus *bus;
3086
} UnitFreezer;
3087

3088
/* Wait for 60 seconds at maximum for freezer operation */
3089
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3090

UNCOV
3091
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
UNCOV
3092
        if (!f)
×
3093
                return NULL;
3094

UNCOV
3095
        free(f->name);
×
3096
        sd_bus_flush_close_unref(f->bus);
×
3097

UNCOV
3098
        return mfree(f);
×
3099
}
3100

3101
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
UNCOV
3102
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
3103
        int r;
×
3104

UNCOV
3105
        assert(name);
×
3106
        assert(ret);
×
3107

3108
        f = new(UnitFreezer, 1);
×
UNCOV
3109
        if (!f)
×
3110
                return log_oom();
×
3111

UNCOV
3112
        *f = (UnitFreezer) {
×
3113
                .name = strdup(name),
×
3114
        };
UNCOV
3115
        if (!f->name)
×
3116
                return log_oom();
×
3117

3118
        r = bus_connect_system_systemd(&f->bus);
×
UNCOV
3119
        if (r < 0)
×
3120
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3121

3122
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3123

UNCOV
3124
        *ret = TAKE_PTR(f);
×
UNCOV
3125
        return 0;
×
3126
}
3127

3128
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
UNCOV
3129
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3130
        int r;
×
3131

3132
        assert(f);
×
UNCOV
3133
        assert(f->name);
×
3134
        assert(f->bus);
×
3135

UNCOV
3136
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3137
                            freeze ? "FreezeUnit" : "ThawUnit",
3138
                            &error,
3139
                            /* ret_reply = */ NULL,
3140
                            "s",
3141
                            f->name);
UNCOV
3142
        if (r < 0) {
×
UNCOV
3143
                if (sd_bus_error_has_names(&error,
×
3144
                                           BUS_ERROR_NO_SUCH_UNIT,
3145
                                           BUS_ERROR_UNIT_INACTIVE,
3146
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3147

UNCOV
3148
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
UNCOV
3149
                        return 0;
×
3150
                }
3151

UNCOV
3152
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3153
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3154
        }
3155

UNCOV
3156
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3157
        return 1;
3158
}
3159

UNCOV
3160
int unit_freezer_freeze(UnitFreezer *f) {
×
UNCOV
3161
        return unit_freezer_action(f, true);
×
3162
}
3163

UNCOV
3164
int unit_freezer_thaw(UnitFreezer *f) {
×
UNCOV
3165
        return unit_freezer_action(f, false);
×
3166
}
3167

3168
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,788✔
3169
        if (isempty(s))
1,788✔
3170
                return 0;
3171

3172
        if (streq(s, "ro"))
74✔
3173
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3174

3175
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3176
}
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