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

systemd / systemd / 15057632786

15 May 2025 09:01PM UTC coverage: 72.267% (+0.02%) from 72.244%
15057632786

push

github

bluca
man: document how to hook stuff into system wakeup

Fixes: #6364

298523 of 413084 relevant lines covered (72.27%)

738132.88 hits per line

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

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

3
#include "af-list.h"
4
#include "alloc-util.h"
5
#include "bus-common-errors.h"
6
#include "bus-error.h"
7
#include "bus-locator.h"
8
#include "bus-unit-util.h"
9
#include "bus-util.h"
10
#include "cap-list.h"
11
#include "cgroup-setup.h"
12
#include "cgroup-util.h"
13
#include "condition.h"
14
#include "coredump-util.h"
15
#include "cpu-set-util.h"
16
#include "dissect-image.h"
17
#include "escape.h"
18
#include "exec-util.h"
19
#include "exit-status.h"
20
#include "fileio.h"
21
#include "firewall-util.h"
22
#include "hexdecoct.h"
23
#include "hostname-util.h"
24
#include "in-addr-util.h"
25
#include "ioprio-util.h"
26
#include "ip-protocol-list.h"
27
#include "libmount-util.h"
28
#include "locale-util.h"
29
#include "log.h"
30
#include "macro.h"
31
#include "missing_fs.h"
32
#include "mountpoint-util.h"
33
#include "nsflags.h"
34
#include "numa-util.h"
35
#include "open-file.h"
36
#include "parse-helpers.h"
37
#include "parse-util.h"
38
#include "path-util.h"
39
#include "percent-util.h"
40
#include "process-util.h"
41
#include "rlimit-util.h"
42
#include "seccomp-util.h"
43
#include "securebits-util.h"
44
#include "signal-util.h"
45
#include "socket-util.h"
46
#include "sort-util.h"
47
#include "stdio-util.h"
48
#include "string-util.h"
49
#include "syslog-util.h"
50
#include "terminal-util.h"
51
#include "unit-def.h"
52
#include "user-util.h"
53
#include "utf8.h"
54

55
int bus_parse_unit_info(sd_bus_message *message, UnitInfo *u) {
11,617✔
56
        assert(message);
11,617✔
57
        assert(u);
11,617✔
58

59
        u->machine = NULL;
11,617✔
60

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

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

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

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

138
static int bus_append_string(sd_bus_message *m, const char *field, const char *eq) {
611✔
139
        int r;
611✔
140

141
        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
611✔
142
        if (r < 0)
611✔
143
                return bus_log_create_error(r);
×
144

145
        return 1;
146
}
147

148
static int bus_append_strv(sd_bus_message *m, const char *field, const char *eq, const char *separator, ExtractFlags flags) {
404✔
149
        int r;
404✔
150

151
        assert(m);
404✔
152
        assert(field);
404✔
153

154
        r = sd_bus_message_open_container(m, 'r', "sv");
404✔
155
        if (r < 0)
404✔
156
                return bus_log_create_error(r);
×
157

158
        r = sd_bus_message_append_basic(m, 's', field);
404✔
159
        if (r < 0)
404✔
160
                return bus_log_create_error(r);
×
161

162
        r = sd_bus_message_open_container(m, 'v', "as");
404✔
163
        if (r < 0)
404✔
164
                return bus_log_create_error(r);
×
165

166
        r = sd_bus_message_open_container(m, 'a', "s");
404✔
167
        if (r < 0)
404✔
168
                return bus_log_create_error(r);
×
169

170
        for (const char *p = eq;;) {
404✔
171
                _cleanup_free_ char *word = NULL;
100✔
172

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

181
                r = sd_bus_message_append_basic(m, 's', word);
100✔
182
                if (r < 0)
100✔
183
                        return bus_log_create_error(r);
×
184
        }
185

186
        r = sd_bus_message_close_container(m);
404✔
187
        if (r < 0)
404✔
188
                return bus_log_create_error(r);
×
189

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

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

198
        return 1;
199
}
200

201
static int bus_append_byte_array(sd_bus_message *m, const char *field, const void *buf, size_t n) {
18✔
202
        int r;
18✔
203

204
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
18✔
205
        if (r < 0)
18✔
206
                return bus_log_create_error(r);
×
207

208
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
18✔
209
        if (r < 0)
18✔
210
                return bus_log_create_error(r);
×
211

212
        r = sd_bus_message_open_container(m, 'v', "ay");
18✔
213
        if (r < 0)
18✔
214
                return bus_log_create_error(r);
×
215

216
        r = sd_bus_message_append_array(m, 'y', buf, n);
18✔
217
        if (r < 0)
18✔
218
                return bus_log_create_error(r);
×
219

220
        r = sd_bus_message_close_container(m);
18✔
221
        if (r < 0)
18✔
222
                return bus_log_create_error(r);
×
223

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

228
        return 1;
229
}
230

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

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

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

246
        r = sd_bus_message_append(m, "(sv)", n, "t", t);
8✔
247
        if (r < 0)
8✔
248
                return bus_log_create_error(r);
×
249

250
        return 1;
251
}
252

253
static int bus_append_parse_size(sd_bus_message *m, const char *field, const char *eq, uint64_t base) {
8✔
254
        uint64_t v;
8✔
255
        int r;
8✔
256

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

261
        r = sd_bus_message_append(m, "(sv)", field, "t", v);
8✔
262
        if (r < 0)
8✔
263
                return bus_log_create_error(r);
×
264

265
        return 1;
266
}
267

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

276
        do {
62✔
277
                switch (*eq) {
62✔
278

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

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

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

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

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

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

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

343
                default:
344
                        done = true;
345
                }
346
        } while (!done);
62✔
347

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

352
                upgraded_name = strjoin(field, "Ex");
9✔
353
                if (!upgraded_name)
9✔
354
                        return log_oom();
×
355
                field = upgraded_name;
356
        }
357

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

364
        if (FLAGS_SET(flags, EXEC_COMMAND_VIA_SHELL)) {
43✔
365
                path = strdup(_PATH_BSHELL);
2✔
366
                if (!path)
2✔
367
                        return log_oom();
×
368

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

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

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

389
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
43✔
390
        if (r < 0)
43✔
391
                return bus_log_create_error(r);
×
392

393
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
43✔
394
        if (r < 0)
43✔
395
                return bus_log_create_error(r);
×
396

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

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

405
        if (!strv_isempty(l)) {
43✔
406

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

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

415
                r = sd_bus_message_append_strv(m, l);
43✔
416
                if (r < 0)
43✔
417
                        return bus_log_create_error(r);
×
418

419
                r = is_ex_prop ? sd_bus_message_append_strv(m, ex_opts) : sd_bus_message_append(m, "b", FLAGS_SET(flags, EXEC_COMMAND_IGNORE_FAILURE));
43✔
420
                if (r < 0)
43✔
421
                        return bus_log_create_error(r);
×
422

423
                r = sd_bus_message_close_container(m);
43✔
424
                if (r < 0)
43✔
425
                        return bus_log_create_error(r);
×
426
        }
427

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

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

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

440
        return 1;
441
}
442

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

447
        assert(m);
5✔
448

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

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

457
        return 1;
458
}
459

460
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
×
461
        int r;
×
462

463
        assert(m);
×
464
        assert(prefix);
×
465

466
        r = sd_bus_message_open_container(m, 'r', "iayu");
×
467
        if (r < 0)
×
468
                return r;
469

470
        r = sd_bus_message_append(m, "i", family);
×
471
        if (r < 0)
×
472
                return r;
473

474
        r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
×
475
        if (r < 0)
×
476
                return r;
477

478
        r = sd_bus_message_append(m, "u", prefixlen);
×
479
        if (r < 0)
×
480
                return r;
481

482
        return sd_bus_message_close_container(m);
×
483
}
484

485
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
2✔
486
        int r;
2✔
487

488
        assert(m);
2✔
489
        assert(field);
2✔
490
        assert(eq);
2✔
491

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

497
                return 1;
498
        }
499

500
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
501
        if (r < 0)
2✔
502
                return bus_log_create_error(r);
×
503

504
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
505
        if (r < 0)
2✔
506
                return bus_log_create_error(r);
×
507

508
        r = sd_bus_message_open_container(m, 'v', "a(iiss)");
2✔
509
        if (r < 0)
2✔
510
                return bus_log_create_error(r);
×
511

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

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

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

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

538
                assert(source_str);
4✔
539
                assert(nfproto_str);
4✔
540
                assert(table);
4✔
541
                assert(set);
4✔
542

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

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

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

559
        r = sd_bus_message_close_container(m);
2✔
560
        if (r < 0)
2✔
561
                return bus_log_create_error(r);
×
562

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

567
        return 1;
568
}
569

570
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
3,201✔
571
        int r;
3,201✔
572

573
        if (STR_IN_SET(field, "DevicePolicy",
3,201✔
574
                              "Slice",
575
                              "ManagedOOMSwap",
576
                              "ManagedOOMMemoryPressure",
577
                              "ManagedOOMPreference",
578
                              "MemoryPressureWatch",
579
                              "DelegateSubgroup"))
580
                return bus_append_string(m, field, eq);
17✔
581

582
        if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
3,184✔
583
                r = parse_permyriad(eq);
×
584
                if (r < 0)
×
585
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
586

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

592
                return 1;
593
        }
594

595
        if (STR_IN_SET(field, "CPUAccounting",
3,184✔
596
                              "MemoryAccounting",
597
                              "MemoryZSwapWriteback",
598
                              "IOAccounting",
599
                              "TasksAccounting",
600
                              "IPAccounting",
601
                              "CoredumpReceive"))
602
                return bus_append_parse_boolean(m, field, eq);
8✔
603

604
        if (STR_IN_SET(field, "CPUWeight",
3,176✔
605
                              "StartupCPUWeight"))
606
                return bus_append_cg_cpu_weight_parse(m, field, eq);
×
607

608
        if (STR_IN_SET(field, "IOWeight",
3,176✔
609
                              "StartupIOWeight"))
610
                return bus_append_cg_weight_parse(m, field, eq);
×
611

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

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

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

628
                return bus_append_byte_array(m, field, array, allocated);
×
629
        }
630

631
        if (streq(field, "DisableControllers"))
3,176✔
632
                return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
633

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

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

643
                return 1;
644
        }
645

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

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

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

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

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

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

689
                        return 1;
690
                }
691

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

695
                return bus_append_parse_size(m, field, eq, 1024);
8✔
696
        }
697

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

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

711
                if (r < 0)
1✔
712
                        return bus_log_create_error(r);
×
713

714
                return 1;
715
        }
716

717
        if (streq(field, "CPUQuotaPeriodSec")) {
2,820✔
718
                usec_t u = USEC_INFINITY;
×
719

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

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

728
                return 1;
729
        }
