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

systemd / systemd / 16082515961

04 Jul 2025 08:23PM UTC coverage: 72.095% (-0.1%) from 72.193%
16082515961

push

github

poettering
seccomp-util: allowlist open_tree() as part of @file-system

Now that we make use of open_tree() in places we previously used
openat() with O_PATH, it makes sense to move it from @mount to
@file-system. Without the OPEN_TREE_CLONE flag open_tree() is after all
unprivileged.

Note that open_tree_attr() I left in @mount, since it's purpose is
really to set mount options when cloning, and that's clearly a mount
related thing, not so much something you could use unpriv.

Follow-up for: c5de7b14a

This addresses an issue tracked down by Antonio Feijoo: since the commit
that started to use open_tree() various apps started to crash because
they used seccomp filters and sd-device started to use open_tree()
internally.

300842 of 417287 relevant lines covered (72.09%)

715300.57 hits per line

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

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

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

6
#include "sd-bus.h"
7

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

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

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

59
        return sd_bus_message_read(
11,912✔
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) {
×
75
        log_warning("D-Bus property %s is deprecated, ignoring assignment: %s=%s", field, field, eq);
×
76
        return 1;
×
77
}
78

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

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

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

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

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

149
        return 1;
150
}
151

152
static int bus_append_strv_full(sd_bus_message *m, const char *field, const char *eq, ExtractFlags flags) {
417✔
153
        int r;
417✔
154

155
        assert(m);
417✔
156
        assert(field);
417✔
157

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

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

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

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

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

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

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

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

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

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

202
        return 1;
203
}
204

205
static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq) {
60✔
206
        return bus_append_strv_full(m, field, eq, EXTRACT_UNQUOTE);
60✔
207
}
208

209
static int bus_append_strv_cunescape(sd_bus_message *m, const char *field, const char *eq) {
357✔
210
        return bus_append_strv_full(m, field, eq, EXTRACT_UNQUOTE | EXTRACT_CUNESCAPE);
357✔
211
}
212

213
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
18✔
214
        int r;
18✔
215

216
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
18✔
217
        if (r < 0)
18✔
218
                return bus_log_create_error(r);
×
219

220
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
18✔
221
        if (r < 0)
18✔
222
                return bus_log_create_error(r);
×
223

224
        r = sd_bus_message_open_container(m, 'v', "ay");
18✔
225
        if (r < 0)
18✔
226
                return bus_log_create_error(r);
×
227

228
        r = sd_bus_message_append_array(m, 'y', buf, n);
18✔
229
        if (r < 0)
18✔
230
                return bus_log_create_error(r);
×
231

232
        r = sd_bus_message_close_container(m);
18✔
233
        if (r < 0)
18✔
234
                return bus_log_create_error(r);
×
235

236
        r = sd_bus_message_close_container(m);
18✔
237
        if (r < 0)
18✔
238
                return bus_log_create_error(r);
×
239

240
        return 1;
241
}
242

243
static int bus_append_parse_sec_rename(sd_bus_message *m, const char *field, const char *eq) {
8✔
244
        char *n;
8✔
245
        usec_t t;
8✔
246
        size_t l;
8✔
247
        int r;
8✔
248

249
        r = parse_sec(eq, &t);
8✔
250
        if (r < 0)
8✔
251
                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
×
252

253
        l = strlen(field);
8✔
254
        n = newa(char, l + 2);
8✔
255
        /* Change suffix Sec → USec */
256
        strcpy(mempcpy(n, field, l - 3), "USec");
8✔
257

258
        r = sd_bus_message_append(m, "(sv)", n, "t", t);
8✔
259
        if (r < 0)
8✔
260
                return bus_log_create_error(r);
×
261

262
        return 1;
263
}
264

265
static int bus_append_parse_sec_rename_infinity(sd_bus_message *m, const char *field, const char *eq) {
×
266
        return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
×
267
}
268

269
static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq) {
8✔
270
        uint64_t v;
8✔
271
        int r;
8✔
272

273
        r = parse_size(eq, /* base= */ 1024, &v);
8✔
274
        if (r < 0)
8✔
275
                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
×
276

277
        r = sd_bus_message_append(m, "(sv)", field, "t", v);
8✔
278
        if (r < 0)
8✔
279
                return bus_log_create_error(r);
×
280

281
        return 1;
282
}
283

284
static int bus_append_parse_permyriad(sd_bus_message *m, const char *field, const char *eq) {
×
285
        int r;
×
286

287
        r = parse_permyriad(eq);
×
288
        if (r < 0)
×
289
                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
×
290

291
        /* Pass around scaled to 2^32-1 == 100% */
292
        r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
293
        if (r < 0)
×
294
                return bus_log_create_error(r);
×
295

296
        return 1;
297
}
298

299
static int bus_append_parse_cpu_set(sd_bus_message *m, const char *field, const char *eq) {
×
300
        _cleanup_(cpu_set_done) CPUSet cpuset = {};
×
301
        _cleanup_free_ uint8_t *array = NULL;
×
302
        size_t allocated;
×
303
        int r;
×
304

305
        r = parse_cpu_set(eq, &cpuset);
×
306
        if (r < 0)
×
307
                return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
308

309
        r = cpu_set_to_dbus(&cpuset, &array, &allocated);
×
310
        if (r < 0)
×
311
                return log_error_errno(r, "Failed to serialize %s: %m", field);
×
312

313
        return bus_append_byte_array(m, field, array, allocated);
×
314
}
315

316
static int bus_append_parse_delegate(sd_bus_message *m, const char *field, const char *eq) {
350✔
317
        int r;
350✔
318

319
        r = parse_boolean(eq);
350✔
320
        if (r < 0)
350✔
321
                return bus_append_strv(m, "DelegateControllers", eq);
9✔
322

323
        r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
341✔
324
        if (r < 0)
341✔
325
                return bus_log_create_error(r);
×
326

327
        return 1;
328
}
329

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

333
        if (isempty(eq) || streq(eq, "infinity")) {
20✔
334
                uint64_t x = streq(eq, "infinity") ? CGROUP_LIMIT_MAX :
×
335
                        STR_IN_SET(field,
×
336
                                   "DefaultMemoryLow",
337
                                   "DefaultMemoryMin",
338
                                   "MemoryLow",
339
                                   "MemoryMin") ? CGROUP_LIMIT_MIN : CGROUP_LIMIT_MAX;
×
340

341
                r = sd_bus_message_append(m, "(sv)", field, "t", x);
×
342
                if (r < 0)
×
343
                        return bus_log_create_error(r);
×
344

345
                return 1;
346
        }
347

348
        r = parse_permyriad(eq);
10✔
349
        if (r >= 0) {
10✔
350
                char *n;
×
351

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

356
                n = strjoina(field, "Scale");
×
357
                r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
358
                if (r < 0)
×
359
                        return bus_log_create_error(r);
×
360

361
                return 1;
362
        }
363

364
        if (streq(field, "TasksMax"))
10✔
365
                return bus_append_safe_atou64(m, field, eq);
2✔
366

367
        return bus_append_parse_size(m, field, eq);
8✔
368
}
369

370
static int bus_append_parse_cpu_quota(sd_bus_message *m, const char *field, const char *eq) {
1✔
371
        uint64_t x;
1✔
372
        int r;
1✔
373

374
        if (isempty(eq))
1✔
375
                x = USEC_INFINITY;
376
        else {
377
                r = parse_permyriad_unbounded(eq);
1✔
378
                if (r == 0)
1✔
379
                        return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "%s value too small.", field);
×
380
                if (r < 0)
1✔
381
                        return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
×
382
                x = r * USEC_PER_SEC / 10000U;
1✔
383
        }
384

385
        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", x);
1✔
386
        if (r < 0)
1✔
387
                return bus_log_create_error(r);
×
388

389
        return 1;
390
}
391

392
static int bus_append_parse_device_allow(sd_bus_message *m, const char *field, const char *eq) {
6✔
393
        int r;
6✔
394

395
        if (isempty(eq))
6✔
396
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
397
        else {
398
                _cleanup_free_ char *_path = NULL;
6✔
399
                const char *path = eq, *rwm = NULL, *e;
6✔
400

401
                e = strchr(eq, ' ');
6✔
402
                if (e) {
6✔
403
                        path = _path = strndup(eq, e - eq);
6✔
404
                        if (!path)
6✔
405
                                return log_oom();
×
406

407
                        rwm = e + 1;
6✔
408
                }
409

410
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
6✔
411
        }
412
        if (r < 0)
6✔
413
                return bus_log_create_error(r);
×
414

415
        return 1;
416
}
417

418
static int bus_try_append_parse_cgroup_io_limit(sd_bus_message *m, const char *field, const char *eq) {
2,857✔
419
        int r;
2,857✔
420

421
        if (cgroup_io_limit_type_from_string(field) < 0)
2,857✔
422
                return 0;
423

424
        if (isempty(eq))
3✔
425
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
426
        else {
427
                const char *e = strchr(eq, ' ');
3✔
428
                if (!e)
3✔
429
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
430
                                               "Failed to parse %s value %s.",
431
                                               field, eq);
432

433
                const char *bandwidth = e + 1;
3✔
434
                _cleanup_free_ char *path = strndup(eq, e - eq);
3✔
435
                if (!path)
3✔
436
                        return log_oom();
×
437

438
                uint64_t bytes;
3✔
439
                if (streq(bandwidth, "infinity"))
3✔
440
                        bytes = CGROUP_LIMIT_MAX;
×
441
                else {
442
                        r = parse_size(bandwidth, 1000, &bytes);
3✔
443
                        if (r < 0)
3✔
444
                                return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
×
445
                }
446

447
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
3✔
448
        }
449
        if (r < 0)
3✔
450
                return bus_log_create_error(r);
×
451

452
        return 1;
453
}
454

455
static int bus_append_parse_io_device_weight(sd_bus_message *m, const char *field, const char *eq) {
×
456
        int r;
×
457

458
        if (isempty(eq))
×
459
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
460
        else {
461
                const char *e = strchr(eq, ' ');
×
462
                if (!e)
×
463
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
464
                                               "Failed to parse %s value %s.",
465
                                               field, eq);
466

467
                const char *weight = e + 1;
×
468
                _cleanup_free_ char *path = strndup(eq, e - eq);
×
469
                if (!path)
×
470
                        return log_oom();
×
471

472
                uint64_t u;
×
473
                r = safe_atou64(weight, &u);
×
474
                if (r < 0)
×
475
                        return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
×
476

477
                r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
×
478
        }
479
        if (r < 0)
×
480
                return bus_log_create_error(r);
×
481

482
        return 1;
483
}
484

485
static int bus_append_parse_io_device_latency(sd_bus_message *m, const char *field, const char *eq) {
×
486
        const char *field_usec = "IODeviceLatencyTargetUSec";
×
487
        int r;
×
488

489
        if (isempty(eq))
×
490
                r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 0);
×
491
        else {
492
                const char *e = strchr(eq, ' ');
×
493
                if (!e)
×
494
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
495
                                               "Failed to parse %s value %s.",
496
                                               field, eq);
497

498
                const char *target = e + 1;
×
499
                _cleanup_free_ char *path = strndup(eq, e - eq);
×
500
                if (!path)
×
501
                        return log_oom();
×
502

503
                usec_t usec;
×
504
                r = parse_sec(target, &usec);
×
505
                if (r < 0)
×
506
                        return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
×
507

508
                r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
×
509
        }
510
        if (r < 0)
×
511
                return bus_log_create_error(r);
×
512

513
        return 1;
514
}
515

