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

systemd / systemd / 20766109442

06 Jan 2026 09:50PM UTC coverage: 72.714% (+0.3%) from 72.444%
20766109442

push

github

YHNdnzj
man: do not manually update man/rules/meson.build

Follow-up for 25393c7c9.

310283 of 426715 relevant lines covered (72.71%)

1142928.51 hits per line

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

74.2
/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) {
15,233✔
54
        assert(message);
15,233✔
55
        assert(u);
15,233✔
56

57
        u->machine = NULL;
15,233✔
58

59
        return sd_bus_message_read(
15,233✔
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) {
12✔
75
        log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq);
12✔
76
        return 1;
12✔
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);
590✔
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) {
895✔
154
        int r;
895✔
155

156
        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
895✔
157
        if (r < 0)
895✔
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, ExtractFlags flags) {
490✔
164
        int r;
490✔
165

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

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

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

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

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

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

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

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

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

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

207
        r = sd_bus_message_close_container(m);
490✔
208
        if (r < 0)
490✔
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, EXTRACT_UNQUOTE);
123✔
216
}
217

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

222
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
38✔
223
        int r;
38✔
224

225
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
38✔
226
        if (r < 0)
38✔
227
                return bus_log_create_error(r);
×
228

229
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
38✔
230
        if (r < 0)
38✔
231
                return bus_log_create_error(r);
×
232

233
        r = sd_bus_message_open_container(m, 'v', "ay");
38✔
234
        if (r < 0)
38✔
235
                return bus_log_create_error(r);
×
236

237
        r = sd_bus_message_append_array(m, 'y', buf, n);
38✔
238
        if (r < 0)
38✔
239
                return bus_log_create_error(r);
×
240

241
        r = sd_bus_message_close_container(m);
38✔
242
        if (r < 0)
38✔
243
                return bus_log_create_error(r);
×
244

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

249
        return 1;
250
}
251

252
static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
62✔
253
        char *n;
62✔
254
        usec_t t;
62✔
255
        size_t l;
62✔
256
        int r;
62✔
257

258
        r = parse_sec(eq, &t);
62✔
259
        if (r < 0)
62✔
260
                return parse_log_error(r, field, eq);
×
261

262
        l = strlen(field);
62✔
263
        n = newa(char, l + 2);
62✔
264
        /* Change suffix Sec → USec */
265
        strcpy(mempcpy(n, field, l - 3), "USec");
62✔
266

267
        r = sd_bus_message_append(m, "(sv)", n, "t", t);
62✔
268
        if (r < 0)
62✔
269
                return bus_log_create_error(r);
×
270

271
        return 1;
272
}
273

274
static int bus_append_parse_sec_rename_infinity(sd_bus_message *m, const char *field, const char *eq) {
4✔
275
        return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
8✔
276
}
277

278
static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq) {
23✔
279
        uint64_t v;
23✔
280
        int r;
23✔
281

282
        r = parse_size(eq, /* base= */ 1024, &v);
23✔
283
        if (r < 0)
23✔
284
                return parse_log_error(r, field, eq);
×
285

286
        r = sd_bus_message_append(m, "(sv)", field, "t", v);
23✔
287
        if (r < 0)
23✔
288
                return bus_log_create_error(r);
×
289

290
        return 1;
291
}
292

293
static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, const char *eq) {
6✔
294
        int r;
6✔
295

296
        r = parse_permyriad(eq);
6✔
297
        if (r < 0)
6✔
298
                return parse_log_error(r, field, eq);
1✔
299

300
        /* Pass around scaled to 2^32-1 == 100% */
301
        r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
10✔
302
        if (r < 0)
5✔
303
                return bus_log_create_error(r);
×
304

305
        return 1;
306
}
307

308
static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const char *eq) {
12✔
309
        _cleanup_(cpu_set_done) CPUSet cpuset = {};
×
310
        _cleanup_free_ uint8_t *array = NULL;
12✔
311
        size_t allocated;
12✔
312
        int r;
12✔
313

314
        r = parse_cpu_set(eq, &cpuset);
12✔
315
        if (r < 0)
12✔
316
                return parse_log_error(r, field, eq);
×
317

318
        r = cpu_set_to_dbus(&cpuset, &array, &allocated);
12✔
319
        if (r < 0)
12✔
320
                return log_error_errno(r, "Failed to serialize %s: %m", field);
×
321

322
        return bus_append_byte_array(m, field, array, allocated);
12✔
323
}
324

325
static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const char *eq) {
356✔
326
        int r;
356✔
327

328
        r = parse_boolean(eq);
356✔
329
        if (r < 0)
356✔
330
                return bus_append_strv(m, "DelegateControllers", eq);
9✔
331

332
        r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
347✔
333
        if (r < 0)
347✔
334
                return bus_log_create_error(r);
×
335

336
        return 1;
337
}
338

339
static int bus_append_parse_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
23✔
340
        int r;
23✔
341

342
        if (isempty(eq) || streq(eq, "infinity")) {
46✔
343
                uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX :
2✔
344
                        STR_IN_SET(field,
×
345
                                   "DefaultMemoryLow",
346
                                   "DefaultMemoryMin",
347
                                   "MemoryLow",
348
                                   "MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX;
×
349

350
                r = sd_bus_message_append(m, "(sv)", field, "t", x);
2✔
351
                if (r < 0)
2✔
352
                        return bus_log_create_error(r);
2✔
353

354
                return 1;
355
        }
356

357
        r = parse_permyriad(eq);
21✔
358
        if (r >= 0) {
21✔
359
                char *n;
×
360

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

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

370
                return 1;
371
        }
372

373
        if (streq(field, "TasksMax"))
21✔
374
                return bus_append_safe_atou64(m, field, eq);
3✔
375

376
        return bus_append_parse_size(m, field, eq);
18✔
377
}
378

379
static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, const char *eq) {
4✔
380
        uint64_t x;
4✔
381
        int r;
4✔
382

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

394
        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", x);
3✔
395
        if (r < 0)
3✔
396
                return bus_log_create_error(r);
×
397

398
        return 1;
399
}
400

401
static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, const char *eq) {
8✔
402
        int r;
8✔
403

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

410
                e = strchr(eq, ' ');
8✔
411
                if (e) {
8✔
412
                        path = _path = strndup(eq, e - eq);
8✔
413
                        if (!path)
8✔
414
                                return log_oom();
×
415

416
                        rwm = e + 1;
8✔
417
                }
418

419
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
8✔
420
        }
421
        if (r < 0)
8✔
422
                return bus_log_create_error(r);
×
423

424
        return 1;
425
}
426

427
static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) {
3,992✔
428
        int r;
3,992✔
429

430
        if (cgroup_io_limit_type_from_string(field) < 0)
3,992✔
431
                return 0;
432

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

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

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

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

459
        return 1;
460
}
461

462
static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *field, const char *eq) {
2✔
463
        int r;
2✔
464

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

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

477
                uint64_t u;
2✔
478
                r = safe_atou64(weight, &u);
2✔
479
                if (r < 0)
2✔
480
                        return parse_log_error(r, field, weight);
×
481

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

487
        return 1;
488
}
489

490
static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *field, const char *eq) {
2✔
491
        const char *field_usec = "IODeviceLatencyTargetUSec";
2✔
492
        int r;
2✔
493

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

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

506
                usec_t usec;
2✔
507
                r = parse_sec(target, &usec);
2✔
508
                if (r < 0)
2✔
509
                        return parse_log_error(r, field, target);
×
510

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

516
        return 1;
517
}
518

519
static int bus_append_bpf_program(sd_bus_message *m, const char *field, const char *eq) {
1✔
520
        int r;
1✔
521

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

527
                r = extract_first_word(&eq, &word, ":", 0);
1✔
528
                if (r < 0)
1✔
529
                        return parse_log_error(r, field, eq);
×
530

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

536
        return 1;
537
}
538

539
static int bus_append_socket_filter(sd_bus_message *m, const char *field, const char *eq) {
5✔
540
        int r;
5✔
541

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

548
                r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
5✔
549
                if (r < 0)
5✔
550
                        return parse_log_error(r, field, eq);
×
551

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

558
        return 1;
559
}
560

561
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
74✔
562
        bool explicit_path = false, done = false, ambient_hack = false;
74✔
563
        _cleanup_strv_free_ char **cmdline = NULL, **ex_opts = NULL;
74✔
564
        _cleanup_free_ char *_path = NULL;
74✔
565
        ExecCommandFlags flags = 0;
74✔
566
        int r;
108✔
567

568
        do {
108✔
569
                switch (*eq) {
108✔
570

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

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

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

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

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

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

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

635
                default:
636
                        done = true;
637
                }
638
        } while (!done);
108✔
639

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

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

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

668
        r = strv_split_full(&cmdline, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
74✔
669
        if (r < 0)
74✔
670
                return parse_log_error(r, field, eq);
×
671

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

678
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
74✔
679
        if (r < 0)
74✔
680
                return bus_log_create_error(r);
×
681

682
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
74✔
683
        if (r < 0)
74✔
684
                return bus_log_create_error(r);
×
685

686
        r = sd_bus_message_open_container(m, 'v', ex_prop ? "a(sasas)" : "a(sasb)");
125✔
687
        if (r < 0)
74✔
688
                return bus_log_create_error(r);
×
689

690
        r = sd_bus_message_open_container(m, 'a', ex_prop ? "(sasas)" : "(sasb)");
125✔
691
        if (r < 0)
74✔
692
                return bus_log_create_error(r);
×
693

694
        if (!strv_isempty(cmdline)) {
74✔
695
                r = sd_bus_message_open_container(m, 'r', ex_prop ? "sasas" : "sasb");
125✔
696
                if (r < 0)
74✔
697
                        return bus_log_create_error(r);
×
698

699
                r = sd_bus_message_append(m, "s", path ?: cmdline[0]);
74✔
700
                if (r < 0)
74✔
701
                        return bus_log_create_error(r);
×
702

703
                r = sd_bus_message_append_strv(m, cmdline);
74✔
704
                if (r < 0)
74✔
705
                        return bus_log_create_error(r);
×
706

707
                r = ex_prop ? sd_bus_message_append_strv(m, ex_opts) :
74✔
708
                              sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
51✔
709
                if (r < 0)
74✔
710
                        return bus_log_create_error(r);
×
711

712
                r = sd_bus_message_close_container(m);
74✔
713
                if (r < 0)
74✔
714
                        return bus_log_create_error(r);
×
715
        }
716

717
        r = sd_bus_message_close_container(m);
74✔
718
        if (r < 0)
74✔
719
                return bus_log_create_error(r);
×
720

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

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

729
        return 1;
730
}
731

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

736
        assert(m);
14✔
737

738
        r = open_file_parse(eq, &of);
14✔
739
        if (r < 0)
14✔
740
                return parse_log_error(r, field, eq);
1✔
741

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

746
        return 1;
747
}
748

749
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
5✔
750
        int r;
5✔
751

752
        assert(m);
5✔
753
        assert(prefix);
5✔
754

755
        r = sd_bus_message_open_container(m, 'r', "iayu");
5✔
756
        if (r < 0)
5✔
757
                return r;
758

759
        r = sd_bus_message_append(m, "i", family);
5✔
760
        if (r < 0)
5✔
761
                return r;
762

763
        r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
5✔
764
        if (r < 0)
5✔
765
                return r;
766

767
        r = sd_bus_message_append(m, "u", prefixlen);
5✔
768
        if (r < 0)
5✔
769
                return r;
770

771
        return sd_bus_message_close_container(m);
5✔
772
}
773

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

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

784
                return 1;
785
        }
786

787
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4✔
788
        if (r < 0)
4✔
789
                return bus_log_create_error(r);
×
790

791
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
4✔
792
        if (r < 0)
4✔
793
                return bus_log_create_error(r);
×
794

795
        r = sd_bus_message_open_container(m, 'v', "a(iayu)");
4✔
796
        if (r < 0)
4✔
797
                return bus_log_create_error(r);
×
798

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

803
        if (streq(eq, "any")) {
4✔
804
                /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
805

806
                r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
×
807
                if (r < 0)
×
808
                        return bus_log_create_error(r);
×
809

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

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

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

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

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

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

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

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

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

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

857
        } else
858
                for (;;) {
14✔
859
                        _cleanup_free_ char *word = NULL;
9✔
860

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

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

871
                        r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
5✔
872
                        if (r < 0)
5✔
873
                                return bus_log_create_error(r);
×
874
                }
875

876
        r = sd_bus_message_close_container(m);
4✔
877
        if (r < 0)