730

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

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

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

746
                if (r < 0)
6✔
747
                        return bus_log_create_error(r);
×
748

749
                return 1;
750
        }
751

752
        if (cgroup_io_limit_type_from_string(field) >= 0) {
2,814✔
753

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

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

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

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

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

780
                if (r < 0)
3✔
781
                        return bus_log_create_error(r);
×
782

783
                return 1;
784
        }
785

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

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

799
                        path = strndupa_safe(eq, e - eq);
×
800
                        weight = e+1;
×
801

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

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

809
                if (r < 0)
×
810
                        return bus_log_create_error(r);
×
811

812
                return 1;
813
        }
814

815
        if (streq(field, "IODeviceLatencyTargetSec")) {
2,811✔
816
                const char *field_usec = "IODeviceLatencyTargetUSec";
×
817

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

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

830
                        path = strndupa_safe(eq, e - eq);
×
831
                        target = e+1;
×
832

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

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

840
                if (r < 0)
×
841
                        return bus_log_create_error(r);
×
842

843
                return 1;
844
        }
845

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

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

857
                        return 1;
858
                }
859

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

952
                r = sd_bus_message_close_container(m);
×
953
                if (r < 0)
×
954
                        return bus_log_create_error(r);
×
955

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

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

964
                return 1;
965
        }
966

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

974
                if (r < 0)
×
975
                        return bus_log_create_error(r);
×
976

977
                return 1;
978
        }
979

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

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

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

997
                return 1;
998
        }
999

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

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

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

1020
                return 1;
1021
        }
1022

1023
        if (streq(field, "MemoryPressureThresholdSec"))
2,811✔
1024
                return bus_append_parse_sec_rename(m, field, eq);
1✔
1025

1026
        if (streq(field, "NFTSet"))
2,810✔
1027
                return bus_append_nft_set(m, field, eq);
2✔
1028

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

1034
        return 0;
1035
}
1036

1037
static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
1✔
1038
        if (STR_IN_SET(field, "Where",
1✔
1039
                              "ExtraOptions"))
1040
                return bus_append_string(m, field, eq);
×
1041

1042
        if (streq(field, "DirectoryMode"))
1✔
1043
                return bus_append_parse_mode(m, field, eq);
×
1044

1045
        if (streq(field, "TimeoutIdleSec"))
1✔
1046
                return bus_append_parse_sec_rename(m, field, eq);
×
1047

1048
        return 0;
1049
}
1050

1051
static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
2,800✔
1052
        const char *suffix;
2,800✔
1053
        int r;
2,800✔
1054

1055
        if (STR_IN_SET(field, "User",
2,800✔
1056
                              "Group",
1057
                              "UtmpIdentifier",
1058
                              "UtmpMode",
1059
                              "PAMName",
1060
                              "TTYPath",
1061
                              "WorkingDirectory",
1062
                              "RootDirectory",
1063
                              "SyslogIdentifier",
1064
                              "ProtectSystem",
1065
                              "ProtectHome",
1066
                              "PrivateTmpEx",
1067
                              "PrivateUsersEx",
1068
                              "ProtectControlGroupsEx",
1069
                              "SELinuxContext",
1070
                              "RootImage",
1071
                              "RootVerity",
1072
                              "RuntimeDirectoryPreserve",
1073
                              "Personality",
1074
                              "KeyringMode",
1075
                              "ProtectProc",
1076
                              "ProcSubset",
1077
                              "NetworkNamespacePath",
1078
                              "IPCNamespacePath",
1079
                              "LogNamespace",
1080
                              "RootImagePolicy",
1081
                              "MountImagePolicy",
1082
                              "ExtensionImagePolicy",
1083
                              "PrivatePIDs"))
1084
                return bus_append_string(m, field, eq);
460✔
1085

1086
        if (STR_IN_SET(field, "IgnoreSIGPIPE",
2,340✔
1087
                              "TTYVHangup",
1088
                              "TTYReset",
1089
                              "TTYVTDisallocate",
1090
                              "PrivateTmp",
1091
                              "PrivateDevices",
1092
                              "PrivateNetwork",
1093
                              "PrivateUsers",
1094
                              "PrivateMounts",
1095
                              "PrivateIPC",
1096
                              "NoNewPrivileges",
1097
                              "SyslogLevelPrefix",
1098
                              "MemoryDenyWriteExecute",
1099
                              "RestrictRealtime",
1100
                              "DynamicUser",
1101
                              "RemoveIPC",
1102
                              "ProtectKernelTunables",
1103
                              "ProtectKernelModules",
1104
                              "ProtectKernelLogs",
1105
                              "ProtectClock",
1106
                              "ProtectControlGroups",
1107
                              "MountAPIVFS",
1108
                              "BindLogSockets",
1109
                              "CPUSchedulingResetOnFork",
1110
                              "LockPersonality",
1111
                              "ProtectHostname",
1112
                              "MemoryKSM",
1113
                              "RestrictSUIDSGID",
1114
                              "RootEphemeral",
1115
                              "SetLoginEnvironment"))
1116
                return bus_append_parse_boolean(m, field, eq);
386✔
1117

1118
        if (STR_IN_SET(field, "ReadWriteDirectories",
1,954✔
1119
                              "ReadOnlyDirectories",
1120
                              "InaccessibleDirectories",
1121
                              "ReadWritePaths",
1122
                              "ReadOnlyPaths",
1123
                              "InaccessiblePaths",
1124
                              "ExecPaths",
1125
                              "NoExecPaths",
1126
                              "ExecSearchPath",
1127
                              "ExtensionDirectories",
1128
                              "ConfigurationDirectory",
1129
                              "SupplementaryGroups",
1130
                              "SystemCallArchitectures"))
1131
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
30✔
1132

1133
        if (STR_IN_SET(field, "SyslogLevel",
1,924✔
1134
                              "LogLevelMax"))
1135
                return bus_append_log_level_from_string(m, field, eq);
1✔
1136

1137
        if (streq(field, "SyslogFacility"))
1,923✔
1138
                return bus_append_log_facility_unshifted_from_string(m, field, eq);
×
1139

1140
        if (streq(field, "SecureBits"))
1,923✔
1141
                return bus_append_secure_bits_from_string(m, field, eq);
×
1142

1143
        if (streq(field, "CPUSchedulingPolicy"))
1,923✔
1144
                return bus_append_sched_policy_from_string(m, field, eq);
×
1145

1146
        if (STR_IN_SET(field, "CPUSchedulingPriority",
1,923✔
1147
                              "OOMScoreAdjust"))
1148
                return bus_append_safe_atoi(m, field, eq);
1✔
1149

1150
        if (streq(field, "CoredumpFilter"))
1,922✔
1151
                return bus_append_coredump_filter_mask_from_string(m, field, eq);
2✔
1152

1153
        if (streq(field, "Nice"))
1,920✔
1154
                return bus_append_parse_nice(m, field, eq);
×
1155

1156
        if (streq(field, "SystemCallErrorNumber"))
1,920✔
1157
                return bus_append_seccomp_parse_errno_or_action(m, field, eq);
×
1158

1159
        if (streq(field, "IOSchedulingClass"))
1,920✔
1160
                return bus_append_ioprio_class_from_string(m, field, eq);
×
1161

1162
        if (streq(field, "IOSchedulingPriority"))
1,920✔
1163
                return bus_append_ioprio_parse_priority(m, field, eq);
×
1164

1165
        if (STR_IN_SET(field, "RuntimeDirectoryMode",
1,920✔
1166
                              "StateDirectoryMode",
1167
                              "CacheDirectoryMode",
1168
                              "LogsDirectoryMode",
1169
                              "ConfigurationDirectoryMode",
1170
                              "UMask"))
1171
                return bus_append_parse_mode(m, field, eq);
20✔
1172

1173
        if (streq(field, "TimerSlackNSec"))
1,900✔
1174
                return bus_append_parse_nsec(m, field, eq);
×
1175

1176
        if (streq(field, "LogRateLimitIntervalSec"))
1,900✔
1177
                return bus_append_parse_sec_rename(m, field, eq);
×
1178

1179
        if (STR_IN_SET(field, "LogRateLimitBurst",
1,900✔
1180
                              "TTYRows",
1181
                              "TTYColumns"))
1182
                return bus_append_safe_atou(m, field, eq);
×
1183

1184
        if (streq(field, "MountFlags"))
1,900✔
1185
                return bus_append_mount_propagation_flag_from_string(m, field, eq);
1✔
1186

1187
        if (STR_IN_SET(field, "Environment",
1,899✔
1188
                              "UnsetEnvironment",
1189
                              "PassEnvironment"))
1190
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
354✔
1191

1192
        if (streq(field, "EnvironmentFile")) {
1,545✔
1193
                if (isempty(eq))
340✔
1194
                        r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
×
1195
                else
1196
                        r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
340✔
1197
                                                  eq[0] == '-' ? eq + 1 : eq,
1198
                                                  eq[0] == '-');
1199
                if (r < 0)
340✔
1200
                        return bus_log_create_error(r);
×
1201

1202
                return 1;
1203
        }
1204

1205
        if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
1,205✔
1206
                r = sd_bus_message_open_container(m, 'r', "sv");
90✔
1207
                if (r < 0)
90✔
1208
                        return bus_log_create_error(r);
90✔
1209

1210
                r = sd_bus_message_append_basic(m, 's', field);
90✔
1211
                if (r < 0)
90✔
1212
                        return bus_log_create_error(r);
×
1213

1214
                r = sd_bus_message_open_container(m, 'v', "a(say)");
90✔
1215
                if (r < 0)
90✔
1216
                        return bus_log_create_error(r);
×
1217

1218
                if (isempty(eq))
90✔
1219
                        r = sd_bus_message_append(m, "a(say)", 0);