516
static int bus_append_bpf_program(sd_bus_message *m, const char *field, const char *eq) {
×
517
        int r;
×
518

519
        if (isempty(eq))
×
520
                r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
521
        else {
522
                _cleanup_free_ char *word = NULL;
×
523

524
                r = extract_first_word(&eq, &word, ":", 0);
×
525
                if (r == -ENOMEM)
×
526
                        return log_oom();
×
527
                if (r < 0)
×
528
                        return log_error_errno(r, "Failed to parse %s: %m", field);
×
529

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

535
        return 1;
536
}
537

538
static int bus_append_socket_filter(sd_bus_message *m, const char *field, const char *eq) {
×
539
        int r;
×
540

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

547
                r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
×
548
                if (r == -ENOMEM)
×
549
                        return log_oom();
×
550
                if (r < 0)
×
551
                        return log_error_errno(r, "Failed to parse %s", field);
×
552

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

559
        return 1;
560
}
561

562
static int bus_append_exec_command(sd_bus_message *m, const char *field, const char *eq) {
45✔
563
        bool explicit_path = false, done = false, ambient_hack = false;
45✔
564
        _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
45✔
565
        _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
45✔
566
        ExecCommandFlags flags = 0;
45✔
567
        bool is_ex_prop = endswith(field, "Ex");
45✔
568
        int r;
64✔
569

570
        do {
64✔
571
                switch (*eq) {
64✔
572

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

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

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

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

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

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

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

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

642
        if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID|EXEC_COMMAND_VIA_SHELL))) {
45✔
643
                /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
644
                is_ex_prop = true;
9✔
645

646
                upgraded_name = strjoin(field, "Ex");
9✔
647
                if (!upgraded_name)
9✔
648
                        return log_oom();
×
649
                field = upgraded_name;
650
        }
651

652
        if (is_ex_prop) {
36✔
653
                r = exec_command_flags_to_strv(flags, &ex_opts);
16✔
654
                if (r < 0)
16✔
655
                        return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
×
656
        }
657

658
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
45✔
659
                path = strdup(_PATH_BSHELL);
2✔
660
                if (!path)
2✔
661
                        return log_oom();
×
662

663
        } else if (explicit_path) {
43✔
664
                r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
×
665
                if (r < 0)
×
666
                        return log_error_errno(r, "Failed to parse path: %m");
×
667
                if (r == 0)
×
668
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "No executable path specified, refusing.");
×
669
                if (isempty(eq))
×
670
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Got empty command line, refusing.");
×
671
        }
672

673
        r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
45✔
674
        if (r < 0)
45✔
675
                return log_error_errno(r, "Failed to parse command line: %m");
×
676

677
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
45✔
678
                r = strv_prepend(&l, explicit_path ? "-sh" : "sh");
3✔
679
                if (r < 0)
2✔
680
                        return log_oom();
×
681
        }
682

683
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
45✔
684
        if (r < 0)
45✔
685
                return bus_log_create_error(r);
×
686

687
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
45✔
688
        if (r < 0)
45✔
689
                return bus_log_create_error(r);
×
690

691
        r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
74✔
692
        if (r < 0)
45✔
693
                return bus_log_create_error(r);
×
694

695
        r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
74✔
696
        if (r < 0)
45✔
697
                return bus_log_create_error(r);
×
698

699
        if (!strv_isempty(l)) {
45✔
700

701
                r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
74✔
702
                if (r < 0)
45✔
703
                        return bus_log_create_error(r);
×
704

705
                r = sd_bus_message_append(m, "s", path ?: l[0]);
45✔
706
                if (r < 0)
45✔
707
                        return bus_log_create_error(r);
×
708

709
                r = sd_bus_message_append_strv(m, l);
45✔
710
                if (r < 0)
45✔
711
                        return bus_log_create_error(r);
×
712

713
                r = is_ex_prop ? sd_bus_message_append_strv(m, ex_opts) : sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
45✔
714
                if (r < 0)
45✔
715
                        return bus_log_create_error(r);
×
716

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

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

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

730
        r = sd_bus_message_close_container(m);
45✔
731
        if (r < 0)
45✔
732
                return bus_log_create_error(r);
×
733

734
        return 1;
735
}
736

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

741
        assert(m);
5✔
742

743
        r = open_file_parse(eq, &of);
5✔
744
        if (r < 0)
5✔
745
                return log_error_errno(r, "Failed to parse OpenFile= setting: %m");
×
746

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

751
        return 1;
752
}
753

754
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
×
755
        int r;
×
756

757
        assert(m);
×
758
        assert(prefix);
×
759

760
        r = sd_bus_message_open_container(m, 'r', "iayu");
×
761
        if (r < 0)
×
762
                return r;
763

764
        r = sd_bus_message_append(m, "i", family);
×
765
        if (r < 0)
×
766
                return r;
767

768
        r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
×
769
        if (r < 0)
×
770
                return r;
771

772
        r = sd_bus_message_append(m, "u", prefixlen);
×
773
        if (r < 0)
×
774
                return r;
775

776
        return sd_bus_message_close_container(m);
×
777
}
778

779
static int bus_append_parse_ip_address_filter(sd_bus_message *m, const char *field, const char *eq) {
×
780
        union in_addr_union prefix = {};
×
781
        unsigned char prefixlen;
×
782
        int family, r;
×
783

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

789
                return 1;
790
        }
791

792
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
793
        if (r < 0)
×
794
                return bus_log_create_error(r);
×
795

796
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
797
        if (r < 0)
×
798
                return bus_log_create_error(r);
×
799

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

804
        r = sd_bus_message_open_container(m, 'a', "(iayu)");
×
805
        if (r < 0)
×
806
                return bus_log_create_error(r);
×
807

808
        if (streq(eq, "any")) {
×
809
                /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
810

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

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

819
        } else if (is_localhost(eq)) {
×
820
                /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
821

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

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

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

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

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

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

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

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

862
        } else
863
                for (;;) {
×
864
                        _cleanup_free_ char *word = NULL;
×
865

866
                        r = extract_first_word(&eq, &word, NULL, 0);
×
867
                        if (r == 0)
×
868
                                break;
869
                        if (r == -ENOMEM)
×
870
                                return log_oom();
×
871
                        if (r < 0)
×
872
                                return log_error_errno(r, "Failed to parse %s: %s", field, eq);
×
873

874
                        r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
×
875
                        if (r < 0)
×
876
                                return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
×
877

878
                        r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
×
879
                        if (r < 0)
×
880
                                return bus_log_create_error(r);
×
881
                }
882

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

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

891
        r = sd_bus_message_close_container(m);
×
892
        if (r < 0)
×
893
                return bus_log_create_error(r);
×
894

895
        return 1;
896
}
897

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

909
static int bus_append_ip_filter_path(sd_bus_message *m, const char *field, const char *eq) {
×
910
        return bus_append_trivial_array(m, field, eq,
×
911
                                        "as", eq);
912
}
913

914
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
2✔
915
        int r;
2✔
916

917
        assert(m);
2✔
918
        assert(field);
2✔
919
        assert(eq);
2✔
920

921
        if (isempty(eq)) {
2✔
922
                r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
×
923
                if (r < 0)
×
924
                        return bus_log_create_error(r);
×
925

926
                return 1;
927
        }
928

929
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
930
        if (r < 0)
2✔
931
                return bus_log_create_error(r);
×
932

933
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
934
        if (r < 0)
2✔
935
                return bus_log_create_error(r);
×
936

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

941
        r = sd_bus_message_open_container(m, 'a', "(iiss)");
2✔
942
        if (r < 0)
2✔
943
                return bus_log_create_error(r);
×
944

945
        for (const char *p = eq;;) {
2✔
946
                _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
4✔
947
                const char *q = NULL;
6✔
948
                int source, nfproto;
6✔
949

950
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
6✔
951
                if (r == -ENOMEM)
6✔
952
                        return log_oom();
×
953
                if (r < 0)
6✔
954
                        return log_error_errno(r, "Failed to parse %s: %m", field);
×
955
                if (r == 0)
6✔
956
                        break;
957
                if (isempty(tuple))
4✔
958
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
959

960
                q = tuple;
4✔
961
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
4✔
962
                if (r == -ENOMEM)
4✔
963
                        return log_oom();
×
964
                if (r != 4 || !isempty(q))
4✔
965
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
966

967
                assert(source_str);
4✔
968
                assert(nfproto_str);
4✔
969
                assert(table);
4✔
970
                assert(set);
4✔
971

972
                source = nft_set_source_from_string(source_str);
4✔
973
                if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
4✔
974
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
975

976
                nfproto = nfproto_from_string(nfproto_str);
4✔
977
                if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set))
4✔
978
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
979

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

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

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

996
        return 1;
997
}
998

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

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

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

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

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

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

1027
                r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
92✔
1028
                if (r == -ENOMEM)
92✔
1029
                        return log_oom();
×
1030
                if (r < 0)
92✔
1031
                        return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1032
                if (r == 0 || !p)
92✔
1033
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1034

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

1039
                r = sd_bus_message_open_container(m, 'r', "say");
92✔
1040
                if (r < 0)
92✔
1041
                        return bus_log_create_error(r);
×
1042

1043
                r = sd_bus_message_append(m, "s", word);
92✔
1044
                if (r < 0)
92✔
1045
                        return bus_log_create_error(r);
×
1046

1047
                if (streq(field, "SetCredentialEncrypted")) {
92✔
1048
                        _cleanup_free_ void *decoded = NULL;
2✔
1049
                        size_t decoded_size;
2✔
1050

1051
                        r = unbase64mem(p, &decoded, &decoded_size);
2✔
1052
                        if (r < 0)
2✔
1053
                                return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
×
1054

1055
                        r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
2✔
1056
                } else {
1057
                        _cleanup_free_ char *unescaped = NULL;
90✔
1058
                        ssize_t l;
90✔
1059

1060
                        l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
90✔
1061
                        if (l < 0)
90✔
1062
                                return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
×
1063

1064
                        r = sd_bus_message_append_array(m, 'y', unescaped, l);
90✔
1065
                }
1066
                if (r < 0)
92✔
1067
                        return bus_log_create_error(r);
×
1068

1069
                r = sd_bus_message_close_container(m);
92✔
1070
                if (r < 0)
92✔
1071
                        return bus_log_create_error(r);
×
1072

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

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

1082
        r = sd_bus_message_close_container(m);
92✔
1083
        if (r < 0)
92✔
1084
                return bus_log_create_error(r);
×
1085

1086
        return 1;
1087
}
1088

1089
static int bus_append_load_credential(sd_bus_message *m, const char *field, const char *eq) {
18✔
1090
        int r;
18✔
1091

1092
        r = sd_bus_message_open_container(m, 'r', "sv");
18✔
1093
        if (r < 0)
18✔
1094
                return bus_log_create_error(r);
×
1095

1096
        r = sd_bus_message_append_basic(m, 's', field);
18✔
1097
        if (r < 0)
18✔
1098
                return bus_log_create_error(r);
×
1099

1100
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
18✔
1101
        if (r < 0)
18✔
1102
                return bus_log_create_error(r);
×
1103

1104
        if (isempty(eq))
18✔
1105
                r = sd_bus_message_append(m, "a(ss)", 0);
×
1106
        else {
1107
                _cleanup_free_ char *word = NULL;
18✔
1108
                const char *p = eq;
18✔
1109

1110
                r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
18✔
1111
                if (r == -ENOMEM)
18✔
1112
                        return log_oom();
×
1113
                if (r < 0)
18✔
1114
                        return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1115
                if (r == 0)
18✔
1116
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1117

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

1121
                r = sd_bus_message_append(m, "a(ss)", 1, word, p);
18✔
1122
        }
1123
        if (r < 0)
18✔
1124
                return bus_log_create_error(r);
×
1125

1126
        r = sd_bus_message_close_container(m);
18✔
1127
        if (r < 0)
18✔
1128
                return bus_log_create_error(r);
×
1129

1130
        r = sd_bus_message_close_container(m);
18✔
1131
        if (r < 0)
18✔
1132
                return bus_log_create_error(r);
×
1133

1134
        return 1;
1135
}
1136

1137
static int bus_append_import_credential(sd_bus_message *m, const char *field, const char *eq) {
12✔
1138
        int r;
12✔
1139

1140
        if (isempty(eq))
12✔
1141
                r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 0);
