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

systemd / systemd / 22007273413

13 Feb 2026 09:37PM UTC coverage: 72.743% (+0.3%) from 72.485%
22007273413

push

github

web-flow
test: do not fail when parsing PID that isn't thread-group leader (#40677)

```
TEST-02-UNITTESTS.sh[4382]: [  707.393188] test-cgroup-util[426]: Failed to open pidfd for pid 414: Invalid argument
TEST-02-UNITTESTS.sh[4382]: [  707.393193] test-cgroup-util[426]: src/test/test-cgroup-util.c:249: Assertion failed: Expected "r = proc_dir_read_pidref(d, &pid)" to succeed, but got error: -22/EINVAL
```

The kernel can return EINVAL on pidfd_open() when the selected PID is
not a thread group leader. Don't fail the test, as we are iterating on
everything, so this can seldomly happen.

3 of 4 new or added lines in 1 file covered. (75.0%)

6126 existing lines in 58 files now uncovered.

312809 of 430017 relevant lines covered (72.74%)

1147140.71 hits per line

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

72.68
/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 "capability-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) {
16,092✔
54
        assert(message);
16,092✔
55
        assert(u);
16,092✔
56

57
        u->machine = NULL;
16,092✔
58

59
        return sd_bus_message_read(
16,092✔
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(_unused_ sd_bus_message *m, const char *field, const char *eq) {
14✔
75
        log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq);
14✔
76
        return 1;
14✔
77
}
78

79
static int parse_log_error(int error, const char *field, const char *eq) {
19✔
80
        if (error == -ENOMEM)
19✔
81
                return log_oom();
×
82
        if (error != 0)  /* Allow SYNTHETIC_ERRNO to be used, i.e. positive values. */
19✔
83
                return log_error_errno(error, "Failed to parse %s= value '%s': %m", field, eq);
17✔
84

85
        /* We don't log the error value for cases where we have a general "syntax error". */
86
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
87
                               "Invalid syntax for %s= value: '%s'", field, eq);
88
}
89

90
#define DEFINE_BUS_APPEND_PARSE_PTR(bus_type, cast_type, type, parse_func) \
91
        static int bus_append_##parse_func(                             \
92
                        sd_bus_message *m,                              \
93
                        const char *field,                              \
94
                        const char *eq) {                               \
95
                type val;                                               \
96
                int r;                                                  \
97
                                                                        \
98
                r = parse_func(eq, &val);                               \
99
                if (r < 0)                                              \
100
                        return parse_log_error(r, field, eq);           \
101
                                                                        \
102
                r = sd_bus_message_append(m, "(sv)", field,             \
103
                                          bus_type, (cast_type) val);   \
104
                if (r < 0)                                              \
105
                        return bus_log_create_error(r);                 \
106
                                                                        \
107
                return 1;                                               \
108
        }
109

110
#define DEFINE_BUS_APPEND_PARSE(bus_type, parse_func)                   \
111
        static int bus_append_##parse_func(                             \
112
                        sd_bus_message *m,                              \
113
                        const char *field,                              \
114
                        const char *eq) {                               \
115
                int r;                                                  \
116
                                                                        \
117
                r = parse_func(eq);                                     \
118
                if (r < 0)                                              \
119
                        return parse_log_error(r, field, eq);           \
120
                                                                        \
121
                r = sd_bus_message_append(m, "(sv)", field,             \
122
                                          bus_type, (int32_t) r);       \
123
                if (r < 0)                                              \
124
                        return bus_log_create_error(r);                 \
125
                                                                        \
126
                return 1;                                               \
127
        }
128

129
DEFINE_BUS_APPEND_PARSE("b", parse_boolean);
591✔
130
DEFINE_BUS_APPEND_PARSE("i", ioprio_class_from_string);
1✔
131
DEFINE_BUS_APPEND_PARSE("i", ip_tos_from_string);
5✔
132
DEFINE_BUS_APPEND_PARSE("i", log_facility_unshifted_from_string);
3✔
133
DEFINE_BUS_APPEND_PARSE("i", log_level_from_string);
9✔
134
DEFINE_BUS_APPEND_PARSE("i", seccomp_parse_errno_or_action);
3✔
135
DEFINE_BUS_APPEND_PARSE("i", sched_policy_from_string);
3✔
136
DEFINE_BUS_APPEND_PARSE("i", secure_bits_from_string);
3✔
137
DEFINE_BUS_APPEND_PARSE("i", signal_from_string);
17✔
138
DEFINE_BUS_APPEND_PARSE("i", parse_ip_protocol);
3✔
139
DEFINE_BUS_APPEND_PARSE("i", mpol_from_string);
11✔
140
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, ioprio_parse_priority);
1✔
141
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, parse_nice);
2✔
142
DEFINE_BUS_APPEND_PARSE_PTR("i", int32_t, int, safe_atoi);
17✔
143
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, nsec_t, parse_nsec);
1✔
144
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_weight_parse);
2✔
145
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, cg_cpu_weight_parse);
2✔
146
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, unsigned long, mount_propagation_flag_from_string);
4✔
147
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, safe_atou64);
3✔
148
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, mode_t, parse_mode);
38✔
149
DEFINE_BUS_APPEND_PARSE_PTR("u", uint32_t, unsigned, safe_atou);
20✔
150
DEFINE_BUS_APPEND_PARSE_PTR("x", int64_t, int64_t, safe_atoi64);
2✔
151
DEFINE_BUS_APPEND_PARSE_PTR("t", uint64_t, uint64_t, coredump_filter_mask_from_string);
4✔
152

153
static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
901✔
154
        int r;
901✔
155

156
        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
901✔
157
        if (r < 0)
901✔
158
                return bus_log_create_error(r);
×
159

160
        return 1;
161
}
162

163
static int bus_append_strv_full(sd_bus_message *m, const char *field, const char *eq, const char *separators, ExtractFlags flags) {
492✔
164
        int r;
492✔
165

166
        assert(m);
492✔
167
        assert(field);
492✔
168

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

173
        r = sd_bus_message_append_basic(m, 's', field);
492✔
174
        if (r < 0)
492✔
175
                return bus_log_create_error(r);
×
176

177
        r = sd_bus_message_open_container(m, 'v', "as");
492✔
178
        if (r < 0)
492✔
179
                return bus_log_create_error(r);
×
180

181
        r = sd_bus_message_open_container(m, 'a', "s");
492✔
182
        if (r < 0)
492✔
183
                return bus_log_create_error(r);
×
184

185
        for (const char *p = eq;;) {
492✔
186
                _cleanup_free_ char *word = NULL;
279✔
187

188
                r = extract_first_word(&p, &word, separators, flags);
771✔
189
                if (r < 0)
771✔
190
                        return parse_log_error(r, field, eq);
×
191
                if (r == 0)
771✔
192
                        break;
193

194
                r = sd_bus_message_append_basic(m, 's', word);
279✔
195
                if (r < 0)
279✔
196
                        return bus_log_create_error(r);
×
197
        }
198

199
        r = sd_bus_message_close_container(m);
492✔
200
        if (r < 0)
492✔
201
                return bus_log_create_error(r);
×
202

203
        r = sd_bus_message_close_container(m);
492✔
204
        if (r < 0)
492✔
205
                return bus_log_create_error(r);
×
206

207
        r = sd_bus_message_close_container(m);
492✔
208
        if (r < 0)
492✔
209
                return bus_log_create_error(r);
×
210

211
        return 1;
212
}
213

214
static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq) {
123✔
215
        return bus_append_strv_full(m, field, eq, /* separators= */ NULL, EXTRACT_UNQUOTE);
123✔
216
}
217

218
static int bus_append_strv_cunescape(sd_bus_message *m, const char *field, const char *eq) {
368✔
219
        return bus_append_strv_full(m, field, eq, /* separators= */ NULL, EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE);
368✔
220
}
221

222
static int bus_append_strv_colon(sd_bus_message *m, const char *field, const char *eq) {
1✔
223
        /* This also accepts colon as the separator. */
224
        return bus_append_strv_full(m, field, eq, ":" WHITESPACE, EXTRACT_UNQUOTE);
1✔
225
}
226

227
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
38✔
228
        int r;
38✔
229

230
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
38✔
231
        if (r < 0)
38✔
232
                return bus_log_create_error(r);
×
233

234
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
38✔
235
        if (r < 0)
38✔
236
                return bus_log_create_error(r);
×
237

238
        r = sd_bus_message_open_container(m, 'v', "ay");
38✔
239
        if (r < 0)
38✔
240
                return bus_log_create_error(r);
×
241

242
        r = sd_bus_message_append_array(m, 'y', buf, n);
38✔
243
        if (r < 0)
38✔
244
                return bus_log_create_error(r);
×
245

246
        r = sd_bus_message_close_container(m);
38✔
247
        if (r < 0)
38✔
248
                return bus_log_create_error(r);
×
249

250
        r = sd_bus_message_close_container(m);
38✔
251
        if (r < 0)
38✔
252
                return bus_log_create_error(r);
×
253

254
        return 1;
255
}
256

257
static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
62✔
258
        char *n;
62✔
259
        usec_t t;
62✔
260
        size_t l;
62✔
261
        int r;
62✔
262

263
        r = parse_sec(eq, &t);
62✔
264
        if (r < 0)
62✔
265
                return parse_log_error(r, field, eq);
×
266

267
        l = strlen(field);
62✔
268
        n = newa(char, l + 2);
62✔
269
        /* Change suffix Sec → USec */
270
        strcpy(mempcpy(n, field, l - 3), "USec");
62✔
271

272
        r = sd_bus_message_append(m, "(sv)", n, "t", t);
62✔
273
        if (r < 0)
62✔
274
                return bus_log_create_error(r);
×
275

276
        return 1;
277
}
278

279
static int bus_append_parse_sec_rename_infinity(sd_bus_message *m, const char *field, const char *eq) {
4✔
280
        return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
8✔
281
}
282

283
static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq) {
21✔
284
        uint64_t v;
21✔
285
        int r;
21✔
286

287
        r = parse_size(eq, /* base= */ 1024, &v);
21✔
288
        if (r < 0)
21✔
289
                return parse_log_error(r, field, eq);
×
290

291
        r = sd_bus_message_append(m, "(sv)", field, "t", v);
21✔
292
        if (r < 0)
21✔
293
                return bus_log_create_error(r);
×
294

295
        return 1;
296
}
297

298
static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, const char *eq) {
6✔
299
        int r;
6✔
300

301
        r = parse_permyriad(eq);
6✔
302
        if (r < 0)
6✔
303
                return parse_log_error(r, field, eq);
1✔
304

305
        /* Pass around scaled to 2^32-1 == 100% */
306
        r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
10✔
307
        if (r < 0)
5✔
308
                return bus_log_create_error(r);
×
309

310
        return 1;
311
}
312

313
static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const char *eq) {
12✔
314
        _cleanup_(cpu_set_done) CPUSet cpuset = {};
×
315
        _cleanup_free_ uint8_t *array = NULL;
12✔
316
        size_t allocated;
12✔
317
        int r;
12✔
318

319
        r = parse_cpu_set(eq, &cpuset);
12✔
320
        if (r < 0)
12✔
321
                return parse_log_error(r, field, eq);
×
322

323
        r = cpu_set_to_dbus(&cpuset, &array, &allocated);
12✔
324
        if (r < 0)
12✔
325
                return log_error_errno(r, "Failed to serialize %s: %m", field);
×
326

327
        return bus_append_byte_array(m, field, array, allocated);
12✔
328
}
329

330
static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const char *eq) {
355✔
331
        int r;
355✔
332

333
        r = parse_boolean(eq);
355✔
334
        if (r < 0)
355✔
335
                return bus_append_strv(m, "DelegateControllers", eq);
9✔
336

337
        r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
346✔
338
        if (r < 0)
346✔
339
                return bus_log_create_error(r);
×
340

341
        return 1;
342
}
343

344
static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
21✔
345
        int r;
21✔
346

347
        if (isempty(eq) || streq(eq, "infinity")) {
42✔
348
                uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX :
2✔
349
                        STR_IN_SET(field,
×
350
                                   "MemoryLow",
351
                                   "MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX;
×
352

353
                r = sd_bus_message_append(m, "(sv)", field, "t", x);
2✔
354
                if (r < 0)
2✔
355
                        return bus_log_create_error(r);
2✔
356

357
                return 1;
358
        }
359

360
        r = parse_permyriad(eq);
19✔
361
        if (r >= 0) {
19✔
362
                char *n;
×
363

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

368
                n = strjoina(field, "Scale");
×
369
                r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
370
                if (r < 0)
×
371
                        return bus_log_create_error(r);
×
372

373
                return 1;
374
        }
375

376
        if (streq(field, "TasksMax"))
19✔
377
                return bus_append_safe_atou64(m, field, eq);
3✔
378

379
        return bus_append_parse_size(m, field, eq);
16✔
380
}
381

382
static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, const char *eq) {
4✔
383
        uint64_t x;
4✔
384
        int r;
4✔
385

386
        if (isempty(eq))
4✔
387
                x = USEC_INFINITY;
388
        else {
389
                r = parse_permyriad_unbounded(eq);
4✔
390
                if (r < 0)
4✔
391
                        return parse_log_error(r, field, eq);
×
392
                if (r == 0)
4✔
393
                        return parse_log_error(SYNTHETIC_ERRNO(ERANGE), field, eq);
1✔
394
                x = r * USEC_PER_SEC / 10000U;
3✔
395
        }
396

397
        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", x);
3✔
398
        if (r < 0)
3✔
399
                return bus_log_create_error(r);
×
400

401
        return 1;
402
}
403

404
static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, const char *eq) {
9✔
405
        int r;
9✔
406

407
        if (isempty(eq))
9✔
408
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
409
        else {
410
                _cleanup_free_ char *_path = NULL;
9✔
411
                const char *path = eq, *rwm = NULL, *e;
9✔
412

413
                e = strchr(eq, ' ');
9✔
414
                if (e) {
9✔
415
                        path = _path = strndup(eq, e - eq);
9✔
416
                        if (!path)
9✔
417
                                return log_oom();
×
418

419
                        rwm = e + 1;
9✔
420
                }
421

422
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
9✔
423
        }
424
        if (r < 0)
9✔
425
                return bus_log_create_error(r);
×
426

427
        return 1;
428
}
429

430
static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) {
4,012✔
431
        int r;
4,012✔
432

433
        if (cgroup_io_limit_type_from_string(field) < 0)
4,012✔
434
                return 0;
435

436
        if (isempty(eq))
16✔
437
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
438
        else {
439
                const char *e = strchr(eq, ' ');
16✔
440
                if (!e)
16✔
441
                        return parse_log_error(0, field, eq);
×
442

443
                const char *bandwidth = e + 1;
16✔
444
                _cleanup_free_ char *path = strndup(eq, e - eq);
16✔
445
                if (!path)
16✔
446
                        return log_oom();
×
447

448
                uint64_t bytes;
16✔
449
                if (streq(bandwidth, "infinity"))
16✔
450
                        bytes = CGROUP_LIMIT_MAX;
2✔
451
                else {
452
                        r = parse_size(bandwidth, 1000, &bytes);
14✔
453
                        if (r < 0)
14✔
454
                                return parse_log_error(r, field, eq);
×
455
                }
456

457
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
16✔
458
        }
459
        if (r < 0)
16✔
460
                return bus_log_create_error(r);
×
461

462
        return 1;
463
}
464

465
static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *field, const char *eq) {
2✔
466
        int r;
2✔
467

468
        if (isempty(eq))
2✔
469
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
470
        else {
471
                const char *e = strchr(eq, ' ');
2✔
472
                if (!e)
2✔
473
                        return parse_log_error(0, field, eq);
×
474

475
                const char *weight = e + 1;
2✔
476
                _cleanup_free_ char *path = strndup(eq, e - eq);
2✔
477
                if (!path)
2✔
478
                        return log_oom();
×
479

480
                uint64_t u;
2✔
481
                r = safe_atou64(weight, &u);
2✔
482
                if (r < 0)
2✔
483
                        return parse_log_error(r, field, weight);
×
484

485
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
2✔
486
        }
487
        if (r < 0)
2✔
488
                return bus_log_create_error(r);
×
489

490
        return 1;
491
}
492