×
1220
                else {
1221
                        _cleanup_free_ char *word = NULL;
90✔
1222
                        const char *p = eq;
90✔
1223

1224
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
90✔
1225
                        if (r == -ENOMEM)
90✔
1226
                                return log_oom();
×
1227
                        if (r < 0)
90✔
1228
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1229
                        if (r == 0 || !p)
90✔
1230
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1231

1232
                        r = sd_bus_message_open_container(m, 'a', "(say)");
90✔
1233
                        if (r < 0)
90✔
1234
                                return bus_log_create_error(r);
×
1235

1236
                        r = sd_bus_message_open_container(m, 'r', "say");
90✔
1237
                        if (r < 0)
90✔
1238
                                return bus_log_create_error(r);
×
1239

1240
                        r = sd_bus_message_append(m, "s", word);
90✔
1241
                        if (r < 0)
90✔
1242
                                return bus_log_create_error(r);
×
1243

1244
                        if (streq(field, "SetCredentialEncrypted")) {
90✔
1245
                                _cleanup_free_ void *decoded = NULL;
2✔
1246
                                size_t decoded_size;
2✔
1247

1248
                                r = unbase64mem(p, &decoded, &decoded_size);
2✔
1249
                                if (r < 0)
2✔
1250
                                        return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
×
1251

1252
                                r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
2✔
1253
                        } else {
1254
                                _cleanup_free_ char *unescaped = NULL;
88✔
1255
                                ssize_t l;
88✔
1256

1257
                                l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
88✔
1258
                                if (l < 0)
88✔
1259
                                        return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
×
1260

1261
                                r = sd_bus_message_append_array(m, 'y', unescaped, l);
88✔
1262
                        }
1263
                        if (r < 0)
90✔
1264
                                return bus_log_create_error(r);
×
1265

1266
                        r = sd_bus_message_close_container(m);
90✔
1267
                        if (r < 0)
90✔
1268
                                return bus_log_create_error(r);
×
1269

1270
                        r = sd_bus_message_close_container(m);
90✔
1271
                }
1272
                if (r < 0)
90✔
1273
                        return bus_log_create_error(r);
×
1274

1275
                r = sd_bus_message_close_container(m);
90✔
1276
                if (r < 0)
90✔
1277
                        return bus_log_create_error(r);
×
1278

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

1283
                return 1;
1284
        }
1285

1286
        if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
1,115✔
1287
                r = sd_bus_message_open_container(m, 'r', "sv");
18✔
1288
                if (r < 0)
18✔
1289
                        return bus_log_create_error(r);
18✔
1290

1291
                r = sd_bus_message_append_basic(m, 's', field);
18✔
1292
                if (r < 0)
18✔
1293
                        return bus_log_create_error(r);
×
1294

1295
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
18✔
1296
                if (r < 0)
18✔
1297
                        return bus_log_create_error(r);
×
1298

1299
                if (isempty(eq))
18✔
1300
                        r = sd_bus_message_append(m, "a(ss)", 0);
×
1301
                else {
1302
                        _cleanup_free_ char *word = NULL;
18✔
1303
                        const char *p = eq;
18✔
1304

1305
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
18✔
1306
                        if (r == -ENOMEM)
18✔
1307
                                return log_oom();
×
1308
                        if (r < 0)
18✔
1309
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1310
                        if (r == 0)
18✔
1311
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1312

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

1316
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
18✔
1317
                }
1318
                if (r < 0)
18✔
1319
                        return bus_log_create_error(r);
×
1320

1321
                r = sd_bus_message_close_container(m);
18✔
1322
                if (r < 0)
18✔
1323
                        return bus_log_create_error(r);
×
1324

1325
                r = sd_bus_message_close_container(m);
18✔
1326
                if (r < 0)
18✔
1327
                        return bus_log_create_error(r);
×
1328

1329
                return 1;
1330
        }
1331

1332
        if (streq(field, "ImportCredential")) {
1,097✔
1333
                if (isempty(eq))
3✔
1334
                        r = sd_bus_message_append(m, "(sv)", field, "as", 0);
×
1335
                else
1336
                        r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
3✔
1337
                if (r < 0)
3✔
1338
                        return bus_log_create_error(r);
×
1339

1340
                return 1;
1341
        }
1342

1343
        if (streq(field, "ImportCredentialEx")) {
1,094✔
1344
                r = sd_bus_message_open_container(m, 'r', "sv");
9✔
1345
                if (r < 0)
9✔
1346
                        return bus_log_create_error(r);
×
1347

1348
                r = sd_bus_message_append_basic(m, 's', field);
9✔
1349
                if (r < 0)
9✔
1350
                        return bus_log_create_error(r);
×
1351

1352
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
9✔
1353
                if (r < 0)
9✔
1354
                        return bus_log_create_error(r);
×
1355

1356
                if (isempty(eq))
9✔
1357
                        r = sd_bus_message_append(m, "a(ss)", 0);
×
1358
                else {
1359
                         _cleanup_free_ char *word = NULL;
9✔
1360
                        const char *p = eq;
9✔
1361

1362
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
9✔
1363
                        if (r == -ENOMEM)
9✔
1364
                                return log_oom();
×
1365
                        if (r < 0)
9✔
1366
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1367
                        if (r == 0)
9✔
1368
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1369

1370
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
9✔
1371
                }
1372
                if (r < 0)
9✔
1373
                        return bus_log_create_error(r);
×
1374

1375
                r = sd_bus_message_close_container(m);
9✔
1376
                if (r < 0)
9✔
1377
                        return bus_log_create_error(r);
×
1378

1379
                r = sd_bus_message_close_container(m);
9✔
1380
                if (r < 0)
9✔
1381
                        return bus_log_create_error(r);
×
1382

1383
                return 1;
1384
        }
1385

1386
        if (streq(field, "LogExtraFields")) {
1,085✔
1387
                r = sd_bus_message_open_container(m, 'r', "sv");
471✔
1388
                if (r < 0)
471✔
1389
                        return bus_log_create_error(r);
×
1390

1391
                r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
471✔
1392
                if (r < 0)
471✔
1393
                        return bus_log_create_error(r);
×
1394

1395
                r = sd_bus_message_open_container(m, 'v', "aay");
471✔
1396
                if (r < 0)
471✔
1397
                        return bus_log_create_error(r);
×
1398

1399
                r = sd_bus_message_open_container(m, 'a', "ay");
471✔
1400
                if (r < 0)
471✔
1401
                        return bus_log_create_error(r);
×
1402

1403
                r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
471✔
1404
                if (r < 0)
471✔
1405
                        return bus_log_create_error(r);
×
1406

1407
                r = sd_bus_message_close_container(m);
471✔
1408
                if (r < 0)
471✔
1409
                        return bus_log_create_error(r);
×
1410

1411
                r = sd_bus_message_close_container(m);
471✔
1412
                if (r < 0)
471✔
1413
                        return bus_log_create_error(r);
×
1414

1415
                r = sd_bus_message_close_container(m);
471✔
1416
                if (r < 0)
471✔
1417
                        return bus_log_create_error(r);
×
1418

1419
                return 1;
1420
        }
1421

1422
        if (streq(field, "LogFilterPatterns")) {
614✔
1423
                r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
×
1424
                                          eq[0] != '~',
1425
                                          eq[0] != '~' ? eq : eq + 1);
×
1426
                if (r < 0)
×
1427
                        return bus_log_create_error(r);
×
1428

1429
                return 1;
1430
        }
1431

1432
        if (STR_IN_SET(field, "StandardInput",
614✔
1433
                              "StandardOutput",
1434
                              "StandardError")) {
1435
                const char *n, *appended;
46✔
1436

1437
                if ((n = startswith(eq, "fd:"))) {
46✔
1438
                        appended = strjoina(field, "FileDescriptorName");
×
1439
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
×
1440
                } else if ((n = startswith(eq, "file:"))) {
46✔
1441
                        appended = strjoina(field, "File");
20✔
1442
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
4✔
1443
                } else if ((n = startswith(eq, "append:"))) {
42✔
1444
                        appended = strjoina(field, "FileToAppend");
10✔
1445
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
2✔
1446
                } else if ((n = startswith(eq, "truncate:"))) {
40✔
1447
                        appended = strjoina(field, "FileToTruncate");
15✔
1448
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
3✔
1449
                } else
1450
                        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
37✔
1451
                if (r < 0)
46✔
1452
                        return bus_log_create_error(r);
46✔
1453

1454
                return 1;
1455
        }
1456

1457
        if (streq(field, "StandardInputText")) {
568✔
1458
                _cleanup_free_ char *unescaped = NULL;
×
1459
                ssize_t l;
×
1460

1461
                l = cunescape(eq, 0, &unescaped);
×
1462
                if (l < 0)
×
1463
                        return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
×
1464

1465
                if (!strextend(&unescaped, "\n"))
×
1466
                        return log_oom();
×
1467

1468
                /* Note that we don't expand specifiers here, but that should be OK, as this is a
1469
                 * programmatic interface anyway */
1470

1471
                return bus_append_byte_array(m, field, unescaped, l + 1);
×
1472
        }
1473

1474
        if (streq(field, "StandardInputData")) {
568✔
1475
                _cleanup_free_ void *decoded = NULL;
1✔
1476
                size_t sz;
1✔
1477

1478
                r = unbase64mem(eq, &decoded, &sz);
1✔
1479
                if (r < 0)
1✔
1480
                        return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
×
1481

1482
                return bus_append_byte_array(m, field, decoded, sz);
1✔
1483
        }
1484

1485
        if ((suffix = startswith(field, "Limit"))) {
567✔
1486
                int rl;
24✔
1487

1488
                rl = rlimit_from_string(suffix);
24✔
1489
                if (rl >= 0) {
24✔
1490
                        const char *sn;
24✔
1491
                        struct rlimit l;
24✔
1492

1493
                        r = rlimit_parse(rl, eq, &l);
24✔
1494
                        if (r < 0)
24✔
1495
                                return log_error_errno(r, "Failed to parse resource limit: %s", eq);
24✔
1496

1497
                        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
24✔
1498
                        if (r < 0)
24✔
1499
                                return bus_log_create_error(r);
×
1500

1501
                        sn = strjoina(field, "Soft");
120✔
1502
                        r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
24✔
1503
                        if (r < 0)
24✔
1504
                                return bus_log_create_error(r);
×
1505

1506
                        return 1;
1507
                }
1508
        }
1509

1510
        if (STR_IN_SET(field, "AppArmorProfile",
543✔
1511
                              "SmackProcessLabel")) {
1512
                int ignore = 0;
×
1513
                const char *s = eq;
×
1514

1515
                if (eq[0] == '-') {
×
1516
                        ignore = 1;
×
1517
                        s = eq + 1;
×
1518
                }
1519

1520
                r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
×
1521
                if (r < 0)
×
1522
                        return bus_log_create_error(r);
×
1523

1524
                return 1;
1525
        }
1526

1527
        if (STR_IN_SET(field, "CapabilityBoundingSet",
543✔
1528
                              "AmbientCapabilities")) {
1529
                uint64_t sum = 0;
6✔
1530
                bool invert = false;
6✔
1531
                const char *p = eq;
6✔
1532

1533
                if (*p == '~') {
6✔
1534
                        invert = true;
3✔
1535
                        p++;
3✔
1536
                }
1537

1538
                r = capability_set_from_string(p, &sum);
6✔
1539
                if (r < 0)
6✔
1540
                        return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
6✔
1541

1542
                sum = invert ? ~sum : sum;
6✔
1543

1544
                r = sd_bus_message_append(m, "(sv)", field, "t", sum);
6✔
1545
                if (r < 0)
6✔
1546
                        return bus_log_create_error(r);
×
1547

1548
                return 1;
1549
        }