×
1142
        else {
1143
                _cleanup_free_ char *word = NULL;
12✔
1144
                const char *p = eq;
12✔
1145

1146
                r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
12✔
1147
                if (r == -ENOMEM)
12✔
1148
                        return log_oom();
×
1149
                if (r < 0)
12✔
1150
                        return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1151
                if (r == 0)
12✔
1152
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1153

1154
                if (!p)
12✔
1155
                        r = sd_bus_message_append(m, "(sv)", "ImportCredential", "as", 1, eq);
5✔
1156
                else {
1157
                        /* We need to send ImportCredentialEx */
1158
                        r = sd_bus_message_open_container(m, 'r', "sv");
7✔
1159
                        if (r < 0)
7✔
1160
                                return bus_log_create_error(r);
×
1161

1162
                        r = sd_bus_message_append_basic(m, 's', "ImportCredentialEx");
7✔
1163
                        if (r < 0)
7✔
1164
                                return bus_log_create_error(r);
×
1165

1166
                        r = sd_bus_message_open_container(m, 'v', "a(ss)");
7✔
1167
                        if (r < 0)
7✔
1168
                                return bus_log_create_error(r);
×
1169

1170
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
7✔
1171
                        if (r < 0)
7✔
1172
                                return bus_log_create_error(r);
×
1173

1174
                        r = sd_bus_message_close_container(m);
7✔
1175
                        if (r < 0)
7✔
1176
                                return bus_log_create_error(r);
×
1177

1178
                        r = sd_bus_message_close_container(m);
7✔
1179
                }
1180
        }
1181
        if (r < 0)
12✔
1182
                return bus_log_create_error(r);
×
1183

1184
        return 1;
1185
}
1186

1187
static int bus_append_log_extra_fields(sd_bus_message *m, const char *field, const char *eq) {
474✔
1188
        int r;
474✔
1189

1190
        r = sd_bus_message_open_container(m, 'r', "sv");
474✔
1191
        if (r < 0)
474✔
1192
                return bus_log_create_error(r);
×
1193

1194
        r = sd_bus_message_append_basic(m, 's', field);
474✔
1195
        if (r < 0)
474✔
1196
                return bus_log_create_error(r);
×
1197

1198
        r = sd_bus_message_open_container(m, 'v', "aay");
474✔
1199
        if (r < 0)
474✔
1200
                return bus_log_create_error(r);
×
1201

1202
        r = sd_bus_message_open_container(m, 'a', "ay");
474✔
1203
        if (r < 0)
474✔
1204
                return bus_log_create_error(r);
×
1205

1206
        r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
474✔
1207
        if (r < 0)
474✔
1208
                return bus_log_create_error(r);
×
1209

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

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

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

1222
        return 1;
1223
}
1224

1225
static int bus_append_log_filter_patterns(sd_bus_message *m, const char *field, const char *eq) {
×
1226
        int r;
×
1227

1228
        r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
×
1229
                                  eq[0] != '~',
1230
                                  eq[0] != '~' ? eq : eq + 1);
×
1231
        if (r < 0)
×
1232
                return bus_log_create_error(r);
×
1233

1234
        return 1;
1235
}
1236

1237
static int bus_append_standard_inputs(sd_bus_message *m, const char *field, const char *eq) {
47✔
1238
        const char *n, *appended;
47✔
1239
        int r;
47✔
1240

1241
        if ((n = startswith(eq, "fd:"))) {
47✔
1242
                appended = strjoina(field, "FileDescriptorName");
×
1243
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
×
1244
        } else if ((n = startswith(eq, "file:"))) {
47✔
1245
                appended = strjoina(field, "File");
25✔
1246
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
5✔
1247
        } else if ((n = startswith(eq, "append:"))) {
42✔
1248
                appended = strjoina(field, "FileToAppend");
10✔
1249
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
2✔
1250
        } else if ((n = startswith(eq, "truncate:"))) {
40✔
1251
                appended = strjoina(field, "FileToTruncate");
15✔
1252
                r = sd_bus_message_append(m, "(sv)", appended, "s", n);
3✔
1253
        } else
1254
                r = sd_bus_message_append(m, "(sv)", field, "s", eq);
37✔
1255
        if (r < 0)
47✔
1256
                return bus_log_create_error(r);
×
1257

1258
        return 1;
1259
}
1260

1261
static int bus_append_standard_input_text(sd_bus_message *m, const char *field, const char *eq) {
×
1262
        _cleanup_free_ char *unescaped = NULL;
×
1263
        ssize_t l;
×
1264

1265
        l = cunescape(eq, 0, &unescaped);
×
1266
        if (l < 0)
×
1267
                return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
×
1268

1269
        if (!strextend(&unescaped, "\n"))
×
1270
                return log_oom();
×
1271

1272
        /* Note that we don't expand specifiers here, but that should be OK, as this is a
1273
         * programmatic interface anyway */
1274

1275
        return bus_append_byte_array(m, field, unescaped, l + 1);
×
1276
}
1277

1278
static int bus_append_standard_input_data(sd_bus_message *m, const char *field, const char *eq) {
1✔
1279
        _cleanup_free_ void *decoded = NULL;
1✔
1280
        size_t sz;
1✔
1281
        int r;
1✔
1282

1283
        r = unbase64mem(eq, &decoded, &sz);
1✔
1284
        if (r < 0)
1✔
1285
                return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
×
1286

1287
        return bus_append_byte_array(m, field, decoded, sz);
1✔
1288
}
1289

1290
static int bus_try_append_resource_limit(sd_bus_message *m, const char *field, const char *eq) {
248✔
1291
        int r;
248✔
1292

1293
        const char *suffix = startswith(field, "Limit");
248✔
1294
        if (!suffix)
248✔
1295
                return 0;
248✔
1296

1297
        int rl = rlimit_from_string(suffix);
24✔
1298
        if (rl < 0)
24✔
1299
                return log_error_errno(rl, "Unknown setting '%s'.", field);
×
1300

1301
        struct rlimit l;
24✔
1302
        r = rlimit_parse(rl, eq, &l);
24✔
1303
        if (r < 0)
24✔
1304
                return log_error_errno(r, "Failed to parse resource limit: %s", eq);
×
1305

1306
        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
24✔
1307
        if (r < 0)
24✔
1308
                return bus_log_create_error(r);
×
1309

1310
        const char *sn = strjoina(field, "Soft");
120✔
1311
        r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
24✔
1312
        if (r < 0)
24✔
1313
                return bus_log_create_error(r);
×
1314

1315
        return 1;
1316
}
1317

1318
static void dump_resource_limits(void) {
11✔
1319
        rlimits_list("Limit");
11✔
1320
}
11✔
1321

1322
static int bus_append_string_with_ignore(sd_bus_message *m, const char *field, const char *eq) {
×
1323
        int ignore = 0;
×
1324
        const char *s = eq;
×
1325
        int r;
×
1326

1327
        if (eq[0] == '-') {
×
1328
                ignore = 1;
×
1329
                s = eq + 1;
×
1330
        }
1331

1332
        r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
×
1333
        if (r < 0)
×
1334
                return bus_log_create_error(r);
×
1335

1336
        return 1;
1337
}
1338

1339
static int bus_append_capabilities(sd_bus_message *m, const char *field, const char *eq) {
6✔
1340
        uint64_t sum = 0;
6✔
1341
        bool invert = false;
6✔
1342
        const char *p = eq;
6✔
1343
        int r;
6✔
1344

1345
        if (*p == '~') {
6✔
1346
                invert = true;
3✔
1347
                p++;
3✔
1348
        }
1349

1350
        r = capability_set_from_string(p, &sum);
6✔
1351
        if (r < 0)
6✔
1352
                return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
×
1353

1354
        sum = invert ? ~sum : sum;
6✔
1355

1356
        r = sd_bus_message_append(m, "(sv)", field, "t", sum);
6✔
1357
        if (r < 0)
6✔
1358
                return bus_log_create_error(r);
×
1359

1360
        return 1;
1361
}
1362

1363
static int bus_append_cpu_affinity(sd_bus_message *m, const char *field, const char *eq) {
1✔
1364
        int r;
1✔
1365

1366
        if (streq_ptr(eq, "numa")) {
1✔
1367
                r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1✔
1368
                if (r < 0)
1✔
1369
                        return bus_log_create_error(r);
×
1370
                return r;
1371
        }
1372

1373
        return bus_append_parse_cpu_set(m, field, eq);
×
1374
}
1375

1376
static int bus_append_numa_mask(sd_bus_message *m, const char *field, const char *eq) {
6✔
1377
        _cleanup_(cpu_set_done) CPUSet nodes = {};
×
1378
        _cleanup_free_ uint8_t *array = NULL;
6✔
1379
        size_t allocated;
6✔
1380
        int r;
6✔
1381

1382
        if (eq && streq(eq, "all")) {
6✔
1383
                r = numa_mask_add_all(&nodes);
×
1384
                if (r < 0)
×
1385
                        return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
×
1386
        } else {
1387
                r = parse_cpu_set(eq, &nodes);
6✔
1388
                if (r < 0)
6✔
1389
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1390
        }
1391

1392
        r = cpu_set_to_dbus(&nodes, &array, &allocated);
6✔
1393
        if (r < 0)
6✔
1394
                return log_error_errno(r, "Failed to serialize %s: %m", field);
×
1395

1396
        return bus_append_byte_array(m, field, array, allocated);
6✔
1397
}
1398

1399
static int bus_append_filter_list(sd_bus_message *m, const char *field, const char *eq) {
7✔
1400
        int allow_list = 1;
7✔
1401
        const char *p = eq;
7✔
1402
        int r;
7✔
1403

1404
        if (*p == '~') {
7✔
1405
                allow_list = 0;
3✔
1406
                p++;
3✔
1407
        }
1408

1409
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
7✔
1410
        if (r < 0)
7✔
1411
                return bus_log_create_error(r);
7✔
1412

1413
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
7✔
1414
        if (r < 0)
7✔
1415
                return bus_log_create_error(r);
×
1416

1417
        r = sd_bus_message_open_container(m, 'v', "(bas)");
7✔
1418
        if (r < 0)
7✔
1419
                return bus_log_create_error(r);
×
1420

1421
        r = sd_bus_message_open_container(m, 'r', "bas");
7✔
1422
        if (r < 0)
7✔
1423
                return bus_log_create_error(r);
×
1424

1425
        r = sd_bus_message_append_basic(m, 'b', &allow_list);
7✔
1426
        if (r < 0)
7✔
1427
                return bus_log_create_error(r);
×
1428

1429
        r = sd_bus_message_open_container(m, 'a', "s");
7✔
1430
        if (r < 0)
7✔
1431
                return bus_log_create_error(r);
×
1432

1433
        for (;;) {
25✔
1434
                _cleanup_free_ char *word = NULL;
9✔
1435

1436
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
16✔
1437
                if (r == 0)
16✔
1438
                        break;
1439
                if (r == -ENOMEM)
9✔
1440
                        return log_oom();
×
1441
                if (r < 0)
9✔
1442
                        return log_error_errno(r, "Invalid syntax: %s", eq);
×
1443

1444
                r = sd_bus_message_append_basic(m, 's', word);
9✔
1445
                if (r < 0)
9✔
1446
                        return bus_log_create_error(r);
×
1447
        }
1448

1449
        r = sd_bus_message_close_container(m);
7✔
1450
        if (r < 0)
7✔
1451
                return bus_log_create_error(r);
×
1452

1453
        r = sd_bus_message_close_container(m);
7✔
1454
        if (r < 0)
7✔
1455
                return bus_log_create_error(r);
×
1456

1457
        r = sd_bus_message_close_container(m);
7✔
1458
        if (r < 0)
7✔
1459
                return bus_log_create_error(r);
×
1460

1461
        r = sd_bus_message_close_container(m);
7✔
1462
        if (r < 0)
7✔
1463
                return bus_log_create_error(r);
×
1464

1465
        return 1;
1466
}
1467