4✔
878
                return bus_log_create_error(r);
×
879

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

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

888
        return 1;
889
}
890

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

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

907
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
3✔
908
        int r;
3✔
909

910
        assert(m);
3✔
911
        assert(field);
3✔
912
        assert(eq);
3✔
913

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

919
                return 1;
920
        }
921

922
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
3✔
923
        if (r < 0)
3✔
924
                return bus_log_create_error(r);
×
925

926
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
3✔
927
        if (r < 0)
3✔
928
                return bus_log_create_error(r);
×
929

930
        r = sd_bus_message_open_container(m, 'v', "a(iiss)");
3✔
931
        if (r < 0)
3✔
932
                return bus_log_create_error(r);
×
933

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

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

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

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

956
                assert(source_str);
6✔
957
                assert(nfproto_str);
6✔
958
                assert(table);
6✔
959
                assert(set);
6✔
960

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

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

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

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

985
        r = sd_bus_message_close_container(m);
3✔
986
        if (r < 0)
3✔
987
                return bus_log_create_error(r);
×
988

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

993
        return 1;
994
}
995

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

1003
static int bus_append_set_credential(sd_bus_message *m, const char *field, const char *eq) {
95✔
1004
        int r;
95✔
1005

1006
        r = sd_bus_message_open_container(m, 'r', "sv");
95✔
1007
        if (r < 0)
95✔
1008
                return bus_log_create_error(r);
×
1009

1010
        r = sd_bus_message_append_basic(m, 's', field);
95✔
1011
        if (r < 0)
95✔
1012
                return bus_log_create_error(r);
×
1013

1014
        r = sd_bus_message_open_container(m, 'v', "a(say)");
95✔
1015
        if (r < 0)
95✔
1016
                return bus_log_create_error(r);
×
1017

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

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

1028
                r = sd_bus_message_open_container(m, 'a', "(say)");
94✔
1029
                if (r < 0)
94✔
1030
                        return bus_log_create_error(r);
×
1031

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

1036
                r = sd_bus_message_append(m, "s", word);
94✔
1037
                if (r < 0)
94✔
1038
                        return bus_log_create_error(r);
×
1039

1040
                if (endswith(field, "Encrypted")) {
94✔
1041
                        _cleanup_free_ void *decoded = NULL;
2✔
1042
                        size_t decoded_size;
2✔
1043

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

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

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

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

1062
                r = sd_bus_message_close_container(m);
94✔
1063
                if (r < 0)
94✔
1064
                        return bus_log_create_error(r);
×
1065

1066
                r = sd_bus_message_close_container(m);
94✔
1067
        }
1068
        if (r < 0)
95✔
1069
                return bus_log_create_error(r);
×
1070

1071
        r = sd_bus_message_close_container(m);
95✔
1072
        if (r < 0)
95✔
1073
                return bus_log_create_error(r);
×
1074

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

1079
        return 1;
1080
}
1081

1082
static int bus_append_load_credential(sd_bus_message *m, const char *field, const char *eq) {
24✔
1083
        int r;
24✔
1084

1085
        r = sd_bus_message_open_container(m, 'r', "sv");
24✔
1086
        if (r < 0)
24✔
1087
                return bus_log_create_error(r);
×
1088

1089
        r = sd_bus_message_append_basic(m, 's', field);
24✔
1090
        if (r < 0)
24✔
1091
                return bus_log_create_error(r);
×
1092

1093
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
24✔
1094
        if (r < 0)
24✔
1095
                return bus_log_create_error(r);
×
1096

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

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

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

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

1115
        r = sd_bus_message_close_container(m);
24✔
1116
        if (r < 0)
24✔
1117
                return bus_log_create_error(r);
×
1118

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

1123
        return 1;
1124
}
1125

1126
static int bus_append_import_credential(sd_bus_message *m, const char *field, const char *eq) {
19✔
1127
        int r;
19✔
1128

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

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

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

1147
                        r = sd_bus_message_append_basic(m, 's', "ImportCredentialEx");
7✔
1148
                        if (r < 0)
7✔
1149
                                return bus_log_create_error(r);
×
1150

1151
                        r = sd_bus_message_open_container(m, 'v', "a(ss)");
7✔
1152
                        if (r < 0)
7✔
1153
                                return bus_log_create_error(r);
×
1154

1155
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
7✔
1156
                        if (r < 0)
7✔
1157
                                return bus_log_create_error(r);
×
1158

1159
                        r = sd_bus_message_close_container(m);
7✔
1160
                        if (r < 0)
7✔
1161
                                return bus_log_create_error(r);
×
1162

1163
                        r = sd_bus_message_close_container(m);
7✔
1164
                }
1165
        }
1166
        if (r < 0)
19✔
1167
                return bus_log_create_error(r);
×
1168

1169
        return 1;
1170
}
1171

1172
static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) {
707✔
1173
        int r;
707✔
1174

1175
        r = sd_bus_message_open_container(m, 'r', "sv");
707✔
1176
        if (r < 0)
707✔
1177
                return bus_log_create_error(r);
×
1178

1179
        r = sd_bus_message_append_basic(m, 's', field);
707✔
1180
        if (r < 0)
707✔
1181
                return bus_log_create_error(r);
×
1182

1183
        r = sd_bus_message_open_container(m, 'v', "aay");
707✔
1184
        if (r < 0)
707✔
1185
                return bus_log_create_error(r);
×
1186

1187
        r = sd_bus_message_open_container(m, 'a', "ay");
707✔
1188
        if (r < 0)
707✔
1189
                return bus_log_create_error(r);
×
1190

1191
        r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
707✔
1192
        if (r < 0)
707✔
1193
                return bus_log_create_error(r);
×
1194

1195
        r = sd_bus_message_close_container(m);
707✔
1196
        if (r < 0)
707✔
1197
                return bus_log_create_error(r);
×
1198

1199
        r = sd_bus_message_close_container(m);
707✔
1200
        if (r < 0)
707✔
1201
                return bus_log_create_error(r);
×
1202

1203
        r = sd_bus_message_close_container(m);
707✔
1204
        if (r < 0)
707✔
1205
                return bus_log_create_error(r);
×
1206

1207
        return 1;
1208
}
1209

1210
static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) {
2✔
1211
        return bus_append_trivial_array(m, field, eq,
4✔
1212
                                        "a(bs)",
1213
                                        eq[0] != '~',
1214
                                        eq[0] != '~' ? eq : eq + 1);
1215
}
1216

1217
static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) {
146✔
1218
        const char *n, *appended;
146✔
1219
        int r;
146✔
1220

1221
        if ((n = startswith(eq, "fd:"))) {
146✔
1222
                appended = strjoina(field, "FileDescriptorName");
×
1223
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
×
1224
        } else if ((n = startswith(eq, "file:"))) {
146✔
1225
                appended = strjoina(field, "File");
475✔
1226
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
95✔
1227
        } else if ((n = startswith(eq, "append:"))) {
51✔
1228
                appended = strjoina(field, "FileToAppend");
10✔
1229
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
2✔
1230
        } else if ((n = startswith(eq, "truncate:"))) {
49✔
1231
                appended = strjoina(field, "FileToTruncate");
15✔
1232
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
3✔
1233
        } else
1234
                r = sd_bus_message_append(m, "(sv)", field, "s", eq);
46✔
1235
        if (r < 0)
146✔
1236
                return bus_log_create_error(r);
×
1237

1238
        return 1;
1239
}
1240

1241
static int bus_append_standard_input_text(sd_bus_message *m, const char *field, const char *eq) {
2✔
1242
        _cleanup_free_ char *unescaped = NULL;
2✔
1243
        ssize_t l;
2✔
1244

1245
        l = cunescape(eq, 0, &unescaped);
2✔
1246
        if (l < 0)
2✔
1247
                return log_error_errno(l, "Failed to unescape value for %s=: %s", field, eq);
×
1248

1249
        if (!strextend(&unescaped, "\n"))
2✔
1250
                return log_oom();
×
1251

1252
        /* Note that we don't expand specifiers here, but that should be OK, as this is a
1253
         * programmatic interface anyway */
1254

1255
        return bus_append_byte_array(m, field, unescaped, l + 1);
2✔
1256
}
1257

1258
static int bus_append_standard_input_data(sd_bus_message *m, const char *field, const char *eq) {
2✔
1259
        _cleanup_free_ void *decoded = NULL;
2✔
1260
        size_t sz;
2✔
1261
        int r;
2✔
1262

1263
        r = unbase64mem(eq, &decoded, &sz);
2✔
1264
        if (r < 0)
2✔
1265
                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1266

1267
        return bus_append_byte_array(m, field, decoded, sz);
2✔
1268
}
1269

1270
static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
517✔
1271
        int r;
517✔
1272

1273
        const char *suffix = startswith(field, "Limit");
517✔
1274
        if (!suffix)
517✔
1275
                return 0;
517✔
1276

1277
        int rl = rlimit_from_string(suffix);
42✔
1278
        if (rl < 0)
42✔
1279
                return 0;  /* We let the generic error machinery handle this. */
1280

1281
        struct rlimit l;
42✔
1282
        r = rlimit_parse(rl, eq, &l);
42✔
1283
        if (r < 0)
42✔
1284
                return parse_log_error(r, field, eq);
×
1285

1286
        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
42✔
1287
        if (r < 0)
42✔
1288
                return bus_log_create_error(r);
×
1289

1290
        const char *sn = strjoina(field, "Soft");
210✔
1291
        r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
42✔
1292
        if (r < 0)
42✔
1293
                return bus_log_create_error(r);
×
1294

1295
        return 1;
1296
}
1297

1298
static void dump_resource_limits(void) {
14✔
1299
        rlimits_list("Limit");
14✔
1300
}
14✔
1301

1302
static int bus_append_string_with_ignore(sd_bus_message *m, const char *field, const char *eq) {
4✔
1303
        int ignore = 0;
4✔
1304
        const char *s = eq;
4✔
1305
        int r;
4✔
1306

1307
        if (eq[0] == '-') {
4✔
1308
                ignore = 1;
×
1309
                s = eq + 1;
×
1310
        }
1311

1312
        r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
4✔
1313
        if (r < 0)
4✔
1314
                return bus_log_create_error(r);
×
1315

1316
        return 1;
1317
}
1318

1319
static int bus_append_capabilities(sd_bus_message *m, const char *field, const char *eq) {
10✔
1320
        uint64_t sum = 0;
10✔
1321
        bool invert = false;
10✔
1322
        const char *p = eq;
10✔
1323
        int r;
10✔
1324

1325
        if (*p == '~') {
10✔
1326
                invert = true;
3✔
1327
                p++;
3✔
1328
        }
1329

1330
        r = capability_set_from_string(p, &sum);
10✔
1331
        if (r < 0)
10✔
1332
                return parse_log_error(r, field, eq);
×
1333

1334
        sum = invert ? ~sum : sum;
10✔
1335

1336
        r = sd_bus_message_append(m, "(sv)", field, "t", sum);
10✔
1337
        if (r < 0)
10✔
1338
                return bus_log_create_error(r);
×
1339

1340
        return 1;
1341
}
1342

1343
static int bus_append_cpu_affinity(sd_bus_message *m, const char *field, const char *eq) {
4✔
1344
        int r;
4✔
1345

1346
        if (streq_ptr(eq, "numa")) {
4✔
1347
                r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1✔
1348
                if (r < 0)
1✔
1349
                        return bus_log_create_error(r);
×
1350
                return r;
1351
        }
1352

1353
        return bus_append_parse_cpu_set(m, field, eq);
3✔
1354
}
1355

1356
static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char *eq) {
8✔
1357
        _cleanup_(cpu_set_done) CPUSet nodes = {};
×
1358
        _cleanup_free_ uint8_t *array = NULL;
8✔
1359
        size_t allocated;
8✔
1360
        int r;
8✔
1361

1362
        if (eq && streq(eq, "all")) {
8✔
1363
                r = numa_mask_add_all(&nodes);
×
1364
                if (r < 0)
×
1365
                        return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
×
1366
        } else {
1367
                r = parse_cpu_set(eq, &nodes);
8✔
1368
                if (r < 0)
8✔
1369
                        return parse_log_error(r, field, eq);
×
1370
        }
1371

1372
        r = cpu_set_to_dbus(&nodes, &array, &allocated);
8✔
1373
        if (r < 0)
8✔
1374
                return log_error_errno(r, "Failed to serialize %s: %m", field);
×
1375

1376
        return bus_append_byte_array(m, field, array, allocated);
8✔
1377
}
1378