493
static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *field, const char *eq) {
2✔
494
        const char *field_usec = "IODeviceLatencyTargetUSec";
2✔
495
        int r;
2✔
496

497
        if (isempty(eq))
2✔
498
                r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 0);
×
499
        else {
500
                const char *e = strchr(eq, ' ');
2✔
501
                if (!e)
2✔
502
                        return parse_log_error(0, field, eq);
×
503

504
                const char *target = e + 1;
2✔
505
                _cleanup_free_ char *path = strndup(eq, e - eq);
2✔
506
                if (!path)
2✔
507
                        return log_oom();
×
508

509
                usec_t usec;
2✔
510
                r = parse_sec(target, &usec);
2✔
511
                if (r < 0)
2✔
512
                        return parse_log_error(r, field, target);
×
513

514
                r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
2✔
515
        }
516
        if (r < 0)
2✔
517
                return bus_log_create_error(r);
×
518

519
        return 1;
520
}
521

522
static int bus_append_bpf_program(sd_bus_message *m, const char *field, const char *eq) {
1✔
523
        int r;
1✔
524

525
        if (isempty(eq))
1✔
526
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
527
        else {
528
                _cleanup_free_ char *word = NULL;
1✔
529

530
                r = extract_first_word(&eq, &word, ":", 0);
1✔
531
                if (r < 0)
1✔
532
                        return parse_log_error(r, field, eq);
×
533

534
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
1✔
535
        }
536
        if (r < 0)
1✔
537
                return bus_log_create_error(r);
×
538

539
        return 1;
540
}
541

542
static int bus_append_socket_filter(sd_bus_message *m, const char *field, const char *eq) {
5✔
543
        int r;
5✔
544

545
        if (isempty(eq))
5✔
546
                r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
×
547
        else {
548
                int32_t family, ip_protocol;
5✔
549
                uint16_t nr_ports, port_min;
5✔
550

551
                r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
5✔
552
                if (r < 0)
5✔
553
                        return parse_log_error(r, field, eq);
×
554

555
                r = sd_bus_message_append(
5✔
556
                                m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
557
        }
558
        if (r < 0)
5✔
559
                return bus_log_create_error(r);
×
560

561
        return 1;
562
}
563

564
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
76✔
565
        bool explicit_path = false, done = false, ambient_hack = false;
76✔
566
        _cleanup_strv_free_ char **cmdline = NULL, **ex_opts = NULL;
76✔
567
        _cleanup_free_ char *_path = NULL;
76✔
568
        ExecCommandFlags flags = 0;
76✔
569
        int r;
110✔
570

571
        do {
110✔
572
                switch (*eq) {
110✔
573

574
                case '-':
3✔
575
                        if (FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE))
3✔
576
                                done = true;
577
                        else {
578
                                flags |= EXEC_COMMAND_IGNORE_FAILURE;
3✔
579
                                eq++;
3✔
580
                        }
581
                        break;
582

583
                case '@':
4✔
584
                        if (explicit_path)
4✔
585
                                done = true;
586
                        else {
587
                                explicit_path = true;
4✔
588
                                eq++;
4✔
589
                        }
590
                        break;
591

592
                case ':':
17✔
593
                        if (FLAGS_SET(flags, EXEC_COMMAND_NO_ENV_EXPAND))
17✔
594
                                done = true;
595
                        else {
596
                                flags |= EXEC_COMMAND_NO_ENV_EXPAND;
17✔
597
                                eq++;
17✔
598
                        }
599
                        break;
600

601
                case '+':
4✔
602
                        if ((flags & (EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID)) != 0 || ambient_hack)
4✔
603
                                done = true;
604
                        else {
605
                                flags |= EXEC_COMMAND_FULLY_PRIVILEGED;
4✔
606
                                eq++;
4✔
607
                        }
608
                        break;
609

610
                case '!':
5✔
611
                        if (FLAGS_SET(flags, EXEC_COMMAND_FULLY_PRIVILEGED) || ambient_hack)
5✔
612
                                done = true;
613
                        else if (FLAGS_SET(flags, EXEC_COMMAND_NO_SETUID)) {
3✔
614
                                /* Compatibility with the old !! ambient caps hack (removed in v258). Since
615
                                 * we don't support that anymore and !! was a noop on non-supporting systems,
616
                                 * we'll just turn off the EXEC_COMMAND_NO_SETUID flag again and be done with
617
                                 * it. */
618
                                flags &= ~EXEC_COMMAND_NO_SETUID;
1✔
619
                                eq++;
1✔
620
                                ambient_hack = true;
1✔
621

622
                                log_notice("!! modifier for %s= fields is no longer supported and is now ignored.", field);
1✔
623
                        } else {
624
                                flags |= EXEC_COMMAND_NO_SETUID;
2✔
625
                                eq++;
2✔
626
                        }
627
                        break;
628

629
                case '|':
3✔
630
                        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL))
3✔
631
                                done = true;
632
                        else {
633
                                flags |= EXEC_COMMAND_VIA_SHELL;
3✔
634
                                eq++;
3✔
635
                        }
636
                        break;
637

638
                default:
639
                        done = true;
640
                }
641
        } while (!done);
110✔
642

643
        bool ex_prop = flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL);
76✔
644
        if (ex_prop) {
76✔
645
                /* We need to use ExecXYZEx=. */
646
                if (!endswith(field, "Ex"))
23✔
647
                        field = strjoina(field, "Ex");
80✔
648

649
                r = exec_command_flags_to_strv(flags, &ex_opts);
23✔
650
                if (r < 0)
23✔
651
                        return log_error_errno(r, "Failed to serialize ExecCommand flags: %m");
×
652
        } else {
653
                if (endswith(field, "Ex"))
53✔
654
                        field = strndupa_safe(field, strlen(field) - 2);
6✔
655
        }
656

657
        const char *path = NULL;
76✔
658
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL))
76✔
659
                path = _PATH_BSHELL;
660
        else if (explicit_path) {
73✔
661
                r = extract_first_word(&eq, &_path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
3✔
662
                if (r < 0)
3✔
663
                        return parse_log_error(r, field, eq);
×
664
                if (r == 0)
3✔
665
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No executable path specified for %s=, refusing.", field);
×
666
                if (isempty(eq))
3✔
667
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got empty command line for %s=, refusing.", field);
×
668
                path = _path;
3✔
669
        }
670

671
        r = strv_split_full(&cmdline, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
76✔
672
        if (r < 0)
76✔
673
                return parse_log_error(r, field, eq);
×
674

675
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
76✔
676
                r = strv_prepend(&cmdline, explicit_path ? "-sh" : "sh");
5✔
677
                if (r < 0)
3✔
678
                        return log_oom();
×
679
        }
680

681
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
76✔
682
        if (r < 0)
76✔
683
                return bus_log_create_error(r);
×
684

685
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
76✔
686
        if (r < 0)
76✔
687
                return bus_log_create_error(r);
×
688

689
        r = sd_bus_message_open_container(m, 'v', ex_prop ? "a(sasas)" : "a(sasb)");
129✔
690
        if (r < 0)
76✔
691
                return bus_log_create_error(r);
×
692

693
        r = sd_bus_message_open_container(m, 'a', ex_prop ? "(sasas)" : "(sasb)");
129✔
694
        if (r < 0)
76✔
695
                return bus_log_create_error(r);
×
696

697
        if (!strv_isempty(cmdline)) {
76✔
698
                r = sd_bus_message_open_container(m, 'r', ex_prop ? "sasas" : "sasb");
129✔
699
                if (r < 0)
76✔
700
                        return bus_log_create_error(r);
×
701

702
                r = sd_bus_message_append(m, "s", path ?: cmdline[0]);
76✔
703
                if (r < 0)
76✔
704
                        return bus_log_create_error(r);
×
705

706
                r = sd_bus_message_append_strv(m, cmdline);
76✔
707
                if (r < 0)
76✔
708
                        return bus_log_create_error(r);
×
709

710
                r = ex_prop ? sd_bus_message_append_strv(m, ex_opts) :
76✔
711
                              sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
53✔
712
                if (r < 0)
76✔
713
                        return bus_log_create_error(r);
×
714

715
                r = sd_bus_message_close_container(m);
76✔
716
                if (r < 0)
76✔
717
                        return bus_log_create_error(r);
×
718
        }
719

720
        r = sd_bus_message_close_container(m);
76✔
721
        if (r < 0)
76✔
722
                return bus_log_create_error(r);
×
723

724
        r = sd_bus_message_close_container(m);
76✔
725
        if (r < 0)
76✔
726
                return bus_log_create_error(r);
×
727

728
        r = sd_bus_message_close_container(m);
76✔
729
        if (r < 0)
76✔
730
                return bus_log_create_error(r);
×
731

732
        return 1;
733
}
734

735
static int bus_append_open_file(sd_bus_message *m, const char *field, const char *eq) {
14✔
736
        _cleanup_(open_file_freep) OpenFile *of = NULL;
14✔
737
        int r;
14✔
738

739
        assert(m);
14✔
740

741
        r = open_file_parse(eq, &of);
14✔
742
        if (r < 0)
14✔
743
                return parse_log_error(r, field, eq);
1✔
744

745
        r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
13✔
746
        if (r < 0)
13✔
747
                return bus_log_create_error(r);
×
748

749
        return 1;
750
}
751

752
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
5✔
753
        int r;
5✔
754

755
        assert(m);
5✔
756
        assert(prefix);
5✔
757

758
        r = sd_bus_message_open_container(m, 'r', "iayu");
5✔
759
        if (r < 0)
5✔
760
                return r;
761

762
        r = sd_bus_message_append(m, "i", family);
5✔
763
        if (r < 0)
5✔
764
                return r;
765

766
        r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
5✔
767
        if (r < 0)
5✔
768
                return r;
769

770
        r = sd_bus_message_append(m, "u", prefixlen);
5✔
771
        if (r < 0)
5✔
772
                return r;
773

774
        return sd_bus_message_close_container(m);
5✔
775
}
776

777
static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *field, const char *eq) {
4✔
778
        union in_addr_union prefix = {};
4✔
779
        unsigned char prefixlen;
4✔
780
        int family, r;
4✔
781

782
        if (isempty(eq)) {
4✔
783
                r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
×
784
                if (r < 0)
×
785
                        return bus_log_create_error(r);
4✔
786

787
                return 1;
788
        }
789

790
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4✔
791
        if (r < 0)
4✔
792
                return bus_log_create_error(r);
×
793

794
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
4✔
795
        if (r < 0)
4✔
796
                return bus_log_create_error(r);
×
797

798
        r = sd_bus_message_open_container(m, 'v', "a(iayu)");
4✔
799
        if (r < 0)
4✔
800
                return bus_log_create_error(r);
×
801

802
        r = sd_bus_message_open_container(m, 'a', "(iayu)");
4✔
803
        if (r < 0)
4✔
804
                return bus_log_create_error(r);
×
805

806
        if (streq(eq, "any")) {
4✔
807
                /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
808

809
                r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
×
810
                if (r < 0)
×
811
                        return bus_log_create_error(r);
×
812

813
                r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
×
814
                if (r < 0)
×
815
                        return bus_log_create_error(r);
×
816

817
        } else if (is_localhost(eq)) {
4✔
818
                /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
819

820
                prefix.in.s_addr = htobe32(0x7f000000);
×
821
                r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
×
822
                if (r < 0)
×
823
                        return bus_log_create_error(r);
×
824

825
                prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
×
826
                r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
×
827
                if (r < 0)
×
828
                        return r;
829

830
        } else if (streq(eq, "link-local")) {
4✔
831
                /* "link-local" is a shortcut for 169.254.0.0/16 and fe80::/64 */
832

833
                prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
×
834
                r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
×
835
                if (r < 0)
×
836
                        return bus_log_create_error(r);
×
837

838
                prefix.in6 = (struct in6_addr) {
×
839
                        .s6_addr32[0] = htobe32(0xfe800000)
×
840
                };
841
                r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
×
842
                if (r < 0)
×
843
                        return bus_log_create_error(r);
×
844

845
        } else if (streq(eq, "multicast")) {
4✔
846
                /* "multicast" is a shortcut for 224.0.0.0/4 and ff00::/8 */
847

848
                prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
×
849
                r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
×
850
                if (r < 0)
×
851
                        return bus_log_create_error(r);
×
852

853
                prefix.in6 = (struct in6_addr) {
×
854
                        .s6_addr32[0] = htobe32(0xff000000)
×
855
                };
856
                r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
×
857
                if (r < 0)
×
858
                        return bus_log_create_error(r);
×
859

860
        } else
861
                for (;;) {
14✔
862
                        _cleanup_free_ char *word = NULL;
9✔
863

864
                        r = extract_first_word(&eq, &word, NULL, 0);
9✔
865
                        if (r < 0)
9✔
866
                                return parse_log_error(r, field, eq);
×
867
                        if (r == 0)
9✔
868
                                break;
869

870
                        r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
5✔
871
                        if (r < 0)
5✔
872
                                return log_error_errno(r, "Failed to parse IP address prefix '%s': %m", word);
×
873

874
                        r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
5✔
875
                        if (r < 0)
5✔
876
                                return bus_log_create_error(r);
×
877
                }
878

879
        r = sd_bus_message_close_container(m);
4✔
880
        if (r < 0)
4✔
881
                return bus_log_create_error(r);
×
882

883
        r = sd_bus_message_close_container(m);
4✔
884
        if (r < 0)
4✔
885
                return bus_log_create_error(r);
×
886

887
        r = sd_bus_message_close_container(m);
4✔
888
        if (r < 0)
4✔
889
                return bus_log_create_error(r);
×
890

891
        return 1;
892
}
893

894
#define bus_append_trivial_array(m, field, eq, types, ...)              \
895
        ({                                                              \
896
                int r;                                                  \
897
                                                                        \
898
                if (isempty(eq))                                        \
899
                        r = sd_bus_message_append(m, "(sv)", field, types, 0); \
900
                else                                                    \
901
                        r = sd_bus_message_append(m, "(sv)", field, types, 1, __VA_ARGS__); \
902
                r < 0 ? bus_log_create_error(r) : 1;                    \
903
        })
904

905
static int bus_append_ip_filter_path(sd_bus_message *m, const char *field, const char *eq) {
2✔
906
        return bus_append_trivial_array(m, field, eq,
4✔
907
                                        "as", eq);
908
}
909

910
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
3✔
911
        int r;
3✔
912

913
        assert(m);
3✔
914
        assert(field);
3✔
915
        assert(eq);
3✔
916

917
        if (isempty(eq)) {
3✔
918
                r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
×
919
                if (r < 0)
×
920
                        return bus_log_create_error(r);
×
921

922
                return 1;
923
        }
924

925
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
3✔
926
        if (r < 0)
3✔
927
                return bus_log_create_error(r);
×
928

929
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
3✔
930
        if (r < 0)
3✔
931
                return bus_log_create_error(r);
×
932

933
        r = sd_bus_message_open_container(m, 'v', "a(iiss)");
3✔
934
        if (r < 0)
3✔
935
                return bus_log_create_error(r);
×
936

937
        r = sd_bus_message_open_container(m, 'a', "(iiss)");
3✔
938
        if (r < 0)
3✔
939
                return bus_log_create_error(r);
×
940

941
        for (const char *p = eq;;) {
3✔
942
                _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
6✔
943
                const char *q = NULL;
9✔
944
                int source, nfproto;
9✔
945

946
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
9✔
947
                if (r < 0)
9✔
948
                        return parse_log_error(r, field, eq);
×
949
                if (r == 0)
9✔
950
                        break;
951
                if (isempty(tuple))
6✔
952
                        return parse_log_error(0, field, eq);
×
953

954
                q = tuple;
6✔
955
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
6✔
956
                if (r != 4 || !isempty(q))
6✔
957
                        return parse_log_error(0, field, tuple);
×
958

959
                assert(source_str);
6✔
960
                assert(nfproto_str);
6✔
961
                assert(table);
6✔
962
                assert(set);
6✔
963

964
                source = r = nft_set_source_from_string(source_str);
6✔
965
                if (r < 0)
6✔
966
                        return log_error_errno(r, "Failed to parse NFT set source '%s': %m", source_str);
×
967
                if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
6✔
968
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad NFT set source value '%s'.",
×
969
                                               nft_set_source_to_string(source));
970

971
                nfproto = r = nfproto_from_string(nfproto_str);