1468
static int bus_append_namespace_list(sd_bus_message *m, const char *field, const char *eq) {
11✔
1469
        bool invert = false;
11✔
1470
        unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
11✔
1471
        unsigned long flags;
11✔
1472
        int r;
11✔
1473

1474
        r = parse_boolean(eq);
11✔
1475
        if (r > 0)
11✔
1476
                /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1477
                 * namespaces which are retained), so RestrictNamespaces=true means we retain no
1478
                 * access to any namespaces and vice-versa. */
1479
                flags = streq(field, "RestrictNamespaces") ? 0 : all;
2✔
1480
        else if (r == 0)
9✔
1481
                flags = streq(field, "RestrictNamespaces") ? all : 0;
2✔
1482
        else {
1483
                if (eq[0] == '~') {
7✔
1484
                        invert = true;
1✔
1485
                        eq++;
1✔
1486
                }
1487

1488
                r = namespace_flags_from_string(eq, &flags);
7✔
1489
                if (r < 0)
7✔
1490
                        return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
×
1491
        }
1492

1493
        if (invert)
11✔
1494
                flags = (~flags) & all;
1✔
1495

1496
        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
11✔
1497
        if (r < 0)
11✔
1498
                return bus_log_create_error(r);
×
1499

1500
        return 1;
1501
}
1502

1503
static int bus_append_bind_paths(sd_bus_message *m, const char *field, const char *eq) {
10✔
1504
        const char *p = eq;
10✔
1505
        int r;
10✔
1506

1507
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
10✔
1508
        if (r < 0)
10✔
1509
                return bus_log_create_error(r);
10✔
1510

1511
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
10✔
1512
        if (r < 0)
10✔
1513
                return bus_log_create_error(r);
×
1514

1515
        r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
10✔
1516
        if (r < 0)
10✔
1517
                return bus_log_create_error(r);
×
1518

1519
        r = sd_bus_message_open_container(m, 'a', "(ssbt)");
10✔
1520
        if (r < 0)
10✔
1521
                return bus_log_create_error(r);
×
1522

1523
        for (;;) {
46✔
1524
                _cleanup_free_ char *source = NULL, *destination = NULL;
18✔
1525
                char *s = NULL, *d = NULL;
28✔
1526
                bool ignore_enoent = false;
28✔
1527
                uint64_t flags = MS_REC;
28✔
1528

1529
                r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
28✔
1530
                if (r < 0)
28✔
1531
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1532
                if (r == 0)
28✔
1533
                        break;
1534

1535
                s = source;
18✔
1536
                if (s[0] == '-') {
18✔
1537
                        ignore_enoent = true;
2✔
1538
                        s++;
2✔
1539
                }
1540

1541
                if (p && p[-1] == ':') {
18✔
1542
                        r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
10✔
1543
                        if (r < 0)
10✔
1544
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1545
                        if (r == 0)
10✔
1546
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1547
                                                       "Missing argument after ':': %s", eq);
1548

1549
                        d = destination;
10✔
1550

1551
                        if (p && p[-1] == ':') {
10✔
1552
                                _cleanup_free_ char *options = NULL;
6✔
1553

1554
                                r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
6✔
1555
                                if (r < 0)
6✔
1556
                                        return log_error_errno(r, "Failed to parse argument: %m");
×
1557

1558
                                if (isempty(options) || streq(options, "rbind"))
16✔
1559
                                        flags = MS_REC;
1560
                                else if (streq(options, "norbind"))
4✔
1561
                                        flags = 0;
1562
                                else
1563
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1564
                                                               "Unknown options: %s", eq);
1565
                        }
1566
                } else
1567
                        d = s;
1568

1569
                r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
18✔
1570
                if (r < 0)
18✔
1571
                        return bus_log_create_error(r);
×
1572
        }
1573

1574
        r = sd_bus_message_close_container(m);
10✔
1575
        if (r < 0)
10✔
1576
                return bus_log_create_error(r);
×
1577

1578
        r = sd_bus_message_close_container(m);
10✔
1579
        if (r < 0)
10✔
1580
                return bus_log_create_error(r);
×
1581

1582
        r = sd_bus_message_close_container(m);
10✔
1583
        if (r < 0)
10✔
1584
                return bus_log_create_error(r);
×
1585

1586
        return 1;
1587
}
1588

1589
static int bus_append_temporary_file_system(sd_bus_message *m, const char *field, const char *eq) {
49✔
1590
        const char *p = eq;
49✔
1591
        int r;
49✔
1592

1593
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
49✔
1594
        if (r < 0)
49✔
1595
                return bus_log_create_error(r);
49✔
1596

1597
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
49✔
1598
        if (r < 0)
49✔
1599
                return bus_log_create_error(r);
×
1600

1601
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
49✔
1602
        if (r < 0)
49✔
1603
                return bus_log_create_error(r);
×
1604

1605
        r = sd_bus_message_open_container(m, 'a', "(ss)");
49✔
1606
        if (r < 0)
49✔
1607
                return bus_log_create_error(r);
×
1608

1609
        for (;;) {
151✔
1610
                _cleanup_free_ char *word = NULL, *path = NULL;
51✔
1611
                const char *w;
100✔
1612

1613
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
100✔
1614
                if (r < 0)
100✔
1615
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1616
                if (r == 0)
100✔
1617
                        break;
1618

1619
                w = word;
51✔
1620
                r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
51✔
1621
                if (r < 0)
51✔
1622
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1623
                if (r == 0)
51✔
1624
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1625
                                               "Failed to parse argument: %s", p);
1626

1627
                r = sd_bus_message_append(m, "(ss)", path, w);
51✔
1628
                if (r < 0)
51✔
1629
                        return bus_log_create_error(r);
×
1630
        }
1631

1632
        r = sd_bus_message_close_container(m);
49✔
1633
        if (r < 0)
49✔
1634
                return bus_log_create_error(r);
×
1635

1636
        r = sd_bus_message_close_container(m);
49✔
1637
        if (r < 0)
49✔
1638
                return bus_log_create_error(r);
×
1639

1640
        r = sd_bus_message_close_container(m);
49✔
1641
        if (r < 0)
49✔
1642
                return bus_log_create_error(r);
×
1643

1644
        return 1;
1645
}
1646

1647
static int bus_append_root_hash(sd_bus_message *m, const char *field, const char *eq) {
12✔
1648
        _cleanup_free_ void *roothash_decoded = NULL;
12✔
1649
        size_t roothash_decoded_size = 0;
12✔
1650
        int r;
12✔
1651

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

1656
        /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1657
        r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
11✔
1658
        if (r < 0)
11✔
1659
                return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
×
1660
        if (roothash_decoded_size < sizeof(sd_id128_t))
11✔
1661
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
×
1662

1663
        return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
11✔
1664
}
1665

1666
static int bus_append_root_hash_signature(sd_bus_message *m, const char *field, const char *eq) {
×
1667
        char *value;
×
1668
        _cleanup_free_ void *roothash_sig_decoded = NULL;
×
1669
        size_t roothash_sig_decoded_size = 0;
×
1670
        int r;
×
1671

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

1676
        if (!(value = startswith(eq, "base64:")))
×
1677
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1678
                                       "Failed to decode %s=%s: neither a path nor starts with 'base64:'.",
1679
                                       field, eq);
1680

1681
        /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1682
        r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
×
1683
        if (r < 0)
×
1684
                return log_error_errno(r, "Failed to decode %s=%s: %m", field, eq);
×
1685

1686
        return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
×
1687
}
1688

1689
static int bus_append_root_image_options(sd_bus_message *m, const char *field, const char *eq) {
2✔
1690
        _cleanup_strv_free_ char **l = NULL;
2✔
1691
        const char *p = eq;
2✔
1692
        int r;
2✔
1693

1694
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
1695
        if (r < 0)
2✔
1696
                return bus_log_create_error(r);
×
1697

1698
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
1699
        if (r < 0)
2✔
1700
                return bus_log_create_error(r);
×
1701

1702
        r = sd_bus_message_open_container(m, 'v', "a(ss)");
2✔
1703
        if (r < 0)
2✔
1704
                return bus_log_create_error(r);
×
1705

1706
        r = sd_bus_message_open_container(m, 'a', "(ss)");
2✔
1707
        if (r < 0)
2✔
1708
                return bus_log_create_error(r);
×
1709

1710
        r = strv_split_colon_pairs(&l, p);
2✔
1711
        if (r < 0)
2✔
1712
                return log_error_errno(r, "Failed to parse argument: %m");
×
1713

1714
        STRV_FOREACH_PAIR(first, second, l) {
7✔
1715
                r = sd_bus_message_append(m, "(ss)",
15✔
1716
                                          !isempty(*second) ? *first : "root",
5✔
1717
                                          !isempty(*second) ? *second : *first);
5✔
1718
                if (r < 0)
5✔
1719
                        return bus_log_create_error(r);
×
1720
        }
1721

1722
        r = sd_bus_message_close_container(m);
2✔
1723
        if (r < 0)
2✔
1724
                return bus_log_create_error(r);
×
1725

1726
        r = sd_bus_message_close_container(m);
2✔
1727
        if (r < 0)
2✔
1728
                return bus_log_create_error(r);
×
1729

1730
        r = sd_bus_message_close_container(m);
2✔
1731
        if (r < 0)
2✔
1732
                return bus_log_create_error(r);
×
1733

1734
        return 1;
1735
}
1736

1737
static int bus_append_mount_images(sd_bus_message *m, const char *field, const char *eq) {
11✔
1738
        const char *p = eq;
11✔
1739
        int r;
11✔
1740

1741
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
11✔
1742
        if (r < 0)
11✔
1743
                return bus_log_create_error(r);
11✔
1744

1745
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
11✔
1746
        if (r < 0)
11✔
1747
                return bus_log_create_error(r);
×
1748

1749
        r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
11✔
1750
        if (r < 0)
11✔
1751
                return bus_log_create_error(r);
×
1752

1753
        r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
11✔
1754
        if (r < 0)
11✔
1755
                return bus_log_create_error(r);
×
1756

1757
        for (;;) {
29✔
1758
                _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
18✔
1759
                const char *q = NULL, *source = NULL;
29✔
1760
                bool permissive = false;
29✔
1761

1762
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
29✔
1763
                if (r < 0)
29✔
1764
                        return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
×
1765
                if (r == 0)
29✔
1766
                        break;
1767

1768
                q = tuple;
18✔
1769
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
18✔
1770
                if (r < 0)
18✔
1771
                        return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
×
1772
                if (r == 0)
18✔
1773
                        continue;
×
1774

1775
                source = first;
18✔
1776
                if (source[0] == '-') {
18✔
1777
                        permissive = true;
×
1778
                        source++;
×
1779
                }
1780

1781
                if (isempty(second))
18✔
1782
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1783
                                               "Missing argument after ':' for %s: %s", field, eq);
1784

1785
                r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
18✔
1786
                if (r < 0)
18✔
1787
                        return bus_log_create_error(r);
×
1788

1789
                r = sd_bus_message_append(m, "ssb", source, second, permissive);
18✔
1790
                if (r < 0)
18✔
1791
                        return bus_log_create_error(r);
×
1792

1793
                r = sd_bus_message_open_container(m, 'a', "(ss)");
18✔
1794
                if (r < 0)
18✔
1795
                        return bus_log_create_error(r);
×
1796

1797
                for (;;) {
22✔
1798
                        _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2✔
1799

1800
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
20✔
1801
                        if (r < 0)
20✔
1802
                                return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
×
1803
                        if (r == 0)
20✔
1804
                                break;
1805
                        /* Single set of options, applying to the root partition/single filesystem */
1806
                        if (r == 1) {
5✔
1807
                                r = sd_bus_message_append(m, "(ss)", "root", partition);
3✔
1808
                                if (r < 0)
3✔
1809
                                        return bus_log_create_error(r);
×
1810

1811
                                break;
1812
                        }
1813

1814
                        r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2✔
1815
                        if (r < 0)
2✔
1816
                                return bus_log_create_error(r);
×
1817
                }
1818

1819
                r = sd_bus_message_close_container(m);
18✔
1820
                if (r < 0)
18✔
1821
                        return bus_log_create_error(r);
×
1822

1823
                r = sd_bus_message_close_container(m);
18✔
1824
                if (r < 0)
18✔
1825
                        return bus_log_create_error(r);
×
1826
        }