1379
static int bus_append_filter_list(sd_bus_message *m, const char *field, const char *eq) {
26✔
1380
        int allow_list = 1;
26✔
1381
        const char *p = eq;
26✔
1382
        int r;
26✔
1383

1384
        if (*p == '~') {
26✔
1385
                allow_list = 0;
12✔
1386
                p++;
12✔
1387
        }
1388

1389
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
26✔
1390
        if (r < 0)
26✔
1391
                return bus_log_create_error(r);
26✔
1392

1393
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
26✔
1394
        if (r < 0)
26✔
1395
                return bus_log_create_error(r);
×
1396

1397
        r = sd_bus_message_open_container(m, 'v', "(bas)");
26✔
1398
        if (r < 0)
26✔
1399
                return bus_log_create_error(r);
×
1400

1401
        r = sd_bus_message_open_container(m, 'r', "bas");
26✔
1402
        if (r < 0)
26✔
1403
                return bus_log_create_error(r);
×
1404

1405
        r = sd_bus_message_append_basic(m, 'b', &allow_list);
26✔
1406
        if (r < 0)
26✔
1407
                return bus_log_create_error(r);
×
1408

1409
        r = sd_bus_message_open_container(m, 'a', "s");
26✔
1410
        if (r < 0)
26✔
1411
                return bus_log_create_error(r);
×
1412

1413
        for (;;) {
98✔
1414
                _cleanup_free_ char *word = NULL;
36✔
1415

1416
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
62✔
1417
                if (r < 0)
62✔
1418
                        return parse_log_error(r, field, eq);
×
1419
                if (r == 0)
62✔
1420
                        break;
1421

1422
                r = sd_bus_message_append_basic(m, 's', word);
36✔
1423
                if (r < 0)
36✔
1424
                        return bus_log_create_error(r);
×
1425
        }
1426

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

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

1435
        r = sd_bus_message_close_container(m);
26✔
1436
        if (r < 0)
26✔
1437
                return bus_log_create_error(r);
×
1438

1439
        r = sd_bus_message_close_container(m);
26✔
1440
        if (r < 0)
26✔
1441
                return bus_log_create_error(r);
×
1442

1443
        return 1;
1444
}
1445

1446
static int bus_append_namespace_list(sd_bus_message *m, const char *field, const char *eq) {
25✔
1447
        bool invert = false;
25✔
1448
        unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
25✔
1449
        unsigned long flags;
25✔
1450
        int r;
25✔
1451

1452
        r = parse_boolean(eq);
25✔
1453
        if (r > 0)
25✔
1454
                /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1455
                 * namespaces which are retained), so RestrictNamespaces=true means we retain no
1456
                 * access to any namespaces and vice-versa. */
1457
                flags = streq(field, "RestrictNamespaces") ? 0 : all;
2✔
1458
        else if (r == 0)
23✔
1459
                flags = streq(field, "RestrictNamespaces") ? all : 0;
2✔
1460
        else {
1461
                if (eq[0] == '~') {
21✔
1462
                        invert = true;
2✔
1463
                        eq++;
2✔
1464
                }
1465

1466
                r = namespace_flags_from_string(eq, &flags);
21✔
1467
                if (r < 0)
21✔
1468
                        return parse_log_error(r, field, eq);
×
1469
        }
1470

1471
        if (invert)
25✔
1472
                flags = (~flags) & all;
2✔
1473

1474
        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
25✔
1475
        if (r < 0)
25✔
1476
                return bus_log_create_error(r);
×
1477

1478
        return 1;
1479
}
1480

1481
static int bus_append_bind_paths(sd_bus_message *m, const char *field, const char *eq) {
14✔
1482
        const char *p = eq;
14✔
1483
        int r;
14✔
1484

1485
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
14✔
1486
        if (r < 0)
14✔
1487
                return bus_log_create_error(r);
14✔
1488

1489
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
14✔
1490
        if (r < 0)
14✔
1491
                return bus_log_create_error(r);
×
1492

1493
        r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
14✔
1494
        if (r < 0)
14✔
1495
                return bus_log_create_error(r);
×
1496

1497
        r = sd_bus_message_open_container(m, 'a', "(ssbt)");
14✔
1498
        if (r < 0)
14✔
1499
                return bus_log_create_error(r);
×
1500

1501
        for (;;) {
58✔
1502
                _cleanup_free_ char *source = NULL, *destination = NULL;
22✔
1503
                char *s = NULL, *d = NULL;
36✔
1504
                bool ignore_enoent = false;
36✔
1505
                uint64_t flags = MS_REC;
36✔
1506

1507
                r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
36✔
1508
                if (r < 0)
36✔
1509
                        return parse_log_error(r, field, eq);
×
1510
                if (r == 0)
36✔
1511
                        break;
1512

1513
                s = source;
22✔
1514
                if (s[0] == '-') {
22✔
1515
                        ignore_enoent = true;
2✔
1516
                        s++;
2✔
1517
                }
1518

1519
                if (p && p[-1] == ':') {
22✔
1520
                        r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
14✔
1521
                        if (r < 0)
14✔
1522
                                return parse_log_error(r, field, p);
×
1523
                        if (r == 0)
14✔
1524
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1525
                                                       "Missing argument after ':': %s", eq);
1526

1527
                        d = destination;
14✔
1528

1529
                        if (p && p[-1] == ':') {
14✔
1530
                                _cleanup_free_ char *options = NULL;
8✔
1531

1532
                                r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
8✔
1533
                                if (r < 0)
8✔
1534
                                        return parse_log_error(r, field, p);
×
1535

1536
                                if (isempty(options) || streq(options, "rbind"))
20✔
1537
                                        flags = MS_REC;
1538
                                else if (streq(options, "norbind"))
4✔
1539
                                        flags = 0;
1540
                                else
1541
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1542
                                                               "Unknown options: %s", eq);
1543
                        }
1544
                } else
1545
                        d = s;
1546

1547
                r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
22✔
1548
                if (r < 0)
22✔
1549
                        return bus_log_create_error(r);
×
1550
        }
1551

1552
        r = sd_bus_message_close_container(m);
14✔
1553
        if (r < 0)
14✔
1554
                return bus_log_create_error(r);
×
1555

1556
        r = sd_bus_message_close_container(m);
14✔
1557
        if (r < 0)
14✔
1558
                return bus_log_create_error(r);
×
1559

1560
        r = sd_bus_message_close_container(m);
14✔
1561
        if (r < 0)
14✔
1562
                return bus_log_create_error(r);
×
1563

1564
        return 1;
1565
}
1566

1567
static int bus_append_temporary_file_system(sd_bus_message *m, const char *field, const char *eq) {
52✔
1568
        const char *p = eq;
52✔
1569
        int r;
52✔
1570

1571
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
52✔
1572
        if (r < 0)
52✔
1573
                return bus_log_create_error(r);
52✔
1574

1575
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
52✔
1576
        if (r < 0)
52✔
1577
                return bus_log_create_error(r);
×
1578

1579
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
52✔
1580
        if (r < 0)
52✔
1581
                return bus_log_create_error(r);
×
1582

1583
        r = sd_bus_message_open_container(m, 'a', "(ss)");
52✔
1584
        if (r < 0)
52✔
1585
                return bus_log_create_error(r);
×
1586

1587
        for (;;) {
162✔
1588
                _cleanup_free_ char *word = NULL, *path = NULL;
55✔
1589
                const char *w;
107✔
1590

1591
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
107✔
1592
                if (r < 0)
107✔
1593
                        return parse_log_error(r, field, eq);
×
1594
                if (r == 0)
107✔
1595
                        break;
1596

1597
                w = word;
55✔
1598
                r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
55✔
1599
                if (r <= 0)
55✔
1600
                        return parse_log_error(r, field, eq);
×
1601

1602
                r = sd_bus_message_append(m, "(ss)", path, w);
55✔
1603
                if (r < 0)
55✔
1604
                        return bus_log_create_error(r);
×
1605
        }
1606

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

1611
        r = sd_bus_message_close_container(m);
52✔
1612
        if (r < 0)
52✔
1613
                return bus_log_create_error(r);
×
1614

1615
        r = sd_bus_message_close_container(m);
52✔
1616
        if (r < 0)
52✔
1617
                return bus_log_create_error(r);
×
1618

1619
        return 1;
1620
}
1621

1622
static int bus_append_root_hash(sd_bus_message *m, const char *field, const char *eq) {
15✔
1623
        _cleanup_free_ void *roothash_decoded = NULL;
15✔
1624
        size_t roothash_decoded_size = 0;
15✔
1625
        int r;
15✔
1626

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

1631
        /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1632
        r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
13✔
1633
        if (r < 0)
13✔
1634
                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1635
        if (roothash_decoded_size < sizeof(sd_id128_t))
13✔
1636
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "%s value '%s' is too short.", field, eq);
×
1637

1638
        return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
13✔
1639
}
1640

1641
static int bus_append_root_hash_signature(sd_bus_message *m, const char *field, const char *eq) {
2✔
1642
        _cleanup_free_ void *roothash_sig_decoded = NULL;
2✔
1643
        size_t roothash_sig_decoded_size = 0;
2✔
1644
        int r;
2✔
1645

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

1650
        const char *value = startswith(eq, "base64:");
1✔
1651
        if (!value)
1✔
1652
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1653
                                       "Failed to decode %s value '%s': neither a path nor starts with 'base64:'.",
1654
                                       field, eq);
1655

1656
        /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1657
        r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
1✔
1658
        if (r < 0)
1✔
1659
                return log_error_errno(r, "Failed to decode base64 data for %s=: %m", field);
×
1660

1661
        return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
1✔
1662
}
1663

1664
static int bus_append_root_image_options(sd_bus_message *m, const char *field, const char *eq) {
4✔
1665
        _cleanup_strv_free_ char **l = NULL;
4✔
1666
        const char *p = eq;
4✔
1667
        int r;
4✔
1668

1669
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
4✔
1670
        if (r < 0)
4✔
1671
                return bus_log_create_error(r);
×
1672

1673
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
4✔
1674
        if (r < 0)
4✔
1675
                return bus_log_create_error(r);
×
1676

1677
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
4✔
1678
        if (r < 0)
4✔
1679
                return bus_log_create_error(r);
×
1680

1681
        r = sd_bus_message_open_container(m, 'a', "(ss)");
4✔
1682
        if (r < 0)
4✔
1683
                return bus_log_create_error(r);
×
1684

1685
        r = strv_split_colon_pairs(&l, p);
4✔
1686
        if (r < 0)
4✔
1687
                return parse_log_error(r, field, eq);
×
1688

1689
        STRV_FOREACH_PAIR(first, second, l) {
11✔
1690
                r = sd_bus_message_append(m, "(ss)",
21✔
1691
                                          !isempty(*second) ? *first : "root",
7✔
1692
                                          !isempty(*second) ? *second : *first);
7✔
1693
                if (r < 0)
7✔
1694
                        return bus_log_create_error(r);
×
1695
        }
1696

1697
        r = sd_bus_message_close_container(m);
4✔
1698
        if (r < 0)
4✔
1699
                return bus_log_create_error(r);
×
1700

1701
        r = sd_bus_message_close_container(m);
4✔
1702
        if (r < 0)
4✔
1703
                return bus_log_create_error(r);
×
1704

1705
        r = sd_bus_message_close_container(m);
4✔
1706
        if (r < 0)
4✔
1707
                return bus_log_create_error(r);
×
1708

1709
        return 1;
1710
}
1711