1550

1551
        if (streq(field, "CPUAffinity")) {
537✔
1552
                _cleanup_(cpu_set_reset) CPUSet cpuset = {};
×
1553
                _cleanup_free_ uint8_t *array = NULL;
1✔
1554
                size_t allocated;
1✔
1555

1556
                if (eq && streq(eq, "numa")) {
1✔
1557
                        r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1✔
1558
                        if (r < 0)
1✔
1559
                                return bus_log_create_error(r);
×
1560
                        return r;
1561
                }
1562

1563
                r = parse_cpu_set(eq, &cpuset);
×
1564
                if (r < 0)
×
1565
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1566

1567
                r = cpu_set_to_dbus(&cpuset, &array, &allocated);
×
1568
                if (r < 0)
×
1569
                        return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
×
1570

1571
                return bus_append_byte_array(m, field, array, allocated);
×
1572
        }
1573

1574
        if (streq(field, "NUMAPolicy")) {
536✔
1575
                r = mpol_from_string(eq);
8✔
1576
                if (r < 0)
8✔
1577
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1578

1579
                r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
8✔
1580
                if (r < 0)
8✔
1581
                        return bus_log_create_error(r);
×
1582

1583
                return 1;
1584
        }
1585

1586
        if (streq(field, "NUMAMask")) {
528✔
1587
                _cleanup_(cpu_set_reset) CPUSet nodes = {};
×
1588
                _cleanup_free_ uint8_t *array = NULL;
6✔
1589
                size_t allocated;
6✔
1590

1591
                if (eq && streq(eq, "all")) {
6✔
1592
                        r = numa_mask_add_all(&nodes);
×
1593
                        if (r < 0)
×
1594
                                return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
×
1595
                } else {
1596
                        r = parse_cpu_set(eq, &nodes);
6✔
1597
                        if (r < 0)
6✔
1598
                                return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1599
                }
1600

1601
                r = cpu_set_to_dbus(&nodes, &array, &allocated);
6✔
1602
                if (r < 0)
6✔
1603
                        return log_error_errno(r, "Failed to serialize NUMAMask: %m");
×
1604

1605
                return bus_append_byte_array(m, field, array, allocated);
6✔
1606
        }
1607

1608
        if (STR_IN_SET(field, "RestrictAddressFamilies",
522✔
1609
                              "RestrictFileSystems",
1610
                              "SystemCallFilter",
1611
                              "SystemCallLog",
1612
                              "RestrictNetworkInterfaces")) {
1613
                int allow_list = 1;
7✔
1614
                const char *p = eq;
7✔
1615

1616
                if (*p == '~') {
7✔
1617
                        allow_list = 0;
3✔
1618
                        p++;
3✔
1619
                }
1620

1621
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
7✔
1622
                if (r < 0)
7✔
1623
                        return bus_log_create_error(r);
7✔
1624

1625
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
7✔
1626
                if (r < 0)
7✔
1627
                        return bus_log_create_error(r);
×
1628

1629
                r = sd_bus_message_open_container(m, 'v', "(bas)");
7✔
1630
                if (r < 0)
7✔
1631
                        return bus_log_create_error(r);
×
1632

1633
                r = sd_bus_message_open_container(m, 'r', "bas");
7✔
1634
                if (r < 0)
7✔
1635
                        return bus_log_create_error(r);
×
1636

1637
                r = sd_bus_message_append_basic(m, 'b', &allow_list);
7✔
1638
                if (r < 0)
7✔
1639
                        return bus_log_create_error(r);
×
1640

1641
                r = sd_bus_message_open_container(m, 'a', "s");
7✔
1642
                if (r < 0)
7✔
1643
                        return bus_log_create_error(r);
×
1644

1645
                for (;;) {
25✔
1646
                        _cleanup_free_ char *word = NULL;
9✔
1647

1648
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
16✔
1649
                        if (r == 0)
16✔
1650
                                break;
1651
                        if (r == -ENOMEM)
9✔
1652
                                return log_oom();
×
1653
                        if (r < 0)
9✔
1654
                                return log_error_errno(r, "Invalid syntax: %s", eq);
×
1655

1656
                        r = sd_bus_message_append_basic(m, 's', word);
9✔
1657
                        if (r < 0)
9✔
1658
                                return bus_log_create_error(r);
×
1659
                }
1660

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

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

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

1673
                r = sd_bus_message_close_container(m);
7✔
1674
                if (r < 0)
7✔
1675
                        return bus_log_create_error(r);
×
1676

1677
                return 1;
1678
        }
1679

1680
        if (STR_IN_SET(field, "RestrictNamespaces",
515✔
1681
                              "DelegateNamespaces")) {
1682
                bool invert = false;
11✔
1683
                unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
11✔
1684
                unsigned long flags;
11✔
1685

1686
                r = parse_boolean(eq);
11✔
1687
                if (r > 0)
11✔
1688
                        /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1689
                         * namespaces which are retained), so RestrictNamespaces=true means we retain no
1690
                         * access to any namespaces and vice-versa. */
1691
                        flags = streq(field, "RestrictNamespaces") ? 0 : all;
2✔
1692
                else if (r == 0)
9✔
1693
                        flags = streq(field, "RestrictNamespaces") ? all : 0;
2✔
1694
                else {
1695
                        if (eq[0] == '~') {
7✔
1696
                                invert = true;
1✔
1697
                                eq++;
1✔
1698
                        }
1699

1700
                        r = namespace_flags_from_string(eq, &flags);
7✔
1701
                        if (r < 0)
7✔
1702
                                return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
11✔
1703
                }
1704

1705
                if (invert)
11✔
1706
                        flags = (~flags) & all;
1✔
1707

1708
                r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
11✔
1709
                if (r < 0)
11✔
1710
                        return bus_log_create_error(r);
×
1711

1712
                return 1;
1713
        }
1714

1715
        if (STR_IN_SET(field, "BindPaths",
504✔
1716
                              "BindReadOnlyPaths")) {
1717
                const char *p = eq;
10✔
1718

1719
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
10✔
1720
                if (r < 0)
10✔
1721
                        return bus_log_create_error(r);
10✔
1722

1723
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
10✔
1724
                if (r < 0)
10✔
1725
                        return bus_log_create_error(r);
×
1726

1727
                r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
10✔
1728
                if (r < 0)
10✔
1729
                        return bus_log_create_error(r);
×
1730

1731
                r = sd_bus_message_open_container(m, 'a', "(ssbt)");
10✔
1732
                if (r < 0)
10✔
1733
                        return bus_log_create_error(r);
×
1734

1735
                for (;;) {
46✔
1736
                        _cleanup_free_ char *source = NULL, *destination = NULL;
18✔
1737
                        char *s = NULL, *d = NULL;
28✔
1738
                        bool ignore_enoent = false;
28✔
1739
                        uint64_t flags = MS_REC;
28✔
1740

1741
                        r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
28✔
1742
                        if (r < 0)
28✔
1743
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1744
                        if (r == 0)
28✔
1745
                                break;
1746

1747
                        s = source;
18✔
1748
                        if (s[0] == '-') {
18✔
1749
                                ignore_enoent = true;
2✔
1750
                                s++;
2✔
1751
                        }
1752

1753
                        if (p && p[-1] == ':') {
18✔
1754
                                r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
10✔
1755
                                if (r < 0)
10✔
1756
                                        return log_error_errno(r, "Failed to parse argument: %m");
×
1757
                                if (r == 0)
10✔
1758
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1759
                                                               "Missing argument after ':': %s",
1760
                                                               eq);
1761

1762
                                d = destination;
10✔
1763

1764
                                if (p && p[-1] == ':') {
10✔
1765
                                        _cleanup_free_ char *options = NULL;
6✔
1766

1767
                                        r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
6✔
1768
                                        if (r < 0)
6✔
1769
                                                return log_error_errno(r, "Failed to parse argument: %m");
×
1770

1771
                                        if (isempty(options) || streq(options, "rbind"))
16✔
1772
                                                flags = MS_REC;
1773
                                        else if (streq(options, "norbind"))
4✔
1774
                                                flags = 0;
1775
                                        else
1776
                                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1777
                                                                       "Unknown options: %s",
1778
                                                                       eq);
1779
                                }
1780
                        } else
1781
                                d = s;
1782

1783
                        r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
18✔
1784
                        if (r < 0)
18✔
1785
                                return bus_log_create_error(r);
×
1786
                }
1787

1788
                r = sd_bus_message_close_container(m);
10✔
1789
                if (r < 0)
10✔
1790
                        return bus_log_create_error(r);
×
1791

1792
                r = sd_bus_message_close_container(m);
10✔
1793
                if (r < 0)
10✔
1794
                        return bus_log_create_error(r);
×
1795

1796
                r = sd_bus_message_close_container(m);
10✔
1797
                if (r < 0)
10✔
1798
                        return bus_log_create_error(r);
×
1799

1800
                return 1;
1801
        }
1802

1803
        if (streq(field, "TemporaryFileSystem")) {
494✔
1804
                const char *p = eq;
48✔
1805

1806
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
48✔
1807
                if (r < 0)
48✔
1808
                        return bus_log_create_error(r);
48✔
1809

1810
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
48✔
1811
                if (r < 0)
48✔
1812
                        return bus_log_create_error(r);
×
1813

1814
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
48✔
1815
                if (r < 0)
48✔
1816
                        return bus_log_create_error(r);
×
1817

1818
                r = sd_bus_message_open_container(m, 'a', "(ss)");
48✔
1819
                if (r < 0)
48✔
1820
                        return bus_log_create_error(r);
×
1821

1822
                for (;;) {
144✔
1823
                        _cleanup_free_ char *word = NULL, *path = NULL;
48✔
1824
                        const char *w;
96✔
1825

1826
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
96✔
1827
                        if (r < 0)
96✔
1828
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1829
                        if (r == 0)
96✔
1830
                                break;
1831

1832
                        w = word;
48✔
1833
                        r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
48✔
1834
                        if (r < 0)
48✔
1835
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1836
                        if (r == 0)
48✔
1837
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1838
                                                       "Failed to parse argument: %s",
1839
                                                       p);
1840

1841
                        r = sd_bus_message_append(m, "(ss)", path, w);
48✔
1842
                        if (r < 0)
48✔
1843
                                return bus_log_create_error(r);
×
1844
                }
1845

1846
                r = sd_bus_message_close_container(m);
48✔
1847
                if (r < 0)
48✔
1848
                        return bus_log_create_error(r);
×
1849

1850
                r = sd_bus_message_close_container(m);
48✔
1851
                if (r < 0)
48✔
1852
                        return bus_log_create_error(r);
×
1853

1854
                r = sd_bus_message_close_container(m);
48✔
1855
                if (r < 0)