1827

1828
        r = sd_bus_message_close_container(m);
11✔
1829
        if (r < 0)
11✔
1830
                return bus_log_create_error(r);
×
1831

1832
        r = sd_bus_message_close_container(m);
11✔
1833
        if (r < 0)
11✔
1834
                return bus_log_create_error(r);
×
1835

1836
        r = sd_bus_message_close_container(m);
11✔
1837
        if (r < 0)
11✔
1838
                return bus_log_create_error(r);
×
1839

1840
        return 1;
1841
}
1842

1843
static int bus_append_extension_images(sd_bus_message *m, const char *field, const char *eq) {
20✔
1844
        const char *p = eq;
20✔
1845
        int r;
20✔
1846

1847
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20✔
1848
        if (r < 0)
20✔
1849
                return bus_log_create_error(r);
20✔
1850

1851
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
20✔
1852
        if (r < 0)
20✔
1853
                return bus_log_create_error(r);
×
1854

1855
        r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
20✔
1856
        if (r < 0)
20✔
1857
                return bus_log_create_error(r);
×
1858

1859
        r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
20✔
1860
        if (r < 0)
20✔
1861
                return bus_log_create_error(r);
×
1862

1863
        for (;;) {
48✔
1864
                _cleanup_free_ char *source = NULL, *tuple = NULL;
28✔
1865
                const char *q = NULL, *s = NULL;
48✔
1866
                bool permissive = false;
48✔
1867

1868
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
48✔
1869
                if (r < 0)
48✔
1870
                        return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
×
1871
                if (r == 0)
48✔
1872
                        break;
1873

1874
                q = tuple;
28✔
1875
                r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
28✔
1876
                if (r < 0)
28✔
1877
                        return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
×
1878
                if (r == 0)
28✔
1879
                        continue;
×
1880

1881
                s = source;
28✔
1882
                if (s[0] == '-') {
28✔
1883
                        permissive = true;
2✔
1884
                        s++;
2✔
1885
                }
1886

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

1891
                r = sd_bus_message_append(m, "sb", s, permissive);
28✔
1892
                if (r < 0)
28✔
1893
                        return bus_log_create_error(r);
×
1894

1895
                r = sd_bus_message_open_container(m, 'a', "(ss)");
28✔
1896
                if (r < 0)
28✔
1897
                        return bus_log_create_error(r);
×
1898

1899
                for (;;) {
28✔
1900
                        _cleanup_free_ char *partition = NULL, *mount_options = NULL;
×
1901

1902
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
28✔
1903
                        if (r < 0)
28✔
1904
                                return log_error_errno(r, "Failed to parse %s property: %s", field, eq);
×
1905
                        if (r == 0)
28✔
1906
                                break;
1907
                        /* Single set of options, applying to the root partition/single filesystem */
1908
                        if (r == 1) {
×
1909
                                r = sd_bus_message_append(m, "(ss)", "root", partition);
×
1910
                                if (r < 0)
×
1911
                                        return bus_log_create_error(r);
×
1912

1913
                                break;
1914
                        }
1915

1916
                        r = sd_bus_message_append(m, "(ss)", partition, mount_options);
×
1917
                        if (r < 0)
×
1918
                                return bus_log_create_error(r);
×
1919
                }
1920

1921
                r = sd_bus_message_close_container(m);
28✔
1922
                if (r < 0)
28✔
1923
                        return bus_log_create_error(r);
×
1924

1925
                r = sd_bus_message_close_container(m);
28✔
1926
                if (r < 0)
28✔
1927
                        return bus_log_create_error(r);
×
1928
        }
1929

1930
        r = sd_bus_message_close_container(m);
20✔
1931
        if (r < 0)
20✔
1932
                return bus_log_create_error(r);
×
1933

1934
        r = sd_bus_message_close_container(m);
20✔
1935
        if (r < 0)
20✔
1936
                return bus_log_create_error(r);
×
1937

1938
        r = sd_bus_message_close_container(m);
20✔
1939
        if (r < 0)
20✔
1940
                return bus_log_create_error(r);
×
1941

1942
        return 1;
1943
}
1944

1945
static int bus_append_directory(sd_bus_message *m, const char *field, const char *eq) {
183✔
1946
        _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
183✔
1947
        const char *p = eq;
183✔
1948
        int r;
424✔
1949

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

1954
        for (;;) {
665✔
1955
                _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
241✔
1956

1957
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
424✔
1958
                if (r < 0)
424✔
1959
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1960
                if (r == 0)
424✔
1961
                        break;
1962

1963
                const char *t = tuple;
241✔
1964
                r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
241✔
1965
                if (r <= 0)
241✔
1966
                        return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
×
1967

1968
                path_simplify(source);
241✔
1969

1970
                if (isempty(dest) && isempty(flags)) {
278✔
1971
                        r = strv_consume(&sources, TAKE_PTR(source));
110✔
1972
                        if (r < 0)
110✔
1973
                                return bus_log_create_error(r);
×
1974
                } else if (isempty(flags)) {
131✔
1975
                        path_simplify(dest);
57✔
1976
                        r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
57✔
1977
                        if (r < 0)
57✔
1978
                                return log_oom();
×
1979
                } else {
1980
                        ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
74✔
1981
                        if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
74✔
1982
                                return log_error_errno(r, "Failed to parse flags: %s", flags);
×
1983

1984
                        if (!isempty(dest)) {
74✔
1985
                                path_simplify(dest);
37✔
1986
                                r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
37✔
1987
                        } else
1988
                                r = strv_consume(&sources_ro, TAKE_PTR(source));
37✔
1989
                        if (r < 0)
74✔
1990
                                return log_oom();
×
1991
                }
1992
        }
1993

1994
        if (!strv_isempty(sources)) {
183✔
1995
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
95✔
1996
                if (r < 0)
95✔
1997
                        return bus_log_create_error(r);
×
1998

1999
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
95✔
2000
                if (r < 0)
95✔
2001
                        return bus_log_create_error(r);
×
2002

2003
                r = sd_bus_message_open_container(m, 'v', "as");
95✔
2004
                if (r < 0)
95✔
2005
                        return bus_log_create_error(r);
×
2006

2007
                r = sd_bus_message_append_strv(m, sources);
95✔
2008
                if (r < 0)
95✔
2009
                        return bus_log_create_error(r);
×
2010

2011
                r = sd_bus_message_close_container(m);
95✔
2012
                if (r < 0)
95✔
2013
                        return bus_log_create_error(r);
×
2014

2015
                r = sd_bus_message_close_container(m);
95✔
2016
                if (r < 0)
95✔
2017
                        return bus_log_create_error(r);
×
2018
        }
2019

2020
        /* For State and Runtime directories we support an optional destination parameter, which
2021
         * will be used to create a symlink to the source. But it is new so we cannot change the
2022
         * old DBUS signatures, so append a new message type. */
2023
        if (!strv_isempty(symlinks) || !strv_isempty(symlinks_ro) || !strv_isempty(sources_ro)) {
266✔
2024
                const char *symlink_field;
83✔
2025

2026
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
83✔
2027
                if (r < 0)
83✔
2028
                        return bus_log_create_error(r);
×
2029

2030
                if (streq(field, "StateDirectory"))
83✔
2031
                        symlink_field = "StateDirectorySymlink";
2032
                else if (streq(field, "RuntimeDirectory"))
62✔
2033
                        symlink_field = "RuntimeDirectorySymlink";
2034
                else if (streq(field, "CacheDirectory"))
38✔
2035
                        symlink_field = "CacheDirectorySymlink";
2036
                else if (streq(field, "LogsDirectory"))
19✔
2037
                        symlink_field = "LogsDirectorySymlink";
2038
                else
2039
                        assert_not_reached();
×
2040

2041
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
83✔
2042
                if (r < 0)
83✔
2043
                        return bus_log_create_error(r);
×
2044

2045
                r = sd_bus_message_open_container(m, 'v', "a(sst)");
83✔
2046
                if (r < 0)
83✔
2047
                        return bus_log_create_error(r);
×
2048

2049
                r = sd_bus_message_open_container(m, 'a', "(sst)");
83✔
2050
                if (r < 0)
83✔
2051
                        return bus_log_create_error(r);
×
2052

2053
                STRV_FOREACH_PAIR(source, destination, symlinks) {
140✔
2054
                        r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
57✔
2055
                        if (r < 0)
57✔
2056
                                return bus_log_create_error(r);
×
2057
                }
2058

2059
                STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
120✔
2060
                        r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2061
                        if (r < 0)
37✔
2062
                                return bus_log_create_error(r);
×
2063
                }
2064

2065
                STRV_FOREACH(source, sources_ro) {
120✔
2066
                        r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2067
                        if (r < 0)
37✔
2068
                                return bus_log_create_error(r);
×
2069
                }
2070

2071
                r = sd_bus_message_close_container(m);
83✔
2072
                if (r < 0)
83✔
2073
                        return bus_log_create_error(r);
×
2074

2075
                r = sd_bus_message_close_container(m);
83✔
2076
                if (r < 0)
83✔
2077
                        return bus_log_create_error(r);
×
2078

2079
                r = sd_bus_message_close_container(m);
83✔
2080
                if (r < 0)
83✔
2081
                        return bus_log_create_error(r);
×
2082
        }
2083

2084
        return 1;
2085
}
2086

2087
static int bus_append_protect_hostname(sd_bus_message *m, const char *field, const char *eq) {
22✔
2088
        int r;
22✔
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);
22✔
2094
        if (r >= 0)
22✔
2095
                r = sd_bus_message_append(m, "(sv)", "ProtectHostname", "b", r);