6✔
972
                if (r < 0)
6✔
973
                        return log_error_errno(r, "Failed to parse nft protocol '%s': %m", nfproto_str);
×
974

975
                if (!nft_identifier_valid(table))
6✔
976
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad NFT identifier name '%s'.", table);
×
977
                if (!nft_identifier_valid(set))
6✔
978
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Bad NFT identifier name '%s'.", set);
×
979

980
                r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
6✔
981
                if (r < 0)
6✔
982
                        return bus_log_create_error(r);
×
983
        }
984
        r = sd_bus_message_close_container(m);
3✔
985
        if (r < 0)
3✔
986
                return bus_log_create_error(r);
×
987

988
        r = sd_bus_message_close_container(m);
3✔
989
        if (r < 0)
3✔
990
                return bus_log_create_error(r);
×
991

992
        r = sd_bus_message_close_container(m);
3✔
993
        if (r < 0)
3✔
994
                return bus_log_create_error(r);
×
995

996
        return 1;
997
}
998

999
static int bus_append_environment_files(sd_bus_message *m, const char *field, const char *eq) {
348✔
1000
        return bus_append_trivial_array(m, "EnvironmentFiles", eq,
696✔
1001
                                        "a(sb)",
1002
                                        eq[0] == '-' ? eq + 1 : eq,
1003
                                        eq[0] == '-');
1004
}
1005

1006
static int bus_append_set_credential(sd_bus_message *m, const char *field, const char *eq) {
95✔
1007
        int r;
95✔
1008

1009
        r = sd_bus_message_open_container(m, 'r', "sv");
95✔
1010
        if (r < 0)
95✔
1011
                return bus_log_create_error(r);
×
1012

1013
        r = sd_bus_message_append_basic(m, 's', field);
95✔
1014
        if (r < 0)
95✔
1015
                return bus_log_create_error(r);
×
1016

1017
        r = sd_bus_message_open_container(m, 'v', "a(say)");
95✔
1018
        if (r < 0)
95✔
1019
                return bus_log_create_error(r);
×
1020

1021
        if (isempty(eq))
95✔
1022
                r = sd_bus_message_append(m, "a(say)", 0);
1✔
1023
        else {
1024
                _cleanup_free_ char *word = NULL;
94✔
1025
                const char *p = eq;
94✔
1026

1027
                r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
94✔
1028
                if (r <= 0 || !p)
94✔
1029
                        return parse_log_error(r < 0 ? r : 0, field, eq);
×
1030

1031
                r = sd_bus_message_open_container(m, 'a', "(say)");
94✔
1032
                if (r < 0)
94✔
1033
                        return bus_log_create_error(r);
×
1034

1035
                r = sd_bus_message_open_container(m, 'r', "say");
94✔
1036
                if (r < 0)
94✔
1037
                        return bus_log_create_error(r);
×
1038

1039
                r = sd_bus_message_append(m, "s", word);
94✔
1040
                if (r < 0)
94✔
1041
                        return bus_log_create_error(r);
×
1042

1043
                if (endswith(field, "Encrypted")) {
94✔
1044
                        _cleanup_free_ void *decoded = NULL;
2✔
1045
                        size_t decoded_size;
2✔
1046

1047
                        r = unbase64mem(p, &decoded, &decoded_size);
2✔
1048
                        if (r < 0)
2✔
1049
                                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1050

1051
                        r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
2✔
1052
                } else {
1053
                        _cleanup_free_ char *unescaped = NULL;
92✔
1054
                        ssize_t l;
92✔
1055

1056
                        l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
92✔
1057
                        if (l < 0)
92✔
1058
                                return log_error_errno(l, "Failed to unescape value for %s=: %s", field, p);
×
1059

1060
                        r = sd_bus_message_append_array(m, 'y', unescaped, l);
92✔
1061
                }
1062
                if (r < 0)
94✔
1063
                        return bus_log_create_error(r);
×
1064

1065
                r = sd_bus_message_close_container(m);
94✔
1066
                if (r < 0)
94✔
1067
                        return bus_log_create_error(r);
×
1068

1069
                r = sd_bus_message_close_container(m);
94✔
1070
        }
1071
        if (r < 0)
95✔
1072
                return bus_log_create_error(r);
×
1073

1074
        r = sd_bus_message_close_container(m);
95✔
1075
        if (r < 0)
95✔
1076
                return bus_log_create_error(r);
×
1077

1078
        r = sd_bus_message_close_container(m);
95✔
1079
        if (r < 0)
95✔
1080
                return bus_log_create_error(r);
×
1081

1082
        return 1;
1083
}
1084

1085
static int bus_append_load_credential(sd_bus_message *m, const char *field, const char *eq) {
24✔
1086
        int r;
24✔
1087

1088
        r = sd_bus_message_open_container(m, 'r', "sv");
24✔
1089
        if (r < 0)
24✔
1090
                return bus_log_create_error(r);
×
1091

1092
        r = sd_bus_message_append_basic(m, 's', field);
24✔
1093
        if (r < 0)
24✔
1094
                return bus_log_create_error(r);
×
1095

1096
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
24✔
1097
        if (r < 0)
24✔
1098
                return bus_log_create_error(r);
×
1099

1100
        if (isempty(eq))
24✔
1101
                r = sd_bus_message_append(m, "a(ss)", 0);
1✔
1102
        else {
1103
                _cleanup_free_ char *word = NULL;
23✔
1104
                const char *p = eq;
23✔
1105

1106
                r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
23✔
1107
                if (r <= 0)
23✔
1108
                        return parse_log_error(r, field, eq);
×
1109

1110
                if (isempty(p)) /* If only one field is specified, then this means "inherit from above" */
23✔
1111
                        p = eq;
3✔
1112

1113
                r = sd_bus_message_append(m, "a(ss)", 1, word, p);
23✔
1114
        }
1115
        if (r < 0)
24✔
1116
                return bus_log_create_error(r);
×
1117

1118
        r = sd_bus_message_close_container(m);
24✔
1119
        if (r < 0)
24✔
1120
                return bus_log_create_error(r);
×
1121

1122
        r = sd_bus_message_close_container(m);
24✔
1123
        if (r < 0)
24✔
1124
                return bus_log_create_error(r);
×
1125

1126
        return 1;
1127
}
1128

1129
static int bus_append_import_credential(sd_bus_message *m, const char *field, const char *eq) {
19✔
1130
        int r;
19✔
1131

1132
        if (isempty(eq))
19✔
1133
                r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 0);
×
1134
        else {
1135
                _cleanup_free_ char *word = NULL;
19✔
1136
                const char *p = eq;
19✔
1137

1138
                r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
19✔
1139
                if (r <= 0)
19✔
1140
                        return parse_log_error(r, field, eq);
×
1141

1142
                if (!p)
19✔
1143
                        r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 1, eq);
12✔
1144
                else {
1145
                        /* We need to send ImportCredentialEx */
1146
                        r = sd_bus_message_open_container(m, 'r', "sv");
7✔
1147
                        if (r < 0)
7✔
1148
                                return bus_log_create_error(r);
×
1149

1150
                        r = sd_bus_message_append_basic(m, 's', "ImportCredentialEx");
7✔
1151
                        if (r < 0)
7✔
1152
                                return bus_log_create_error(r);
×
1153

1154
                        r = sd_bus_message_open_container(m, 'v', "a(ss)");
7✔
1155
                        if (r < 0)
7✔
1156
                                return bus_log_create_error(r);
×
1157

1158
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
7✔
1159
                        if (r < 0)
7✔
1160
                                return bus_log_create_error(r);
×
1161

1162
                        r = sd_bus_message_close_container(m);
7✔
1163
                        if (r < 0)
7✔
1164
                                return bus_log_create_error(r);
×
1165

1166
                        r = sd_bus_message_close_container(m);
7✔
1167
                }
1168
        }
1169
        if (r < 0)
19✔
1170
                return bus_log_create_error(r);
×
1171

1172
        return 1;
1173
}
1174

UNCOV
1175
static int bus_append_refresh_on_reload(sd_bus_message *m, const char *field, const char *eq) {
×
UNCOV
1176
        int r;
×
1177

UNCOV
1178
        r = sd_bus_message_open_container(m, 'r', "sv");
×
UNCOV
1179
        if (r < 0)
×
1180
                return bus_log_create_error(r);
×
1181

UNCOV
1182
        r = sd_bus_message_append_basic(m, 's', field);
×
UNCOV
1183
        if (r < 0)
×
1184
                return bus_log_create_error(r);
×
1185

UNCOV
1186
        r = sd_bus_message_open_container(m, 'v', "a(bs)");
×
UNCOV
1187
        if (r < 0)
×
1188
                return bus_log_create_error(r);
×
1189

UNCOV
1190
        r = sd_bus_message_open_container(m, 'a', "(bs)");
×
UNCOV
1191
        if (r < 0)
×
1192
                return bus_log_create_error(r);
×
1193

UNCOV
1194
        bool invert = *eq == '~';
×
1195

1196
        for (const char *p = eq + invert;;) {
×
UNCOV
1197
                _cleanup_free_ char *word = NULL;
×
1198

UNCOV
1199
                r = extract_first_word(&p, &word, NULL, 0);
×
1200
                if (r < 0)
×
UNCOV
1201
                        return parse_log_error(r, field, eq);
×
UNCOV
1202
                if (r == 0)
×
1203
                        break;
1204

UNCOV
1205
                r = sd_bus_message_append(m, "(bs)", invert, word);
×
UNCOV
1206
                if (r < 0)
×
UNCOV
1207
                        return bus_log_create_error(r);
×
1208
        }
1209

UNCOV
1210
        r = sd_bus_message_close_container(m);
×
UNCOV
1211
        if (r < 0)
×
UNCOV
1212
                return bus_log_create_error(r);
×
1213

UNCOV
1214
        r = sd_bus_message_close_container(m);
×
UNCOV
1215
        if (r < 0)
×
UNCOV
1216
                return bus_log_create_error(r);
×
1217

UNCOV
1218
        r = sd_bus_message_close_container(m);
×
UNCOV
1219
        if (r < 0)
×
UNCOV
1220
                return bus_log_create_error(r);
×
1221

1222
        return 1;
1223
}
1224

1225
static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) {
710✔
1226
        int r;
710✔
1227

1228
        r = sd_bus_message_open_container(m, 'r', "sv");
710✔
1229
        if (r < 0)
710✔
UNCOV
1230
                return bus_log_create_error(r);
×
1231

1232
        r = sd_bus_message_append_basic(m, 's', field);
710✔
1233
        if (r < 0)
710✔
UNCOV
1234
                return bus_log_create_error(r);
×
1235

1236
        r = sd_bus_message_open_container(m, 'v', "aay");
710✔
1237
        if (r < 0)
710✔
UNCOV
1238
                return bus_log_create_error(r);
×
1239

1240
        r = sd_bus_message_open_container(m, 'a', "ay");
710✔
1241
        if (r < 0)
710✔
UNCOV
1242
                return bus_log_create_error(r);
×
1243

1244
        r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
710✔
1245
        if (r < 0)
710✔
UNCOV
1246
                return bus_log_create_error(r);
×
1247

1248
        r = sd_bus_message_close_container(m);
710✔
1249
        if (r < 0)
710✔
1250
                return bus_log_create_error(r);
×
1251

1252
        r = sd_bus_message_close_container(m);
710✔
1253
        if (r < 0)
710✔
UNCOV
1254
                return bus_log_create_error(r);
×
1255

1256
        r = sd_bus_message_close_container(m);
710✔
1257
        if (r < 0)
710✔
UNCOV
1258
                return bus_log_create_error(r);
×
1259

1260
        return 1;
1261
}
1262

1263
static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) {
2✔
1264
        return bus_append_trivial_array(m, field, eq,
4✔
1265
                                        "a(bs)",
1266
                                        eq[0] != '~',
1267
                                        eq[0] != '~' ? eq : eq + 1);
1268
}
1269

1270
static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) {
146✔
1271
        const char *n, *appended;
146✔
1272
        int r;
146✔
1273

1274
        if ((n = startswith(eq, "fd:"))) {
146✔
UNCOV
1275
                appended = strjoina(field, "FileDescriptorName");
×
UNCOV
1276
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
×
1277
        } else if ((n = startswith(eq, "file:"))) {
146✔
1278
                appended = strjoina(field, "File");
475✔
1279
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
95✔
1280
        } else if ((n = startswith(eq, "append:"))) {
51✔
1281
                appended = strjoina(field, "FileToAppend");
10✔
1282
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
2✔
1283
        } else if ((n = startswith(eq, "truncate:"))) {
49✔
1284
                appended = strjoina(field, "FileToTruncate");
15✔
1285
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
3✔
1286
        } else
1287
                r = sd_bus_message_append(m, "(sv)", field, "s", eq);
46✔
1288
        if (r < 0)
146✔
UNCOV
1289
                return bus_log_create_error(r);
×
1290

1291
        return 1;
1292
}
1293

1294
static int bus_append_standard_input_text(sd_bus_message *m, const char *field, const char *eq) {
2✔
1295
        _cleanup_free_ char *unescaped = NULL;
2✔
1296
        ssize_t l;
2✔
1297

1298
        l = cunescape(eq, 0, &unescaped);
2✔
1299
        if (l < 0)
2✔
UNCOV
1300
                return log_error_errno(l, "Failed to unescape value for %s=: %s", field, eq);
×
1301

1302
        if (!strextend(&unescaped, "\n"))
2✔
UNCOV
1303
                return log_oom();
×
1304

1305
        /* Note that we don't expand specifiers here, but that should be OK, as this is a
1306
         * programmatic interface anyway */
1307

1308
        /* The server side does not have StandardInputText, using StandardInputData instead. */
1309
        return bus_append_byte_array(m, "StandardInputData", unescaped, l + 1);
2✔
1310
}
1311

1312
static int bus_append_standard_input_data(sd_bus_message *m, const char *field, const char *eq) {
2✔
1313
        _cleanup_free_ void *decoded = NULL;
2✔
1314
        size_t sz;
2✔
1315
        int r;
2✔
1316

1317
        r = unbase64mem(eq, &decoded, &sz);
2✔
1318
        if (r < 0)
2✔
UNCOV
1319
                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1320

1321
        return bus_append_byte_array(m, field, decoded, sz);
2✔
1322
}
1323

1324
static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
520✔
1325
        int r;
520✔
1326

1327
        const char *suffix = startswith(field, "Limit");
520✔
1328
        if (!suffix)
520✔
1329
                return 0;
520✔
1330

1331
        int rl = rlimit_from_string(suffix);
42✔
1332
        if (rl < 0)
42✔
1333
                return 0;  /* We let the generic error machinery handle this. */
1334

1335
        struct rlimit l;
42✔
1336
        r = rlimit_parse(rl, eq, &l);
42✔
1337
        if (r < 0)
42✔
UNCOV
1338
                return parse_log_error(r, field, eq);
×
1339

1340
        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
42✔
1341
        if (r < 0)
42✔
1342
                return bus_log_create_error(r);
×
1343

1344
        const char *sn = strjoina(field, "Soft");
210✔
1345
        r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
42✔
1346
        if (r < 0)
42✔
UNCOV
1347
                return bus_log_create_error(r);
×
1348

1349
        return 1;
1350
}
1351

1352
static void dump_resource_limits(void) {
14✔
1353
        rlimits_list("Limit");
14✔
1354
}
14✔
1355

1356
static int bus_append_string_with_ignore(sd_bus_message *m, const char *field, const char *eq) {
4✔
1357
        int ignore = 0;
4✔
1358
        const char *s = eq;
4✔
1359
        int r;
4✔
1360

1361
        if (eq[0] == '-') {
4✔
UNCOV
1362
                ignore = 1;
×
UNCOV
1363
                s = eq + 1;
×
1364
        }
1365

1366
        r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
4✔
1367
        if (r < 0)
4✔
1368
                return bus_log_create_error(r);
×
1369

1370
        return 1;
1371
}
1372