48✔
1856
                        return bus_log_create_error(r);
×
1857

1858
                return 1;
1859
        }
1860

1861
        if (streq(field, "RootHash")) {
446✔
1862
                _cleanup_free_ void *roothash_decoded = NULL;
12✔
1863
                size_t roothash_decoded_size = 0;
12✔
1864

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

1869
                /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1870
                r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
11✔
1871
                if (r < 0)
11✔
1872
                        return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
×
1873
                if (roothash_decoded_size < sizeof(sd_id128_t))
11✔
1874
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
×
1875

1876
                return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
11✔
1877
        }
1878

1879
        if (streq(field, "RootHashSignature")) {
434✔
1880
                _cleanup_free_ void *roothash_sig_decoded = NULL;
×
1881
                char *value;
×
1882
                size_t roothash_sig_decoded_size = 0;
×
1883

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

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

1891
                /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1892
                r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
×
1893
                if (r < 0)
×
1894
                        return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
×
1895

1896
                return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
×
1897
        }
1898

1899
        if (streq(field, "RootImageOptions")) {
434✔
1900
                _cleanup_strv_free_ char **l = NULL;
2✔
1901
                const char *p = eq;
2✔
1902

1903
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
1904
                if (r < 0)
2✔
1905
                        return bus_log_create_error(r);
×
1906

1907
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
1908
                if (r < 0)
2✔
1909
                        return bus_log_create_error(r);
×
1910

1911
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
2✔
1912
                if (r < 0)
2✔
1913
                        return bus_log_create_error(r);
×
1914

1915
                r = sd_bus_message_open_container(m, 'a', "(ss)");
2✔
1916
                if (r < 0)
2✔
1917
                        return bus_log_create_error(r);
×
1918

1919
                r = strv_split_colon_pairs(&l, p);
2✔
1920
                if (r < 0)
2✔
1921
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1922

1923
                STRV_FOREACH_PAIR(first, second, l) {
7✔
1924
                        r = sd_bus_message_append(m, "(ss)",
15✔
1925
                                                  !isempty(*second) ? *first : "root",
5✔
1926
                                                  !isempty(*second) ? *second : *first);
5✔
1927
                        if (r < 0)
5✔
1928
                                return bus_log_create_error(r);
×
1929
                }
1930

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

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

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

1943
                return 1;
1944
        }
1945

1946
        if (streq(field, "MountImages")) {
432✔
1947
                const char *p = eq;
11✔
1948

1949
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
11✔
1950
                if (r < 0)
11✔
1951
                        return bus_log_create_error(r);
11✔
1952

1953
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
11✔
1954
                if (r < 0)
11✔
1955
                        return bus_log_create_error(r);
×
1956

1957
                r = sd_bus_message_open_container(m, 'v', "a(ssba(ss))");
11✔
1958
                if (r < 0)
11✔
1959
                        return bus_log_create_error(r);
×
1960

1961
                r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
11✔
1962
                if (r < 0)
11✔
1963
                        return bus_log_create_error(r);
×
1964

1965
                for (;;) {
29✔
1966
                        _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
18✔
1967
                        const char *q = NULL, *source = NULL;
29✔
1968
                        bool permissive = false;
29✔
1969

1970
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
29✔
1971
                        if (r < 0)
29✔
1972
                                return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1973
                        if (r == 0)
29✔
1974
                                break;
1975

1976
                        q = tuple;
18✔
1977
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
18✔
1978
                        if (r < 0)
18✔
1979
                                return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1980
                        if (r == 0)
18✔
1981
                                continue;
×
1982

1983
                        source = first;
18✔
1984
                        if (source[0] == '-') {
18✔
1985
                                permissive = true;
×
1986
                                source++;
×
1987
                        }
1988

1989
                        if (isempty(second))
18✔
1990
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1991
                                                        "Missing argument after ':': %s",
1992
                                                        eq);
1993

1994
                        r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
18✔
1995
                        if (r < 0)
18✔
1996
                                return bus_log_create_error(r);
×
1997

1998
                        r = sd_bus_message_append(m, "ssb", source, second, permissive);
18✔
1999
                        if (r < 0)
18✔
2000
                                return bus_log_create_error(r);
×
2001

2002
                        r = sd_bus_message_open_container(m, 'a', "(ss)");
18✔
2003
                        if (r < 0)
18✔
2004
                                return bus_log_create_error(r);
×
2005

2006
                        for (;;) {
22✔
2007
                                _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2✔
2008

2009
                                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
20✔
2010
                                if (r < 0)
20✔
2011
                                        return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
2012
                                if (r == 0)
20✔
2013
                                        break;
2014
                                /* Single set of options, applying to the root partition/single filesystem */
2015
                                if (r == 1) {
5✔
2016
                                        r = sd_bus_message_append(m, "(ss)", "root", partition);
3✔
2017
                                        if (r < 0)
3✔
2018
                                                return bus_log_create_error(r);
×
2019

2020
                                        break;
2021
                                }
2022

2023
                                r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2✔
2024
                                if (r < 0)
2✔
2025
                                        return bus_log_create_error(r);
×
2026
                        }
2027

2028
                        r = sd_bus_message_close_container(m);
18✔
2029
                        if (r < 0)
18✔
2030
                                return bus_log_create_error(r);
×
2031

2032
                        r = sd_bus_message_close_container(m);
18✔
2033
                        if (r < 0)
18✔
2034
                                return bus_log_create_error(r);
×
2035
                }
2036

2037
                r = sd_bus_message_close_container(m);
11✔
2038
                if (r < 0)
11✔
2039
                        return bus_log_create_error(r);
×
2040

2041
                r = sd_bus_message_close_container(m);
11✔
2042
                if (r < 0)
11✔
2043
                        return bus_log_create_error(r);
×
2044

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

2049
                return 1;
2050
        }
2051

2052
        if (streq(field, "ExtensionImages")) {
421✔
2053
                const char *p = eq;
20✔
2054

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

2059
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
20✔
2060
                if (r < 0)
20✔
2061
                        return bus_log_create_error(r);
×
2062

2063
                r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
20✔
2064
                if (r < 0)
20✔
2065
                        return bus_log_create_error(r);
×
2066

2067
                r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
20✔
2068
                if (r < 0)
20✔
2069
                        return bus_log_create_error(r);
×
2070

2071
                for (;;) {
48✔
2072
                        _cleanup_free_ char *source = NULL, *tuple = NULL;
28✔
2073
                        const char *q = NULL, *s = NULL;
48✔
2074
                        bool permissive = false;
48✔
2075

2076
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
48✔
2077
                        if (r < 0)
48✔
2078
                                return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2079
                        if (r == 0)
48✔
2080
                                break;
2081

2082
                        q = tuple;
28✔
2083
                        r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
28✔
2084
                        if (r < 0)
28✔
2085
                                return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2086
                        if (r == 0)
28✔
2087
                                continue;
×
2088

2089
                        s = source;
28✔
2090
                        if (s[0] == '-') {
28✔
2091
                                permissive = true;
2✔
2092
                                s++;
2✔
2093
                        }
2094

2095
                        r = sd_bus_message_open_container(m, 'r', "sba(ss)");
28✔
2096
                        if (r < 0)
28✔
2097
                                return bus_log_create_error(r);
×
2098

2099
                        r = sd_bus_message_append(m, "sb", s, permissive);
28✔
2100
                        if (r < 0)
28✔
2101
                                return bus_log_create_error(r);
×
2102

2103
                        r = sd_bus_message_open_container(m, 'a', "(ss)");
28✔
2104
                        if (r < 0)
28✔
2105
                                return bus_log_create_error(r);
×
2106

2107
                        for (;;) {
28✔
2108
                                _cleanup_free_ char *partition = NULL, *mount_options = NULL;
×
2109

2110
                                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
28✔
2111
                                if (r < 0)
28✔
2112
                                        return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2113
                                if (r == 0)
28✔
2114
                                        break;
2115
                                /* Single set of options, applying to the root partition/single filesystem */
2116
                                if (r == 1) {
×
2117
                                        r = sd_bus_message_append(m, "(ss)", "root", partition);
×
2118
                                        if (r < 0)
×
2119
                                                return bus_log_create_error(r);
×
2120

2121
                                        break;
2122
                                }
2123

2124
                                r = sd_bus_message_append(m, "(ss)", partition, mount_options);
×
2125
                                if (r < 0)
×
2126
                                        return bus_log_create_error(r);
×
2127
                        }
2128

2129
                        r = sd_bus_message_close_container(m);
28✔
2130
                        if (r < 0)
28✔
2131
                                return bus_log_create_error(r);
×
2132

2133
                        r = sd_bus_message_close_container(m);
28✔
2134
                        if (r < 0)
28✔
2135
                                return bus_log_create_error(r);
×
2136
                }
2137

2138
                r = sd_bus_message_close_container(m);
20✔
2139
                if (r < 0)
20✔
2140
                        return bus_log_create_error(r);
×
2141

2142
                r = sd_bus_message_close_container(m);
20✔
2143
                if (r < 0)
20✔
2144
                        return bus_log_create_error(r);
×
2145

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

2150
                return 1;
2151
        }
2152

2153
        if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
401✔
2154
                _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
183✔
2155
                const char *p = eq;
183✔
2156

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

2161
                for (;;) {
665✔
2162
                        _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
241✔
2163

2164
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
424✔
2165
                        if (r < 0)
424✔
2166
                                return log_error_errno(r, "Failed to parse argument: %m");
×
2167
                        if (r == 0)
424✔
2168
                                break;
2169

2170
                        const char *t = tuple;
241✔
2171
                        r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
241✔
2172
                        if (r <= 0)
241✔
2173
                                return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
×
2174

2175
                        path_simplify(source);
241✔
2176

2177
                        if (isempty(dest) && isempty(flags)) {
278✔
2178
                                r = strv_consume(&sources, TAKE_PTR(source));
110✔
2179
                                if (r < 0)
110✔
2180
                                        return bus_log_create_error(r);
×
2181
                        } else if (isempty(flags)) {
131✔
2182
                                path_simplify(dest);
57✔
2183
                                r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
57✔
2184
                                if (r < 0)
57✔
2185
                                        return log_oom();
×
2186
                        } else {
2187
                                ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
74✔
2188
                                if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
74✔
2189
                                        return log_error_errno(r, "Failed to parse flags: %s", flags);
×
2190

2191
                                if (!isempty(dest)) {
74✔
2192
                                        path_simplify(dest);
37✔
2193
                                        r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
37✔
2194
                                } else
2195
                                        r = strv_consume(&sources_ro, TAKE_PTR(source));
37✔
2196
                                if (r < 0)
74✔
2197
                                        return log_oom();
×
2198
                        }
2199
                }
2200