1712
static int bus_append_mount_images(sd_bus_message *m, const char *field, const char *eq) {
13✔
1713
        const char *p = eq;
13✔
1714
        int r;
13✔
1715

1716
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
13✔
1717
        if (r < 0)
13✔
1718
                return bus_log_create_error(r);
13✔
1719

1720
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
13✔
1721
        if (r < 0)
13✔
1722
                return bus_log_create_error(r);
×
1723

1724
        r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
13✔
1725
        if (r < 0)
13✔
1726
                return bus_log_create_error(r);
×
1727

1728
        r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
13✔
1729
        if (r < 0)
13✔
1730
                return bus_log_create_error(r);
×
1731

1732
        for (;;) {
33✔
1733
                _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
20✔
1734
                const char *q = NULL, *source = NULL;
33✔
1735
                bool permissive = false;
33✔
1736

1737
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
33✔
1738
                if (r < 0)
33✔
1739
                        return parse_log_error(r, field, eq);
×
1740
                if (r == 0)
33✔
1741
                        break;
1742

1743
                q = tuple;
20✔
1744
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
20✔
1745
                if (r < 0)
20✔
1746
                        return parse_log_error(r, field, eq);
×
1747
                if (r == 0)
20✔
1748
                        continue;
×
1749

1750
                source = first;
20✔
1751
                if (source[0] == '-') {
20✔
1752
                        permissive = true;
×
1753
                        source++;
×
1754
                }
1755

1756
                if (isempty(second))
20✔
1757
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1758
                                               "Missing argument after ':' for %s=: '%s'", field, eq);
1759

1760
                r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
20✔
1761
                if (r < 0)
20✔
1762
                        return bus_log_create_error(r);
×
1763

1764
                r = sd_bus_message_append(m, "ssb", source, second, permissive);
20✔
1765
                if (r < 0)
20✔
1766
                        return bus_log_create_error(r);
×
1767

1768
                r = sd_bus_message_open_container(m, 'a', "(ss)");
20✔
1769
                if (r < 0)
20✔
1770
                        return bus_log_create_error(r);
×
1771

1772
                for (;;) {
24✔
1773
                        _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2✔
1774

1775
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
22✔
1776
                        if (r < 0)
22✔
1777
                                return parse_log_error(r, field, eq);
×
1778
                        if (r == 0)
22✔
1779
                                break;
1780
                        /* Single set of options, applying to the root partition/single filesystem */
1781
                        if (r == 1) {
6✔
1782
                                r = sd_bus_message_append(m, "(ss)", "root", partition);
4✔
1783
                                if (r < 0)
4✔
1784
                                        return bus_log_create_error(r);
×
1785

1786
                                break;
1787
                        }
1788

1789
                        r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2✔
1790
                        if (r < 0)
2✔
1791
                                return bus_log_create_error(r);
×
1792
                }
1793

1794
                r = sd_bus_message_close_container(m);
20✔
1795
                if (r < 0)
20✔
1796
                        return bus_log_create_error(r);
×
1797

1798
                r = sd_bus_message_close_container(m);
20✔
1799
                if (r < 0)
20✔
1800
                        return bus_log_create_error(r);
×
1801
        }
1802

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

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

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

1815
        return 1;
1816
}
1817

1818
static int bus_append_extension_images(sd_bus_message *m, const char *field, const char *eq) {
27✔
1819
        const char *p = eq;
27✔
1820
        int r;
27✔
1821

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

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

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

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

1838
        for (;;) {
62✔
1839
                _cleanup_free_ char *source = NULL, *tuple = NULL;
35✔
1840
                const char *q = NULL, *s = NULL;
62✔
1841
                bool permissive = false;
62✔
1842

1843
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
62✔
1844
                if (r < 0)
62✔
1845
                        return parse_log_error(r, field, eq);
×
1846
                if (r == 0)
62✔
1847
                        break;
1848

1849
                q = tuple;
35✔
1850
                r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
35✔
1851
                if (r < 0)
35✔
1852
                        return parse_log_error(r, field, eq);
×
1853
                if (r == 0)
35✔
1854
                        continue;
×
1855

1856
                s = source;
35✔
1857
                if (s[0] == '-') {
35✔
1858
                        permissive = true;
2✔
1859
                        s++;
2✔
1860
                }
1861

1862
                r = sd_bus_message_open_container(m, 'r', "sba(ss)");
35✔
1863
                if (r < 0)
35✔
1864
                        return bus_log_create_error(r);
×
1865

1866
                r = sd_bus_message_append(m, "sb", s, permissive);
35✔
1867
                if (r < 0)
35✔
1868
                        return bus_log_create_error(r);
×
1869

1870
                r = sd_bus_message_open_container(m, 'a', "(ss)");
35✔
1871
                if (r < 0)
35✔
1872
                        return bus_log_create_error(r);
×
1873

1874
                for (;;) {
35✔
1875
                        _cleanup_free_ char *partition = NULL, *mount_options = NULL;
×
1876

1877
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
35✔
1878
                        if (r < 0)
35✔
1879
                                return parse_log_error(r, field, eq);
×
1880
                        if (r == 0)
35✔
1881
                                break;
1882
                        /* Single set of options, applying to the root partition/single filesystem */
1883
                        if (r == 1) {
1✔
1884
                                r = sd_bus_message_append(m, "(ss)", "root", partition);
1✔
1885
                                if (r < 0)
1✔
1886
                                        return bus_log_create_error(r);
×
1887

1888
                                break;
1889
                        }
1890

1891
                        r = sd_bus_message_append(m, "(ss)", partition, mount_options);
×
1892
                        if (r < 0)
×
1893
                                return bus_log_create_error(r);
×
1894
                }
1895

1896
                r = sd_bus_message_close_container(m);
35✔
1897
                if (r < 0)
35✔
1898
                        return bus_log_create_error(r);
×
1899

1900
                r = sd_bus_message_close_container(m);
35✔
1901
                if (r < 0)
35✔
1902
                        return bus_log_create_error(r);
×
1903
        }
1904

1905
        r = sd_bus_message_close_container(m);
27✔
1906
        if (r < 0)
27✔
1907
                return bus_log_create_error(r);
×
1908

1909
        r = sd_bus_message_close_container(m);
27✔
1910
        if (r < 0)
27✔
1911
                return bus_log_create_error(r);
×
1912

1913
        r = sd_bus_message_close_container(m);
27✔
1914
        if (r < 0)
27✔
1915
                return bus_log_create_error(r);
×
1916

1917
        return 1;
1918
}
1919

1920
static int bus_append_directory(sd_bus_message *m, const char *field, const char *eq) {
191✔
1921
        _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
191✔
1922
        const char *p = eq;
191✔
1923
        int r;
444✔
1924

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

1929
        for (;;) {
697✔
1930
                _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
253✔
1931

1932
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
444✔
1933
                if (r < 0)
444✔
1934
                        return parse_log_error(r, field, eq);
×
1935
                if (r == 0)
444✔
1936
                        break;
1937

1938
                const char *t = tuple;
253✔
1939
                r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
253✔
1940
                if (r <= 0)
253✔
1941
                        return parse_log_error(r, field, eq);
×
1942

1943
                path_simplify(source);
253✔
1944

1945
                if (isempty(dest) && isempty(flags)) {
290✔
1946
                        r = strv_consume(&sources, TAKE_PTR(source));
122✔
1947
                        if (r < 0)
122✔
1948
                                return bus_log_create_error(r);
×
1949
                } else if (isempty(flags)) {
131✔
1950
                        path_simplify(dest);
57✔
1951
                        r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
57✔
1952
                        if (r < 0)
57✔
1953
                                return log_oom();
×
1954
                } else {
1955
                        ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
74✔
1956
                        if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
74✔
1957
                                return log_error_errno(r, "Failed to parse flags for %s=: '%s'", field, flags);
×
1958

1959
                        if (!isempty(dest)) {
74✔
1960
                                path_simplify(dest);
37✔
1961
                                r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
37✔
1962
                        } else
1963
                                r = strv_consume(&sources_ro, TAKE_PTR(source));
37✔
1964
                        if (r < 0)
74✔
1965
                                return log_oom();
×
1966
                }
1967
        }
1968

1969
        if (!strv_isempty(sources)) {
191✔
1970
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
103✔
1971
                if (r < 0)
103✔
1972
                        return bus_log_create_error(r);
×
1973

1974
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
103✔
1975
                if (r < 0)
103✔
1976
                        return bus_log_create_error(r);
×
1977

1978
                r = sd_bus_message_open_container(m, 'v', "as");
103✔
1979
                if (r < 0)
103✔
1980
                        return bus_log_create_error(r);
×
1981

1982
                r = sd_bus_message_append_strv(m, sources);
103✔
1983
                if (r < 0)
103✔
1984
                        return bus_log_create_error(r);
×
1985

1986
                r = sd_bus_message_close_container(m);
103✔
1987
                if (r < 0)
103✔
1988
                        return bus_log_create_error(r);
×
1989

1990
                r = sd_bus_message_close_container(m);
103✔
1991
                if (r < 0)
103✔
1992
                        return bus_log_create_error(r);
×
1993
        }
1994

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

2001
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
83✔
2002
                if (r < 0)
83✔
2003
                        return bus_log_create_error(r);
×
2004

2005
                if (streq(field, "StateDirectory"))
83✔
2006
                        symlink_field = "StateDirectorySymlink";
2007
                else if (streq(field, "RuntimeDirectory"))
62✔
2008
                        symlink_field = "RuntimeDirectorySymlink";
2009
                else if (streq(field, "CacheDirectory"))
38✔
2010
                        symlink_field = "CacheDirectorySymlink";
2011
                else if (streq(field, "LogsDirectory"))
19✔
2012
                        symlink_field = "LogsDirectorySymlink";
2013
                else
2014
                        assert_not_reached();
×
2015

2016
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
83✔
2017
                if (r < 0)
83✔
2018
                        return bus_log_create_error(r);
×
2019

2020
                r = sd_bus_message_open_container(m, 'v', "a(sst)");
83✔
2021
                if (r < 0)
83✔
2022
                        return bus_log_create_error(r);
×
2023

2024
                r = sd_bus_message_open_container(m, 'a', "(sst)");
83✔
2025
                if (r < 0)
83✔
2026
                        return bus_log_create_error(r);
×
2027

2028
                STRV_FOREACH_PAIR(source, destination, symlinks) {
140✔
2029
                        r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
57✔
2030
                        if (r < 0)
57✔
2031
                                return bus_log_create_error(r);
×
2032
                }
2033

2034
                STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
120✔
2035
                        r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2036
                        if (r < 0)
37✔
2037
                                return bus_log_create_error(r);
×
2038
                }
2039

2040
                STRV_FOREACH(source, sources_ro) {
120✔
2041
                        r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2042
                        if (r < 0)
37✔
2043
                                return bus_log_create_error(r);
×
2044
                }
2045

2046
                r = sd_bus_message_close_container(m);
83✔
2047
                if (r < 0)
83✔
2048
                        return bus_log_create_error(r);
×
2049

2050
                r = sd_bus_message_close_container(m);
83✔
2051
                if (r < 0)
83✔
2052
                        return bus_log_create_error(r);
×
2053

2054
                r = sd_bus_message_close_container(m);
83✔
2055
                if (r < 0)
83✔
2056
                        return bus_log_create_error(r);
×
2057
        }
2058

2059
        return 1;
2060
}
2061

2062
static int bus_append_quota_directory(sd_bus_message *m, const char *field, const char *eq) {
×
2063
        uint64_t quota_absolute = UINT64_MAX;
×
2064
        uint32_t quota_scale = UINT32_MAX;
×
2065
        int quota_enforce = false;
×
2066
        int r;
×
2067

2068
        if (!isempty(eq) && !streq(eq, "off")) {
×
2069
                r = parse_permyriad(eq);
×
2070
                if (r < 0) {
×
2071
                        r = parse_size(eq, 1024, &quota_absolute);
×
2072
                        if (r < 0)
×
2073
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
×
2074
                } else
2075
                        quota_scale = UINT32_SCALE_FROM_PERMYRIAD(r);
×
2076

2077
                quota_enforce = true;
2078
        }
2079

2080
        r = sd_bus_message_append(m, "(sv)", field, "(tus)", quota_absolute, quota_scale, yes_no(quota_enforce));
×
2081
        if (r < 0)
×
2082
                return bus_log_create_error(r);
×
2083

2084
        return 1;
2085
}
2086

2087
static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) {
35✔
2088
        int r;
35✔
2089

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

2093
        r = parse_boolean(eq);
35✔
2094
        if (r >= 0)
35✔
2095
                r = sd_bus_message_append(m, "(sv)", "ProtectHostname", "b", r);
9✔
2096
        else {
2097
                const char *colon = strchr(eq, ':');
26✔
2098
                if (colon) {
26✔
2099
                        if (isempty(colon + 1))
19✔
2100
                                return parse_log_error(0, field, eq);
35✔
2101

2102
                        _cleanup_free_ char *p = strndup(eq, colon - eq);
17✔
2103
                        if (!p)
17✔
2104
                                return -ENOMEM;
×
2105

2106
                        r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", p, colon + 1);
17✔
2107
                } else
2108
                        r = sd_bus_message_append(m, "(sv)", "ProtectHostnameEx", "(ss)", eq, NULL);
7✔
2109
        }
2110
        if (r < 0)
33✔
2111
                return bus_log_create_error(r);
×
2112

2113
        return 1;
2114
}
2115