1373
static int bus_append_capabilities(sd_bus_message *m, const char *field, const char *eq) {
10✔
1374
        uint64_t sum = 0;
10✔
1375
        bool invert = false;
10✔
1376
        const char *p = eq;
10✔
1377
        int r;
10✔
1378

1379
        if (*p == '~') {
10✔
1380
                invert = true;
3✔
1381
                p++;
3✔
1382
        }
1383

1384
        r = capability_set_from_string(p, &sum);
10✔
1385
        if (r < 0)
10✔
UNCOV
1386
                return parse_log_error(r, field, eq);
×
1387

1388
        sum = invert ? ~sum : sum;
10✔
1389

1390
        r = sd_bus_message_append(m, "(sv)", field, "t", sum);
10✔
1391
        if (r < 0)
10✔
UNCOV
1392
                return bus_log_create_error(r);
×
1393

1394
        return 1;
1395
}
1396

1397
static int bus_append_cpu_affinity(sd_bus_message *m, const char *field, const char *eq) {
4✔
1398
        int r;
4✔
1399

1400
        if (streq_ptr(eq, "numa")) {
4✔
1401
                r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1✔
1402
                if (r < 0)
1✔
1403
                        return bus_log_create_error(r);
×
1404
                return r;
1405
        }
1406

1407
        return bus_append_parse_cpu_set(m, field, eq);
3✔
1408
}
1409

1410
static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char *eq) {
8✔
1411
        _cleanup_(cpu_set_done) CPUSet nodes = {};
×
1412
        _cleanup_free_ uint8_t *array = NULL;
8✔
1413
        size_t allocated;
8✔
1414
        int r;
8✔
1415

1416
        if (eq && streq(eq, "all")) {
8✔
UNCOV
1417
                r = numa_mask_add_all(&nodes);
×
UNCOV
1418
                if (r < 0)
×
UNCOV
1419
                        return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
×
1420
        } else {
1421
                r = parse_cpu_set(eq, &nodes);
8✔
1422
                if (r < 0)
8✔
UNCOV
1423
                        return parse_log_error(r, field, eq);
×
1424
        }
1425

1426
        r = cpu_set_to_dbus(&nodes, &array, &allocated);
8✔
1427
        if (r < 0)
8✔
1428
                return log_error_errno(r, "Failed to serialize %s: %m", field);
×
1429

1430
        return bus_append_byte_array(m, field, array, allocated);
8✔
1431
}
1432

1433
static int bus_append_filter_list(sd_bus_message *m, const char *field, const char *eq) {
26✔
1434
        int allow_list = 1;
26✔
1435
        const char *p = eq;
26✔
1436
        int r;
26✔
1437

1438
        if (*p == '~') {
26✔
1439
                allow_list = 0;
12✔
1440
                p++;
12✔
1441
        }
1442

1443
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
26✔
1444
        if (r < 0)
26✔
1445
                return bus_log_create_error(r);
26✔
1446

1447
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
26✔
1448
        if (r < 0)
26✔
UNCOV
1449
                return bus_log_create_error(r);
×
1450

1451
        r = sd_bus_message_open_container(m, 'v', "(bas)");
26✔
1452
        if (r < 0)
26✔
UNCOV
1453
                return bus_log_create_error(r);
×
1454

1455
        r = sd_bus_message_open_container(m, 'r', "bas");
26✔
1456
        if (r < 0)
26✔
UNCOV
1457
                return bus_log_create_error(r);
×
1458

1459
        r = sd_bus_message_append_basic(m, 'b', &allow_list);
26✔
1460
        if (r < 0)
26✔
UNCOV
1461
                return bus_log_create_error(r);
×
1462

1463
        r = sd_bus_message_open_container(m, 'a', "s");
26✔
1464
        if (r < 0)
26✔
UNCOV
1465
                return bus_log_create_error(r);
×
1466

1467
        for (;;) {
98✔
1468
                _cleanup_free_ char *word = NULL;
36✔
1469

1470
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
62✔
1471
                if (r < 0)
62✔
1472
                        return parse_log_error(r, field, eq);
×
1473
                if (r == 0)
62✔
1474
                        break;
1475

1476
                r = sd_bus_message_append_basic(m, 's', word);
36✔
1477
                if (r < 0)
36✔
UNCOV
1478
                        return bus_log_create_error(r);
×
1479
        }
1480

1481
        r = sd_bus_message_close_container(m);
26✔
1482
        if (r < 0)
26✔
UNCOV
1483
                return bus_log_create_error(r);
×
1484

1485
        r = sd_bus_message_close_container(m);
26✔
1486
        if (r < 0)
26✔
UNCOV
1487
                return bus_log_create_error(r);
×
1488

1489
        r = sd_bus_message_close_container(m);
26✔
1490
        if (r < 0)
26✔
UNCOV
1491
                return bus_log_create_error(r);
×
1492

1493
        r = sd_bus_message_close_container(m);
26✔
1494
        if (r < 0)
26✔
1495
                return bus_log_create_error(r);
×
1496

1497
        return 1;
1498
}
1499

1500
static int bus_append_namespace_list(sd_bus_message *m, const char *field, const char *eq) {
25✔
1501
        bool invert = false;
25✔
1502
        unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
25✔
1503
        unsigned long flags;
25✔
1504
        int r;
25✔
1505

1506
        r = parse_boolean(eq);
25✔
1507
        if (r > 0)
25✔
1508
                /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1509
                 * namespaces which are retained), so RestrictNamespaces=true means we retain no
1510
                 * access to any namespaces and vice-versa. */
1511
                flags = streq(field, "RestrictNamespaces") ? 0 : all;
2✔
1512
        else if (r == 0)
23✔
1513
                flags = streq(field, "RestrictNamespaces") ? all : 0;
2✔
1514
        else {
1515
                if (eq[0] == '~') {
21✔
1516
                        invert = true;
2✔
1517
                        eq++;
2✔
1518
                }
1519

1520
                r = namespace_flags_from_string(eq, &flags);
21✔
1521
                if (r < 0)
21✔
UNCOV
1522
                        return parse_log_error(r, field, eq);
×
1523
        }
1524

1525
        if (invert)
25✔
1526
                flags = (~flags) & all;
2✔
1527

1528
        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
25✔
1529
        if (r < 0)
25✔
UNCOV
1530
                return bus_log_create_error(r);
×
1531

1532
        return 1;
1533
}
1534

1535
static int bus_append_bind_paths(sd_bus_message *m, const char *field, const char *eq) {
14✔
1536
        const char *p = eq;
14✔
1537
        int r;
14✔
1538

1539
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
14✔
1540
        if (r < 0)
14✔
1541
                return bus_log_create_error(r);
14✔
1542

1543
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
14✔
1544
        if (r < 0)
14✔
1545
                return bus_log_create_error(r);
×
1546

1547
        r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
14✔
1548
        if (r < 0)
14✔
UNCOV
1549
                return bus_log_create_error(r);
×
1550

1551
        r = sd_bus_message_open_container(m, 'a', "(ssbt)");
14✔
1552
        if (r < 0)
14✔
1553
                return bus_log_create_error(r);
×
1554

1555
        for (;;) {
58✔
1556
                _cleanup_free_ char *source = NULL, *destination = NULL;
22✔
1557
                char *s = NULL, *d = NULL;
36✔
1558
                bool ignore_enoent = false;
36✔
1559
                uint64_t flags = MS_REC;
36✔
1560

1561
                r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
36✔
1562
                if (r < 0)
36✔
UNCOV
1563
                        return parse_log_error(r, field, eq);
×
1564
                if (r == 0)
36✔
1565
                        break;
1566

1567
                s = source;
22✔
1568
                if (s[0] == '-') {
22✔
1569
                        ignore_enoent = true;
2✔
1570
                        s++;
2✔
1571
                }
1572

1573
                if (p && p[-1] == ':') {
22✔
1574
                        r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
14✔
1575
                        if (r < 0)
14✔
UNCOV
1576
                                return parse_log_error(r, field, p);
×
1577
                        if (r == 0)
14✔
UNCOV
1578
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1579
                                                       "Missing argument after ':': %s", eq);
1580

1581
                        d = destination;
14✔
1582

1583
                        if (p && p[-1] == ':') {
14✔
1584
                                _cleanup_free_ char *options = NULL;
8✔
1585

1586
                                r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
8✔
1587
                                if (r < 0)
8✔
UNCOV
1588
                                        return parse_log_error(r, field, p);
×
1589

1590
                                if (isempty(options) || streq(options, "rbind"))
20✔
1591
                                        flags = MS_REC;
1592
                                else if (streq(options, "norbind"))
4✔
1593
                                        flags = 0;
1594
                                else
UNCOV
1595
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1596
                                                               "Unknown options: %s", eq);
1597
                        }
1598
                } else
1599
                        d = s;
1600

1601
                r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
22✔
1602
                if (r < 0)
22✔
UNCOV
1603
                        return bus_log_create_error(r);
×
1604
        }
1605

1606
        r = sd_bus_message_close_container(m);
14✔
1607
        if (r < 0)
14✔
1608
                return bus_log_create_error(r);
×
1609

1610
        r = sd_bus_message_close_container(m);
14✔
1611
        if (r < 0)
14✔
UNCOV
1612
                return bus_log_create_error(r);
×
1613

1614
        r = sd_bus_message_close_container(m);
14✔
1615
        if (r < 0)
14✔
UNCOV
1616
                return bus_log_create_error(r);
×
1617

1618
        return 1;
1619
}
1620

1621
static int bus_append_temporary_file_system(sd_bus_message *m, const char *field, const char *eq) {
52✔
1622
        const char *p = eq;
52✔
1623
        int r;
52✔
1624

1625
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
52✔
1626
        if (r < 0)
52✔
1627
                return bus_log_create_error(r);
52✔
1628

1629
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
52✔
1630
        if (r < 0)
52✔
UNCOV
1631
                return bus_log_create_error(r);
×
1632

1633
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
52✔
1634
        if (r < 0)
52✔
UNCOV
1635
                return bus_log_create_error(r);
×
1636

1637
        r = sd_bus_message_open_container(m, 'a', "(ss)");
52✔
1638
        if (r < 0)
52✔
UNCOV
1639
                return bus_log_create_error(r);
×
1640

1641
        for (;;) {
162✔
1642
                _cleanup_free_ char *word = NULL, *path = NULL;
55✔
1643
                const char *w;
107✔
1644

1645
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
107✔
1646
                if (r < 0)
107✔
UNCOV
1647
                        return parse_log_error(r, field, eq);
×
1648
                if (r == 0)
107✔
1649
                        break;
1650

1651
                w = word;
55✔
1652
                r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
55✔
1653
                if (r <= 0)
55✔
UNCOV
1654
                        return parse_log_error(r, field, eq);
×
1655

1656
                r = sd_bus_message_append(m, "(ss)", path, w);
55✔
1657
                if (r < 0)
55✔
UNCOV
1658
                        return bus_log_create_error(r);
×
1659
        }
1660

1661
        r = sd_bus_message_close_container(m);
52✔
1662
        if (r < 0)
52✔
1663
                return bus_log_create_error(r);
×
1664

1665
        r = sd_bus_message_close_container(m);
52✔
1666
        if (r < 0)
52✔
UNCOV
1667
                return bus_log_create_error(r);
×
1668

1669
        r = sd_bus_message_close_container(m);
52✔
1670
        if (r < 0)
52✔
UNCOV
1671
                return bus_log_create_error(r);
×
1672

1673
        return 1;
1674
}
1675

1676
static int bus_append_root_hash(sd_bus_message *m, const char *field, const char *eq) {
15✔
1677
        _cleanup_free_ void *roothash_decoded = NULL;
15✔
1678
        size_t roothash_decoded_size = 0;
15✔
1679
        int r;
15✔
1680

1681
        /* We have the path to a roothash to load and decode, eg: RootHash=/foo/bar.roothash */
1682
        if (path_is_absolute(eq))
15✔
1683
                return bus_append_string(m, "RootHashPath", eq);
2✔
1684

1685
        /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1686
        r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
13✔
1687
        if (r < 0)
13✔
UNCOV
1688
                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1689
        if (roothash_decoded_size < sizeof(sd_id128_t))
13✔
UNCOV
1690
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s value '%s' is too short.", field, eq);
×
1691

1692
        return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
13✔
1693
}
1694

1695
static int bus_append_root_hash_signature(sd_bus_message *m, const char *field, const char *eq) {
2✔
1696
        _cleanup_free_ void *roothash_sig_decoded = NULL;
2✔
1697
        size_t roothash_sig_decoded_size = 0;
2✔
1698
        int r;
2✔
1699

1700
        /* We have the path to a roothash signature to load and decode, eg: RootHash=/foo/bar.roothash.p7s */
1701
        if (path_is_absolute(eq))
2✔
1702
                return bus_append_string(m, "RootHashSignaturePath", eq);
1✔
1703

1704
        const char *value = startswith(eq, "base64:");
1✔
1705
        if (!value)
1✔
UNCOV
1706
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1707
                                       "Failed to decode %s value '%s': neither a path nor starts with 'base64:'.",
1708
                                       field, eq);
1709

1710
        /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1711
        r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
1✔
1712
        if (r < 0)
1✔
UNCOV
1713
                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1714

1715
        return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1✔
1716
}
1717

1718
static int bus_append_root_image_options(sd_bus_message *m, const char *field, const char *eq) {
7✔
1719
        _cleanup_strv_free_ char **l = NULL;
7✔
1720
        const char *p = eq;
7✔
1721
        int r;
7✔
1722

1723
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
7✔
1724
        if (r < 0)
7✔
UNCOV
1725
                return bus_log_create_error(r);
×
1726

1727
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
7✔
1728
        if (r < 0)
7✔
UNCOV
1729
                return bus_log_create_error(r);
×
1730

1731
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
7✔
1732
        if (r < 0)
7✔
UNCOV
1733
                return bus_log_create_error(r);
×
1734

1735
        r = sd_bus_message_open_container(m, 'a', "(ss)");
7✔
1736
        if (r < 0)
7✔
UNCOV
1737
                return bus_log_create_error(r);
×
1738

1739
        r = strv_split_colon_pairs(&l, p);
7✔
1740
        if (r < 0)
7✔
UNCOV
1741
                return parse_log_error(r, field, eq);
×
1742

1743
        STRV_FOREACH_PAIR(first, second, l) {
20✔
1744
                r = sd_bus_message_append(m, "(ss)",
39✔
1745
                                          !isempty(*second) ? *first : "root",
13✔
1746
                                          !isempty(*second) ? *second : *first);
13✔
1747
                if (r < 0)
13✔
UNCOV
1748
                        return bus_log_create_error(r);
×
1749
        }
1750

1751
        r = sd_bus_message_close_container(m);
7✔
1752
        if (r < 0)
7✔
UNCOV
1753
                return bus_log_create_error(r);
×
1754

1755
        r = sd_bus_message_close_container(m);
7✔
1756
        if (r < 0)
7✔
1757
                return bus_log_create_error(r);
×
1758

1759
        r = sd_bus_message_close_container(m);
7✔
1760
        if (r < 0)
7✔
1761
                return bus_log_create_error(r);
×
1762

1763
        return 1;
1764
}
1765