5✔
2096
        else {
2097
                const char *colon = strchr(eq, ':');
17✔
2098
                if (colon) {
17✔
2099
                        if (isempty(colon + 1))
12✔
2100
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
22✔
2101

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

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

2113
        return 1;
2114
}
2115

2116
static int bus_append_paths(sd_bus_message *m, const char *field, const char *eq) {
3✔
2117
        return bus_append_trivial_array(m, "Paths", eq,
6✔
2118
                                        "a(ss)", field, eq);
2119
}
2120

2121
static int bus_append_exit_status(sd_bus_message *m, const char *field, const char *eq) {
×
2122
        _cleanup_free_ int *status = NULL, *signal = NULL;
×
2123
        size_t n_status = 0, n_signal = 0;
×
2124
        int r;
×
2125

2126
        for (const char *p = eq;;) {
×
2127
                _cleanup_free_ char *word = NULL;
×
2128

2129
                r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
×
2130
                if (r == 0)
×
2131
                        break;
2132
                if (r == -ENOMEM)
×
2133
                        return log_oom();
×
2134
                if (r < 0)
×
2135
                        return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
×
2136

2137
                /* We need to call exit_status_from_string() first, because we want
2138
                 * to parse numbers as exit statuses, not signals. */
2139

2140
                r = exit_status_from_string(word);
×
2141
                if (r >= 0) {
×
2142
                        assert(r >= 0 && r < 256);
×
2143

2144
                        if (!GREEDY_REALLOC(status, n_status + 1))
×
2145
                                return log_oom();
×
2146

2147
                        status[n_status++] = r;
×
2148

2149
                } else if ((r = signal_from_string(word)) >= 0) {
×
2150
                        if (!GREEDY_REALLOC(signal, n_signal + 1))
×
2151
                                return log_oom();
×
2152

2153
                        signal[n_signal++] = r;
×
2154

2155
                } else
2156
                        /* original r from exit_status_to_string() */
2157
                        return log_error_errno(r, "Invalid status or signal %s in %s: %m",
×
2158
                                               word, field);
2159
        }
2160

2161
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
2162
        if (r < 0)
×
2163
                return bus_log_create_error(r);
×
2164

2165
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
2166
        if (r < 0)
×
2167
                return bus_log_create_error(r);
×
2168

2169
        r = sd_bus_message_open_container(m, 'v', "(aiai)");
×
2170
        if (r < 0)
×
2171
                return bus_log_create_error(r);
×
2172

2173
        r = sd_bus_message_open_container(m, 'r', "aiai");
×
2174
        if (r < 0)
×
2175
                return bus_log_create_error(r);
×
2176

2177
        r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
×
2178
        if (r < 0)
×
2179
                return bus_log_create_error(r);
×
2180

2181
        r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
×
2182
        if (r < 0)
×
2183
                return bus_log_create_error(r);
×
2184

2185
        r = sd_bus_message_close_container(m);
×
2186
        if (r < 0)
×
2187
                return bus_log_create_error(r);
×
2188

2189
        r = sd_bus_message_close_container(m);
×
2190
        if (r < 0)
×
2191
                return bus_log_create_error(r);
×
2192

2193
        r = sd_bus_message_close_container(m);
×
2194
        if (r < 0)
×
2195
                return bus_log_create_error(r);
×
2196

2197
        return 1;
2198
}
2199

2200
static int bus_append_action_exit_status(sd_bus_message *m, const char *field, const char *eq) {
×
2201
        int r;
×
2202

2203
        if (isempty(eq))
×
2204
                r = sd_bus_message_append(m, "(sv)", field, "i", -1);
×
2205
        else {
2206
                uint8_t u;
×
2207

2208
                r = safe_atou8(eq, &u);
×
2209
                if (r < 0)
×
2210
                        return log_error_errno(r, "Failed to parse %s=%s", field, eq);
×
2211

2212
                r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
×
2213
        }
2214
        if (r < 0)
×
2215
                return bus_log_create_error(r);
×
2216

2217
        return 1;
2218
}
2219

2220
static int bus_append_listen(sd_bus_message *m, const char *field, const char *eq) {
2✔
2221
        const char *p = ASSERT_PTR(startswith(field, "Listen"));
2✔
2222

2223
        return bus_append_trivial_array(m, "Listen", eq,
4✔
2224
                                        "a(ss)", p, eq);
2225
}
2226

2227
static int bus_append_timers_monotonic(sd_bus_message *m, const char *field, const char *eq) {
17✔
2228
        int r;
17✔
2229

2230
        if (isempty(eq))
17✔
2231
                r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
5✔
2232
        else {
2233
                usec_t t;
12✔
2234
                r = parse_sec(eq, &t);
12✔
2235
                if (r < 0)
12✔
2236
                        return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
5✔
2237

2238
                r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
7✔
2239
        }
2240
        if (r < 0)
12✔
2241
                return bus_log_create_error(r);
×
2242

2243
        return 1;
2244
}
2245

2246
static int bus_append_timers_calendar(sd_bus_message *m, const char *field, const char *eq) {
2✔
2247
        return bus_append_trivial_array(m, "TimersCalendar", eq,
4✔
2248
                                        "a(ss)", field, eq);
2249
}
2250

2251
static int bus_append_timeout_sec(sd_bus_message *m, const char *field, const char *eq) {
×
2252
        int r;
×
2253

2254
        r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
×
2255
        if (r < 0)
×
2256
                return r;
2257

2258
        return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
×
2259
}
2260

2261
static int bus_try_append_condition(sd_bus_message *m, const char *field, const char *eq) {
2✔
2262
        ConditionType t = condition_type_from_string(field);
2✔
2263
        bool is_condition = t >= 0;
2✔
2264

2265
        if (!is_condition) {
2✔
2266
                t = assert_type_from_string(field);
2✔
2267
                if (t < 0)
2✔
2268
                        return 0;
2269
        }
2270

2271
        const char *p = eq;
2✔
2272

2273
        int trigger = p && *p == '|';
2✔
2274
        if (trigger)
2✔
2275
                p++;
×
2276

2277
        int negate = p && *p == '!';
2✔
2278
        if (negate)
×
2279
                p++;
×
2280

2281
        return bus_append_trivial_array(m,
6✔
2282
                                        is_condition ? "Conditions" : "Asserts",
2283
                                        eq,
2284
                                        "a(sbbs)",
2285
                                        field, trigger, negate, p);
2286
}
2287

2288
static void dump_conditions(void) {
27✔
2289
        condition_types_list();
27✔
2290
        assert_types_list();
27✔
2291
}
27✔
2292

2293
static int bus_try_append_unit_dependency(sd_bus_message *m, const char *field, const char *eq) {
22✔
2294
        if (unit_dependency_from_string(field) < 0)
22✔
2295
                return 0;
2296

2297
        return bus_append_strv(m, field, eq);
20✔
2298
}
2299

2300
typedef struct BusProperty {
2301
        const char *name;
2302
        int (*convert)(sd_bus_message *m, const char *field, const char *eq);
2303
        void (*dump)(void);
2304
} BusProperty;
2305

2306
static const BusProperty cgroup_properties[] = {
2307
        { "DevicePolicy",                          bus_append_string                             },
2308
        { "Slice",                                 bus_append_string                             },
2309
        { "ManagedOOMSwap",                        bus_append_string                             },
2310
        { "ManagedOOMMemoryPressure",              bus_append_string                             },
2311
        { "ManagedOOMPreference",                  bus_append_string                             },
2312
        { "MemoryPressureWatch",                   bus_append_string                             },
2313
        { "DelegateSubgroup",                      bus_append_string                             },
2314
        { "ManagedOOMMemoryPressureLimit",         bus_append_parse_permyriad                    },
2315
        { "MemoryAccounting",                      bus_append_parse_boolean                      },
2316
        { "MemoryZSwapWriteback",                  bus_append_parse_boolean                      },
2317
        { "IOAccounting",                          bus_append_parse_boolean                      },
2318
        { "TasksAccounting",                       bus_append_parse_boolean                      },
2319
        { "IPAccounting",                          bus_append_parse_boolean                      },
2320
        { "CoredumpReceive",                       bus_append_parse_boolean                      },
2321
        { "CPUWeight",                             bus_append_cg_cpu_weight_parse                },
2322
        { "StartupCPUWeight",                      bus_append_cg_cpu_weight_parse                },
2323
        { "IOWeight",                              bus_append_cg_weight_parse                    },
2324
        { "StartupIOWeight",                       bus_append_cg_weight_parse                    },
2325
        { "AllowedCPUs",                           bus_append_parse_cpu_set                      },
2326
        { "StartupAllowedCPUs",                    bus_append_parse_cpu_set                      },
2327
        { "AllowedMemoryNodes",                    bus_append_parse_cpu_set                      },
2328
        { "StartupAllowedMemoryNodes",             bus_append_parse_cpu_set                      },
2329
        { "DisableControllers",                    bus_append_strv                               },
2330
        { "Delegate",                              bus_append_parse_delegate                     },
2331
        { "MemoryMin",                             bus_append_parse_resource_limit               },
2332
        { "DefaultMemoryLow",                      bus_append_parse_resource_limit               },
2333
        { "DefaultMemoryMin",                      bus_append_parse_resource_limit               },
2334
        { "MemoryLow",                             bus_append_parse_resource_limit               },
2335
        { "MemoryHigh",                            bus_append_parse_resource_limit               },
2336
        { "MemoryMax",                             bus_append_parse_resource_limit               },
2337
        { "MemorySwapMax",                         bus_append_parse_resource_limit               },
2338
        { "MemoryZSwapMax",                        bus_append_parse_resource_limit               },
2339
        { "TasksMax",                              bus_append_parse_resource_limit               },
2340
        { "CPUQuota",                              bus_append_parse_cpu_quota                    },
2341
        { "CPUQuotaPeriodSec",                     bus_append_parse_sec_rename_infinity          },
2342
        { "DeviceAllow",                           bus_append_parse_device_allow                 },
2343
        { "IODeviceWeight",                        bus_append_parse_io_device_weight             },
2344
        { "IODeviceLatencyTargetSec",              bus_append_parse_io_device_latency            },
2345
        { "IPAddressAllow",                        bus_append_parse_ip_address_filter            },
2346
        { "IPAddressDeny",                         bus_append_parse_ip_address_filter            },
2347
        { "IPIngressFilterPath",                   bus_append_ip_filter_path                     },
2348
        { "IPEgressFilterPath",                    bus_append_ip_filter_path                     },
2349
        { "BPFProgram",                            bus_append_bpf_program                        },
2350
        { "SocketBindAllow",                       bus_append_socket_filter                      },
2351
        { "SocketBindDeny",                        bus_append_socket_filter                      },
2352
        { "MemoryPressureThresholdSec",            bus_append_parse_sec_rename                   },
2353
        { "NFTSet",                                bus_append_nft_set                            },
2354

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

2359
        { "MemoryLimit",                           warn_deprecated                               },
2360
        { "CPUShares",                             warn_deprecated                               },
2361
        { "StartupCPUShares",                      warn_deprecated                               },
2362
        { "BlockIOAccounting",                     warn_deprecated                               },
2363
        { "BlockIOWeight",                         warn_deprecated                               },
2364
        { "StartupBlockIOWeight",                  warn_deprecated                               },
2365
        { "BlockIODeviceWeight",                   warn_deprecated                               },
2366
        { "BlockIOReadBandwidth",                  warn_deprecated                               },
2367
        { "BlockIOWriteBandwidth",                 warn_deprecated                               },
2368
        { "CPUAccounting",                         warn_deprecated                               },
2369

2370
        { NULL, bus_try_append_parse_cgroup_io_limit, cgroup_io_limits_list                      },
2371
        {}
2372
};
2373

2374
static const BusProperty automount_properties[] = {
2375
        { "Where",                                 bus_append_string                             },
2376
        { "ExtraOptions",                          bus_append_string                             },
2377
        { "DirectoryMode",                         bus_append_parse_mode                         },
2378
        { "TimeoutIdleSec",                        bus_append_parse_sec_rename                   },
2379
        {}
2380
};
2381

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

2524
        { NULL, bus_try_append_resource_limit,     dump_resource_limits                          },
2525
        {}
2526
};
2527

2528
static const BusProperty kill_properties[] = {
2529
        { "KillMode",                              bus_append_string                             },
2530
        { "SendSIGHUP",                            bus_append_parse_boolean                      },
2531
        { "SendSIGKILL",                           bus_append_parse_boolean                      },
2532
        { "KillSignal",                            bus_append_signal_from_string                 },
2533
        { "RestartKillSignal",                     bus_append_signal_from_string                 },
2534
        { "FinalKillSignal",                       bus_append_signal_from_string                 },
2535
        { "WatchdogSignal",                        bus_append_signal_from_string                 },
2536
        { "ReloadSignal",                          bus_append_signal_from_string                 },
2537
        {}
2538
};
2539

2540
static const BusProperty mount_properties[] = {
2541
        { "What",                                  bus_append_string                             },
2542
        { "Where",                                 bus_append_string                             },
2543
        { "Options",                               bus_append_string                             },
2544
        { "Type",                                  bus_append_string                             },
2545
        { "TimeoutSec",                            bus_append_parse_sec_rename                   },
2546
        { "DirectoryMode",                         bus_append_parse_mode                         },
2547
        { "SloppyOptions",                         bus_append_parse_boolean                      },
2548
        { "LazyUnmount",                           bus_append_parse_boolean                      },
2549
        { "ForceUnmount",                          bus_append_parse_boolean                      },
2550
        { "ReadwriteOnly",                         bus_append_parse_boolean                      },
2551
        {}
2552
};
2553