2201
                if (!strv_isempty(sources)) {
183✔
2202
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
95✔
2203
                        if (r < 0)
95✔
2204
                                return bus_log_create_error(r);
×
2205

2206
                        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
95✔
2207
                        if (r < 0)
95✔
2208
                                return bus_log_create_error(r);
×
2209

2210
                        r = sd_bus_message_open_container(m, 'v', "as");
95✔
2211
                        if (r < 0)
95✔
2212
                                return bus_log_create_error(r);
×
2213

2214
                        r = sd_bus_message_append_strv(m, sources);
95✔
2215
                        if (r < 0)
95✔
2216
                                return bus_log_create_error(r);
×
2217

2218
                        r = sd_bus_message_close_container(m);
95✔
2219
                        if (r < 0)
95✔
2220
                                return bus_log_create_error(r);
×
2221

2222
                        r = sd_bus_message_close_container(m);
95✔
2223
                        if (r < 0)
95✔
2224
                                return bus_log_create_error(r);
×
2225
                }
2226

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

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

2237
                        if (streq(field, "StateDirectory"))
83✔
2238
                                symlink_field = "StateDirectorySymlink";
2239
                        else if (streq(field, "RuntimeDirectory"))
62✔
2240
                                symlink_field = "RuntimeDirectorySymlink";
2241
                        else if (streq(field, "CacheDirectory"))
38✔
2242
                                symlink_field = "CacheDirectorySymlink";
2243
                        else if (streq(field, "LogsDirectory"))
19✔
2244
                                symlink_field = "LogsDirectorySymlink";
2245
                        else
2246
                                assert_not_reached();
×
2247

2248
                        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, symlink_field);
83✔
2249
                        if (r < 0)
83✔
2250
                                return bus_log_create_error(r);
×
2251

2252
                        r = sd_bus_message_open_container(m, 'v', "a(sst)");
83✔
2253
                        if (r < 0)
83✔
2254
                                return bus_log_create_error(r);
×
2255

2256
                        r = sd_bus_message_open_container(m, 'a', "(sst)");
83✔
2257
                        if (r < 0)
83✔
2258
                                return bus_log_create_error(r);
×
2259

2260
                        STRV_FOREACH_PAIR(source, destination, symlinks) {
140✔
2261
                                r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
57✔
2262
                                if (r < 0)
57✔
2263
                                        return bus_log_create_error(r);
×
2264
                        }
2265

2266
                        STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
120✔
2267
                                r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2268
                                if (r < 0)
37✔
2269
                                        return bus_log_create_error(r);
×
2270
                        }
2271

2272
                        STRV_FOREACH(source, sources_ro) {
120✔
2273
                                r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2274
                                if (r < 0)
37✔
2275
                                        return bus_log_create_error(r);
×
2276
                        }
2277

2278
                        r = sd_bus_message_close_container(m);
83✔
2279
                        if (r < 0)
83✔
2280
                                return bus_log_create_error(r);
×
2281

2282
                        r = sd_bus_message_close_container(m);
83✔
2283
                        if (r < 0)
83✔
2284
                                return bus_log_create_error(r);
×
2285

2286
                        r = sd_bus_message_close_container(m);
83✔
2287
                        if (r < 0)
83✔
2288
                                return bus_log_create_error(r);
×
2289
                }
2290

2291
                return 1;
183✔
2292
        }
2293

2294
        if (streq(field, "ProtectHostnameEx")) {
218✔
2295
                const char *colon = strchr(eq, ':');
16✔
2296
                if (colon) {
16✔
2297
                        if (isempty(colon + 1))
11✔
2298
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
2,800✔
2299

2300
                        _cleanup_free_ char *p = strndup(eq, colon - eq);
9✔
2301
                        if (!p)
9✔
2302
                                return -ENOMEM;
×
2303

2304
                        r = sd_bus_message_append(m, "(sv)", field, "(ss)", p, colon + 1);
9✔
2305
                } else
2306
                        r = sd_bus_message_append(m, "(sv)", field, "(ss)", eq, NULL);
5✔
2307
                if (r < 0)
14✔
2308
                        return bus_log_create_error(r);
×
2309

2310
                return 1;
2311
        }
2312
        return 0;
2313
}
2314

2315
static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
210✔
2316
        if (streq(field, "KillMode"))
210✔
2317
                return bus_append_string(m, field, eq);
1✔
2318

2319
        if (STR_IN_SET(field, "SendSIGHUP",
209✔
2320
                              "SendSIGKILL"))
2321
                return bus_append_parse_boolean(m, field, eq);
×
2322

2323
        if (STR_IN_SET(field, "KillSignal",
209✔
2324
                              "RestartKillSignal",
2325
                              "FinalKillSignal",
2326
                              "WatchdogSignal",
2327
                              "ReloadSignal"))
2328
                return bus_append_signal_from_string(m, field, eq);
2✔
2329

2330
        return 0;
207✔
2331
}
2332

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

2335
        if (STR_IN_SET(field, "What",
1✔
2336
                              "Where",
2337
                              "Options",
2338
                              "Type"))
2339
                return bus_append_string(m, field, eq);
×
2340

2341
        if (streq(field, "TimeoutSec"))
1✔
2342
                return bus_append_parse_sec_rename(m, field, eq);
×
2343

2344
        if (streq(field, "DirectoryMode"))
1✔
2345
                return bus_append_parse_mode(m, field, eq);
×
2346

2347
        if (STR_IN_SET(field, "SloppyOptions",
1✔
2348
                              "LazyUnmount",
2349
                              "ForceUnmount",
2350
                              "ReadwriteOnly"))
2351
                return bus_append_parse_boolean(m, field, eq);
×
2352

2353
        return 0;
1✔
2354
}
2355

2356
static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
3✔
2357
        int r;
3✔
2358

2359
        if (streq(field, "MakeDirectory"))
3✔
2360
                return bus_append_parse_boolean(m, field, eq);
×
2361

2362
        if (streq(field, "DirectoryMode"))
3✔
2363
                return bus_append_parse_mode(m, field, eq);
×
2364

2365
        if (STR_IN_SET(field, "PathExists",
3✔
2366
                              "PathExistsGlob",
2367
                              "PathChanged",
2368
                              "PathModified",
2369
                              "DirectoryNotEmpty")) {
2370
                if (isempty(eq))
3✔
2371
                        r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
×
2372
                else
2373
                        r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
3✔
2374
                if (r < 0)
3✔
2375
                        return bus_log_create_error(r);
3✔
2376

2377
                return 1;
2378
        }
2379

2380
        if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
×
2381
                return bus_append_safe_atou(m, field, eq);
×
2382

2383
        if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
×
2384
                return bus_append_parse_sec_rename(m, field, eq);
×
2385

2386
        return 0;
×
2387
}
2388

2389
static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
8✔
2390
        if (streq(field, "RuntimeMaxSec"))
8✔
2391
                return bus_append_parse_sec_rename(m, field, eq);
4✔
2392

2393
        if (streq(field, "RuntimeRandomizedExtraSec"))
4✔
2394
                return bus_append_parse_sec_rename(m, field, eq);
×
2395

2396
        if (streq(field, "TimeoutStopSec"))
4✔
2397
                return bus_append_parse_sec_rename(m, field, eq);
×
2398

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

2404
        if (streq(field, "OOMPolicy"))
3✔
2405
                return bus_append_string(m, field, eq);
×
2406

2407
        return 0;
2408
}
2409

2410
static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
194✔
2411
        int r;
194✔
2412

2413
        if (STR_IN_SET(field, "PIDFile",
194✔
2414
                              "Type",
2415
                              "ExitType",
2416
                              "Restart",
2417
                              "RestartMode",
2418
                              "BusName",
2419
                              "NotifyAccess",
2420
                              "USBFunctionDescriptors",
2421
                              "USBFunctionStrings",
2422
                              "OOMPolicy",
2423
                              "TimeoutStartFailureMode",
2424
                              "TimeoutStopFailureMode",
2425
                              "FileDescriptorStorePreserve"))
2426
                return bus_append_string(m, field, eq);
119✔
2427

2428
        if (STR_IN_SET(field, "PermissionsStartOnly",
75✔
2429
                              "RootDirectoryStartOnly",
2430
                              "RemainAfterExit",
2431
                              "GuessMainPID"))
2432
                return bus_append_parse_boolean(m, field, eq);
1✔
2433

2434
        if (STR_IN_SET(field, "RestartSec",
74✔
2435
                              "RestartMaxDelaySec",
2436
                              "TimeoutStartSec",
2437
                              "TimeoutStopSec",
2438
                              "TimeoutAbortSec",
2439
                              "RuntimeMaxSec",
2440
                              "RuntimeRandomizedExtraSec",
2441
                              "WatchdogSec"))
2442
                return bus_append_parse_sec_rename(m, field, eq);
2✔
2443

2444
        if (streq(field, "TimeoutSec")) {
72✔
2445
                r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
×
2446
                if (r < 0)
×
2447
                        return r;
2448

2449
                return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
×
2450
        }
2451

2452
        if (STR_IN_SET(field, "FileDescriptorStoreMax",
72✔
2453
                              "RestartSteps"))
2454
                return bus_append_safe_atou(m, field, eq);
1✔
2455

2456
        if (STR_IN_SET(field, "ExecCondition",
71✔
2457
                              "ExecStartPre",
2458
                              "ExecStart",
2459
                              "ExecStartPost",
2460
                              "ExecConditionEx",
2461
                              "ExecStartPreEx",
2462
                              "ExecStartEx",
2463
                              "ExecStartPostEx",
2464
                              "ExecReload",
2465
                              "ExecStop",
2466
                              "ExecStopPost",
2467
                              "ExecReloadEx",
2468
                              "ExecStopEx",
2469
                              "ExecStopPostEx"))
2470
                return bus_append_exec_command(m, field, eq);
43✔
2471