1766
static int bus_append_mount_images(sd_bus_message *m, const char *field, const char *eq) {
15✔
1767
        const char *p = eq;
15✔
1768
        int r;
15✔
1769

1770
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
15✔
1771
        if (r < 0)
15✔
1772
                return bus_log_create_error(r);
15✔
1773

1774
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
15✔
1775
        if (r < 0)
15✔
UNCOV
1776
                return bus_log_create_error(r);
×
1777

1778
        r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
15✔
1779
        if (r < 0)
15✔
UNCOV
1780
                return bus_log_create_error(r);
×
1781

1782
        r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
15✔
1783
        if (r < 0)
15✔
UNCOV
1784
                return bus_log_create_error(r);
×
1785

1786
        for (;;) {
37✔
1787
                _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
22✔
1788
                const char *q = NULL, *source = NULL;
37✔
1789
                bool permissive = false;
37✔
1790

1791
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
37✔
1792
                if (r < 0)
37✔
UNCOV
1793
                        return parse_log_error(r, field, eq);
×
1794
                if (r == 0)
37✔
1795
                        break;
1796

1797
                q = tuple;
22✔
1798
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
22✔
1799
                if (r < 0)
22✔
1800
                        return parse_log_error(r, field, eq);
×
1801
                if (r == 0)
22✔
UNCOV
1802
                        continue;
×
1803

1804
                source = first;
22✔
1805
                if (source[0] == '-') {
22✔
UNCOV
1806
                        permissive = true;
×
UNCOV
1807
                        source++;
×
1808
                }
1809

1810
                if (isempty(second))
22✔
UNCOV
1811
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1812
                                               "Missing argument after ':' for %s=: '%s'", field, eq);
1813

1814
                r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
22✔
1815
                if (r < 0)
22✔
UNCOV
1816
                        return bus_log_create_error(r);
×
1817

1818
                r = sd_bus_message_append(m, "ssb", source, second, permissive);
22✔
1819
                if (r < 0)
22✔
UNCOV
1820
                        return bus_log_create_error(r);
×
1821

1822
                r = sd_bus_message_open_container(m, 'a', "(ss)");
22✔
1823
                if (r < 0)
22✔
UNCOV
1824
                        return bus_log_create_error(r);
×
1825

1826
                for (;;) {
26✔
1827
                        _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2✔
1828

1829
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
24✔
1830
                        if (r < 0)
24✔
UNCOV
1831
                                return parse_log_error(r, field, eq);
×
1832
                        if (r == 0)
24✔
1833
                                break;
1834
                        /* Single set of options, applying to the root partition/single filesystem */
1835
                        if (r == 1) {
8✔
1836
                                r = sd_bus_message_append(m, "(ss)", "root", partition);
6✔
1837
                                if (r < 0)
6✔
UNCOV
1838
                                        return bus_log_create_error(r);
×
1839

1840
                                break;
1841
                        }
1842

1843
                        r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2✔
1844
                        if (r < 0)
2✔
UNCOV
1845
                                return bus_log_create_error(r);
×
1846
                }
1847

1848
                r = sd_bus_message_close_container(m);
22✔
1849
                if (r < 0)
22✔
UNCOV
1850
                        return bus_log_create_error(r);
×
1851

1852
                r = sd_bus_message_close_container(m);
22✔
1853
                if (r < 0)
22✔
UNCOV
1854
                        return bus_log_create_error(r);
×
1855
        }
1856

1857
        r = sd_bus_message_close_container(m);
15✔
1858
        if (r < 0)
15✔
UNCOV
1859
                return bus_log_create_error(r);
×
1860

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

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

1869
        return 1;
1870
}
1871

1872
static int bus_append_extension_images(sd_bus_message *m, const char *field, const char *eq) {
29✔
1873
        const char *p = eq;
29✔
1874
        int r;
29✔
1875

1876
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
29✔
1877
        if (r < 0)
29✔
1878
                return bus_log_create_error(r);
29✔
1879

1880
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
29✔
1881
        if (r < 0)
29✔
UNCOV
1882
                return bus_log_create_error(r);
×
1883

1884
        r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
29✔
1885
        if (r < 0)
29✔
UNCOV
1886
                return bus_log_create_error(r);
×
1887

1888
        r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
29✔
1889
        if (r < 0)
29✔
1890
                return bus_log_create_error(r);
×
1891

1892
        for (;;) {
66✔
1893
                _cleanup_free_ char *source = NULL, *tuple = NULL;
37✔
1894
                const char *q = NULL, *s = NULL;
66✔
1895
                bool permissive = false;
66✔
1896

1897
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
66✔
1898
                if (r < 0)
66✔
UNCOV
1899
                        return parse_log_error(r, field, eq);
×
1900
                if (r == 0)
66✔
1901
                        break;
1902

1903
                q = tuple;
37✔
1904
                r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
37✔
1905
                if (r < 0)
37✔
1906
                        return parse_log_error(r, field, eq);
×
1907
                if (r == 0)
37✔
UNCOV
1908
                        continue;
×
1909

1910
                s = source;
37✔
1911
                if (s[0] == '-') {
37✔
1912
                        permissive = true;
2✔
1913
                        s++;
2✔
1914
                }
1915

1916
                r = sd_bus_message_open_container(m, 'r', "sba(ss)");
37✔
1917
                if (r < 0)
37✔
UNCOV
1918
                        return bus_log_create_error(r);
×
1919

1920
                r = sd_bus_message_append(m, "sb", s, permissive);
37✔
1921
                if (r < 0)
37✔
UNCOV
1922
                        return bus_log_create_error(r);
×
1923

1924
                r = sd_bus_message_open_container(m, 'a', "(ss)");
37✔
1925
                if (r < 0)
37✔
UNCOV
1926
                        return bus_log_create_error(r);
×
1927

1928
                for (;;) {
37✔
UNCOV
1929
                        _cleanup_free_ char *partition = NULL, *mount_options = NULL;
×
1930

1931
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
37✔
1932
                        if (r < 0)
37✔
UNCOV
1933
                                return parse_log_error(r, field, eq);
×
1934
                        if (r == 0)
37✔
1935
                                break;
1936
                        /* Single set of options, applying to the root partition/single filesystem */
1937
                        if (r == 1) {
1✔
1938
                                r = sd_bus_message_append(m, "(ss)", "root", partition);
1✔
1939
                                if (r < 0)
1✔
UNCOV
1940
                                        return bus_log_create_error(r);
×
1941

1942
                                break;
1943
                        }
1944

1945
                        r = sd_bus_message_append(m, "(ss)", partition, mount_options);
×
UNCOV
1946
                        if (r < 0)
×
UNCOV
1947
                                return bus_log_create_error(r);
×
1948
                }
1949

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

1954
                r = sd_bus_message_close_container(m);
37✔
1955
                if (r < 0)
37✔
UNCOV
1956
                        return bus_log_create_error(r);
×
1957
        }
1958

1959
        r = sd_bus_message_close_container(m);
29✔
1960
        if (r < 0)
29✔
1961
                return bus_log_create_error(r);
×
1962

1963
        r = sd_bus_message_close_container(m);
29✔
1964
        if (r < 0)
29✔
UNCOV
1965
                return bus_log_create_error(r);
×
1966

1967
        r = sd_bus_message_close_container(m);
29✔
1968
        if (r < 0)
29✔
1969
                return bus_log_create_error(r);
×
1970

1971
        return 1;
1972
}
1973

1974
static int bus_append_directory(sd_bus_message *m, const char *field, const char *eq) {
191✔
1975
        _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
191✔
1976
        const char *p = eq;
191✔
1977
        int r;
444✔
1978

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

1983
        for (;;) {
697✔
1984
                _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
253✔
1985

1986
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
444✔
1987
                if (r < 0)
444✔
1988
                        return parse_log_error(r, field, eq);
×
1989
                if (r == 0)
444✔
1990
                        break;
1991

1992
                const char *t = tuple;
253✔
1993
                r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
253✔
1994
                if (r <= 0)
253✔
UNCOV
1995
                        return parse_log_error(r, field, eq);
×
1996

1997
                path_simplify(source);
253✔
1998

1999
                if (isempty(dest) && isempty(flags)) {
290✔
2000
                        r = strv_consume(&sources, TAKE_PTR(source));
122✔
2001
                        if (r < 0)
122✔
UNCOV
2002
                                return bus_log_create_error(r);
×
2003
                } else if (isempty(flags)) {
131✔
2004
                        path_simplify(dest);
57✔
2005
                        r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
57✔
2006
                        if (r < 0)
57✔
2007
                                return log_oom();
×
2008
                } else {
2009
                        ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
74✔
2010
                        if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
74✔
UNCOV
2011
                                return log_error_errno(r, "Failed to parse flags for %s=: '%s'", field, flags);
×
2012

2013
                        if (!isempty(dest)) {
74✔
2014
                                path_simplify(dest);
37✔
2015
                                r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
37✔
2016
                        } else
2017
                                r = strv_consume(&sources_ro, TAKE_PTR(source));
37✔
2018
                        if (r < 0)
74✔
UNCOV
2019
                                return log_oom();
×
2020
                }
2021
        }
2022

2023
        if (!strv_isempty(sources)) {
191✔
2024
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
103✔
2025
                if (r < 0)
103✔
2026
                        return bus_log_create_error(r);
×
2027

2028
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
103✔
2029
                if (r < 0)
103✔
2030
                        return bus_log_create_error(r);
×
2031

2032
                r = sd_bus_message_open_container(m, 'v', "as");
103✔
2033
                if (r < 0)
103✔
UNCOV
2034
                        return bus_log_create_error(r);
×
2035

2036
                r = sd_bus_message_append_strv(m, sources);
103✔
2037
                if (r < 0)
103✔
UNCOV
2038
                        return bus_log_create_error(r);
×
2039

2040
                r = sd_bus_message_close_container(m);
103✔
2041
                if (r < 0)
103✔
UNCOV
2042
                        return bus_log_create_error(r);
×
2043

2044
                r = sd_bus_message_close_container(m);
103✔
2045
                if (r < 0)
103✔
UNCOV
2046
                        return bus_log_create_error(r);
×
2047
        }
2048

2049
        /* For State and Runtime directories we support an optional destination parameter, which
2050
         * will be used to create a symlink to the source. But it is new so we cannot change the
2051
         * old DBUS signatures, so append a new message type. */
2052
        if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) {
274✔
2053
                const char *symlink_field;
83✔
2054

2055
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
83✔
2056
                if (r < 0)
83✔
UNCOV
2057
                        return bus_log_create_error(r);
×
2058

2059
                if (streq(field, "StateDirectory"))
83✔
2060
                        symlink_field = "StateDirectorySymlink";
2061
                else if (streq(field, "RuntimeDirectory"))
62✔
2062
                        symlink_field = "RuntimeDirectorySymlink";
2063
                else if (streq(field, "CacheDirectory"))
38✔
2064
                        symlink_field = "CacheDirectorySymlink";
2065
                else if (streq(field, "LogsDirectory"))
19✔
2066
                        symlink_field = "LogsDirectorySymlink";
2067
                else
2068
                        assert_not_reached();
×
2069

2070
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
83✔
2071
                if (r < 0)
83✔
2072
                        return bus_log_create_error(r);
×
2073

2074
                r = sd_bus_message_open_container(m, 'v', "a(sst)");
83✔
2075
                if (r < 0)
83✔
2076
                        return bus_log_create_error(r);
×
2077

2078
                r = sd_bus_message_open_container(m, 'a', "(sst)");
83✔
2079
                if (r < 0)
83✔
UNCOV
2080
                        return bus_log_create_error(r);
×
2081

2082
                STRV_FOREACH_PAIR(source, destination, symlinks) {
140✔
2083
                        r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
57✔
2084
                        if (r < 0)
57✔
2085
                                return bus_log_create_error(r);
×
2086
                }
2087

2088
                STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
120✔
2089
                        r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2090
                        if (r < 0)
37✔
UNCOV
2091
                                return bus_log_create_error(r);
×
2092
                }
2093

2094
                STRV_FOREACH(source, sources_ro) {
120✔
2095
                        r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2096
                        if (r < 0)
37✔
UNCOV
2097
                                return bus_log_create_error(r);
×
2098
                }
2099

2100
                r = sd_bus_message_close_container(m);
83✔
2101
                if (r < 0)
83✔
UNCOV
2102
                        return bus_log_create_error(r);
×
2103

2104
                r = sd_bus_message_close_container(m);
83✔
2105
                if (r < 0)
83✔
UNCOV
2106
                        return bus_log_create_error(r);
×
2107

2108
                r = sd_bus_message_close_container(m);
83✔
2109
                if (r < 0)
83✔
UNCOV
2110
                        return bus_log_create_error(r);
×
2111
        }
2112

2113
        return 1;
2114
}
2115

UNCOV
2116
static int bus_append_quota_directory(sd_bus_message *m, const char *field, const char *eq) {
×
UNCOV
2117
        uint64_t quota_absolute = UINT64_MAX;
×
UNCOV
2118
        uint32_t quota_scale = UINT32_MAX;
×
UNCOV
2119
        int quota_enforce = false;
×
UNCOV
2120
        int r;
×
2121

UNCOV
2122
        if (!isempty(eq) && !streq(eq, "off")) {
×
UNCOV
2123
                r = parse_permyriad(eq);
×
UNCOV
2124
                if (r < 0) {
×
UNCOV
2125
                        r = parse_size(eq, 1024, &quota_absolute);
×
UNCOV
2126
                        if (r < 0)
×
UNCOV
2127
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
×
2128
                } else
UNCOV
2129
                        quota_scale = UINT32_SCALE_FROM_PERMYRIAD(r);
×
2130

2131
                quota_enforce = true;
2132
        }
2133

UNCOV
2134
        r = sd_bus_message_append(m, "(sv)", field, "(tus)", quota_absolute, quota_scale, yes_no(quota_enforce));
×
UNCOV
2135
        if (r < 0)
×
UNCOV
2136
                return bus_log_create_error(r);
×
2137

2138
        return 1;
2139
}
2140

2141
static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) {
35✔
2142
        int r;
35✔
2143

2144
        /* The command-line field is called "ProtectHostname". We also accept "ProtectHostnameEx" as the
2145
         * field name for backward compatibility. We set ProtectHostame or ProtectHostnameEx. */
2146

2147
        r = parse_boolean(eq);
35✔
2148
        if (r >= 0)
35✔
2149
                r = sd_bus_message_append(m, "(sv)", "ProtectHostname", "b", r);
9✔
2150
        else {
2151
                const char *colon = strchr(eq, ':');
26✔
2152
                if (colon) {
26✔
2153
                        if (isempty(colon + 1))
19✔
2154
                                return parse_log_error(0, field, eq);
35✔
2155

2156
                        _cleanup_free_ char *p = strndup(eq, colon - eq);
17✔
2157
                        if (!p)
17✔
UNCOV
2158
                                return -ENOMEM;
×
2159

2160
                        r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", p, colon + 1);
17✔
2161
                } else
2162
                        r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", eq, NULL);
7✔
2163
        }
2164
        if (r < 0)
33✔
UNCOV
2165
                return bus_log_create_error(r);
×
2166

2167
        return 1;
2168
}
2169

2170
static int bus_append_boolean_or_ex_string(sd_bus_message *m, const char *field, const char *eq) {
85✔
2171
        int r;
85✔
2172

2173
        r = parse_boolean(eq);
85✔
2174
        if (r >= 0) {
85✔
2175
                if (endswith(field, "Ex"))
45✔
2176
                        field = strndupa_safe(field, strlen(field) - 2);
15✔
2177

2178
                r = sd_bus_message_append(m, "(sv)", field, "b", r);
45✔
2179
        } else {
2180
                if (!endswith(field, "Ex"))
40✔
2181
                        field = strjoina(field, "Ex");
10✔
2182

2183
                /* We allow any string through and let the server perform the verification. */
2184
                r = sd_bus_message_append(m, "(sv)", field, "s", eq);
40✔
2185
        }
2186
        if (r < 0)
85✔
UNCOV
2187
                return bus_log_create_error(r);
×
2188

2189
        return 1;
2190
}
2191

2192
static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) {
10✔
2193
        return bus_append_trivial_array(m, "Paths", eq,
20✔
2194
                                        "a(ss)", field, eq);
2195
}
2196