2116
static int bus_append_boolean_or_ex_string(sd_bus_message *m, const char *field, const char *eq) {
85✔
2117
        int r;
85✔
2118

2119
        r = parse_boolean(eq);
85✔
2120
        if (r >= 0) {
85✔
2121
                if (endswith(field, "Ex"))
45✔
2122
                        field = strndupa_safe(field, strlen(field) - 2);
15✔
2123

2124
                r = sd_bus_message_append(m, "(sv)", field, "b", r);
45✔
2125
        } else {
2126
                if (!endswith(field, "Ex"))
40✔
2127
                        field = strjoina(field, "Ex");
10✔
2128

2129
                /* We allow any string through and let the server perform the verification. */
2130
                r = sd_bus_message_append(m, "(sv)", field, "s", eq);
40✔
2131
        }
2132
        if (r < 0)
85✔
2133
                return bus_log_create_error(r);
×
2134

2135
        return 1;
2136
}
2137

2138
static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) {
10✔
2139
        return bus_append_trivial_array(m, "Paths", eq,
20✔
2140
                                        "a(ss)", field, eq);
2141
}
2142

2143
static int bus_append_exit_status(sd_bus_message *m, const char *field, const char *eq) {
9✔
2144
        _cleanup_free_ int *status = NULL, *signal = NULL;
9✔
2145
        size_t n_status = 0, n_signal = 0;
9✔
2146
        int r;
9✔
2147

2148
        for (const char *p = eq;;) {
9✔
2149
                _cleanup_free_ char *word = NULL;
21✔
2150

2151
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
30✔
2152
                if (r < 0)
30✔
2153
                        return parse_log_error(r, field, eq);
×
2154
                if (r == 0)
30✔
2155
                        break;
2156

2157
                /* We need to call exit_status_from_string() first, because we want
2158
                 * to parse numbers as exit statuses, not signals. */
2159

2160
                r = exit_status_from_string(word);
21✔
2161
                if (r >= 0) {
21✔
2162
                        assert(r >= 0 && r < 256);
13✔
2163

2164
                        if (!GREEDY_REALLOC(status, n_status + 1))
13✔
2165
                                return log_oom();
×
2166

2167
                        status[n_status++] = r;
13✔
2168

2169
                } else if ((r = signal_from_string(word)) >= 0) {
8✔
2170
                        if (!GREEDY_REALLOC(signal, n_signal + 1))
8✔
2171
                                return log_oom();
×
2172

2173
                        signal[n_signal++] = r;
8✔
2174

2175
                } else
2176
                        /* original r from exit_status_to_string() */
2177
                        return parse_log_error(r, field, word);
×
2178
        }
2179

2180
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
9✔
2181
        if (r < 0)
9✔
2182
                return bus_log_create_error(r);
×
2183

2184
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
9✔
2185
        if (r < 0)
9✔
2186
                return bus_log_create_error(r);
×
2187

2188
        r = sd_bus_message_open_container(m, 'v', "(aiai)");
9✔
2189
        if (r < 0)
9✔
2190
                return bus_log_create_error(r);
×
2191

2192
        r = sd_bus_message_open_container(m, 'r', "aiai");
9✔
2193
        if (r < 0)
9✔
2194
                return bus_log_create_error(r);
×
2195

2196
        r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
9✔
2197
        if (r < 0)
9✔
2198
                return bus_log_create_error(r);
×
2199

2200
        r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
9✔
2201
        if (r < 0)
9✔
2202
                return bus_log_create_error(r);
×
2203

2204
        r = sd_bus_message_close_container(m);
9✔
2205
        if (r < 0)
9✔
2206
                return bus_log_create_error(r);
×
2207

2208
        r = sd_bus_message_close_container(m);
9✔
2209
        if (r < 0)
9✔
2210
                return bus_log_create_error(r);
×
2211

2212
        r = sd_bus_message_close_container(m);
9✔
2213
        if (r < 0)
9✔
2214
                return bus_log_create_error(r);
×
2215

2216
        return 1;
2217
}
2218

2219
static int bus_append_action_exit_status(sd_bus_message *m, const char *field, const char *eq) {
4✔
2220
        int r;
4✔
2221

2222
        if (isempty(eq))
4✔
2223
                r = sd_bus_message_append(m, "(sv)", field, "i", -1);
2✔
2224
        else {
2225
                uint8_t u;
2✔
2226

2227
                r = safe_atou8(eq, &u);
2✔
2228
                if (r < 0)
2✔
2229
                        return parse_log_error(r, field, eq);
×
2230

2231
                r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
2✔
2232
        }
2233
        if (r < 0)
4✔
2234
                return bus_log_create_error(r);
×
2235

2236
        return 1;
2237
}
2238

2239
static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) {
23✔
2240
        const char *p = ASSERT_PTR(startswith(field, "Listen"));
23✔
2241

2242
        return bus_append_trivial_array(m, "Listen", eq,
46✔
2243
                                        "a(ss)", p, eq);
2244
}
2245

2246
static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, const char *eq) {
27✔
2247
        int r;
27✔
2248

2249
        if (isempty(eq))
27✔
2250
                r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
5✔
2251
        else {
2252
                usec_t t;
22✔
2253
                r = parse_sec(eq, &t);
22✔
2254
                if (r < 0)
22✔
2255
                        return parse_log_error(r, field, eq);
5✔
2256

2257
                r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
17✔
2258
        }
2259
        if (r < 0)
22✔
2260
                return bus_log_create_error(r);
×
2261

2262
        return 1;
2263
}
2264

2265
static int bus_append_timers_calendar(sd_bus_message *m, const char *field, const char *eq) {
6✔
2266
        return bus_append_trivial_array(m, "TimersCalendar", eq,
12✔
2267
                                        "a(ss)", field, eq);
2268
}
2269

2270
static int bus_append_timeout_sec(sd_bus_message *m, const char *field, const char *eq) {
1✔
2271
        int r;
1✔
2272

2273
        r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
1✔
2274
        if (r < 0)
1✔
2275
                return r;
2276

2277
        return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
1✔
2278
}
2279

2280
static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) {
74✔
2281
        ConditionType t = condition_type_from_string(field);
74✔
2282
        bool is_condition = t >= 0;
74✔
2283

2284
        if (!is_condition) {
74✔
2285
                t = assert_type_from_string(field);
36✔
2286
                if (t < 0)
36✔
2287
                        return 0;
2288
        }
2289

2290
        const char *p = eq;
74✔
2291

2292
        int trigger = p && *p == '|';
74✔
2293
        if (trigger)
74✔
2294
                p++;
69✔
2295

2296
        int negate = p && *p == '!';
74✔
2297
        if (negate)
3✔
2298
                p++;
3✔
2299

2300
        return bus_append_trivial_array(m,
184✔
2301
                                        is_condition ? "Conditions" : "Asserts",
2302
                                        eq,
2303
                                        "a(sbbs)",
2304
                                        field, trigger, negate, p);
2305
}
2306

2307
static void dump_conditions(void) {
35✔
2308
        condition_types_list();
35✔
2309
        assert_types_list();
35✔
2310
}
35✔
2311

2312
static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) {
125✔
2313
        if (unit_dependency_from_string(field) < 0)
125✔
2314
                return 0;
2315

2316
        return bus_append_strv(m, field, eq);
51✔
2317
}
2318

2319
typedef struct BusProperty {
2320
        const char *name;
2321
        int (*convert)(sd_bus_message *m, const char *field, const char *eq);
2322
        void (*dump)(void);
2323
} BusProperty;
2324

2325
static const BusProperty cgroup_properties[] = {
2326
        { "DevicePolicy",                          bus_append_string                             },
2327
        { "Slice",                                 bus_append_string                             },
2328
        { "ManagedOOMSwap",                        bus_append_string                             },
2329
        { "ManagedOOMMemoryPressure",              bus_append_string                             },
2330
        { "ManagedOOMPreference",                  bus_append_string                             },
2331
        { "MemoryPressureWatch",                   bus_append_string                             },
2332
        { "DelegateSubgroup",                      bus_append_string                             },
2333
        { "ManagedOOMMemoryPressureLimit",         bus_append_parse_permyriad                    },
2334
        { "MemoryAccounting",                      bus_append_parse_boolean                      },
2335
        { "MemoryZSwapWriteback",                  bus_append_parse_boolean                      },
2336
        { "IOAccounting",                          bus_append_parse_boolean                      },
2337
        { "TasksAccounting",                       bus_append_parse_boolean                      },
2338
        { "IPAccounting",                          bus_append_parse_boolean                      },
2339
        { "CoredumpReceive",                       bus_append_parse_boolean                      },
2340
        { "CPUWeight",                             bus_append_cg_cpu_weight_parse                },
2341
        { "StartupCPUWeight",                      bus_append_cg_cpu_weight_parse                },
2342
        { "IOWeight",                              bus_append_cg_weight_parse                    },
2343
        { "StartupIOWeight",                       bus_append_cg_weight_parse                    },
2344
        { "AllowedCPUs",                           bus_append_parse_cpu_set                      },
2345
        { "StartupAllowedCPUs",                    bus_append_parse_cpu_set                      },
2346
        { "AllowedMemoryNodes",                    bus_append_parse_cpu_set                      },
2347
        { "StartupAllowedMemoryNodes",             bus_append_parse_cpu_set                      },
2348
        { "DisableControllers",                    bus_append_strv                               },
2349
        { "Delegate",                              bus_append_parse_delegate                     },
2350
        { "MemoryMin",                             bus_append_parse_resource_limit               },
2351
        { "DefaultMemoryLow",                      bus_append_parse_resource_limit               },
2352
        { "DefaultMemoryMin",                      bus_append_parse_resource_limit               },
2353
        { "MemoryLow",                             bus_append_parse_resource_limit               },
2354
        { "MemoryHigh",                            bus_append_parse_resource_limit               },
2355
        { "MemoryMax",                             bus_append_parse_resource_limit               },
2356
        { "MemorySwapMax",                         bus_append_parse_resource_limit               },
2357
        { "MemoryZSwapMax",                        bus_append_parse_resource_limit               },
2358
        { "TasksMax",                              bus_append_parse_resource_limit               },
2359
        { "CPUQuota",                              bus_append_parse_cpu_quota                    },
2360
        { "CPUQuotaPeriodSec",                     bus_append_parse_sec_rename_infinity          },
2361
        { "DeviceAllow",                           bus_append_parse_device_allow                 },
2362
        { "IODeviceWeight",                        bus_append_parse_io_device_weight             },
2363
        { "IODeviceLatencyTargetSec",              bus_append_parse_io_device_latency            },
2364
        { "IPAddressAllow",                        bus_append_parse_ip_address_filter            },
2365
        { "IPAddressDeny",                         bus_append_parse_ip_address_filter            },
2366
        { "IPIngressFilterPath",                   bus_append_ip_filter_path                     },
2367
        { "IPEgressFilterPath",                    bus_append_ip_filter_path                     },
2368
        { "BPFProgram",                            bus_append_bpf_program                        },
2369
        { "SocketBindAllow",                       bus_append_socket_filter                      },
2370
        { "SocketBindDeny",                        bus_append_socket_filter                      },
2371
        { "MemoryPressureThresholdSec",            bus_append_parse_sec_rename                   },
2372
        { "NFTSet",                                bus_append_nft_set                            },
2373
        { "BindNetworkInterface",                  bus_append_string                             },
2374

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

2379
        { "MemoryLimit",                           warn_deprecated                               },
2380
        { "CPUShares",                             warn_deprecated                               },
2381
        { "StartupCPUShares",                      warn_deprecated                               },
2382
        { "BlockIOAccounting",                     warn_deprecated                               },
2383
        { "BlockIOWeight",                         warn_deprecated                               },
2384
        { "StartupBlockIOWeight",                  warn_deprecated                               },
2385
        { "BlockIODeviceWeight",                   warn_deprecated                               },
2386
        { "BlockIOReadBandwidth",                  warn_deprecated                               },
2387
        { "BlockIOWriteBandwidth",                 warn_deprecated                               },
2388
        { "CPUAccounting",                         warn_deprecated                               },
2389

2390
        { NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list                      },
2391
        {}
2392
};
2393

2394
static const BusProperty automount_properties[] = {
2395
        { "Where",                                 bus_append_string                             },
2396
        { "ExtraOptions",                          bus_append_string                             },
2397
        { "DirectoryMode",                         bus_append_parse_mode                         },
2398
        { "TimeoutIdleSec",                        bus_append_parse_sec_rename                   },
2399
        {}
2400
};
2401