2554
static const BusProperty path_properties[] = {
2555
        { "MakeDirectory",                         bus_append_parse_boolean                      },
2556
        { "DirectoryMode",                         bus_append_parse_mode                         },
2557
        { "PathExists",                            bus_append_paths                              },
2558
        { "PathExistsGlob",                        bus_append_paths                              },
2559
        { "PathChanged",                           bus_append_paths                              },
2560
        { "PathModified",                          bus_append_paths                              },
2561
        { "DirectoryNotEmpty",                     bus_append_paths                              },
2562
        { "TriggerLimitBurst",                     bus_append_safe_atou                          },
2563
        { "PollLimitBurst",                        bus_append_safe_atou                          },
2564
        { "TriggerLimitIntervalSec",               bus_append_parse_sec_rename                   },
2565
        { "PollLimitIntervalSec",                  bus_append_parse_sec_rename                   },
2566
        {}
2567
};
2568

2569
static const BusProperty scope_properties[] = {
2570
        { "RuntimeMaxSec",                         bus_append_parse_sec_rename                   },
2571
        { "RuntimeRandomizedExtraSec",             bus_append_parse_sec_rename                   },
2572
        { "TimeoutStopSec",                        bus_append_parse_sec_rename                   },
2573
        { "OOMPolicy",                             bus_append_string                             },
2574

2575
        /* Scope units don't have execution context but we still want to allow setting these two,
2576
         * so let's handle them separately. */
2577
        { "User",                                  bus_append_string                             },
2578
        { "Group",                                 bus_append_string                             },
2579
        {}
2580
};
2581

2582
static const BusProperty service_properties[] = {
2583
        { "PIDFile",                               bus_append_string                             },
2584
        { "Type",                                  bus_append_string                             },
2585
        { "ExitType",                              bus_append_string                             },
2586
        { "Restart",                               bus_append_string                             },
2587
        { "RestartMode",                           bus_append_string                             },
2588
        { "BusName",                               bus_append_string                             },
2589
        { "NotifyAccess",                          bus_append_string                             },
2590
        { "USBFunctionDescriptors",                bus_append_string                             },
2591
        { "USBFunctionStrings",                    bus_append_string                             },
2592
        { "OOMPolicy",                             bus_append_string                             },
2593
        { "TimeoutStartFailureMode",               bus_append_string                             },
2594
        { "TimeoutStopFailureMode",                bus_append_string                             },
2595
        { "FileDescriptorStorePreserve",           bus_append_string                             },
2596
        { "PermissionsStartOnly",                  bus_append_parse_boolean                      },
2597
        { "RootDirectoryStartOnly",                bus_append_parse_boolean                      },
2598
        { "RemainAfterExit",                       bus_append_parse_boolean                      },
2599
        { "GuessMainPID",                          bus_append_parse_boolean                      },
2600
        { "RestartSec",                            bus_append_parse_sec_rename                   },
2601
        { "RestartMaxDelaySec",                    bus_append_parse_sec_rename                   },
2602
        { "TimeoutStartSec",                       bus_append_parse_sec_rename                   },
2603
        { "TimeoutStopSec",                        bus_append_parse_sec_rename                   },
2604
        { "TimeoutAbortSec",                       bus_append_parse_sec_rename                   },
2605
        { "RuntimeMaxSec",                         bus_append_parse_sec_rename                   },
2606
        { "RuntimeRandomizedExtraSec",             bus_append_parse_sec_rename                   },
2607
        { "WatchdogSec",                           bus_append_parse_sec_rename                   },
2608
        { "TimeoutSec",                            bus_append_timeout_sec                        },
2609
        { "FileDescriptorStoreMax",                bus_append_safe_atou                          },
2610
        { "RestartSteps",                          bus_append_safe_atou                          },
2611
        { "ExecCondition",                         bus_append_exec_command                       },
2612
        { "ExecStartPre",                          bus_append_exec_command                       },
2613
        { "ExecStart",                             bus_append_exec_command                       },
2614
        { "ExecStartPost",                         bus_append_exec_command                       },
2615
        { "ExecConditionEx",                       bus_append_exec_command                       },
2616
        { "ExecStartPreEx",                        bus_append_exec_command                       },
2617
        { "ExecStartEx",                           bus_append_exec_command                       },
2618
        { "ExecStartPostEx",                       bus_append_exec_command                       },
2619
        { "ExecReload",                            bus_append_exec_command                       },
2620
        { "ExecStop",                              bus_append_exec_command                       },
2621
        { "ExecStopPost",                          bus_append_exec_command                       },
2622
        { "ExecReloadEx",                          bus_append_exec_command                       },
2623
        { "ExecStopEx",                            bus_append_exec_command                       },
2624
        { "ExecStopPostEx",                        bus_append_exec_command                       },
2625
        { "RestartPreventExitStatus",              bus_append_exit_status                        },
2626
        { "RestartForceExitStatus",                bus_append_exit_status                        },
2627
        { "SuccessExitStatus",                     bus_append_exit_status                        },
2628
        { "OpenFile",                              bus_append_open_file                          },
2629
        {}
2630
};
2631

2632
static const BusProperty socket_properties[] = {
2633
        { "Accept",                                bus_append_parse_boolean                      },
2634
        { "FlushPending",                          bus_append_parse_boolean                      },
2635
        { "Writable",                              bus_append_parse_boolean                      },
2636
        { "KeepAlive",                             bus_append_parse_boolean                      },
2637
        { "NoDelay",                               bus_append_parse_boolean                      },
2638
        { "FreeBind",                              bus_append_parse_boolean                      },
2639
        { "Transparent",                           bus_append_parse_boolean                      },
2640
        { "Broadcast",                             bus_append_parse_boolean                      },
2641
        { "PassCredentials",                       bus_append_parse_boolean                      },
2642
        { "PassFileDescriptorsToExec",             bus_append_parse_boolean                      },
2643
        { "PassSecurity",                          bus_append_parse_boolean                      },
2644
        { "PassPacketInfo",                        bus_append_parse_boolean                      },
2645
        { "ReusePort",                             bus_append_parse_boolean                      },
2646
        { "RemoveOnStop",                          bus_append_parse_boolean                      },
2647
        { "SELinuxContextFromNet",                 bus_append_parse_boolean                      },
2648
        { "Priority",                              bus_append_safe_atoi                          },
2649
        { "IPTTL",                                 bus_append_safe_atoi                          },
2650
        { "Mark",                                  bus_append_safe_atoi                          },
2651
        { "IPTOS",                                 bus_append_ip_tos_from_string                 },
2652
        { "Backlog",                               bus_append_safe_atou                          },
2653
        { "MaxConnections",                        bus_append_safe_atou                          },
2654
        { "MaxConnectionsPerSource",               bus_append_safe_atou                          },
2655
        { "KeepAliveProbes",                       bus_append_safe_atou                          },
2656
        { "TriggerLimitBurst",                     bus_append_safe_atou                          },
2657
        { "PollLimitBurst",                        bus_append_safe_atou                          },
2658
        { "SocketMode",                            bus_append_parse_mode                         },
2659
        { "DirectoryMode",                         bus_append_parse_mode                         },
2660
        { "MessageQueueMaxMessages",               bus_append_safe_atoi64                        },
2661
        { "MessageQueueMessageSize",               bus_append_safe_atoi64                        },
2662
        { "TimeoutSec",                            bus_append_parse_sec_rename                   },
2663
        { "KeepAliveTimeSec",                      bus_append_parse_sec_rename                   },
2664
        { "KeepAliveIntervalSec",                  bus_append_parse_sec_rename                   },
2665
        { "DeferAcceptSec",                        bus_append_parse_sec_rename                   },
2666
        { "TriggerLimitIntervalSec",               bus_append_parse_sec_rename                   },
2667
        { "PollLimitIntervalSec",                  bus_append_parse_sec_rename                   },
2668
        { "DeferTriggerMaxSec",                    bus_append_parse_sec_rename                   },
2669
        { "ReceiveBuffer",                         bus_append_parse_size                         },
2670
        { "SendBuffer",                            bus_append_parse_size                         },
2671
        { "PipeSize",                              bus_append_parse_size                         },
2672
        { "ExecStartPre",                          bus_append_exec_command                       },
2673
        { "ExecStartPost",                         bus_append_exec_command                       },
2674
        { "ExecReload",                            bus_append_exec_command                       },
2675
        { "ExecStopPost",                          bus_append_exec_command                       },
2676
        { "SmackLabel",                            bus_append_string                             },
2677
        { "SmackLabelIPIn",                        bus_append_string                             },
2678
        { "SmackLabelIPOut",                       bus_append_string                             },
2679
        { "TCPCongestion",                         bus_append_string                             },
2680
        { "BindToDevice",                          bus_append_string                             },
2681
        { "BindIPv6Only",                          bus_append_string                             },
2682
        { "FileDescriptorName",                    bus_append_string                             },
2683
        { "SocketUser",                            bus_append_string                             },
2684
        { "SocketGroup",                           bus_append_string                             },
2685
        { "Timestamping",                          bus_append_string                             },
2686
        { "DeferTrigger",                          bus_append_string                             },
2687
        { "Symlinks",                              bus_append_strv                               },
2688
        { "SocketProtocol",                        bus_append_parse_ip_protocol                  },
2689
        { "ListenStream",                          bus_append_listen                             },
2690
        { "ListenDatagram",                        bus_append_listen                             },
2691
        { "ListenSequentialPacket",                bus_append_listen                             },
2692
        { "ListenNetlink",                         bus_append_listen                             },
2693
        { "ListenSpecial",                         bus_append_listen                             },
2694
        { "ListenMessageQueue",                    bus_append_listen                             },
2695
        { "ListenFIFO",                            bus_append_listen                             },
2696
        { "ListenUSBFunction",                     bus_append_listen                             },
2697
        {}
2698
};
2699

2700
static const BusProperty timer_properties[] = {
2701
        { "WakeSystem",                            bus_append_parse_boolean                      },
2702
        { "RemainAfterElapse",                     bus_append_parse_boolean                      },
2703
        { "Persistent",                            bus_append_parse_boolean                      },
2704
        { "OnTimezoneChange",                      bus_append_parse_boolean                      },
2705
        { "OnClockChange",                         bus_append_parse_boolean                      },
2706
        { "FixedRandomDelay",                      bus_append_parse_boolean                      },
2707
        { "DeferReactivation",                     bus_append_parse_boolean                      },
2708
        { "AccuracySec",                           bus_append_parse_sec_rename                   },
2709
        { "RandomizedDelaySec",                    bus_append_parse_sec_rename                   },
2710
        { "RandomizedOffsetSec",                   bus_append_parse_sec_rename                   },
2711
        { "OnActiveSec",                           bus_append_timers_monotonic                   },
2712
        { "OnBootSec",                             bus_append_timers_monotonic                   },
2713
        { "OnStartupSec",                          bus_append_timers_monotonic                   },
2714
        { "OnUnitActiveSec",                       bus_append_timers_monotonic                   },
2715
        { "OnUnitInactiveSec",                     bus_append_timers_monotonic                   },
2716
        { "OnCalendar",                            bus_append_timers_calendar                    },
2717
        {}
2718
};
2719