2197
static int bus_append_exit_status(sd_bus_message *m, const char *field, const char *eq) {
9✔
2198
        _cleanup_free_ int *status = NULL, *signal = NULL;
9✔
2199
        size_t n_status = 0, n_signal = 0;
9✔
2200
        int r;
9✔
2201

2202
        for (const char *p = eq;;) {
9✔
2203
                _cleanup_free_ char *word = NULL;
21✔
2204

2205
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
30✔
2206
                if (r < 0)
30✔
UNCOV
2207
                        return parse_log_error(r, field, eq);
×
2208
                if (r == 0)
30✔
2209
                        break;
2210

2211
                /* We need to call exit_status_from_string() first, because we want
2212
                 * to parse numbers as exit statuses, not signals. */
2213

2214
                r = exit_status_from_string(word);
21✔
2215
                if (r >= 0) {
21✔
2216
                        assert(r >= 0 && r < 256);
13✔
2217

2218
                        if (!GREEDY_REALLOC(status, n_status + 1))
13✔
UNCOV
2219
                                return log_oom();
×
2220

2221
                        status[n_status++] = r;
13✔
2222

2223
                } else if ((r = signal_from_string(word)) >= 0) {
8✔
2224
                        if (!GREEDY_REALLOC(signal, n_signal + 1))
8✔
UNCOV
2225
                                return log_oom();
×
2226

2227
                        signal[n_signal++] = r;
8✔
2228

2229
                } else
2230
                        /* original r from exit_status_to_string() */
UNCOV
2231
                        return parse_log_error(r, field, word);
×
2232
        }
2233

2234
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
9✔
2235
        if (r < 0)
9✔
UNCOV
2236
                return bus_log_create_error(r);
×
2237

2238
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
9✔
2239
        if (r < 0)
9✔
UNCOV
2240
                return bus_log_create_error(r);
×
2241

2242
        r = sd_bus_message_open_container(m, 'v', "(aiai)");
9✔
2243
        if (r < 0)
9✔
UNCOV
2244
                return bus_log_create_error(r);
×
2245

2246
        r = sd_bus_message_open_container(m, 'r', "aiai");
9✔
2247
        if (r < 0)
9✔
UNCOV
2248
                return bus_log_create_error(r);
×
2249

2250
        r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
9✔
2251
        if (r < 0)
9✔
UNCOV
2252
                return bus_log_create_error(r);
×
2253

2254
        r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
9✔
2255
        if (r < 0)
9✔
UNCOV
2256
                return bus_log_create_error(r);
×
2257

2258
        r = sd_bus_message_close_container(m);
9✔
2259
        if (r < 0)
9✔
UNCOV
2260
                return bus_log_create_error(r);
×
2261

2262
        r = sd_bus_message_close_container(m);
9✔
2263
        if (r < 0)
9✔
2264
                return bus_log_create_error(r);
×
2265

2266
        r = sd_bus_message_close_container(m);
9✔
2267
        if (r < 0)
9✔
UNCOV
2268
                return bus_log_create_error(r);
×
2269

2270
        return 1;
2271
}
2272

2273
static int bus_append_action_exit_status(sd_bus_message *m, const char *field, const char *eq) {
4✔
2274
        int r;
4✔
2275

2276
        if (isempty(eq))
4✔
2277
                r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2✔
2278
        else {
2279
                uint8_t u;
2✔
2280

2281
                r = safe_atou8(eq, &u);
2✔
2282
                if (r < 0)
2✔
UNCOV
2283
                        return parse_log_error(r, field, eq);
×
2284

2285
                r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2✔
2286
        }
2287
        if (r < 0)
4✔
UNCOV
2288
                return bus_log_create_error(r);
×
2289

2290
        return 1;
2291
}
2292

2293
static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) {
23✔
2294
        const char *p = ASSERT_PTR(startswith(field, "Listen"));
23✔
2295

2296
        return bus_append_trivial_array(m, "Listen", eq,
46✔
2297
                                        "a(ss)", p, eq);
2298
}
2299

2300
static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, const char *eq) {
27✔
2301
        int r;
27✔
2302

2303
        if (isempty(eq))
27✔
2304
                r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
5✔
2305
        else {
2306
                usec_t t;
22✔
2307
                r = parse_sec(eq, &t);
22✔
2308
                if (r < 0)
22✔
2309
                        return parse_log_error(r, field, eq);
5✔
2310

2311
                r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
17✔
2312
        }
2313
        if (r < 0)
22✔
UNCOV
2314
                return bus_log_create_error(r);
×
2315

2316
        return 1;
2317
}
2318

2319
static int bus_append_timers_calendar(sd_bus_message *m, const char *field, const char *eq) {
6✔
2320
        return bus_append_trivial_array(m, "TimersCalendar", eq,
12✔
2321
                                        "a(ss)", field, eq);
2322
}
2323

2324
static int bus_append_timeout_sec(sd_bus_message *m, const char *field, const char *eq) {
1✔
2325
        int r;
1✔
2326

2327
        r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1✔
2328
        if (r < 0)
1✔
2329
                return r;
2330

2331
        return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1✔
2332
}
2333

2334
static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) {
74✔
2335
        ConditionType t = condition_type_from_string(field);
74✔
2336
        bool is_condition = t >= 0;
74✔
2337

2338
        if (!is_condition) {
74✔
2339
                t = assert_type_from_string(field);
36✔
2340
                if (t < 0)
36✔
2341
                        return 0;
2342
        }
2343

2344
        const char *p = eq;
74✔
2345

2346
        int trigger = p && *p == '|';
74✔
2347
        if (trigger)
74✔
2348
                p++;
69✔
2349

2350
        int negate = p && *p == '!';
74✔
2351
        if (negate)
3✔
2352
                p++;
3✔
2353

2354
        return bus_append_trivial_array(m,
184✔
2355
                                        is_condition ? "Conditions" : "Asserts",
2356
                                        eq,
2357
                                        "a(sbbs)",
2358
                                        field, trigger, negate, p);
2359
}
2360

2361
static void dump_conditions(void) {
35✔
2362
        condition_types_list();
35✔
2363
        assert_types_list();
35✔
2364
}
35✔
2365

2366
static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) {
125✔
2367
        if (unit_dependency_from_string(field) < 0)
125✔
2368
                return 0;
2369

2370
        return bus_append_strv(m, field, eq);
51✔
2371
}
2372

2373
typedef struct BusProperty {
2374
        const char *name;
2375
        int (*convert)(sd_bus_message *m, const char *field, const char *eq);
2376
        void (*dump)(void);
2377
} BusProperty;
2378

2379
static const BusProperty cgroup_properties[] = {
2380
        { "DevicePolicy",                          bus_append_string                             },
2381
        { "Slice",                                 bus_append_string                             },
2382
        { "ManagedOOMSwap",                        bus_append_string                             },
2383
        { "ManagedOOMMemoryPressure",              bus_append_string                             },
2384
        { "ManagedOOMPreference",                  bus_append_string                             },
2385
        { "MemoryPressureWatch",                   bus_append_string                             },
2386
        { "DelegateSubgroup",                      bus_append_string                             },
2387
        { "ManagedOOMMemoryPressureLimit",         bus_append_parse_permyriad                    },
2388
        { "MemoryAccounting",                      bus_append_parse_boolean                      },
2389
        { "MemoryZSwapWriteback",                  bus_append_parse_boolean                      },
2390
        { "IOAccounting",                          bus_append_parse_boolean                      },
2391
        { "TasksAccounting",                       bus_append_parse_boolean                      },
2392
        { "IPAccounting",                          bus_append_parse_boolean                      },
2393
        { "CoredumpReceive",                       bus_append_parse_boolean                      },
2394
        { "CPUWeight",                             bus_append_cg_cpu_weight_parse                },
2395
        { "StartupCPUWeight",                      bus_append_cg_cpu_weight_parse                },
2396
        { "IOWeight",                              bus_append_cg_weight_parse                    },
2397
        { "StartupIOWeight",                       bus_append_cg_weight_parse                    },
2398
        { "AllowedCPUs",                           bus_append_parse_cpu_set                      },
2399
        { "StartupAllowedCPUs",                    bus_append_parse_cpu_set                      },
2400
        { "AllowedMemoryNodes",                    bus_append_parse_cpu_set                      },
2401
        { "StartupAllowedMemoryNodes",             bus_append_parse_cpu_set                      },
2402
        { "DisableControllers",                    bus_append_strv                               },
2403
        { "Delegate",                              bus_append_parse_delegate                     },
2404
        { "MemoryMin",                             bus_append_parse_resource_limit               },
2405
        { "MemoryLow",                             bus_append_parse_resource_limit               },
2406
        { "MemoryHigh",                            bus_append_parse_resource_limit               },
2407
        { "MemoryMax",                             bus_append_parse_resource_limit               },
2408
        { "MemorySwapMax",                         bus_append_parse_resource_limit               },
2409
        { "MemoryZSwapMax",                        bus_append_parse_resource_limit               },
2410
        { "TasksMax",                              bus_append_parse_resource_limit               },
2411
        { "CPUQuota",                              bus_append_parse_cpu_quota                    },
2412
        { "CPUQuotaPeriodSec",                     bus_append_parse_sec_rename_infinity          },
2413
        { "DeviceAllow",                           bus_append_parse_device_allow                 },
2414
        { "IODeviceWeight",                        bus_append_parse_io_device_weight             },
2415
        { "IODeviceLatencyTargetSec",              bus_append_parse_io_device_latency            },
2416
        { "IPAddressAllow",                        bus_append_parse_ip_address_filter            },
2417
        { "IPAddressDeny",                         bus_append_parse_ip_address_filter            },
2418
        { "IPIngressFilterPath",                   bus_append_ip_filter_path                     },
2419
        { "IPEgressFilterPath",                    bus_append_ip_filter_path                     },
2420
        { "BPFProgram",                            bus_append_bpf_program                        },
2421
        { "SocketBindAllow",                       bus_append_socket_filter                      },
2422
        { "SocketBindDeny",                        bus_append_socket_filter                      },
2423
        { "MemoryPressureThresholdSec",            bus_append_parse_sec_rename                   },
2424
        { "NFTSet",                                bus_append_nft_set                            },
2425
        { "BindNetworkInterface",                  bus_append_string                             },
2426

2427
        /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
2428
         * means use the default memory pressure duration from oomd.conf. */
2429
        { "ManagedOOMMemoryPressureDurationSec",   bus_append_parse_sec_rename_infinity          },
2430

2431
        { "MemoryLimit",                           warn_deprecated                               },
2432
        { "CPUShares",                             warn_deprecated                               },
2433
        { "StartupCPUShares",                      warn_deprecated                               },
2434
        { "BlockIOAccounting",                     warn_deprecated                               },
2435
        { "BlockIOWeight",                         warn_deprecated                               },
2436
        { "StartupBlockIOWeight",                  warn_deprecated                               },
2437
        { "BlockIODeviceWeight",                   warn_deprecated                               },
2438
        { "BlockIOReadBandwidth",                  warn_deprecated                               },
2439
        { "BlockIOWriteBandwidth",                 warn_deprecated                               },
2440
        { "CPUAccounting",                         warn_deprecated                               },
2441
        { "DefaultMemoryMin",                      warn_deprecated                               },
2442
        { "DefaultMemoryLow",                      warn_deprecated                               },
2443

2444
        { NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list                      },
2445
        {}
2446
};
2447

2448
static const BusProperty automount_properties[] = {
2449
        { "Where",                                 bus_append_string                             },
2450
        { "ExtraOptions",                          bus_append_string                             },
2451
        { "DirectoryMode",                         bus_append_parse_mode                         },
2452
        { "TimeoutIdleSec",                        bus_append_parse_sec_rename                   },
2453
        {}
2454
};
2455

2456
static const BusProperty execute_properties[] = {
2457
        { "User",                                  bus_append_string                             },
2458
        { "Group",                                 bus_append_string                             },
2459
        { "UtmpIdentifier",                        bus_append_string                             },
2460
        { "UtmpMode",                              bus_append_string                             },
2461
        { "PAMName",                               bus_append_string                             },
2462
        { "TTYPath",                               bus_append_string                             },
2463
        { "WorkingDirectory",                      bus_append_string                             },
2464
        { "RootDirectory",                         bus_append_string                             },
2465
        { "SyslogIdentifier",                      bus_append_string                             },
2466
        { "ProtectSystem",                         bus_append_string                             },
2467
        { "ProtectHome",                           bus_append_string                             },
2468
        { "SELinuxContext",                        bus_append_string                             },
2469
        { "RootImage",                             bus_append_string                             },
2470
        { "RootVerity",                            bus_append_string                             },
2471
        { "RuntimeDirectoryPreserve",              bus_append_string                             },
2472
        { "Personality",                           bus_append_string                             },
2473
        { "KeyringMode",                           bus_append_string                             },
2474
        { "ProtectProc",                           bus_append_string                             },
2475
        { "ProcSubset",                            bus_append_string                             },
2476
        { "NetworkNamespacePath",                  bus_append_string                             },
2477
        { "UserNamespacePath",                     bus_append_string                             },
2478
        { "IPCNamespacePath",                      bus_append_string                             },
2479
        { "LogNamespace",                          bus_append_string                             },
2480
        { "RootImagePolicy",                       bus_append_string                             },
2481
        { "MountImagePolicy",                      bus_append_string                             },
2482
        { "ExtensionImagePolicy",                  bus_append_string                             },
2483
        { "PrivatePIDs",                           bus_append_string                             },
2484
        { "PrivateBPF",                            bus_append_string                             },
2485
        { "BPFDelegateCommands",                   bus_append_string                             },
2486
        { "BPFDelegateMaps",                       bus_append_string                             },
2487
        { "BPFDelegatePrograms",                   bus_append_string                             },
2488
        { "BPFDelegateAttachments",                bus_append_string                             },
2489
        { "IgnoreSIGPIPE",                         bus_append_parse_boolean                      },
2490
        { "TTYVHangup",                            bus_append_parse_boolean                      },
2491
        { "TTYReset",                              bus_append_parse_boolean                      },
2492
        { "TTYVTDisallocate",                      bus_append_parse_boolean                      },
2493
        { "PrivateDevices",                        bus_append_parse_boolean                      },
2494
        { "PrivateNetwork",                        bus_append_parse_boolean                      },
2495
        { "PrivateMounts",                         bus_append_parse_boolean                      },
2496
        { "PrivateIPC",                            bus_append_parse_boolean                      },
2497
        { "NoNewPrivileges",                       bus_append_parse_boolean                      },
2498
        { "SyslogLevelPrefix",                     bus_append_parse_boolean                      },
2499
        { "MemoryDenyWriteExecute",                bus_append_parse_boolean                      },
2500
        { "RestrictRealtime",                      bus_append_parse_boolean                      },
2501
        { "DynamicUser",                           bus_append_parse_boolean                      },
2502
        { "RemoveIPC",                             bus_append_parse_boolean                      },
2503
        { "ProtectKernelTunables",                 bus_append_parse_boolean                      },
2504
        { "ProtectKernelModules",                  bus_append_parse_boolean                      },
2505
        { "ProtectKernelLogs",                     bus_append_parse_boolean                      },
2506
        { "ProtectClock",                          bus_append_parse_boolean                      },
2507
        { "MountAPIVFS",                           bus_append_parse_boolean                      },
2508
        { "BindLogSockets",                        bus_append_parse_boolean                      },
2509
        { "CPUSchedulingResetOnFork",              bus_append_parse_boolean                      },
2510
        { "LockPersonality",                       bus_append_parse_boolean                      },
2511
        { "MemoryKSM",                             bus_append_parse_boolean                      },
2512
        { "MemoryTHP",                             bus_append_string                             },
2513
        { "RestrictSUIDSGID",                      bus_append_parse_boolean                      },
2514
        { "RootEphemeral",                         bus_append_parse_boolean                      },
2515
        { "SetLoginEnvironment",                   bus_append_parse_boolean                      },
2516
        { "ReadWriteDirectories",                  bus_append_strv                               },
2517
        { "ReadOnlyDirectories",                   bus_append_strv                               },
2518
        { "InaccessibleDirectories",               bus_append_strv                               },
2519
        { "ReadWritePaths",                        bus_append_strv                               },
2520
        { "ReadOnlyPaths",                         bus_append_strv                               },
2521
        { "InaccessiblePaths",                     bus_append_strv                               },
2522
        { "ExecPaths",                             bus_append_strv                               },
2523
        { "NoExecPaths",                           bus_append_strv                               },
2524
        { "ExecSearchPath",                        bus_append_strv_colon                         },
2525
        { "ExtensionDirectories",                  bus_append_strv                               },
2526
        { "ConfigurationDirectory",                bus_append_strv                               },
2527
        { "SupplementaryGroups",                   bus_append_strv                               },
2528
        { "SystemCallArchitectures",               bus_append_strv                               },
2529
        { "SyslogLevel",                           bus_append_log_level_from_string              },
2530
        { "LogLevelMax",                           bus_append_log_level_from_string              },
2531
        { "SyslogFacility",                        bus_append_log_facility_unshifted_from_string },
2532
        { "SecureBits",                            bus_append_secure_bits_from_string            },
2533
        { "CPUSchedulingPolicy",                   bus_append_sched_policy_from_string           },
2534
        { "CPUSchedulingPriority",                 bus_append_safe_atoi                          },
2535
        { "OOMScoreAdjust",                        bus_append_safe_atoi                          },
2536
        { "CoredumpFilter",                        bus_append_coredump_filter_mask_from_string   },
2537
        { "Nice",                                  bus_append_parse_nice                         },
2538
        { "SystemCallErrorNumber",                 bus_append_seccomp_parse_errno_or_action      },
2539
        { "IOSchedulingClass",                     bus_append_ioprio_class_from_string           },
2540
        { "IOSchedulingPriority",                  bus_append_ioprio_parse_priority              },
2541
        { "RuntimeDirectoryMode",                  bus_append_parse_mode                         },
2542
        { "StateDirectoryMode",                    bus_append_parse_mode                         },
2543
        { "CacheDirectoryMode",                    bus_append_parse_mode                         },
2544
        { "LogsDirectoryMode",                     bus_append_parse_mode                         },
2545
        { "ConfigurationDirectoryMode",            bus_append_parse_mode                         },
2546
        { "UMask",                                 bus_append_parse_mode                         },
2547
        { "TimerSlackNSec",                        bus_append_parse_nsec                         },
2548
        { "LogRateLimitIntervalSec",               bus_append_parse_sec_rename                   },
2549
        { "LogRateLimitBurst",                     bus_append_safe_atou                          },
2550
        { "TTYRows",                               bus_append_safe_atou                          },
2551
        { "TTYColumns",                            bus_append_safe_atou                          },
2552
        { "MountFlags",                            bus_append_mount_propagation_flag_from_string },
2553
        { "Environment",                           bus_append_strv_cunescape                     },
2554
        { "UnsetEnvironment",                      bus_append_strv_cunescape                     },
2555
        { "PassEnvironment",                       bus_append_strv_cunescape                     },
2556
        { "EnvironmentFile",                       bus_append_environment_files                  },
2557
        { "SetCredential",                         bus_append_set_credential                     },
2558
        { "SetCredentialEncrypted",                bus_append_set_credential                     },
2559
        { "LoadCredential",                        bus_append_load_credential                    },
2560
        { "LoadCredentialEncrypted",               bus_append_load_credential                    },
2561
        { "ImportCredential",                      bus_append_import_credential                  },
2562
        { "ImportCredentialEx",                    bus_append_import_credential                  }, /* compat */
2563
        { "LogExtraFields",                        bus_append_log_extra_fields                   },
2564
        { "LogFilterPatterns",                     bus_append_log_filter_patterns                },
2565
        { "StandardInput",                         bus_append_standard_inputs                    },
2566
        { "StandardOutput",                        bus_append_standard_inputs                    },
2567
        { "StandardError",                         bus_append_standard_inputs                    },
2568
        { "StandardInputText",                     bus_append_standard_input_text                },
2569
        { "StandardInputData",                     bus_append_standard_input_data                },
2570
        { "AppArmorProfile",                       bus_append_string_with_ignore                 },
2571
        { "SmackProcessLabel",                     bus_append_string_with_ignore                 },
2572
        { "CapabilityBoundingSet",                 bus_append_capabilities                       },
2573
        { "AmbientCapabilities",                   bus_append_capabilities                       },
2574
        { "CPUAffinity",                           bus_append_cpu_affinity                       },
2575
        { "NUMAPolicy",                            bus_append_mpol_from_string                   },
2576
        { "NUMAMask",                              bus_append_numa_mask                          },
2577
        { "RestrictAddressFamilies",               bus_append_filter_list                        },
2578
        { "RestrictFileSystems",                   bus_append_filter_list                        },
2579
        { "SystemCallFilter",                      bus_append_filter_list                        },
2580
        { "SystemCallLog",                         bus_append_filter_list                        },
2581
        { "RestrictNetworkInterfaces",             bus_append_filter_list                        },
2582
        { "RestrictNamespaces",                    bus_append_namespace_list                     },
2583
        { "DelegateNamespaces",                    bus_append_namespace_list                     },
2584
        { "BindPaths",                             bus_append_bind_paths                         },
2585
        { "BindReadOnlyPaths",                     bus_append_bind_paths                         },
2586
        { "TemporaryFileSystem",                   bus_append_temporary_file_system              },
2587
        { "RootHash",                              bus_append_root_hash                          },
2588
        { "RootHashSignature",                     bus_append_root_hash_signature                },
2589
        { "RootImageOptions",                      bus_append_root_image_options                 },
2590
        { "MountImages",                           bus_append_mount_images                       },
2591
        { "ExtensionImages",                       bus_append_extension_images                   },
2592
        { "StateDirectory",                        bus_append_directory                          },
2593
        { "RuntimeDirectory",                      bus_append_directory                          },
2594
        { "CacheDirectory",                        bus_append_directory                          },
2595
        { "LogsDirectory",                         bus_append_directory                          },
2596
        { "ProtectHostname",                       bus_append_protect_hostname                   },
2597
        { "ProtectHostnameEx",                     bus_append_protect_hostname                   }, /* compat */
2598
        { "PrivateTmp",                            bus_append_boolean_or_ex_string               },
2599
        { "PrivateTmpEx",                          bus_append_boolean_or_ex_string               }, /* compat */
2600
        { "ProtectControlGroups",                  bus_append_boolean_or_ex_string               },
2601
        { "ProtectControlGroupsEx",                bus_append_boolean_or_ex_string               }, /* compat */
2602
        { "PrivateUsers",                          bus_append_boolean_or_ex_string               },
2603
        { "PrivateUsersEx",                        bus_append_boolean_or_ex_string               }, /* compat */
2604
        { "StateDirectoryQuota",                   bus_append_quota_directory                    },
2605
        { "CacheDirectoryQuota",                   bus_append_quota_directory                    },
2606
        { "LogsDirectoryQuota",                    bus_append_quota_directory                    },
2607
        { "StateDirectoryAccounting",              bus_append_parse_boolean                      },
2608
        { "CacheDirectoryAccounting",              bus_append_parse_boolean                      },
2609
        { "LogsDirectoryAccounting",               bus_append_parse_boolean                      },
2610

2611
        { NULL, bus_try_append_resource_limit,     dump_resource_limits                          },
2612
        {}
2613
};
2614