2402
static const BusProperty execute_properties[] = {
2403
        { "User",                                  bus_append_string                             },
2404
        { "Group",                                 bus_append_string                             },
2405
        { "UtmpIdentifier",                        bus_append_string                             },
2406
        { "UtmpMode",                              bus_append_string                             },
2407
        { "PAMName",                               bus_append_string                             },
2408
        { "TTYPath",                               bus_append_string                             },
2409
        { "WorkingDirectory",                      bus_append_string                             },
2410
        { "RootDirectory",                         bus_append_string                             },
2411
        { "SyslogIdentifier",                      bus_append_string                             },
2412
        { "ProtectSystem",                         bus_append_string                             },
2413
        { "ProtectHome",                           bus_append_string                             },
2414
        { "SELinuxContext",                        bus_append_string                             },
2415
        { "RootImage",                             bus_append_string                             },
2416
        { "RootVerity",                            bus_append_string                             },
2417
        { "RuntimeDirectoryPreserve",              bus_append_string                             },
2418
        { "Personality",                           bus_append_string                             },
2419
        { "KeyringMode",                           bus_append_string                             },
2420
        { "ProtectProc",                           bus_append_string                             },
2421
        { "ProcSubset",                            bus_append_string                             },
2422
        { "NetworkNamespacePath",                  bus_append_string                             },
2423
        { "UserNamespacePath",                     bus_append_string                             },
2424
        { "IPCNamespacePath",                      bus_append_string                             },
2425
        { "LogNamespace",                          bus_append_string                             },
2426
        { "RootImagePolicy",                       bus_append_string                             },
2427
        { "MountImagePolicy",                      bus_append_string                             },
2428
        { "ExtensionImagePolicy",                  bus_append_string                             },
2429
        { "PrivatePIDs",                           bus_append_string                             },
2430
        { "PrivateBPF",                            bus_append_string                             },
2431
        { "BPFDelegateCommands",                   bus_append_string                             },
2432
        { "BPFDelegateMaps",                       bus_append_string                             },
2433
        { "BPFDelegatePrograms",                   bus_append_string                             },
2434
        { "BPFDelegateAttachments",                bus_append_string                             },
2435
        { "IgnoreSIGPIPE",                         bus_append_parse_boolean                      },
2436
        { "TTYVHangup",                            bus_append_parse_boolean                      },
2437
        { "TTYReset",                              bus_append_parse_boolean                      },
2438
        { "TTYVTDisallocate",                      bus_append_parse_boolean                      },
2439
        { "PrivateDevices",                        bus_append_parse_boolean                      },
2440
        { "PrivateNetwork",                        bus_append_parse_boolean                      },
2441
        { "PrivateMounts",                         bus_append_parse_boolean                      },
2442
        { "PrivateIPC",                            bus_append_parse_boolean                      },
2443
        { "NoNewPrivileges",                       bus_append_parse_boolean                      },
2444
        { "SyslogLevelPrefix",                     bus_append_parse_boolean                      },
2445
        { "MemoryDenyWriteExecute",                bus_append_parse_boolean                      },
2446
        { "RestrictRealtime",                      bus_append_parse_boolean                      },
2447
        { "DynamicUser",                           bus_append_parse_boolean                      },
2448
        { "RemoveIPC",                             bus_append_parse_boolean                      },
2449
        { "ProtectKernelTunables",                 bus_append_parse_boolean                      },
2450
        { "ProtectKernelModules",                  bus_append_parse_boolean                      },
2451
        { "ProtectKernelLogs",                     bus_append_parse_boolean                      },
2452
        { "ProtectClock",                          bus_append_parse_boolean                      },
2453
        { "MountAPIVFS",                           bus_append_parse_boolean                      },
2454
        { "BindLogSockets",                        bus_append_parse_boolean                      },
2455
        { "CPUSchedulingResetOnFork",              bus_append_parse_boolean                      },
2456
        { "LockPersonality",                       bus_append_parse_boolean                      },
2457
        { "MemoryKSM",                             bus_append_parse_boolean                      },
2458
        { "RestrictSUIDSGID",                      bus_append_parse_boolean                      },
2459
        { "RootEphemeral",                         bus_append_parse_boolean                      },
2460
        { "SetLoginEnvironment",                   bus_append_parse_boolean                      },
2461
        { "ReadWriteDirectories",                  bus_append_strv                               },
2462
        { "ReadOnlyDirectories",                   bus_append_strv                               },
2463
        { "InaccessibleDirectories",               bus_append_strv                               },
2464
        { "ReadWritePaths",                        bus_append_strv                               },
2465
        { "ReadOnlyPaths",                         bus_append_strv                               },
2466
        { "InaccessiblePaths",                     bus_append_strv                               },
2467
        { "ExecPaths",                             bus_append_strv                               },
2468
        { "NoExecPaths",                           bus_append_strv                               },
2469
        { "ExecSearchPath",                        bus_append_strv                               },
2470
        { "ExtensionDirectories",                  bus_append_strv                               },
2471
        { "ConfigurationDirectory",                bus_append_strv                               },
2472
        { "SupplementaryGroups",                   bus_append_strv                               },
2473
        { "SystemCallArchitectures",               bus_append_strv                               },
2474
        { "SyslogLevel",                           bus_append_log_level_from_string              },
2475
        { "LogLevelMax",                           bus_append_log_level_from_string              },
2476
        { "SyslogFacility",                        bus_append_log_facility_unshifted_from_string },
2477
        { "SecureBits",                            bus_append_secure_bits_from_string            },
2478
        { "CPUSchedulingPolicy",                   bus_append_sched_policy_from_string           },
2479
        { "CPUSchedulingPriority",                 bus_append_safe_atoi                          },
2480
        { "OOMScoreAdjust",                        bus_append_safe_atoi                          },
2481
        { "CoredumpFilter",                        bus_append_coredump_filter_mask_from_string   },
2482
        { "Nice",                                  bus_append_parse_nice                         },
2483
        { "SystemCallErrorNumber",                 bus_append_seccomp_parse_errno_or_action      },
2484
        { "IOSchedulingClass",                     bus_append_ioprio_class_from_string           },
2485
        { "IOSchedulingPriority",                  bus_append_ioprio_parse_priority              },
2486
        { "RuntimeDirectoryMode",                  bus_append_parse_mode                         },
2487
        { "StateDirectoryMode",                    bus_append_parse_mode                         },
2488
        { "CacheDirectoryMode",                    bus_append_parse_mode                         },
2489
        { "LogsDirectoryMode",                     bus_append_parse_mode                         },
2490
        { "ConfigurationDirectoryMode",            bus_append_parse_mode                         },
2491
        { "UMask",                                 bus_append_parse_mode                         },
2492
        { "TimerSlackNSec",                        bus_append_parse_nsec                         },
2493
        { "LogRateLimitIntervalSec",               bus_append_parse_sec_rename                   },
2494
        { "LogRateLimitBurst",                     bus_append_safe_atou                          },
2495
        { "TTYRows",                               bus_append_safe_atou                          },
2496
        { "TTYColumns",                            bus_append_safe_atou                          },
2497
        { "MemoryTHP",                             bus_append_string                             },
2498
        { "MountFlags",                            bus_append_mount_propagation_flag_from_string },
2499
        { "Environment",                           bus_append_strv_cunescape                     },
2500
        { "UnsetEnvironment",                      bus_append_strv_cunescape                     },
2501
        { "PassEnvironment",                       bus_append_strv_cunescape                     },
2502
        { "EnvironmentFile",                       bus_append_environment_files                  },
2503
        { "SetCredential",                         bus_append_set_credential                     },
2504
        { "SetCredentialEncrypted",                bus_append_set_credential                     },
2505
        { "LoadCredential",                        bus_append_load_credential                    },
2506
        { "LoadCredentialEncrypted",               bus_append_load_credential                    },
2507
        { "ImportCredential",                      bus_append_import_credential                  },
2508
        { "ImportCredentialEx",                    bus_append_import_credential                  }, /* compat */
2509
        { "LogExtraFields",                        bus_append_log_extra_fields                   },
2510
        { "LogFilterPatterns",                     bus_append_log_filter_patterns                },
2511
        { "StandardInput",                         bus_append_standard_inputs                    },
2512
        { "StandardOutput",                        bus_append_standard_inputs                    },
2513
        { "StandardError",                         bus_append_standard_inputs                    },
2514
        { "StandardInputText",                     bus_append_standard_input_text                },
2515
        { "StandardInputData",                     bus_append_standard_input_data                },
2516
        { "AppArmorProfile",                       bus_append_string_with_ignore                 },
2517
        { "SmackProcessLabel",                     bus_append_string_with_ignore                 },
2518
        { "CapabilityBoundingSet",                 bus_append_capabilities                       },
2519
        { "AmbientCapabilities",                   bus_append_capabilities                       },
2520
        { "CPUAffinity",                           bus_append_cpu_affinity                       },
2521
        { "NUMAPolicy",                            bus_append_mpol_from_string                   },
2522
        { "NUMAMask",                              bus_append_numa_mask                          },
2523
        { "RestrictAddressFamilies",               bus_append_filter_list                        },
2524
        { "RestrictFileSystems",                   bus_append_filter_list                        },
2525
        { "SystemCallFilter",                      bus_append_filter_list                        },
2526
        { "SystemCallLog",                         bus_append_filter_list                        },
2527
        { "RestrictNetworkInterfaces",             bus_append_filter_list                        },
2528
        { "RestrictNamespaces",                    bus_append_namespace_list                     },
2529
        { "DelegateNamespaces",                    bus_append_namespace_list                     },
2530
        { "BindPaths",                             bus_append_bind_paths                         },
2531
        { "BindReadOnlyPaths",                     bus_append_bind_paths                         },
2532
        { "TemporaryFileSystem",                   bus_append_temporary_file_system              },
2533
        { "RootHash",                              bus_append_root_hash                          },
2534
        { "RootHashSignature",                     bus_append_root_hash_signature                },
2535
        { "RootImageOptions",                      bus_append_root_image_options                 },
2536
        { "MountImages",                           bus_append_mount_images                       },
2537
        { "ExtensionImages",                       bus_append_extension_images                   },
2538
        { "StateDirectory",                        bus_append_directory                          },
2539
        { "RuntimeDirectory",                      bus_append_directory                          },
2540
        { "CacheDirectory",                        bus_append_directory                          },
2541
        { "LogsDirectory",                         bus_append_directory                          },
2542
        { "ProtectHostname",                       bus_append_protect_hostname                   },
2543
        { "ProtectHostnameEx",                     bus_append_protect_hostname                   }, /* compat */
2544
        { "PrivateTmp",                            bus_append_boolean_or_ex_string               },
2545
        { "PrivateTmpEx",                          bus_append_boolean_or_ex_string               }, /* compat */
2546
        { "ProtectControlGroups",                  bus_append_boolean_or_ex_string               },
2547
        { "ProtectControlGroupsEx",                bus_append_boolean_or_ex_string               }, /* compat */
2548
        { "PrivateUsers",                          bus_append_boolean_or_ex_string               },
2549
        { "PrivateUsersEx",                        bus_append_boolean_or_ex_string               }, /* compat */
2550
        { "StateDirectoryQuota",                   bus_append_quota_directory                    },
2551
        { "CacheDirectoryQuota",                   bus_append_quota_directory                    },
2552
        { "LogsDirectoryQuota",                    bus_append_quota_directory                    },
2553
        { "StateDirectoryAccounting",              bus_append_parse_boolean                      },
2554
        { "CacheDirectoryAccounting",              bus_append_parse_boolean                      },
2555
        { "LogsDirectoryAccounting",               bus_append_parse_boolean                      },
2556

2557
        { NULL, bus_try_append_resource_limit,     dump_resource_limits                          },
2558
        {}
2559
};
2560

2561
static const BusProperty kill_properties[] = {
2562
        { "KillMode",                              bus_append_string                             },
2563
        { "SendSIGHUP",                            bus_append_parse_boolean                      },
2564
        { "SendSIGKILL",                           bus_append_parse_boolean                      },
2565
        { "KillSignal",                            bus_append_signal_from_string                 },
2566
        { "RestartKillSignal",                     bus_append_signal_from_string                 },
2567
        { "FinalKillSignal",                       bus_append_signal_from_string                 },
2568
        { "WatchdogSignal",                        bus_append_signal_from_string                 },
2569
        {}
2570
};
2571