2720
static const BusProperty unit_properties[] = {
2721
        { "Description",                           bus_append_string                             },
2722
        { "SourcePath",                            bus_append_string                             },
2723
        { "OnFailureJobMode",                      bus_append_string                             },
2724
        { "JobTimeoutAction",                      bus_append_string                             },
2725
        { "JobTimeoutRebootArgument",              bus_append_string                             },
2726
        { "StartLimitAction",                      bus_append_string                             },
2727
        { "FailureAction",                         bus_append_string                             },
2728
        { "SuccessAction",                         bus_append_string                             },
2729
        { "RebootArgument",                        bus_append_string                             },
2730
        { "CollectMode",                           bus_append_string                             },
2731
        { "StopWhenUnneeded",                      bus_append_parse_boolean                      },
2732
        { "RefuseManualStart",                     bus_append_parse_boolean                      },
2733
        { "RefuseManualStop",                      bus_append_parse_boolean                      },
2734
        { "AllowIsolate",                          bus_append_parse_boolean                      },
2735
        { "IgnoreOnIsolate",                       bus_append_parse_boolean                      },
2736
        { "SurviveFinalKillSignal",                bus_append_parse_boolean                      },
2737
        { "DefaultDependencies",                   bus_append_parse_boolean                      },
2738
        { "JobTimeoutSec",                         bus_append_parse_sec_rename                   },
2739
        { "JobRunningTimeoutSec",                  bus_append_parse_sec_rename                   },
2740
        { "StartLimitIntervalSec",                 bus_append_parse_sec_rename                   },
2741
        { "StartLimitBurst",                       bus_append_safe_atou                          },
2742
        { "SuccessActionExitStatus",               bus_append_action_exit_status                 },
2743
        { "FailureActionExitStatus",               bus_append_action_exit_status                 },
2744
        { "Documentation",                         bus_append_strv                               },
2745
        { "RequiresMountsFor",                     bus_append_strv                               },
2746
        { "WantsMountsFor",                        bus_append_strv                               },
2747
        { "Markers",                               bus_append_strv                               },
2748

2749
        { NULL, bus_try_append_unit_dependency,    unit_types_list                               },
2750
        { NULL, bus_try_append_condition,          dump_conditions                               },
2751
        {}
2752
};
2753

2754
static const BusProperty* service_unit_properties[] = {
2755
        cgroup_properties,
2756
        execute_properties,
2757
        kill_properties,
2758
        service_properties,
2759
        unit_properties,
2760
        NULL,
2761
};
2762

2763
static const BusProperty* socket_unit_properties[] = {
2764
        cgroup_properties,
2765
        execute_properties,
2766
        kill_properties,
2767
        socket_properties,
2768
        unit_properties,
2769
        NULL,
2770
};
2771

2772
static const BusProperty* timer_unit_properties[] = {
2773
        timer_properties,
2774
        unit_properties,
2775
        NULL,
2776
};
2777

2778
static const BusProperty* path_unit_properties[] = {
2779
        path_properties,
2780
        unit_properties,
2781
        NULL,
2782
};
2783

2784
static const BusProperty* slice_unit_properties[] = {
2785
        cgroup_properties,
2786
        unit_properties,
2787
        NULL,
2788
};
2789

2790
static const BusProperty* scope_unit_properties[] = {
2791
        cgroup_properties,
2792
        kill_properties,
2793
        scope_properties,
2794
        unit_properties,
2795
        NULL,
2796
};
2797

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

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

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

2818
static const BusProperty** unit_type_properties[_UNIT_TYPE_MAX] = {
2819
        [UNIT_SERVICE]   = service_unit_properties,
2820
        [UNIT_SOCKET]    = socket_unit_properties,
2821
        [UNIT_TIMER]     = timer_unit_properties,
2822
        [UNIT_PATH]      = path_unit_properties,
2823
        [UNIT_SLICE]     = slice_unit_properties,
2824
        [UNIT_SCOPE]     = scope_unit_properties,
2825
        [UNIT_MOUNT]     = mount_unit_properties,
2826
        [UNIT_AUTOMOUNT] = automount_unit_properties,
2827
        [UNIT_TARGET]    = other_unit_properties,
2828
        [UNIT_DEVICE]    = other_unit_properties,
2829
        [UNIT_SWAP]      = other_unit_properties,
2830
};
2831

2832
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
3,288✔
2833
        _cleanup_free_ char *field = NULL;
3,288✔
2834
        const char *eq;
3,288✔
2835
        int r;
3,288✔
2836

2837
        assert(m);
3,288✔
2838
        assert(assignment);
3,288✔
2839
        assert(t >= 0 && t < _UNIT_TYPE_MAX);
3,288✔
2840

2841
        eq = strchr(assignment, '=');
3,288✔
2842
        if (!eq)
3,288✔
2843
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2844
                                       "Not an assignment: %s", assignment);
2845

2846

2847
        field = strndup(assignment, eq - assignment);
3,286✔
2848
        if (!field)
3,286✔
2849
                return log_oom();
×
2850
        eq++;
3,286✔
2851

2852
        for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
6,643✔
2853
                for (const BusProperty *item = *tables; item->convert; item++)
430,124✔
2854
                        if (item->name) {
426,767✔
2855
                                if (streq(item->name, field))
423,638✔
2856
                                        return item->convert(m, field, eq);
3,237✔
2857
                        } else {
2858
                                /* If .name is not set, the function must be a "try" helper */
2859
                                r = item->convert(m, field, eq);
3,129✔
2860
                                if (r != 0)
3,129✔
2861
                                        return r;
2862
                        }
2863

2864
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2865
                               "Unknown assignment: %s", assignment);
2866
}
2867

2868
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char * const *l) {
1,396✔
2869
        int r;
1,396✔
2870

2871
        assert(m);
1,396✔
2872

2873
        STRV_FOREACH(i, l) {
4,675✔
2874
                r = bus_append_unit_property_assignment(m, t, *i);
3,288✔
2875
                if (r < 0)
3,288✔
2876
                        return r;
2877
        }
2878

2879
        return 0;
2880
}
2881

2882
void bus_dump_transient_settings(UnitType t) {
27✔
2883
        assert(t >= 0 && t < _UNIT_TYPE_MAX);
27✔
2884

2885
        for (const BusProperty** tables = ASSERT_PTR(unit_type_properties[t]); *tables; tables++)
112✔
2886
                for (const BusProperty *item = *tables; item->convert; item++) {
3,916✔
2887
                        assert(item->name || item->dump);
3,831✔
2888

2889
                        /* Do not print deprecated names */
2890
                        if (item->convert == warn_deprecated)
3,831✔
2891
                                continue;
150✔
2892

2893
                        if (item->name)
3,681✔
2894
                                puts(item->name);
3,601✔
2895
                        else
2896
                                item->dump();
80✔
2897
                }
2898
}
27✔
2899

2900
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
446✔
2901
        assert(m);
446✔
2902

2903
        if (!pidref_is_set(pidref))
446✔
2904
                return -ESRCH;
2905

2906
        if (pidref->fd >= 0 && allow_pidfd)
446✔
2907
                return sd_bus_message_append(
446✔
2908
                                m, "(sv)",
2909
                                "PIDFDs", "ah", 1, pidref->fd);
2910

2911
        return sd_bus_message_append(
×
2912
                        m, "(sv)",
2913
                        "PIDs", "au", 1, pidref->pid);
2914
}
2915

2916
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
58✔
2917
        const char *type, *path, *source;
58✔
2918
        InstallChange *changes = NULL;
58✔
2919
        size_t n_changes = 0;
58✔
2920
        int r;
58✔
2921

2922
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
58✔
2923

2924
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
58✔
2925
        if (r < 0)
58✔
2926
                return bus_log_parse_error(r);
×
2927

2928
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
115✔
2929
                InstallChangeType t;
57✔
2930

2931
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2932
                 * negative. */
2933
                t = install_change_type_from_string(type);
57✔
2934
                if (t < 0) {
57✔
2935
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
2936
                                         type, path);
2937
                        continue;
×
2938
                }
2939

2940
                r = install_changes_add(&changes, &n_changes, t, path, source);
57✔
2941
                if (r < 0)
57✔
2942
                        return r;
2943
        }
2944
        if (r < 0)
58✔
2945
                return bus_log_parse_error(r);
×
2946

2947
        r = sd_bus_message_exit_container(m);
58✔
2948
        if (r < 0)
58✔
2949
                return bus_log_parse_error(r);
×
2950

2951
        install_changes_dump(0, NULL, changes, n_changes, quiet);
58✔
2952

2953
        return 0;
2954
}
2955

2956
int unit_load_state(sd_bus *bus, const char *name, char **ret) {
3,809✔
2957
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2958
        _cleanup_free_ char *path = NULL;
3,809✔
2959
        int r;
3,809✔
2960

2961
        path = unit_dbus_path_from_name(name);
3,809✔
2962
        if (!path)
3,809✔
2963
                return log_oom();
×
2964

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

2968
        r = sd_bus_get_property_string(
3,809✔
2969
                        bus,
2970
                        "org.freedesktop.systemd1",
2971
                        path,
2972
                        "org.freedesktop.systemd1.Unit",
2973
                        "LoadState",
2974
                        &error,
2975
                        ret);
2976
        if (r < 0)
3,809✔
2977
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
2978

2979
        return 0;
2980
}
2981

2982
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
31,624✔
2983
        int r;
31,624✔
2984

2985
        /* First, order by machine */
2986
        r = strcasecmp_ptr(a->machine, b->machine);
31,624✔
2987
        if (r != 0)
31,624✔
2988
                return r;
2989

2990
        /* Second, order by unit type */
2991
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
31,624✔
2992
        if (r != 0)
31,624✔
2993
                return r;
2994

2995
        /* Third, order by name */
2996
        return strcasecmp(a->id, b->id);
29,347✔
2997
}
2998

2999
int bus_service_manager_reload(sd_bus *bus) {
63✔
3000
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3001
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
63✔
3002
        int r;
63✔
3003

3004
        assert(bus);
63✔
3005

3006
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
63✔
3007
        if (r < 0)
63✔
3008
                return bus_log_create_error(r);
×
3009

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

3015
        return 0;
3016
}
3017

3018
typedef struct UnitFreezer {
3019
        char *name;
3020
        sd_bus *bus;
3021
} UnitFreezer;
3022

3023
/* Wait for 60 seconds at maximum for freezer operation */
3024
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3025

3026
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
3027
        if (!f)
×
3028
                return NULL;
3029

3030
        free(f->name);
×
3031
        sd_bus_flush_close_unref(f->bus);
×
3032

3033
        return mfree(f);
×
3034
}
3035

3036
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
3037
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
3038
        int r;
×
3039

3040
        assert(name);
×
3041
        assert(ret);
×
3042

3043
        f = new(UnitFreezer, 1);
×
3044
        if (!f)
×
3045
                return log_oom();
×
3046

3047
        *f = (UnitFreezer) {
×
3048
                .name = strdup(name),
×
3049
        };
3050
        if (!f->name)
×
3051
                return log_oom();
×
3052

3053
        r = bus_connect_system_systemd(&f->bus);
×
3054
        if (r < 0)
×
3055
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3056

3057
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3058

3059
        *ret = TAKE_PTR(f);
×
3060
        return 0;
×
3061
}
3062

3063
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
3064
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3065
        int r;
×
3066

3067
        assert(f);
×
3068
        assert(f->name);
×
3069
        assert(f->bus);
×
3070

3071
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3072
                            freeze ? "FreezeUnit" : "ThawUnit",
3073
                            &error,
3074
                            /* ret_reply = */ NULL,
3075
                            "s",
3076
                            f->name);
3077
        if (r < 0) {
×
3078
                if (sd_bus_error_has_names(&error,
×
3079
                                           BUS_ERROR_NO_SUCH_UNIT,
3080
                                           BUS_ERROR_UNIT_INACTIVE,
3081
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3082

3083
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
3084
                        return 0;
×
3085
                }
3086

3087
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3088
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3089
        }
3090

3091
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3092
        return 1;
3093
}
3094

3095
int unit_freezer_freeze(UnitFreezer *f) {
×
3096
        return unit_freezer_action(f, true);
×
3097
}
3098

3099
int unit_freezer_thaw(UnitFreezer *f) {
×
3100
        return unit_freezer_action(f, false);
×
3101
}
3102

3103
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,779✔
3104
        if (isempty(s))
1,779✔
3105
                return 0;
3106

3107
        if (streq(s, "ro"))
74✔
3108
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3109

3110
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3111
}
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