2615
static const BusProperty kill_properties[] = {
2616
        { "KillMode",                              bus_append_string                             },
2617
        { "SendSIGHUP",                            bus_append_parse_boolean                      },
2618
        { "SendSIGKILL",                           bus_append_parse_boolean                      },
2619
        { "KillSignal",                            bus_append_signal_from_string                 },
2620
        { "RestartKillSignal",                     bus_append_signal_from_string                 },
2621
        { "FinalKillSignal",                       bus_append_signal_from_string                 },
2622
        { "WatchdogSignal",                        bus_append_signal_from_string                 },
2623
        {}
2624
};
2625

2626
static const BusProperty mount_properties[] = {
2627
        { "What",                                  bus_append_string                             },
2628
        { "Where",                                 bus_append_string                             },
2629
        { "Options",                               bus_append_string                             },
2630
        { "Type",                                  bus_append_string                             },
2631
        { "TimeoutSec",                            bus_append_parse_sec_rename                   },
2632
        { "DirectoryMode",                         bus_append_parse_mode                         },
2633
        { "SloppyOptions",                         bus_append_parse_boolean                      },
2634
        { "LazyUnmount",                           bus_append_parse_boolean                      },
2635
        { "ForceUnmount",                          bus_append_parse_boolean                      },
2636
        { "ReadwriteOnly",                         bus_append_parse_boolean                      },
2637
        {}
2638
};
2639

2640
static const BusProperty path_properties[] = {
2641
        { "MakeDirectory",                         bus_append_parse_boolean                      },
2642
        { "DirectoryMode",                         bus_append_parse_mode                         },
2643
        { "PathExists",                            bus_append_paths                              },
2644
        { "PathExistsGlob",                        bus_append_paths                              },
2645
        { "PathChanged",                           bus_append_paths                              },
2646
        { "PathModified",                          bus_append_paths                              },
2647
        { "DirectoryNotEmpty",                     bus_append_paths                              },
2648
        { "TriggerLimitBurst",                     bus_append_safe_atou                          },
2649
        { "PollLimitBurst",                        bus_append_safe_atou                          },
2650
        { "TriggerLimitIntervalSec",               bus_append_parse_sec_rename                   },
2651
        { "PollLimitIntervalSec",                  bus_append_parse_sec_rename                   },
2652
        {}
2653
};
2654

2655
static const BusProperty scope_properties[] = {
2656
        { "RuntimeMaxSec",                         bus_append_parse_sec_rename                   },
2657
        { "RuntimeRandomizedExtraSec",             bus_append_parse_sec_rename                   },
2658
        { "TimeoutStopSec",                        bus_append_parse_sec_rename                   },
2659
        { "OOMPolicy",                             bus_append_string                             },
2660

2661
        /* Scope units don't have execution context but we still want to allow setting these two,
2662
         * so let's handle them separately. */
2663
        { "User",                                  bus_append_string                             },
2664
        { "Group",                                 bus_append_string                             },
2665
        {}
2666
};
2667

2668
static const BusProperty service_properties[] = {
2669
        { "PIDFile",                               bus_append_string                             },
2670
        { "Type",                                  bus_append_string                             },
2671
        { "ExitType",                              bus_append_string                             },
2672
        { "Restart",                               bus_append_string                             },
2673
        { "RestartMode",                           bus_append_string                             },
2674
        { "BusName",                               bus_append_string                             },
2675
        { "NotifyAccess",                          bus_append_string                             },
2676
        { "USBFunctionDescriptors",                bus_append_string                             },
2677
        { "USBFunctionStrings",                    bus_append_string                             },
2678
        { "OOMPolicy",                             bus_append_string                             },
2679
        { "TimeoutStartFailureMode",               bus_append_string                             },
2680
        { "TimeoutStopFailureMode",                bus_append_string                             },
2681
        { "FileDescriptorStorePreserve",           bus_append_string                             },
2682
        { "PermissionsStartOnly",                  bus_append_parse_boolean                      },
2683
        { "RootDirectoryStartOnly",                bus_append_parse_boolean                      },
2684
        { "RemainAfterExit",                       bus_append_parse_boolean                      },
2685
        { "GuessMainPID",                          bus_append_parse_boolean                      },
2686
        { "RestartSec",                            bus_append_parse_sec_rename                   },
2687
        { "RestartMaxDelaySec",                    bus_append_parse_sec_rename                   },
2688
        { "TimeoutStartSec",                       bus_append_parse_sec_rename                   },
2689
        { "TimeoutStopSec",                        bus_append_parse_sec_rename                   },
2690
        { "TimeoutAbortSec",                       bus_append_parse_sec_rename                   },
2691
        { "RuntimeMaxSec",                         bus_append_parse_sec_rename                   },
2692
        { "RuntimeRandomizedExtraSec",             bus_append_parse_sec_rename                   },
2693
        { "WatchdogSec",                           bus_append_parse_sec_rename                   },
2694
        { "TimeoutSec",                            bus_append_timeout_sec                        },
2695
        { "FileDescriptorStoreMax",                bus_append_safe_atou                          },
2696
        { "RestartSteps",                          bus_append_safe_atou                          },
2697
        { "ExecCondition",                         bus_append_exec_command                       },
2698
        { "ExecConditionEx",                       bus_append_exec_command                       }, /* compat */
2699
        { "ExecStartPre",                          bus_append_exec_command                       },
2700
        { "ExecStartPreEx",                        bus_append_exec_command                       }, /* compat */
2701
        { "ExecStart",                             bus_append_exec_command                       },
2702
        { "ExecStartEx",                           bus_append_exec_command                       }, /* compat */
2703
        { "ExecStartPost",                         bus_append_exec_command                       },
2704
        { "ExecStartPostEx",                       bus_append_exec_command                       }, /* compat */
2705
        { "ExecReload",                            bus_append_exec_command                       },
2706
        { "ExecReloadEx",                          bus_append_exec_command                       }, /* compat */
2707
        { "ExecReloadPost",                        bus_append_exec_command                       },
2708
        { "ExecReloadPostEx",                      bus_append_exec_command                       }, /* compat */
2709
        { "ExecStop",                              bus_append_exec_command                       },
2710
        { "ExecStopEx",                            bus_append_exec_command                       }, /* compat */
2711
        { "ExecStopPost",                          bus_append_exec_command                       },
2712
        { "ExecStopPostEx",                        bus_append_exec_command                       }, /* compat */
2713
        { "RestartPreventExitStatus",              bus_append_exit_status                        },
2714
        { "RestartForceExitStatus",                bus_append_exit_status                        },
2715
        { "SuccessExitStatus",                     bus_append_exit_status                        },
2716
        { "OpenFile",                              bus_append_open_file                          },
2717
        { "ReloadSignal",                          bus_append_signal_from_string                 },
2718
        { "RefreshOnReload",                       bus_append_refresh_on_reload                  },
2719
        {}
2720
};
2721

2722
static const BusProperty socket_properties[] = {
2723
        { "Accept",                                bus_append_parse_boolean                      },
2724
        { "FlushPending",                          bus_append_parse_boolean                      },
2725
        { "Writable",                              bus_append_parse_boolean                      },
2726
        { "KeepAlive",                             bus_append_parse_boolean                      },
2727
        { "NoDelay",                               bus_append_parse_boolean                      },
2728
        { "FreeBind",                              bus_append_parse_boolean                      },
2729
        { "Transparent",                           bus_append_parse_boolean                      },
2730
        { "Broadcast",                             bus_append_parse_boolean                      },
2731
        { "PassCredentials",                       bus_append_parse_boolean                      },
2732
        { "PassFileDescriptorsToExec",             bus_append_parse_boolean                      },
2733
        { "PassSecurity",                          bus_append_parse_boolean                      },
2734
        { "PassPacketInfo",                        bus_append_parse_boolean                      },
2735
        { "ReusePort",                             bus_append_parse_boolean                      },
2736
        { "RemoveOnStop",                          bus_append_parse_boolean                      },
2737
        { "SELinuxContextFromNet",                 bus_append_parse_boolean                      },
2738
        { "Priority",                              bus_append_safe_atoi                          },
2739
        { "IPTTL",                                 bus_append_safe_atoi                          },
2740
        { "Mark",                                  bus_append_safe_atoi                          },
2741
        { "IPTOS",                                 bus_append_ip_tos_from_string                 },
2742
        { "Backlog",                               bus_append_safe_atou                          },
2743
        { "MaxConnections",                        bus_append_safe_atou                          },
2744
        { "MaxConnectionsPerSource",               bus_append_safe_atou                          },
2745
        { "KeepAliveProbes",                       bus_append_safe_atou                          },
2746
        { "TriggerLimitBurst",                     bus_append_safe_atou                          },
2747
        { "PollLimitBurst",                        bus_append_safe_atou                          },
2748
        { "SocketMode",                            bus_append_parse_mode                         },
2749
        { "DirectoryMode",                         bus_append_parse_mode                         },
2750
        { "MessageQueueMaxMessages",               bus_append_safe_atoi64                        },
2751
        { "MessageQueueMessageSize",               bus_append_safe_atoi64                        },
2752
        { "TimeoutSec",                            bus_append_parse_sec_rename                   },
2753
        { "KeepAliveTimeSec",                      bus_append_parse_sec_rename                   },
2754
        { "KeepAliveIntervalSec",                  bus_append_parse_sec_rename                   },
2755
        { "DeferAcceptSec",                        bus_append_parse_sec_rename                   },
2756
        { "TriggerLimitIntervalSec",               bus_append_parse_sec_rename                   },
2757
        { "PollLimitIntervalSec",                  bus_append_parse_sec_rename                   },
2758
        { "DeferTriggerMaxSec",                    bus_append_parse_sec_rename                   },
2759
        { "ReceiveBuffer",                         bus_append_parse_size                         },
2760
        { "SendBuffer",                            bus_append_parse_size                         },
2761
        { "PipeSize",                              bus_append_parse_size                         },
2762
        { "ExecStartPre",                          bus_append_exec_command                       },
2763
        { "ExecStartPost",                         bus_append_exec_command                       },
2764
        { "ExecReload",                            bus_append_exec_command                       },
2765
        { "ExecStopPost",                          bus_append_exec_command                       },
2766
        { "SmackLabel",                            bus_append_string                             },
2767
        { "SmackLabelIPIn",                        bus_append_string                             },
2768
        { "SmackLabelIPOut",                       bus_append_string                             },
2769
        { "TCPCongestion",                         bus_append_string                             },
2770
        { "BindToDevice",                          bus_append_string                             },
2771
        { "BindIPv6Only",                          bus_append_string                             },
2772
        { "FileDescriptorName",                    bus_append_string                             },
2773
        { "SocketUser",                            bus_append_string                             },
2774
        { "SocketGroup",                           bus_append_string                             },
2775
        { "Timestamping",                          bus_append_string                             },
2776
        { "DeferTrigger",                          bus_append_string                             },
2777
        { "Symlinks",                              bus_append_strv                               },
2778
        { "SocketProtocol",                        bus_append_parse_ip_protocol                  },
2779
        { "ListenStream",                          bus_append_listen                             },
2780
        { "ListenDatagram",                        bus_append_listen                             },
2781
        { "ListenSequentialPacket",                bus_append_listen                             },
2782
        { "ListenNetlink",                         bus_append_listen                             },
2783
        { "ListenSpecial",                         bus_append_listen                             },
2784
        { "ListenMessageQueue",                    bus_append_listen                             },
2785
        { "ListenFIFO",                            bus_append_listen                             },
2786
        { "ListenUSBFunction",                     bus_append_listen                             },
2787
        {}
2788
};
2789