2572
static const BusProperty mount_properties[] = {
2573
        { "What",                                  bus_append_string                             },
2574
        { "Where",                                 bus_append_string                             },
2575
        { "Options",                               bus_append_string                             },
2576
        { "Type",                                  bus_append_string                             },
2577
        { "TimeoutSec",                            bus_append_parse_sec_rename                   },
2578
        { "DirectoryMode",                         bus_append_parse_mode                         },
2579
        { "SloppyOptions",                         bus_append_parse_boolean                      },
2580
        { "LazyUnmount",                           bus_append_parse_boolean                      },
2581
        { "ForceUnmount",                          bus_append_parse_boolean                      },
2582
        { "ReadwriteOnly",                         bus_append_parse_boolean                      },
2583
        {}
2584
};
2585

2586
static const BusProperty path_properties[] = {
2587
        { "MakeDirectory",                         bus_append_parse_boolean                      },
2588
        { "DirectoryMode",                         bus_append_parse_mode                         },
2589
        { "PathExists",                            bus_append_paths                              },
2590
        { "PathExistsGlob",                        bus_append_paths                              },
2591
        { "PathChanged",                           bus_append_paths                              },
2592
        { "PathModified",                          bus_append_paths                              },
2593
        { "DirectoryNotEmpty",                     bus_append_paths                              },
2594
        { "TriggerLimitBurst",                     bus_append_safe_atou                          },
2595
        { "PollLimitBurst",                        bus_append_safe_atou                          },
2596
        { "TriggerLimitIntervalSec",               bus_append_parse_sec_rename                   },
2597
        { "PollLimitIntervalSec",                  bus_append_parse_sec_rename                   },
2598
        {}
2599
};
2600

2601
static const BusProperty scope_properties[] = {
2602
        { "RuntimeMaxSec",                         bus_append_parse_sec_rename                   },
2603
        { "RuntimeRandomizedExtraSec",             bus_append_parse_sec_rename                   },
2604
        { "TimeoutStopSec",                        bus_append_parse_sec_rename                   },
2605
        { "OOMPolicy",                             bus_append_string                             },
2606

2607
        /* Scope units don't have execution context but we still want to allow setting these two,
2608
         * so let's handle them separately. */
2609
        { "User",                                  bus_append_string                             },
2610
        { "Group",                                 bus_append_string                             },
2611
        {}
2612
};
2613

2614
static const BusProperty service_properties[] = {
2615
        { "PIDFile",                               bus_append_string                             },
2616
        { "Type",                                  bus_append_string                             },
2617
        { "ExitType",                              bus_append_string                             },
2618
        { "Restart",                               bus_append_string                             },
2619
        { "RestartMode",                           bus_append_string                             },
2620
        { "BusName",                               bus_append_string                             },
2621
        { "NotifyAccess",                          bus_append_string                             },
2622
        { "USBFunctionDescriptors",                bus_append_string                             },
2623
        { "USBFunctionStrings",                    bus_append_string                             },
2624
        { "OOMPolicy",                             bus_append_string                             },
2625
        { "TimeoutStartFailureMode",               bus_append_string                             },
2626
        { "TimeoutStopFailureMode",                bus_append_string                             },
2627
        { "FileDescriptorStorePreserve",           bus_append_string                             },
2628
        { "PermissionsStartOnly",                  bus_append_parse_boolean                      },
2629
        { "RootDirectoryStartOnly",                bus_append_parse_boolean                      },
2630
        { "RemainAfterExit",                       bus_append_parse_boolean                      },
2631
        { "GuessMainPID",                          bus_append_parse_boolean                      },
2632
        { "RestartSec",                            bus_append_parse_sec_rename                   },
2633
        { "RestartMaxDelaySec",                    bus_append_parse_sec_rename                   },
2634
        { "TimeoutStartSec",                       bus_append_parse_sec_rename                   },
2635
        { "TimeoutStopSec",                        bus_append_parse_sec_rename                   },
2636
        { "TimeoutAbortSec",                       bus_append_parse_sec_rename                   },
2637
        { "RuntimeMaxSec",                         bus_append_parse_sec_rename                   },
2638
        { "RuntimeRandomizedExtraSec",             bus_append_parse_sec_rename                   },
2639
        { "WatchdogSec",                           bus_append_parse_sec_rename                   },
2640
        { "TimeoutSec",                            bus_append_timeout_sec                        },
2641
        { "FileDescriptorStoreMax",                bus_append_safe_atou                          },
2642
        { "RestartSteps",                          bus_append_safe_atou                          },
2643
        { "ExecCondition",                         bus_append_exec_command                       },
2644
        { "ExecConditionEx",                       bus_append_exec_command                       }, /* compat */
2645
        { "ExecStartPre",                          bus_append_exec_command                       },
2646
        { "ExecStartPreEx",                        bus_append_exec_command                       }, /* compat */
2647
        { "ExecStart",                             bus_append_exec_command                       },
2648
        { "ExecStartEx",                           bus_append_exec_command                       }, /* compat */
2649
        { "ExecStartPost",                         bus_append_exec_command                       },
2650
        { "ExecStartPostEx",                       bus_append_exec_command                       }, /* compat */
2651
        { "ExecReload",                            bus_append_exec_command                       },
2652
        { "ExecReloadEx",                          bus_append_exec_command                       }, /* compat */
2653
        { "ExecReloadPost",                        bus_append_exec_command                       },
2654
        { "ExecReloadPostEx",                      bus_append_exec_command                       }, /* compat */
2655
        { "ExecStop",                              bus_append_exec_command                       },
2656
        { "ExecStopEx",                            bus_append_exec_command                       }, /* compat */
2657
        { "ExecStopPost",                          bus_append_exec_command                       },
2658
        { "ExecStopPostEx",                        bus_append_exec_command                       }, /* compat */
2659
        { "RestartPreventExitStatus",              bus_append_exit_status                        },
2660
        { "RestartForceExitStatus",                bus_append_exit_status                        },
2661
        { "SuccessExitStatus",                     bus_append_exit_status                        },
2662
        { "OpenFile",                              bus_append_open_file                          },
2663
        { "ReloadSignal",                          bus_append_signal_from_string                 },
2664
        {}
2665
};
2666

2667
static const BusProperty socket_properties[] = {
2668
        { "Accept",                                bus_append_parse_boolean                      },
2669
        { "FlushPending",                          bus_append_parse_boolean                      },
2670
        { "Writable",                              bus_append_parse_boolean                      },
2671
        { "KeepAlive",                             bus_append_parse_boolean                      },
2672
        { "NoDelay",                               bus_append_parse_boolean                      },
2673
        { "FreeBind",                              bus_append_parse_boolean                      },
2674
        { "Transparent",                           bus_append_parse_boolean                      },
2675
        { "Broadcast",                             bus_append_parse_boolean                      },
2676
        { "PassCredentials",                       bus_append_parse_boolean                      },
2677
        { "PassFileDescriptorsToExec",             bus_append_parse_boolean                      },
2678
        { "PassSecurity",                          bus_append_parse_boolean                      },
2679
        { "PassPacketInfo",                        bus_append_parse_boolean                      },
2680
        { "ReusePort",                             bus_append_parse_boolean                      },
2681
        { "RemoveOnStop",                          bus_append_parse_boolean                      },
2682
        { "SELinuxContextFromNet",                 bus_append_parse_boolean                      },
2683
        { "Priority",                              bus_append_safe_atoi                          },
2684
        { "IPTTL",                                 bus_append_safe_atoi                          },
2685
        { "Mark",                                  bus_append_safe_atoi                          },
2686
        { "IPTOS",                                 bus_append_ip_tos_from_string                 },
2687
        { "Backlog",                               bus_append_safe_atou                          },
2688
        { "MaxConnections",                        bus_append_safe_atou                          },
2689
        { "MaxConnectionsPerSource",               bus_append_safe_atou                          },
2690
        { "KeepAliveProbes",                       bus_append_safe_atou                          },
2691
        { "TriggerLimitBurst",                     bus_append_safe_atou                          },
2692
        { "PollLimitBurst",                        bus_append_safe_atou                          },
2693
        { "SocketMode",                            bus_append_parse_mode                         },
2694
        { "DirectoryMode",                         bus_append_parse_mode                         },
2695
        { "MessageQueueMaxMessages",               bus_append_safe_atoi64                        },
2696
        { "MessageQueueMessageSize",               bus_append_safe_atoi64                        },
2697
        { "TimeoutSec",                            bus_append_parse_sec_rename                   },
2698
        { "KeepAliveTimeSec",                      bus_append_parse_sec_rename                   },
2699
        { "KeepAliveIntervalSec",                  bus_append_parse_sec_rename                   },
2700
        { "DeferAcceptSec",                        bus_append_parse_sec_rename                   },
2701
        { "TriggerLimitIntervalSec",               bus_append_parse_sec_rename                   },
2702
        { "PollLimitIntervalSec",                  bus_append_parse_sec_rename                   },
2703
        { "DeferTriggerMaxSec",                    bus_append_parse_sec_rename                   },
2704
        { "ReceiveBuffer",                         bus_append_parse_size                         },
2705
        { "SendBuffer",                            bus_append_parse_size                         },
2706
        { "PipeSize",                              bus_append_parse_size                         },
2707
        { "ExecStartPre",                          bus_append_exec_command                       },
2708
        { "ExecStartPost",                         bus_append_exec_command                       },
2709
        { "ExecReload",                            bus_append_exec_command                       },
2710
        { "ExecStopPost",                          bus_append_exec_command                       },
2711
        { "SmackLabel",                            bus_append_string                             },
2712
        { "SmackLabelIPIn",                        bus_append_string                             },
2713
        { "SmackLabelIPOut",                       bus_append_string                             },
2714
        { "TCPCongestion",                         bus_append_string                             },
2715
        { "BindToDevice",                          bus_append_string                             },
2716
        { "BindIPv6Only",                          bus_append_string                             },
2717
        { "FileDescriptorName",                    bus_append_string                             },
2718
        { "SocketUser",                            bus_append_string                             },
2719
        { "SocketGroup",                           bus_append_string                             },
2720
        { "Timestamping",                          bus_append_string                             },
2721
        { "DeferTrigger",                          bus_append_string                             },
2722
        { "Symlinks",                              bus_append_strv                               },
2723
        { "SocketProtocol",                        bus_append_parse_ip_protocol                  },
2724
        { "ListenStream",                          bus_append_listen                             },
2725
        { "ListenDatagram",                        bus_append_listen                             },
2726
        { "ListenSequentialPacket",                bus_append_listen                             },
2727
        { "ListenNetlink",                         bus_append_listen                             },
2728
        { "ListenSpecial",                         bus_append_listen                             },
2729
        { "ListenMessageQueue",                    bus_append_listen                             },
2730
        { "ListenFIFO",                            bus_append_listen                             },
2731
        { "ListenUSBFunction",                     bus_append_listen                             },
2732
        {}
2733
};
2734

2735
static const BusProperty timer_properties[] = {
2736
        { "WakeSystem",                            bus_append_parse_boolean                      },
2737
        { "RemainAfterElapse",                     bus_append_parse_boolean                      },
2738
        { "Persistent",                            bus_append_parse_boolean                      },
2739
        { "OnTimezoneChange",                      bus_append_parse_boolean                      },
2740
        { "OnClockChange",                         bus_append_parse_boolean                      },
2741
        { "FixedRandomDelay",                      bus_append_parse_boolean                      },
2742
        { "DeferReactivation",                     bus_append_parse_boolean                      },
2743
        { "AccuracySec",                           bus_append_parse_sec_rename                   },
2744
        { "RandomizedDelaySec",                    bus_append_parse_sec_rename                   },
2745
        { "RandomizedOffsetSec",                   bus_append_parse_sec_rename                   },
2746
        { "OnActiveSec",                           bus_append_timers_monotonic                   },
2747
        { "OnBootSec",                             bus_append_timers_monotonic                   },
2748
        { "OnStartupSec",                          bus_append_timers_monotonic                   },
2749
        { "OnUnitActiveSec",                       bus_append_timers_monotonic                   },
2750
        { "OnUnitInactiveSec",                     bus_append_timers_monotonic                   },
2751
        { "OnCalendar",                            bus_append_timers_calendar                    },
2752
        {}
2753
};
2754