2472
        if (STR_IN_SET(field, "RestartPreventExitStatus",
28✔
2473
                              "RestartForceExitStatus",
2474
                              "SuccessExitStatus")) {
2475
                _cleanup_free_ int *status = NULL, *signal = NULL;
×
2476
                size_t n_status = 0, n_signal = 0;
×
2477
                const char *p;
×
2478

2479
                for (p = eq;;) {
×
2480
                        _cleanup_free_ char *word = NULL;
×
2481

2482
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
×
2483
                        if (r == 0)
×
2484
                                break;
2485
                        if (r == -ENOMEM)
×
2486
                                return log_oom();
×
2487
                        if (r < 0)
×
2488
                                return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
×
2489

2490
                        /* We need to call exit_status_from_string() first, because we want
2491
                         * to parse numbers as exit statuses, not signals. */
2492

2493
                        r = exit_status_from_string(word);
×
2494
                        if (r >= 0) {
×
2495
                                assert(r >= 0 && r < 256);
×
2496

2497
                                if (!GREEDY_REALLOC(status, n_status + 1))
×
2498
                                        return log_oom();
×
2499

2500
                                status[n_status++] = r;
×
2501

2502
                        } else if ((r = signal_from_string(word)) >= 0) {
×
2503
                                if (!GREEDY_REALLOC(signal, n_signal + 1))
×
2504
                                        return log_oom();
×
2505

2506
                                signal[n_signal++] = r;
×
2507

2508
                        } else
2509
                                /* original r from exit_status_to_string() */
2510
                                return log_error_errno(r, "Invalid status or signal %s in %s: %m",
×
2511
                                                       word, field);
2512
                }
2513

2514
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
2515
                if (r < 0)
×
2516
                        return bus_log_create_error(r);
×
2517

2518
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
2519
                if (r < 0)
×
2520
                        return bus_log_create_error(r);
×
2521

2522
                r = sd_bus_message_open_container(m, 'v', "(aiai)");
×
2523
                if (r < 0)
×
2524
                        return bus_log_create_error(r);
×
2525

2526
                r = sd_bus_message_open_container(m, 'r', "aiai");
×
2527
                if (r < 0)
×
2528
                        return bus_log_create_error(r);
×
2529

2530
                r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
×
2531
                if (r < 0)
×
2532
                        return bus_log_create_error(r);
×
2533

2534
                r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
×
2535
                if (r < 0)
×
2536
                        return bus_log_create_error(r);
×
2537

2538
                r = sd_bus_message_close_container(m);
×
2539
                if (r < 0)
×
2540
                        return bus_log_create_error(r);
×
2541

2542
                r = sd_bus_message_close_container(m);
×
2543
                if (r < 0)
×
2544
                        return bus_log_create_error(r);
×
2545

2546
                r = sd_bus_message_close_container(m);
×
2547
                if (r < 0)
×
2548
                        return bus_log_create_error(r);
×
2549

2550
                return 1;
2551
        }
2552

2553
        if (streq(field, "OpenFile"))
28✔
2554
                return bus_append_open_file(m, field, eq);
5✔
2555

2556
        return 0;
2557
}
2558

2559
static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
4✔
2560
        int r;
4✔
2561

2562
        if (STR_IN_SET(field, "Accept",
4✔
2563
                              "FlushPending",
2564
                              "Writable",
2565
                              "KeepAlive",
2566
                              "NoDelay",
2567
                              "FreeBind",
2568
                              "Transparent",
2569
                              "Broadcast",
2570
                              "PassCredentials",
2571
                              "PassFileDescriptorsToExec",
2572
                              "PassSecurity",
2573
                              "PassPacketInfo",
2574
                              "ReusePort",
2575
                              "RemoveOnStop",
2576
                              "SELinuxContextFromNet"))
2577
                return bus_append_parse_boolean(m, field, eq);
×
2578

2579
        if (STR_IN_SET(field, "Priority",
4✔
2580
                              "IPTTL",
2581
                              "Mark"))
2582
                return bus_append_safe_atoi(m, field, eq);
×
2583

2584
        if (streq(field, "IPTOS"))
4✔
2585
                return bus_append_ip_tos_from_string(m, field, eq);
×
2586

2587
        if (STR_IN_SET(field, "Backlog",
4✔
2588
                              "MaxConnections",
2589
                              "MaxConnectionsPerSource",
2590
                              "KeepAliveProbes",
2591
                              "TriggerLimitBurst",
2592
                              "PollLimitBurst"))
2593
                return bus_append_safe_atou(m, field, eq);
×
2594

2595
        if (STR_IN_SET(field, "SocketMode",
4✔
2596
                              "DirectoryMode"))
2597
                return bus_append_parse_mode(m, field, eq);
2✔
2598

2599
        if (STR_IN_SET(field, "MessageQueueMaxMessages",
2✔
2600
                              "MessageQueueMessageSize"))
2601
                return bus_append_safe_atoi64(m, field, eq);
×
2602

2603
        if (STR_IN_SET(field, "TimeoutSec",
2✔
2604
                              "KeepAliveTimeSec",
2605
                              "KeepAliveIntervalSec",
2606
                              "DeferAcceptSec",
2607
                              "TriggerLimitIntervalSec",
2608
                              "PollLimitIntervalSec"))
2609
                return bus_append_parse_sec_rename(m, field, eq);
×
2610

2611
        if (STR_IN_SET(field, "ReceiveBuffer",
2✔
2612
                              "SendBuffer",
2613
                              "PipeSize"))
2614
                return bus_append_parse_size(m, field, eq, 1024);
×
2615

2616
        if (STR_IN_SET(field, "ExecStartPre",
2✔
2617
                              "ExecStartPost",
2618
                              "ExecReload",
2619
                              "ExecStopPost"))
2620
                return bus_append_exec_command(m, field, eq);
×
2621

2622
        if (STR_IN_SET(field, "SmackLabel",
2✔
2623
                              "SmackLabelIPIn",
2624
                              "SmackLabelIPOut",
2625
                              "TCPCongestion",
2626
                              "BindToDevice",
2627
                              "BindIPv6Only",
2628
                              "FileDescriptorName",
2629
                              "SocketUser",
2630
                              "SocketGroup",
2631
                              "Timestamping"))
2632
                return bus_append_string(m, field, eq);
×
2633

2634
        if (streq(field, "Symlinks"))
2✔
2635
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
2636

2637
        if (streq(field, "SocketProtocol"))
2✔
2638
                return bus_append_parse_ip_protocol(m, field, eq);
×
2639

2640
        if (STR_IN_SET(field, "ListenStream",
2✔
2641
                              "ListenDatagram",
2642
                              "ListenSequentialPacket",
2643
                              "ListenNetlink",
2644
                              "ListenSpecial",
2645
                              "ListenMessageQueue",
2646
                              "ListenFIFO",
2647
                              "ListenUSBFunction")) {
2648
                if (isempty(eq))
2✔
2649
                        r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
×
2650
                else
2651
                        r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2✔
2652
                if (r < 0)
2✔
2653
                        return bus_log_create_error(r);
2✔
2654

2655
                return 1;
2656
        }
2657

2658
        return 0;
×
2659
}
2660
static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
25✔
2661
        int r;
25✔
2662

2663
        if (STR_IN_SET(field, "WakeSystem",
25✔
2664
                              "RemainAfterElapse",
2665
                              "Persistent",
2666
                              "OnTimezoneChange",
2667
                              "OnClockChange",
2668
                              "FixedRandomDelay",
2669
                              "DeferReactivation"))
2670
                return bus_append_parse_boolean(m, field, eq);
5✔
2671

2672
        if (STR_IN_SET(field, "AccuracySec",
20✔
2673
                              "RandomizedDelaySec"))
2674
                return bus_append_parse_sec_rename(m, field, eq);
×
2675

2676
        if (STR_IN_SET(field, "OnActiveSec",
20✔
2677
                              "OnBootSec",
2678
                              "OnStartupSec",
2679
                              "OnUnitActiveSec",
2680
                              "OnUnitInactiveSec")) {
2681
                if (isempty(eq))
17✔
2682
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
5✔
2683
                else {
2684
                        usec_t t;
12✔
2685
                        r = parse_sec(eq, &t);
12✔
2686
                        if (r < 0)
12✔
2687
                                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
5✔
2688

2689
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
7✔
2690
                }
2691
                if (r < 0)
12✔
2692
                        return bus_log_create_error(r);
×
2693

2694
                return 1;
2695
        }
2696

2697
        if (streq(field, "OnCalendar")) {
3✔
2698
                if (isempty(eq))
2✔
2699
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
×
2700
                else
2701
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2✔
2702
                if (r < 0)
2✔
2703
                        return bus_log_create_error(r);
×
2704

2705
                return 1;
2706
        }
2707

2708
        return 0;
2709
}
2710

2711
static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
29✔
2712
        ConditionType t = _CONDITION_TYPE_INVALID;
29✔
2713
        bool is_condition = false;
29✔
2714
        int r;
29✔
2715

2716
        if (STR_IN_SET(field, "Description",
29✔
2717
                              "SourcePath",
2718
                              "OnFailureJobMode",
2719
                              "JobTimeoutAction",
2720
                              "JobTimeoutRebootArgument",
2721
                              "StartLimitAction",
2722
                              "FailureAction",
2723
                              "SuccessAction",
2724
                              "RebootArgument",
2725
                              "CollectMode"))
2726
                return bus_append_string(m, field, eq);
12✔
2727

2728
        if (STR_IN_SET(field, "StopWhenUnneeded",
17✔
2729
                              "RefuseManualStart",
2730
                              "RefuseManualStop",
2731
                              "AllowIsolate",
2732
                              "IgnoreOnIsolate",
2733
                              "SurviveFinalKillSignal",
2734
                              "DefaultDependencies"))
2735
                return bus_append_parse_boolean(m, field, eq);
2✔
2736

2737
        if (STR_IN_SET(field, "JobTimeoutSec",
15✔
2738
                              "JobRunningTimeoutSec",
2739
                              "StartLimitIntervalSec"))
2740
                return bus_append_parse_sec_rename(m, field, eq);
1✔
2741

2742
        if (streq(field, "StartLimitBurst"))
14✔
2743
                return bus_append_safe_atou(m, field, eq);
1✔
2744

2745
        if (STR_IN_SET(field, "SuccessActionExitStatus",
13✔
2746
                              "FailureActionExitStatus")) {
2747
                if (isempty(eq))
×
2748
                        r = sd_bus_message_append(m, "(sv)", field, "i", -1);
×
2749
                else {
2750
                        uint8_t u;
×
2751

2752
                        r = safe_atou8(eq, &u);
×
2753
                        if (r < 0)
×
2754
                                return log_error_errno(r, "Failed to parse %s=%s", field, eq);
×
2755

2756
                        r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
×
2757
                }
2758
                if (r < 0)
×
2759
                        return bus_log_create_error(r);
×
2760

2761
                return 1;
2762
        }
2763

2764
        if (unit_dependency_from_string(field) >= 0 ||
16✔
2765
            STR_IN_SET(field, "Documentation",
3✔
2766
                              "RequiresMountsFor",
2767
                              "WantsMountsFor",
2768
                              "Markers"))
2769
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
11✔
2770

2771
        t = condition_type_from_string(field);
2✔
2772
        if (t >= 0)
2✔
2773
                is_condition = true;
2774
        else
2775
                t = assert_type_from_string(field);
2✔
2776
        if (t >= 0) {
2✔
2777
                if (isempty(eq))
2✔
2778
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
×
2779
                else {
2780
                        const char *p = eq;
2✔
2781
                        int trigger, negate;
2✔
2782

2783
                        trigger = *p == '|';
2✔
2784
                        if (trigger)
2✔
2785
                                p++;
×
2786

2787
                        negate = *p == '!';
2✔
2788
                        if (negate)
2✔
2789
                                p++;
×
2790

2791
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
4✔
2792
                                                  field, trigger, negate, p);
2793
                }