2790
static const BusProperty timer_properties[] = {
2791
        { "WakeSystem",                            bus_append_parse_boolean                      },
2792
        { "RemainAfterElapse",                     bus_append_parse_boolean                      },
2793
        { "Persistent",                            bus_append_parse_boolean                      },
2794
        { "OnTimezoneChange",                      bus_append_parse_boolean                      },
2795
        { "OnClockChange",                         bus_append_parse_boolean                      },
2796
        { "FixedRandomDelay",                      bus_append_parse_boolean                      },
2797
        { "DeferReactivation",                     bus_append_parse_boolean                      },
2798
        { "AccuracySec",                           bus_append_parse_sec_rename                   },
2799
        { "RandomizedDelaySec",                    bus_append_parse_sec_rename                   },
2800
        { "RandomizedOffsetSec",                   bus_append_parse_sec_rename                   },
2801
        { "OnActiveSec",                           bus_append_timers_monotonic                   },
2802
        { "OnBootSec",                             bus_append_timers_monotonic                   },
2803
        { "OnStartupSec",                          bus_append_timers_monotonic                   },
2804
        { "OnUnitActiveSec",                       bus_append_timers_monotonic                   },
2805
        { "OnUnitInactiveSec",                     bus_append_timers_monotonic                   },
2806
        { "OnCalendar",                            bus_append_timers_calendar                    },
2807
        {}
2808
};
2809

2810
static const BusProperty unit_properties[] = {
2811
        { "Description",                           bus_append_string                             },
2812
        { "SourcePath",                            bus_append_string                             },
2813
        { "OnFailureJobMode",                      bus_append_string                             },
2814
        { "JobTimeoutAction",                      bus_append_string                             },
2815
        { "JobTimeoutRebootArgument",              bus_append_string                             },
2816
        { "StartLimitAction",                      bus_append_string                             },
2817
        { "FailureAction",                         bus_append_string                             },
2818
        { "SuccessAction",                         bus_append_string                             },
2819
        { "RebootArgument",                        bus_append_string                             },
2820
        { "CollectMode",                           bus_append_string                             },
2821
        { "StopWhenUnneeded",                      bus_append_parse_boolean                      },
2822
        { "RefuseManualStart",                     bus_append_parse_boolean                      },
2823
        { "RefuseManualStop",                      bus_append_parse_boolean                      },
2824
        { "AllowIsolate",                          bus_append_parse_boolean                      },
2825
        { "IgnoreOnIsolate",                       bus_append_parse_boolean                      },
2826
        { "SurviveFinalKillSignal",                bus_append_parse_boolean                      },
2827
        { "DefaultDependencies",                   bus_append_parse_boolean                      },
2828
        { "JobTimeoutSec",                         bus_append_parse_sec_rename                   },
2829
        { "JobRunningTimeoutSec",                  bus_append_parse_sec_rename                   },
2830
        { "StartLimitIntervalSec",                 bus_append_parse_sec_rename                   },
2831
        { "StartLimitBurst",                       bus_append_safe_atou                          },
2832
        { "SuccessActionExitStatus",               bus_append_action_exit_status                 },
2833
        { "FailureActionExitStatus",               bus_append_action_exit_status                 },
2834
        { "Documentation",                         bus_append_strv                               },
2835
        { "RequiresMountsFor",                     bus_append_strv                               },
2836
        { "WantsMountsFor",                        bus_append_strv                               },
2837
        { "Markers",                               bus_append_strv                               },
2838

2839
        { NULL, bus_try_append_unit_dependency,    unit_types_list                               },
2840
        { NULL, bus_try_append_condition,          dump_conditions                               },
2841
        {}
2842
};
2843

2844
static const BusProperty* service_unit_properties[] = {
2845
        cgroup_properties,
2846
        execute_properties,
2847
        kill_properties,
2848
        service_properties,
2849
        unit_properties,
2850
        NULL,
2851
};
2852

2853
static const BusProperty* socket_unit_properties[] = {
2854
        cgroup_properties,
2855
        execute_properties,
2856
        kill_properties,
2857
        socket_properties,
2858
        unit_properties,
2859
        NULL,
2860
};
2861

2862
static const BusProperty* timer_unit_properties[] = {
2863
        timer_properties,
2864
        unit_properties,
2865
        NULL,
2866
};
2867

2868
static const BusProperty* path_unit_properties[] = {
2869
        path_properties,
2870
        unit_properties,
2871
        NULL,
2872
};
2873

2874
static const BusProperty* slice_unit_properties[] = {
2875
        cgroup_properties,
2876
        unit_properties,
2877
        NULL,
2878
};
2879

2880
static const BusProperty* scope_unit_properties[] = {
2881
        cgroup_properties,
2882
        kill_properties,
2883
        scope_properties,
2884
        unit_properties,
2885
        NULL,
2886
};
2887

2888
static const BusProperty* mount_unit_properties[] = {
2889
        cgroup_properties,
2890
        execute_properties,
2891
        kill_properties,
2892
        mount_properties,
2893
        unit_properties,
2894
        NULL,
2895
};
2896

2897
static const BusProperty* automount_unit_properties[] = {
2898
        automount_properties,
2899
        unit_properties,
2900
        NULL,
2901
};
2902

2903
static const BusProperty* other_unit_properties[] = {
2904
        unit_properties,
2905
        NULL,
2906
};
2907

2908
static const BusProperty** unit_type_properties[_UNIT_TYPE_MAX] = {
2909
        [UNIT_SERVICE]   = service_unit_properties,
2910
        [UNIT_SOCKET]    = socket_unit_properties,
2911
        [UNIT_TIMER]     = timer_unit_properties,
2912
        [UNIT_PATH]      = path_unit_properties,
2913
        [UNIT_SLICE]     = slice_unit_properties,
2914
        [UNIT_SCOPE]     = scope_unit_properties,
2915
        [UNIT_MOUNT]     = mount_unit_properties,
2916
        [UNIT_AUTOMOUNT] = automount_unit_properties,
2917
        [UNIT_TARGET]    = other_unit_properties,
2918
        [UNIT_DEVICE]    = other_unit_properties,
2919
        [UNIT_SWAP]      = other_unit_properties,
2920
};
2921

2922
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
4,799✔
2923
        _cleanup_free_ char *field = NULL;
4,799✔
2924
        const char *eq;
4,799✔
2925
        int r;
4,799✔
2926

2927
        assert(m);
4,799✔
2928
        assert(assignment);
4,799✔
2929
        assert(t >= 0 && t < _UNIT_TYPE_MAX);
4,799✔
2930

2931
        eq = strchr(assignment, '=');
4,799✔
2932
        if (!eq)
4,799✔
2933
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2934
                                       "Not an assignment: %s", assignment);
2935

2936

2937
        field = strndup(assignment, eq - assignment);
4,797✔
2938
        if (!field)
4,797✔
UNCOV
2939
                return log_oom();
×
2940
        eq++;
4,797✔
2941

2942
        for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
9,816✔
2943
                for (const BusProperty *item = *tables; item->convert; item++)
642,860✔
2944
                        if (item->name) {
637,841✔
2945
                                if (streq(item->name, field))
633,110✔
2946
                                        return item->convert(m, field, eq);
4,614✔
2947
                        } else {
2948
                                /* If .name is not set, the function must be a "try" helper */
2949
                                r = item->convert(m, field, eq);
4,731✔
2950
                                if (r != 0)
4,731✔
2951
                                        return r;
2952
                        }
2953

UNCOV
2954
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2955
                               "Unknown assignment: %s", assignment);
2956
}
2957

2958
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char * const *l) {
1,614✔
2959
        int r;
1,614✔
2960

2961
        assert(m);
1,614✔
2962

2963
        STRV_FOREACH(i, l) {
5,502✔
2964
                r = bus_append_unit_property_assignment(m, t, *i);
3,897✔
2965
                if (r < 0)
3,897✔
2966
                        return r;
2967
        }
2968

2969
        return 0;
2970
}
2971

2972
void bus_dump_transient_settings(UnitType t) {
35✔
2973
        assert(t >= 0 && t < _UNIT_TYPE_MAX);
35✔
2974

2975
        for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
147✔
2976
                for (const BusProperty *item = *tables; item->convert; item++) {
5,295✔
2977
                        assert(item->name || item->dump);
5,183✔
2978

2979
                        /* Do not print deprecated names. All "Ex" variants are deprecated. */
2980
                        if (item->convert == warn_deprecated)
5,183✔
2981
                                continue;
240✔
2982
                        if (item->name && endswith(item->name, "Ex"))
4,943✔
2983
                                continue;
126✔
2984

2985
                        if (item->name)
4,817✔
2986
                                puts(item->name);
4,713✔
2987
                        else
2988
                                item->dump();
104✔
2989
                }
2990
}
35✔
2991

2992
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
561✔
2993
        assert(m);
561✔
2994

2995
        if (!pidref_is_set(pidref))
561✔
2996
                return -ESRCH;
2997

2998
        if (pidref->fd >= 0 && allow_pidfd)
561✔
2999
                return sd_bus_message_append(
561✔
3000
                                m, "(sv)",
3001
                                "PIDFDs", "ah", 1, pidref->fd);
3002

UNCOV
3003
        return sd_bus_message_append(
×
3004
                        m, "(sv)",
3005
                        "PIDs", "au", 1, pidref->pid);
3006
}
3007

3008
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
69✔
3009
        const char *type, *path, *source;
69✔
3010
        InstallChange *changes = NULL;
69✔
3011
        size_t n_changes = 0;
69✔
3012
        int r;
69✔
3013

3014
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
69✔
3015

3016
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
69✔
3017
        if (r < 0)
69✔
3018
                return bus_log_parse_error(r);
×
3019

3020
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
130✔
3021
                InstallChangeType t;
61✔
3022

3023
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
3024
                 * negative. */
3025
                t = install_change_type_from_string(type);
61✔
3026
                if (t < 0) {
61✔
UNCOV
3027
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
3028
                                         type, path);
UNCOV
3029
                        continue;
×
3030
                }
3031

3032
                r = install_changes_add(&changes, &n_changes, t, path, source);
61✔
3033
                if (r < 0)
61✔
3034
                        return r;
3035
        }
3036
        if (r < 0)
69✔
UNCOV
3037
                return bus_log_parse_error(r);
×
3038

3039
        r = sd_bus_message_exit_container(m);
69✔
3040
        if (r < 0)
69✔
3041
                return bus_log_parse_error(r);
×
3042

3043
        install_changes_dump(0, NULL, changes, n_changes, quiet);
69✔
3044

3045
        return 0;
3046
}
3047

3048
int unit_load_state(sd_bus *bus, const char *name, char **ret) {
4,886✔
3049
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3050
        _cleanup_free_ char *path = NULL;
4,886✔
3051
        int r;
4,886✔
3052

3053
        path = unit_dbus_path_from_name(name);
4,886✔
3054
        if (!path)
4,886✔
UNCOV
3055
                return log_oom();
×
3056

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

3060
        r = sd_bus_get_property_string(
4,886✔
3061
                        bus,
3062
                        "org.freedesktop.systemd1",
3063
                        path,
3064
                        "org.freedesktop.systemd1.Unit",
3065
                        "LoadState",
3066
                        &error,
3067
                        ret);
3068
        if (r < 0)
4,886✔
UNCOV
3069
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
3070

3071
        return 0;
3072
}
3073

3074
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
65,071✔
3075
        int r;
65,071✔
3076

3077
        /* First, order by machine */
3078
        r = strcasecmp_ptr(a->machine, b->machine);
65,071✔
3079
        if (r != 0)
65,071✔
3080
                return r;
3081

3082
        /* Second, order by unit type */
3083
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
65,071✔
3084
        if (r != 0)
65,071✔
3085
                return r;
3086

3087
        /* Third, order by name */
3088
        return strcasecmp(a->id, b->id);
62,727✔
3089
}
3090

3091
int bus_service_manager_reload(sd_bus *bus) {
95✔
3092
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3093
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
95✔
3094
        int r;
95✔
3095

3096
        assert(bus);
95✔
3097

3098
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
95✔
3099
        if (r < 0)
95✔
3100
                return bus_log_create_error(r);
×
3101

3102
        /* Reloading the daemon may take long, hence set a longer timeout here */
3103
        r = sd_bus_call(bus, m, DAEMON_RELOAD_TIMEOUT_SEC, &error, NULL);
95✔
3104
        if (r < 0)
95✔
3105
                return log_error_errno(r, "Failed to reload service manager: %s", bus_error_message(&error, r));
×
3106

3107
        return 0;
3108
}
3109

3110
typedef struct UnitFreezer {
3111
        char *name;
3112
        sd_bus *bus;
3113
} UnitFreezer;
3114

3115
/* Wait for 60 seconds at maximum for freezer operation */
3116
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3117

3118
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
3119
        if (!f)
×
3120
                return NULL;
3121

UNCOV
3122
        free(f->name);
×
UNCOV
3123
        sd_bus_flush_close_unref(f->bus);
×
3124

3125
        return mfree(f);
×
3126
}
3127

3128
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
UNCOV
3129
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
UNCOV
3130
        int r;
×
3131

3132
        assert(name);
×
UNCOV
3133
        assert(ret);
×
3134

UNCOV
3135
        f = new(UnitFreezer, 1);
×
3136
        if (!f)
×
3137
                return log_oom();
×
3138

UNCOV
3139
        *f = (UnitFreezer) {
×
3140
                .name = strdup(name),
×
3141
        };
UNCOV
3142
        if (!f->name)
×
UNCOV
3143
                return log_oom();
×
3144

UNCOV
3145
        r = bus_connect_system_systemd(&f->bus);
×
UNCOV
3146
        if (r < 0)
×
UNCOV
3147
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3148

UNCOV
3149
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3150

UNCOV
3151
        *ret = TAKE_PTR(f);
×
UNCOV
3152
        return 0;
×
3153
}
3154

UNCOV
3155
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
UNCOV
3156
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
UNCOV
3157
        int r;
×
3158

UNCOV
3159
        assert(f);
×
UNCOV
3160
        assert(f->name);
×
UNCOV
3161
        assert(f->bus);
×
3162

UNCOV
3163
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3164
                            freeze ? "FreezeUnit" : "ThawUnit",
3165
                            &error,
3166
                            /* ret_reply= */ NULL,
3167
                            "s",
3168
                            f->name);
UNCOV
3169
        if (r < 0) {
×
UNCOV
3170
                if (sd_bus_error_has_names(&error,
×
3171
                                           BUS_ERROR_NO_SUCH_UNIT,
3172
                                           BUS_ERROR_UNIT_INACTIVE,
3173
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3174

UNCOV
3175
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
UNCOV
3176
                        return 0;
×
3177
                }
3178

UNCOV
3179
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3180
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3181
        }
3182

UNCOV
3183
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3184
        return 1;
3185
}
3186

UNCOV
3187
int unit_freezer_freeze(UnitFreezer *f) {
×
UNCOV
3188
        return unit_freezer_action(f, true);
×
3189
}
3190

UNCOV
3191
int unit_freezer_thaw(UnitFreezer *f) {
×
UNCOV
3192
        return unit_freezer_action(f, false);
×
3193
}
3194

3195
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,700✔
3196
        if (isempty(s))
1,700✔
3197
                return 0;
3198

3199
        if (streq(s, "ro"))
74✔
3200
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3201

3202
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3203
}
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