2755
static const BusProperty unit_properties[] = {
2756
        { "Description",                           bus_append_string                             },
2757
        { "SourcePath",                            bus_append_string                             },
2758
        { "OnFailureJobMode",                      bus_append_string                             },
2759
        { "JobTimeoutAction",                      bus_append_string                             },
2760
        { "JobTimeoutRebootArgument",              bus_append_string                             },
2761
        { "StartLimitAction",                      bus_append_string                             },
2762
        { "FailureAction",                         bus_append_string                             },
2763
        { "SuccessAction",                         bus_append_string                             },
2764
        { "RebootArgument",                        bus_append_string                             },
2765
        { "CollectMode",                           bus_append_string                             },
2766
        { "StopWhenUnneeded",                      bus_append_parse_boolean                      },
2767
        { "RefuseManualStart",                     bus_append_parse_boolean                      },
2768
        { "RefuseManualStop",                      bus_append_parse_boolean                      },
2769
        { "AllowIsolate",                          bus_append_parse_boolean                      },
2770
        { "IgnoreOnIsolate",                       bus_append_parse_boolean                      },
2771
        { "SurviveFinalKillSignal",                bus_append_parse_boolean                      },
2772
        { "DefaultDependencies",                   bus_append_parse_boolean                      },
2773
        { "JobTimeoutSec",                         bus_append_parse_sec_rename                   },
2774
        { "JobRunningTimeoutSec",                  bus_append_parse_sec_rename                   },
2775
        { "StartLimitIntervalSec",                 bus_append_parse_sec_rename                   },
2776
        { "StartLimitBurst",                       bus_append_safe_atou                          },
2777
        { "SuccessActionExitStatus",               bus_append_action_exit_status                 },
2778
        { "FailureActionExitStatus",               bus_append_action_exit_status                 },
2779
        { "Documentation",                         bus_append_strv                               },
2780
        { "RequiresMountsFor",                     bus_append_strv                               },
2781
        { "WantsMountsFor",                        bus_append_strv                               },
2782
        { "Markers",                               bus_append_strv                               },
2783

2784
        { NULL, bus_try_append_unit_dependency,    unit_types_list                               },
2785
        { NULL, bus_try_append_condition,          dump_conditions                               },
2786
        {}
2787
};
2788

2789
static const BusProperty* service_unit_properties[] = {
2790
        cgroup_properties,
2791
        execute_properties,
2792
        kill_properties,
2793
        service_properties,
2794
        unit_properties,
2795
        NULL,
2796
};
2797

2798
static const BusProperty* socket_unit_properties[] = {
2799
        cgroup_properties,
2800
        execute_properties,
2801
        kill_properties,
2802
        socket_properties,
2803
        unit_properties,
2804
        NULL,
2805
};
2806

2807
static const BusProperty* timer_unit_properties[] = {
2808
        timer_properties,
2809
        unit_properties,
2810
        NULL,
2811
};
2812

2813
static const BusProperty* path_unit_properties[] = {
2814
        path_properties,
2815
        unit_properties,
2816
        NULL,
2817
};
2818

2819
static const BusProperty* slice_unit_properties[] = {
2820
        cgroup_properties,
2821
        unit_properties,
2822
        NULL,
2823
};
2824

2825
static const BusProperty* scope_unit_properties[] = {
2826
        cgroup_properties,
2827
        kill_properties,
2828
        scope_properties,
2829
        unit_properties,
2830
        NULL,
2831
};
2832

2833
static const BusProperty* mount_unit_properties[] = {
2834
        cgroup_properties,
2835
        execute_properties,
2836
        kill_properties,
2837
        mount_properties,
2838
        unit_properties,
2839
        NULL,
2840
};
2841

2842
static const BusProperty* automount_unit_properties[] = {
2843
        automount_properties,
2844
        unit_properties,
2845
        NULL,
2846
};
2847

2848
static const BusProperty* other_unit_properties[] = {
2849
        unit_properties,
2850
        NULL,
2851
};
2852

2853
static const BusProperty** unit_type_properties[_UNIT_TYPE_MAX] = {
2854
        [UNIT_SERVICE]   = service_unit_properties,
2855
        [UNIT_SOCKET]    = socket_unit_properties,
2856
        [UNIT_TIMER]     = timer_unit_properties,
2857
        [UNIT_PATH]      = path_unit_properties,
2858
        [UNIT_SLICE]     = slice_unit_properties,
2859
        [UNIT_SCOPE]     = scope_unit_properties,
2860
        [UNIT_MOUNT]     = mount_unit_properties,
2861
        [UNIT_AUTOMOUNT] = automount_unit_properties,
2862
        [UNIT_TARGET]    = other_unit_properties,
2863
        [UNIT_DEVICE]    = other_unit_properties,
2864
        [UNIT_SWAP]      = other_unit_properties,
2865
};
2866

2867
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
4,778✔
2868
        _cleanup_free_ char *field = NULL;
4,778✔
2869
        const char *eq;
4,778✔
2870
        int r;
4,778✔
2871

2872
        assert(m);
4,778✔
2873
        assert(assignment);
4,778✔
2874
        assert(t >= 0 && t < _UNIT_TYPE_MAX);
4,778✔
2875

2876
        eq = strchr(assignment, '=');
4,778✔
2877
        if (!eq)
4,778✔
2878
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2879
                                       "Not an assignment: %s", assignment);
2880

2881

2882
        field = strndup(assignment, eq - assignment);
4,776✔
2883
        if (!field)
4,776✔
2884
                return log_oom();
×
2885
        eq++;
4,776✔
2886

2887
        for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
9,768✔
2888
                for (const BusProperty *item = *tables; item->convert; item++)
639,534✔
2889
                        if (item->name) {
634,542✔
2890
                                if (streq(item->name, field))
629,834✔
2891
                                        return item->convert(m, field, eq);
4,593✔
2892
                        } else {
2893
                                /* If .name is not set, the function must be a "try" helper */
2894
                                r = item->convert(m, field, eq);
4,708✔
2895
                                if (r != 0)
4,708✔
2896
                                        return r;
2897
                        }
2898

2899
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2900
                               "Unknown assignment: %s", assignment);
2901
}
2902

2903
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char * const *l) {
1,606✔
2904
        int r;
1,606✔
2905

2906
        assert(m);
1,606✔
2907

2908
        STRV_FOREACH(i, l) {
5,473✔
2909
                r = bus_append_unit_property_assignment(m, t, *i);
3,876✔
2910
                if (r < 0)
3,876✔
2911
                        return r;
2912
        }
2913

2914
        return 0;
2915
}
2916

2917
void bus_dump_transient_settings(UnitType t) {
35✔
2918
        assert(t >= 0 && t < _UNIT_TYPE_MAX);
35✔
2919

2920
        for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
147✔
2921
                for (const BusProperty *item = *tables; item->convert; item++) {
5,288✔
2922
                        assert(item->name || item->dump);
5,176✔
2923

2924
                        /* Do not print deprecated names. All "Ex" variants are deprecated. */
2925
                        if (item->convert == warn_deprecated)
5,176✔
2926
                                continue;
200✔
2927
                        if (item->name && endswith(item->name, "Ex"))
4,976✔
2928
                                continue;
126✔
2929

2930
                        if (item->name)
4,850✔
2931
                                puts(item->name);
4,746✔
2932
                        else
2933
                                item->dump();
104✔
2934
                }
2935
}
35✔
2936

2937
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
553✔
2938
        assert(m);
553✔
2939

2940
        if (!pidref_is_set(pidref))
553✔
2941
                return -ESRCH;
2942

2943
        if (pidref->fd >= 0 && allow_pidfd)
553✔
2944
                return sd_bus_message_append(
553✔
2945
                                m, "(sv)",
2946
                                "PIDFDs", "ah", 1, pidref->fd);
2947

2948
        return sd_bus_message_append(
×
2949
                        m, "(sv)",
2950
                        "PIDs", "au", 1, pidref->pid);
2951
}
2952

2953
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
68✔
2954
        const char *type, *path, *source;
68✔
2955
        InstallChange *changes = NULL;
68✔
2956
        size_t n_changes = 0;
68✔
2957
        int r;
68✔
2958

2959
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
68✔
2960

2961
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
68✔
2962
        if (r < 0)
68✔
2963
                return bus_log_parse_error(r);
×
2964

2965
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
127✔
2966
                InstallChangeType t;
59✔
2967

2968
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2969
                 * negative. */
2970
                t = install_change_type_from_string(type);
59✔
2971
                if (t < 0) {
59✔
2972
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
2973
                                         type, path);
2974
                        continue;
×
2975
                }
2976

2977
                r = install_changes_add(&changes, &n_changes, t, path, source);
59✔
2978
                if (r < 0)
59✔
2979
                        return r;
2980
        }
2981
        if (r < 0)
68✔
2982
                return bus_log_parse_error(r);
×
2983

2984
        r = sd_bus_message_exit_container(m);
68✔
2985
        if (r < 0)
68✔
2986
                return bus_log_parse_error(r);
×
2987

2988
        install_changes_dump(0, NULL, changes, n_changes, quiet);
68✔
2989

2990
        return 0;
2991
}
2992

2993
int unit_load_state(sd_bus *bus, const char *name, char **ret) {
4,836✔
2994
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2995
        _cleanup_free_ char *path = NULL;
4,836✔
2996
        int r;
4,836✔
2997

2998
        path = unit_dbus_path_from_name(name);
4,836✔
2999
        if (!path)
4,836✔
3000
                return log_oom();
×
3001

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

3005
        r = sd_bus_get_property_string(
4,836✔
3006
                        bus,
3007
                        "org.freedesktop.systemd1",
3008
                        path,
3009
                        "org.freedesktop.systemd1.Unit",
3010
                        "LoadState",
3011
                        &error,
3012
                        ret);
3013
        if (r < 0)
4,836✔
3014
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
3015

3016
        return 0;
3017
}
3018

3019
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
60,887✔
3020
        int r;
60,887✔
3021

3022
        /* First, order by machine */
3023
        r = strcasecmp_ptr(a->machine, b->machine);
60,887✔
3024
        if (r != 0)
60,887✔
3025
                return r;
3026

3027
        /* Second, order by unit type */
3028
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
60,887✔
3029
        if (r != 0)
60,887✔
3030
                return r;
3031

3032
        /* Third, order by name */
3033
        return strcasecmp(a->id, b->id);
58,480✔
3034
}
3035

3036
int bus_service_manager_reload(sd_bus *bus) {
63✔
3037
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3038
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
63✔
3039
        int r;
63✔
3040

3041
        assert(bus);
63✔
3042

3043
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
63✔
3044
        if (r < 0)
63✔
3045
                return bus_log_create_error(r);
×
3046

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

3052
        return 0;
3053
}
3054

3055
typedef struct UnitFreezer {
3056
        char *name;
3057
        sd_bus *bus;
3058
} UnitFreezer;
3059

3060
/* Wait for 60 seconds at maximum for freezer operation */
3061
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3062

3063
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
3064
        if (!f)
×
3065
                return NULL;
3066

3067
        free(f->name);
×
3068
        sd_bus_flush_close_unref(f->bus);
×
3069

3070
        return mfree(f);
×
3071
}
3072

3073
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
3074
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
3075
        int r;
×
3076

3077
        assert(name);
×
3078
        assert(ret);
×
3079

3080
        f = new(UnitFreezer, 1);
×
3081
        if (!f)
×
3082
                return log_oom();
×
3083

3084
        *f = (UnitFreezer) {
×
3085
                .name = strdup(name),
×
3086
        };
3087
        if (!f->name)
×
3088
                return log_oom();
×
3089

3090
        r = bus_connect_system_systemd(&f->bus);
×
3091
        if (r < 0)
×
3092
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3093

3094
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3095

3096
        *ret = TAKE_PTR(f);
×
3097
        return 0;
×
3098
}
3099

3100
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
3101
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3102
        int r;
×
3103

3104
        assert(f);
×
3105
        assert(f->name);
×
3106
        assert(f->bus);
×
3107

3108
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3109
                            freeze ? "FreezeUnit" : "ThawUnit",
3110
                            &error,
3111
                            /* ret_reply= */ NULL,
3112
                            "s",
3113
                            f->name);
3114
        if (r < 0) {
×
3115
                if (sd_bus_error_has_names(&error,
×
3116
                                           BUS_ERROR_NO_SUCH_UNIT,
3117
                                           BUS_ERROR_UNIT_INACTIVE,
3118
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3119

3120
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
3121
                        return 0;
×
3122
                }
3123

3124
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3125
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3126
        }
3127

3128
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3129
        return 1;
3130
}
3131

3132
int unit_freezer_freeze(UnitFreezer *f) {
×
3133
        return unit_freezer_action(f, true);
×
3134
}
3135

3136
int unit_freezer_thaw(UnitFreezer *f) {
×
3137
        return unit_freezer_action(f, false);
×
3138
}
3139

3140
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,592✔
3141
        if (isempty(s))
1,592✔
3142
                return 0;
3143

3144
        if (streq(s, "ro"))
74✔
3145
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3146

3147
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3148
}
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