2794
                if (r < 0)
2✔
2795
                        return bus_log_create_error(r);
×
2796

2797
                return 1;
2798
        }
2799

2800
        return 0;
2801
}
2802

2803
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
3,232✔
2804
        const char *eq, *field;
3,232✔
2805
        int r;
3,232✔
2806

2807
        assert(m);
3,232✔
2808
        assert(assignment);
3,232✔
2809

2810
        eq = strchr(assignment, '=');
3,232✔
2811
        if (!eq)
3,232✔
2812
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2813
                                       "Not an assignment: %s", assignment);
2814

2815
        field = strndupa_safe(assignment, eq - assignment);
3,230✔
2816
        eq++;
3,230✔
2817

2818
        switch (t) {
3,230✔
2819
        case UNIT_SERVICE:
3,181✔
2820
                r = bus_append_cgroup_property(m, field, eq);
3,181✔
2821
                if (r != 0)
3,181✔
2822
                        return r;
2823

2824
                r = bus_append_execute_property(m, field, eq);
2,793✔
2825
                if (r != 0)
2,793✔
2826
                        return r;
2827

2828
                r = bus_append_kill_property(m, field, eq);
197✔
2829
                if (r != 0)
197✔
2830
                        return r;
2831

2832
                r = bus_append_service_property(m, field, eq);
194✔
2833
                if (r != 0)
194✔
2834
                        return r;
2835
                break;
2836

2837
        case UNIT_SOCKET:
4✔
2838
                r = bus_append_cgroup_property(m, field, eq);
4✔
2839
                if (r != 0)
4✔
2840
                        return r;
2841

2842
                r = bus_append_execute_property(m, field, eq);
4✔
2843
                if (r != 0)
4✔
2844
                        return r;
2845

2846
                r = bus_append_kill_property(m, field, eq);
4✔
2847
                if (r != 0)
4✔
2848
                        return r;
2849

2850
                r = bus_append_socket_property(m, field, eq);
4✔
2851
                if (r != 0)
4✔
2852
                        return r;
2853
                break;
2854

2855
        case UNIT_TIMER:
25✔
2856
                r = bus_append_timer_property(m, field, eq);
25✔
2857
                if (r != 0)
25✔
2858
                        return r;
2859
                break;
2860

2861
        case UNIT_PATH:
3✔
2862
                r = bus_append_path_property(m, field, eq);
3✔
2863
                if (r != 0)
3✔
2864
                        return r;
2865
                break;
2866

2867
        case UNIT_SLICE:
3✔
2868
                r = bus_append_cgroup_property(m, field, eq);
3✔
2869
                if (r != 0)
3✔
2870
                        return r;
2871
                break;
2872

2873
        case UNIT_SCOPE:
10✔
2874
                r = bus_append_cgroup_property(m, field, eq);
10✔
2875
                if (r != 0)
10✔
2876
                        return r;
2877

2878
                r = bus_append_kill_property(m, field, eq);
8✔
2879
                if (r != 0)
8✔
2880
                        return r;
2881

2882
                r = bus_append_scope_property(m, field, eq);
8✔
2883
                if (r != 0)
8✔
2884
                        return r;
2885
                break;
2886

2887
        case UNIT_MOUNT:
3✔
2888
                r = bus_append_cgroup_property(m, field, eq);
3✔
2889
                if (r != 0)
3✔
2890
                        return r;
2891

2892
                r = bus_append_execute_property(m, field, eq);
3✔
2893
                if (r != 0)
3✔
2894
                        return r;
2895

2896
                r = bus_append_kill_property(m, field, eq);
1✔
2897
                if (r != 0)
1✔
2898
                        return r;
2899

2900
                r = bus_append_mount_property(m, field, eq);
1✔
2901
                if (r != 0)
1✔
2902
                        return r;
2903

2904
                break;
2905

2906
        case UNIT_AUTOMOUNT:
1✔
2907
                r = bus_append_automount_property(m, field, eq);
1✔
2908
                if (r != 0)
1✔
2909
                        return r;
2910

2911
                break;
2912

2913
        case UNIT_TARGET:
2914
        case UNIT_DEVICE:
2915
        case UNIT_SWAP:
2916
                break;
2917

2918
        default:
×
2919
                assert_not_reached();
×
2920
        }
2921

2922
        r = bus_append_unit_property(m, field, eq);
29✔
2923
        if (r != 0)
29✔
2924
                return r;
2925

2926
        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
2927
                               "Unknown assignment: %s", assignment);
2928
}
2929

2930
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1,335✔
2931
        int r;
1,335✔
2932

2933
        assert(m);
1,335✔
2934

2935
        STRV_FOREACH(i, l) {
4,558✔
2936
                r = bus_append_unit_property_assignment(m, t, *i);
3,232✔
2937
                if (r < 0)
3,232✔
2938
                        return r;
2939
        }
2940

2941
        return 0;
2942
}
2943

2944
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
429✔
2945
        assert(m);
429✔
2946

2947
        if (!pidref_is_set(pidref))
429✔
2948
                return -ESRCH;
2949

2950
        if (pidref->fd >= 0 && allow_pidfd)
429✔
2951
                return sd_bus_message_append(
429✔
2952
                                m, "(sv)",
2953
                                "PIDFDs", "ah", 1, pidref->fd);
2954

2955
        return sd_bus_message_append(
×
2956
                        m, "(sv)",
2957
                        "PIDs", "au", 1, pidref->pid);
2958
}
2959

2960
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
58✔
2961
        const char *type, *path, *source;
58✔
2962
        InstallChange *changes = NULL;
58✔
2963
        size_t n_changes = 0;
58✔
2964
        int r;
58✔
2965

2966
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
58✔
2967

2968
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
58✔
2969
        if (r < 0)
58✔
2970
                return bus_log_parse_error(r);
×
2971

2972
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
115✔
2973
                InstallChangeType t;
57✔
2974

2975
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2976
                 * negative. */
2977
                t = install_change_type_from_string(type);
57✔
2978
                if (t < 0) {
57✔
2979
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
2980
                                         type, path);
2981
                        continue;
×
2982
                }
2983

2984
                r = install_changes_add(&changes, &n_changes, t, path, source);
57✔
2985
                if (r < 0)
57✔
2986
                        return r;
2987
        }
2988
        if (r < 0)
58✔
2989
                return bus_log_parse_error(r);
×
2990

2991
        r = sd_bus_message_exit_container(m);
58✔
2992
        if (r < 0)
58✔
2993
                return bus_log_parse_error(r);
×
2994

2995
        install_changes_dump(0, NULL, changes, n_changes, quiet);
58✔
2996

2997
        return 0;
2998
}
2999

3000
int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
3,477✔
3001
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3002
        _cleanup_free_ char *path = NULL;
3,477✔
3003
        int r;
3,477✔
3004

3005
        path = unit_dbus_path_from_name(name);
3,477✔
3006
        if (!path)
3,477✔
3007
                return log_oom();
×
3008

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

3012
        r = sd_bus_get_property_string(
3,477✔
3013
                        bus,
3014
                        "org.freedesktop.systemd1",
3015
                        path,
3016
                        "org.freedesktop.systemd1.Unit",
3017
                        "LoadState",
3018
                        &error,
3019
                        load_state);
3020
        if (r < 0)
3,477✔
3021
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
3022

3023
        return 0;
3024
}
3025

3026
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
31,561✔
3027
        int r;
31,561✔
3028

3029
        /* First, order by machine */
3030
        r = strcasecmp_ptr(a->machine, b->machine);
31,561✔
3031
        if (r != 0)
31,561✔
3032
                return r;
3033

3034
        /* Second, order by unit type */
3035
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
31,561✔
3036
        if (r != 0)
31,561✔
3037
                return r;
3038

3039
        /* Third, order by name */
3040
        return strcasecmp(a->id, b->id);
29,356✔
3041
}
3042

3043
int bus_service_manager_reload(sd_bus *bus) {
62✔
3044
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3045
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
62✔
3046
        int r;
62✔
3047

3048
        assert(bus);
62✔
3049

3050
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
62✔
3051
        if (r < 0)
62✔
3052
                return bus_log_create_error(r);
×
3053

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

3059
        return 0;
3060
}
3061

3062
typedef struct UnitFreezer {
3063
        char *name;
3064
        sd_bus *bus;
3065
} UnitFreezer;
3066

3067
/* Wait for 60 seconds at maximum for freezer operation */
3068
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3069

3070
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
3071
        if (!f)
×
3072
                return NULL;
3073

3074
        free(f->name);
×
3075
        sd_bus_flush_close_unref(f->bus);
×
3076

3077
        return mfree(f);
×
3078
}
3079

3080
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
3081
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
3082
        int r;
×
3083

3084
        assert(name);
×
3085
        assert(ret);
×
3086

3087
        f = new(UnitFreezer, 1);
×
3088
        if (!f)
×
3089
                return log_oom();
×
3090

3091
        *f = (UnitFreezer) {
×
3092
                .name = strdup(name),
×
3093
        };
3094
        if (!f->name)
×
3095
                return log_oom();
×
3096

3097
        r = bus_connect_system_systemd(&f->bus);
×
3098
        if (r < 0)
×
3099
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3100

3101
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3102

3103
        *ret = TAKE_PTR(f);
×
3104
        return 0;
×
3105
}
3106

3107
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
3108
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3109
        int r;
×
3110

3111
        assert(f);
×
3112
        assert(f->name);
×
3113
        assert(f->bus);
×
3114

3115
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3116
                            freeze ? "FreezeUnit" : "ThawUnit",
3117
                            &error,
3118
                            /* reply = */ NULL,
3119
                            "s",
3120
                            f->name);
3121
        if (r < 0) {
×
3122
                if (sd_bus_error_has_names(&error,
×
3123
                                           BUS_ERROR_NO_SUCH_UNIT,
3124
                                           BUS_ERROR_UNIT_INACTIVE,
3125
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3126

3127
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
3128
                        return 0;
×
3129
                }
3130

3131
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3132
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3133
        }
3134

3135
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3136
        return 1;
3137
}
3138

3139
int unit_freezer_freeze(UnitFreezer *f) {
×
3140
        return unit_freezer_action(f, true);
×
3141
}
3142

3143
int unit_freezer_thaw(UnitFreezer *f) {
×
3144
        return unit_freezer_action(f, false);
×
3145
}
3146

3147
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,802✔
3148
        if (isempty(s))
1,802✔
3149
                return 0;
3150

3151
        if (streq(s, "ro"))
74✔
3152
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3153

3154
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3155
}
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