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

systemd / systemd / 14606977008

22 Apr 2025 11:53PM UTC coverage: 72.18% (+0.1%) from 72.043%
14606977008

push

github

web-flow
network: enable ARP when IPv4LL and/or IPv4ACD is enabled (#37190)

51 of 56 new or added lines in 5 files covered. (91.07%)

1842 existing lines in 57 files now uncovered.

297069 of 411566 relevant lines covered (72.18%)

691007.91 hits per line

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

60.47
/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,490✔
56
        assert(message);
11,490✔
57
        assert(u);
11,490✔
58

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

61
        return sd_bus_message_read(
11,490✔
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);
240✔
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);
×
UNCOV
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) {
582✔
139
        int r;
582✔
140

141
        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
582✔
142
        if (r < 0)
582✔
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) {
400✔
149
        int r;
400✔
150

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

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

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

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

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

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

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

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

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

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

194
        r = sd_bus_message_close_container(m);
400✔
195
        if (r < 0)
400✔
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) {
41✔
269
        bool explicit_path = false, done = false, ambient_hack = false;
41✔
270
        _cleanup_strv_free_ char **l = NULL, **ex_opts = NULL;
41✔
271
        _cleanup_free_ char *path = NULL, *upgraded_name = NULL;
41✔
272
        ExecCommandFlags flags = 0;
41✔
273
        bool is_ex_prop = endswith(field, "Ex");
41✔
274
        int r;
57✔
275

276
        do {
57✔
277
                switch (*eq) {
57✔
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 '@':
×
289
                        if (explicit_path)
×
290
                                done = true;
291
                        else {
292
                                explicit_path = true;
×
293
                                eq++;
×
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
                default:
335
                        done = true;
336
                }
337
        } while (!done);
57✔
338

339
        if (!is_ex_prop && (flags & (EXEC_COMMAND_NO_ENV_EXPAND|EXEC_COMMAND_FULLY_PRIVILEGED|EXEC_COMMAND_NO_SETUID))) {
41✔
340
                /* Upgrade the ExecXYZ= property to ExecXYZEx= for convenience */
341
                is_ex_prop = true;
7✔
342
                upgraded_name = strjoin(field, "Ex");
7✔
343
                if (!upgraded_name)
7✔
344
                        return log_oom();
×
345
        }
346

347
        if (is_ex_prop) {
34✔
348
                r = exec_command_flags_to_strv(flags, &ex_opts);
14✔
349
                if (r < 0)
14✔
350
                        return log_error_errno(r, "Failed to convert ExecCommandFlags to strv: %m");
×
351
        }
352

353
        if (explicit_path) {
41✔
354
                r = extract_first_word(&eq, &path, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
×
355
                if (r < 0)
×
356
                        return log_error_errno(r, "Failed to parse path: %m");
×
357
        }
358

359
        r = strv_split_full(&l, eq, NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
41✔
360
        if (r < 0)
41✔
361
                return log_error_errno(r, "Failed to parse command line: %m");
×
362

363
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
41✔
364
        if (r < 0)
41✔
365
                return bus_log_create_error(r);
×
366

367
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, upgraded_name ?: field);
75✔
368
        if (r < 0)
41✔
369
                return bus_log_create_error(r);
×
370

371
        r = sd_bus_message_open_container(m, 'v', is_ex_prop ? "a(sasas)" : "a(sasb)");
68✔
372
        if (r < 0)
41✔
373
                return bus_log_create_error(r);
×
374

375
        r = sd_bus_message_open_container(m, 'a', is_ex_prop ? "(sasas)" : "(sasb)");
68✔
376
        if (r < 0)
41✔
377
                return bus_log_create_error(r);
×
378

379
        if (!strv_isempty(l)) {
41✔
380

381
                r = sd_bus_message_open_container(m, 'r', is_ex_prop ? "sasas" : "sasb");
68✔
382
                if (r < 0)
41✔
383
                        return bus_log_create_error(r);
×
384

385
                r = sd_bus_message_append(m, "s", path ?: l[0]);
41✔
386
                if (r < 0)
41✔
387
                        return bus_log_create_error(r);
×
388

389
                r = sd_bus_message_append_strv(m, l);
41✔
390
                if (r < 0)
41✔
391
                        return bus_log_create_error(r);
×
392

393
                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));
41✔
394
                if (r < 0)
41✔
395
                        return bus_log_create_error(r);
×
396

397
                r = sd_bus_message_close_container(m);
41✔
398
                if (r < 0)
41✔
399
                        return bus_log_create_error(r);
×
400
        }
401

402
        r = sd_bus_message_close_container(m);
41✔
403
        if (r < 0)
41✔
404
                return bus_log_create_error(r);
×
405

406
        r = sd_bus_message_close_container(m);
41✔
407
        if (r < 0)
41✔
408
                return bus_log_create_error(r);
×
409

410
        r = sd_bus_message_close_container(m);
41✔
411
        if (r < 0)
41✔
412
                return bus_log_create_error(r);
×
413

414
        return 1;
415
}
416

417
static int bus_append_open_file(sd_bus_message *m, const char *field, const char *eq) {
5✔
418
        _cleanup_(open_file_freep) OpenFile *of = NULL;
5✔
419
        int r;
5✔
420

421
        assert(m);
5✔
422

423
        r = open_file_parse(eq, &of);
5✔
424
        if (r < 0)
5✔
425
                return log_error_errno(r, "Failed to parse OpenFile= setting: %m");
×
426

427
        r = sd_bus_message_append(m, "(sv)", field, "a(sst)", (size_t) 1, of->path, of->fdname, of->flags);
5✔
428
        if (r < 0)
5✔
429
                return bus_log_create_error(r);
×
430

431
        return 1;
432
}
433

434
static int bus_append_ip_address_access(sd_bus_message *m, int family, const union in_addr_union *prefix, unsigned char prefixlen) {
×
435
        int r;
×
436

437
        assert(m);
×
438
        assert(prefix);
×
439

440
        r = sd_bus_message_open_container(m, 'r', "iayu");
×
441
        if (r < 0)
×
442
                return r;
443

444
        r = sd_bus_message_append(m, "i", family);
×
445
        if (r < 0)
×
446
                return r;
447

448
        r = sd_bus_message_append_array(m, 'y', prefix, FAMILY_ADDRESS_SIZE(family));
×
449
        if (r < 0)
×
450
                return r;
451

452
        r = sd_bus_message_append(m, "u", prefixlen);
×
453
        if (r < 0)
×
454
                return r;
455

456
        return sd_bus_message_close_container(m);
×
457
}
458

459
static int bus_append_nft_set(sd_bus_message *m, const char *field, const char *eq) {
2✔
460
        int r;
2✔
461

462
        assert(m);
2✔
463
        assert(field);
2✔
464
        assert(eq);
2✔
465

466
        if (isempty(eq)) {
2✔
467
                r = sd_bus_message_append(m, "(sv)", field, "a(iiss)", 0);
×
468
                if (r < 0)
×
469
                        return bus_log_create_error(r);
×
470

471
                return 1;
472
        }
473

474
        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
2✔
475
        if (r < 0)
2✔
476
                return bus_log_create_error(r);
×
477

478
        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
2✔
479
        if (r < 0)
2✔
480
                return bus_log_create_error(r);
×
481

482
        r = sd_bus_message_open_container(m, 'v', "a(iiss)");
2✔
483
        if (r < 0)
2✔
484
                return bus_log_create_error(r);
×
485

486
        r = sd_bus_message_open_container(m, 'a', "(iiss)");
2✔
487
        if (r < 0)
2✔
488
                return bus_log_create_error(r);
×
489

490
        for (const char *p = eq;;) {
2✔
491
                _cleanup_free_ char *tuple = NULL, *source_str = NULL, *nfproto_str = NULL, *table = NULL, *set = NULL;
4✔
492
                const char *q = NULL;
6✔
493
                int source, nfproto;
6✔
494

495
                r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
6✔
496
                if (r == -ENOMEM)
6✔
497
                        return log_oom();
×
498
                if (r < 0)
6✔
499
                        return log_error_errno(r, "Failed to parse %s: %m", field);
×
500
                if (r == 0)
6✔
501
                        break;
502
                if (isempty(tuple))
4✔
503
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
504

505
                q = tuple;
4✔
506
                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE, &source_str, &nfproto_str, &table, &set);
4✔
507
                if (r == -ENOMEM)
4✔
508
                        return log_oom();
×
509
                if (r != 4 || !isempty(q))
4✔
510
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
511

512
                assert(source_str);
4✔
513
                assert(nfproto_str);
4✔
514
                assert(table);
4✔
515
                assert(set);
4✔
516

517
                source = nft_set_source_from_string(source_str);
4✔
518
                if (!IN_SET(source, NFT_SET_SOURCE_CGROUP, NFT_SET_SOURCE_USER, NFT_SET_SOURCE_GROUP))
4✔
519
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
520

521
                nfproto = nfproto_from_string(nfproto_str);
4✔
522
                if (nfproto < 0 || !nft_identifier_valid(table) || !nft_identifier_valid(set))
4✔
523
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse %s.", field);
×
524

525
                r = sd_bus_message_append(m, "(iiss)", source, nfproto, table, set);
4✔
526
                if (r < 0)
4✔
527
                        return bus_log_create_error(r);
×
528
        }
529
        r = sd_bus_message_close_container(m);
2✔
530
        if (r < 0)
2✔
531
                return bus_log_create_error(r);
×
532

533
        r = sd_bus_message_close_container(m);
2✔
534
        if (r < 0)
2✔
535
                return bus_log_create_error(r);
×
536

537
        r = sd_bus_message_close_container(m);
2✔
538
        if (r < 0)
2✔
539
                return bus_log_create_error(r);
×
540

541
        return 1;
542
}
543

544
static int bus_append_cgroup_property(sd_bus_message *m, const char *field, const char *eq) {
2,924✔
545
        int r;
2,924✔
546

547
        if (STR_IN_SET(field, "DevicePolicy",
2,924✔
548
                              "Slice",
549
                              "ManagedOOMSwap",
550
                              "ManagedOOMMemoryPressure",
551
                              "ManagedOOMPreference",
552
                              "MemoryPressureWatch",
553
                              "DelegateSubgroup"))
554
                return bus_append_string(m, field, eq);
16✔
555

556
        if (STR_IN_SET(field, "ManagedOOMMemoryPressureLimit")) {
2,908✔
557
                r = parse_permyriad(eq);
×
558
                if (r < 0)
×
559
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
560

561
                /* Pass around scaled to 2^32-1 == 100% */
562
                r = sd_bus_message_append(m, "(sv)", field, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
563
                if (r < 0)
×
564
                        return bus_log_create_error(r);
×
565

566
                return 1;
567
        }
568

569
        if (STR_IN_SET(field, "CPUAccounting",
2,908✔
570
                              "MemoryAccounting",
571
                              "MemoryZSwapWriteback",
572
                              "IOAccounting",
573
                              "TasksAccounting",
574
                              "IPAccounting",
575
                              "CoredumpReceive"))
576
                return bus_append_parse_boolean(m, field, eq);
8✔
577

578
        if (STR_IN_SET(field, "CPUWeight",
2,900✔
579
                              "StartupCPUWeight"))
UNCOV
580
                return bus_append_cg_cpu_weight_parse(m, field, eq);
×
581

582
        if (STR_IN_SET(field, "IOWeight",
2,900✔
583
                              "StartupIOWeight"))
584
                return bus_append_cg_weight_parse(m, field, eq);
×
585

586
        if (STR_IN_SET(field, "AllowedCPUs",
2,900✔
587
                              "StartupAllowedCPUs",
588
                              "AllowedMemoryNodes",
589
                              "StartupAllowedMemoryNodes")) {
590
                _cleanup_(cpu_set_reset) CPUSet cpuset = {};
×
591
                _cleanup_free_ uint8_t *array = NULL;
×
592
                size_t allocated;
×
593

594
                r = parse_cpu_set(eq, &cpuset);
×
595
                if (r < 0)
×
596
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
597

598
                r = cpu_set_to_dbus(&cpuset, &array, &allocated);
×
599
                if (r < 0)
×
600
                        return log_error_errno(r, "Failed to serialize CPUSet: %m");
×
601

602
                return bus_append_byte_array(m, field, array, allocated);
×
603
        }
604

605
        if (streq(field, "DisableControllers"))
2,900✔
606
                return bus_append_strv(m, "DisableControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
607

608
        if (streq(field, "Delegate")) {
2,900✔
609
                r = parse_boolean(eq);
343✔
610
                if (r < 0)
343✔
611
                        return bus_append_strv(m, "DelegateControllers", eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
9✔
612

613
                r = sd_bus_message_append(m, "(sv)", "Delegate", "b", r);
334✔
614
                if (r < 0)
334✔
615
                        return bus_log_create_error(r);
×
616

617
                return 1;
618
        }
619

620
        if (STR_IN_SET(field, "MemoryMin",
2,557✔
621
                              "DefaultMemoryLow",
622
                              "DefaultMemoryMin",
623
                              "MemoryLow",
624
                              "MemoryHigh",
625
                              "MemoryMax",
626
                              "MemorySwapMax",
627
                              "MemoryZSwapMax",
628
                              "TasksMax")) {
629

630
                if (streq(eq, "infinity")) {
10✔
631
                        r = sd_bus_message_append(m, "(sv)", field, "t", CGROUP_LIMIT_MAX);
×
632
                        if (r < 0)
×
633
                                return bus_log_create_error(r);
10✔
634
                        return 1;
635
                } else if (isempty(eq)) {
10✔
636
                        uint64_t empty_value = STR_IN_SET(field,
×
637
                                                          "DefaultMemoryLow",
638
                                                          "DefaultMemoryMin",
639
                                                          "MemoryLow",
640
                                                          "MemoryMin") ?
641
                                               CGROUP_LIMIT_MIN :
×
642
                                               CGROUP_LIMIT_MAX;
643

644
                        r = sd_bus_message_append(m, "(sv)", field, "t", empty_value);
×
645
                        if (r < 0)
×
646
                                return bus_log_create_error(r);
×
647
                        return 1;
648
                }
649

650
                r = parse_permyriad(eq);
10✔
651
                if (r >= 0) {
10✔
652
                        char *n;
×
653

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

658
                        n = strjoina(field, "Scale");
×
659
                        r = sd_bus_message_append(m, "(sv)", n, "u", UINT32_SCALE_FROM_PERMYRIAD(r));
×
660
                        if (r < 0)
×
661
                                return bus_log_create_error(r);
×
662

663
                        return 1;
664
                }
665

666
                if (streq(field, "TasksMax"))
10✔
667
                        return bus_append_safe_atou64(m, field, eq);
2✔
668

669
                return bus_append_parse_size(m, field, eq, 1024);
8✔
670
        }
671

672
        if (streq(field, "CPUQuota")) {
2,547✔
673
                if (isempty(eq))
1✔
674
                        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", USEC_INFINITY);
×
675
                else {
676
                        r = parse_permyriad_unbounded(eq);
1✔
677
                        if (r == 0)
1✔
678
                                return log_error_errno(SYNTHETIC_ERRNO(ERANGE), "CPU quota too small.");
×
679
                        if (r < 0)
1✔
680
                                return log_error_errno(r, "CPU quota '%s' invalid.", eq);
×
681

682
                        r = sd_bus_message_append(m, "(sv)", "CPUQuotaPerSecUSec", "t", (((uint64_t) r * USEC_PER_SEC) / 10000U));
1✔
683
                }
684

685
                if (r < 0)
1✔
686
                        return bus_log_create_error(r);
×
687

688
                return 1;
689
        }
690

691
        if (streq(field, "CPUQuotaPeriodSec")) {
2,546✔
692
                usec_t u = USEC_INFINITY;
×
693

694
                r = parse_sec_def_infinity(eq, &u);
×
695
                if (r < 0)
×
696
                        return log_error_errno(r, "CPU quota period '%s' invalid.", eq);
×
697

698
                r = sd_bus_message_append(m, "(sv)", "CPUQuotaPeriodUSec", "t", u);
×
699
                if (r < 0)
×
700
                        return bus_log_create_error(r);
×
701

702
                return 1;
703
        }
704

705
        if (streq(field, "DeviceAllow")) {
2,546✔
706
                if (isempty(eq))
6✔
707
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
708
                else {
709
                        const char *path = eq, *rwm = NULL, *e;
6✔
710

711
                        e = strchr(eq, ' ');
6✔
712
                        if (e) {
6✔
713
                                path = strndupa_safe(eq, e - eq);
6✔
714
                                rwm = e+1;
6✔
715
                        }
716

717
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, path, strempty(rwm));
6✔
718
                }
719

720
                if (r < 0)
6✔
721
                        return bus_log_create_error(r);
×
722

723
                return 1;
724
        }
725

726
        if (cgroup_io_limit_type_from_string(field) >= 0) {
2,540✔
727

728
                if (isempty(eq))
3✔
729
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
730
                else {
731
                        const char *path, *bandwidth, *e;
3✔
732
                        uint64_t bytes;
3✔
733

734
                        e = strchr(eq, ' ');
3✔
735
                        if (!e)
3✔
736
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
737
                                                       "Failed to parse %s value %s.",
738
                                                       field, eq);
739

740
                        path = strndupa_safe(eq, e - eq);
3✔
741
                        bandwidth = e+1;
3✔
742

743
                        if (streq(bandwidth, "infinity"))
3✔
744
                                bytes = CGROUP_LIMIT_MAX;
×
745
                        else {
746
                                r = parse_size(bandwidth, 1000, &bytes);
3✔
747
                                if (r < 0)
3✔
748
                                        return log_error_errno(r, "Failed to parse byte value %s: %m", bandwidth);
×
749
                        }
750

751
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, bytes);
3✔
752
                }
753

754
                if (r < 0)
3✔
755
                        return bus_log_create_error(r);
×
756

757
                return 1;
758
        }
759

760
        if (streq(field, "IODeviceWeight")) {
2,537✔
761
                if (isempty(eq))
×
762
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 0);
×
763
                else {
764
                        const char *path, *weight, *e;
×
765
                        uint64_t u;
×
766

767
                        e = strchr(eq, ' ');
×
768
                        if (!e)
×
769
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
770
                                                       "Failed to parse %s value %s.",
771
                                                       field, eq);
772

773
                        path = strndupa_safe(eq, e - eq);
×
774
                        weight = e+1;
×
775

776
                        r = safe_atou64(weight, &u);
×
777
                        if (r < 0)
×
778
                                return log_error_errno(r, "Failed to parse %s value %s: %m", field, weight);
×
779

780
                        r = sd_bus_message_append(m, "(sv)", field, "a(st)", 1, path, u);
×
781
                }
782

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

786
                return 1;
787
        }
788

789
        if (streq(field, "IODeviceLatencyTargetSec")) {
2,537✔
790
                const char *field_usec = "IODeviceLatencyTargetUSec";
×
791

792
                if (isempty(eq))
×
793
                        r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", USEC_INFINITY);
×
794
                else {
795
                        const char *path, *target, *e;
×
796
                        usec_t usec;
×
797

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

804
                        path = strndupa_safe(eq, e - eq);
×
805
                        target = e+1;
×
806

807
                        r = parse_sec(target, &usec);
×
808
                        if (r < 0)
×
809
                                return log_error_errno(r, "Failed to parse %s value %s: %m", field, target);
×
810

811
                        r = sd_bus_message_append(m, "(sv)", field_usec, "a(st)", 1, path, usec);
×
812
                }
813

814
                if (r < 0)
×
815
                        return bus_log_create_error(r);
×
816

817
                return 1;
818
        }
819

820
        if (STR_IN_SET(field, "IPAddressAllow",
2,537✔
821
                              "IPAddressDeny")) {
822
                unsigned char prefixlen;
×
823
                union in_addr_union prefix = {};
×
824
                int family;
×
825

826
                if (isempty(eq)) {
×
827
                        r = sd_bus_message_append(m, "(sv)", field, "a(iayu)", 0);
×
828
                        if (r < 0)
×
829
                                return bus_log_create_error(r);
×
830

831
                        return 1;
832
                }
833

834
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
835
                if (r < 0)
×
836
                        return bus_log_create_error(r);
×
837

838
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
839
                if (r < 0)
×
840
                        return bus_log_create_error(r);
×
841

842
                r = sd_bus_message_open_container(m, 'v', "a(iayu)");
×
843
                if (r < 0)
×
844
                        return bus_log_create_error(r);
×
845

846
                r = sd_bus_message_open_container(m, 'a', "(iayu)");
×
847
                if (r < 0)
×
848
                        return bus_log_create_error(r);
×
849

850
                if (streq(eq, "any")) {
×
851
                        /* "any" is a shortcut for 0.0.0.0/0 and ::/0 */
852

853
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 0);
×
854
                        if (r < 0)
×
855
                                return bus_log_create_error(r);
×
856

857
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 0);
×
858
                        if (r < 0)
×
859
                                return bus_log_create_error(r);
×
860

861
                } else if (is_localhost(eq)) {
×
862
                        /* "localhost" is a shortcut for 127.0.0.0/8 and ::1/128 */
863

864
                        prefix.in.s_addr = htobe32(0x7f000000);
×
865
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 8);
×
866
                        if (r < 0)
×
867
                                return bus_log_create_error(r);
×
868

869
                        prefix.in6 = (struct in6_addr) IN6ADDR_LOOPBACK_INIT;
×
870
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 128);
×
871
                        if (r < 0)
×
872
                                return r;
873

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

877
                        prefix.in.s_addr = htobe32((UINT32_C(169) << 24 | UINT32_C(254) << 16));
×
878
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 16);
×
879
                        if (r < 0)
×
880
                                return bus_log_create_error(r);
×
881

882
                        prefix.in6 = (struct in6_addr) {
×
883
                                .s6_addr32[0] = htobe32(0xfe800000)
×
884
                        };
885
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 64);
×
886
                        if (r < 0)
×
887
                                return bus_log_create_error(r);
×
888

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

892
                        prefix.in.s_addr = htobe32((UINT32_C(224) << 24));
×
893
                        r = bus_append_ip_address_access(m, AF_INET, &prefix, 4);
×
894
                        if (r < 0)
×
895
                                return bus_log_create_error(r);
×
896

897
                        prefix.in6 = (struct in6_addr) {
×
898
                                .s6_addr32[0] = htobe32(0xff000000)
×
899
                        };
900
                        r = bus_append_ip_address_access(m, AF_INET6, &prefix, 8);
×
901
                        if (r < 0)
×
902
                                return bus_log_create_error(r);
×
903

904
                } else {
905
                        for (;;) {
×
906
                                _cleanup_free_ char *word = NULL;
×
907

908
                                r = extract_first_word(&eq, &word, NULL, 0);
×
909
                                if (r == 0)
×
910
                                        break;
911
                                if (r == -ENOMEM)
×
912
                                        return log_oom();
×
913
                                if (r < 0)
×
914
                                        return log_error_errno(r, "Failed to parse %s: %s", field, eq);
×
915

916
                                r = in_addr_prefix_from_string_auto(word, &family, &prefix, &prefixlen);
×
917
                                if (r < 0)
×
918
                                        return log_error_errno(r, "Failed to parse IP address prefix: %s", word);
×
919

920
                                r = bus_append_ip_address_access(m, family, &prefix, prefixlen);
×
921
                                if (r < 0)
×
922
                                        return bus_log_create_error(r);
×
923
                        }
924
                }
925

926
                r = sd_bus_message_close_container(m);
×
927
                if (r < 0)
×
928
                        return bus_log_create_error(r);
×
929

930
                r = sd_bus_message_close_container(m);
×
931
                if (r < 0)
×
932
                        return bus_log_create_error(r);
×
933

934
                r = sd_bus_message_close_container(m);
×
935
                if (r < 0)
×
936
                        return bus_log_create_error(r);
×
937

938
                return 1;
939
        }
940

941
        if (STR_IN_SET(field, "IPIngressFilterPath",
2,537✔
942
                              "IPEgressFilterPath")) {
943
                if (isempty(eq))
×
944
                        r = sd_bus_message_append(m, "(sv)", field, "as", 0);
×
945
                else
946
                        r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
×
947

948
                if (r < 0)
×
949
                        return bus_log_create_error(r);
×
950

951
                return 1;
952
        }
953

954
        if (streq(field, "BPFProgram")) {
2,537✔
955
                if (isempty(eq))
×
956
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 0);
×
957
                else {
958
                        _cleanup_free_ char *word = NULL;
×
959

960
                        r = extract_first_word(&eq, &word, ":", 0);
×
961
                        if (r == -ENOMEM)
×
962
                                return log_oom();
×
963
                        if (r < 0)
×
964
                                return log_error_errno(r, "Failed to parse %s: %m", field);
×
965

966
                        r = sd_bus_message_append(m, "(sv)", field, "a(ss)", 1, word, eq);
×
967
                }
968
                if (r < 0)
×
969
                        return bus_log_create_error(r);
×
970

971
                return 1;
972
        }
973

974
        if (STR_IN_SET(field, "SocketBindAllow",
2,537✔
975
                              "SocketBindDeny")) {
976
                if (isempty(eq))
×
977
                        r = sd_bus_message_append(m, "(sv)", field, "a(iiqq)", 0);
×
978
                else {
979
                        int32_t family, ip_protocol;
×
980
                        uint16_t nr_ports, port_min;
×
981

982
                        r = parse_socket_bind_item(eq, &family, &ip_protocol, &nr_ports, &port_min);
×
983
                        if (r == -ENOMEM)
×
984
                                return log_oom();
×
985
                        if (r < 0)
×
986
                                return log_error_errno(r, "Failed to parse %s", field);
×
987

988
                        r = sd_bus_message_append(
×
989
                                        m, "(sv)", field, "a(iiqq)", 1, family, ip_protocol, nr_ports, port_min);
990
                }
991
                if (r < 0)
×
992
                        return bus_log_create_error(r);
×
993

994
                return 1;
995
        }
996

997
        if (streq(field, "MemoryPressureThresholdSec"))
2,537✔
998
                return bus_append_parse_sec_rename(m, field, eq);
1✔
999

1000
        if (streq(field, "NFTSet"))
2,536✔
1001
                return bus_append_nft_set(m, field, eq);
2✔
1002

1003
        if (streq(field, "ManagedOOMMemoryPressureDurationSec"))
2,534✔
1004
                /* While infinity is disallowed in unit file, infinity is allowed in D-Bus API which
1005
                 * means use the default memory pressure duration from oomd.conf. */
1006
                return bus_append_parse_sec_rename(m, field, isempty(eq) ? "infinity" : eq);
×
1007

1008
        return 0;
1009
}
1010

1011
static int bus_append_automount_property(sd_bus_message *m, const char *field, const char *eq) {
1✔
1012
        if (STR_IN_SET(field, "Where",
1✔
1013
                              "ExtraOptions"))
1014
                return bus_append_string(m, field, eq);
×
1015

1016
        if (streq(field, "DirectoryMode"))
1✔
1017
                return bus_append_parse_mode(m, field, eq);
×
1018

1019
        if (streq(field, "TimeoutIdleSec"))
1✔
1020
                return bus_append_parse_sec_rename(m, field, eq);
×
1021

1022
        return 0;
1023
}
1024

1025
static int bus_append_execute_property(sd_bus_message *m, const char *field, const char *eq) {
2,526✔
1026
        const char *suffix;
2,526✔
1027
        int r;
2,526✔
1028

1029
        if (STR_IN_SET(field, "User",
2,526✔
1030
                              "Group",
1031
                              "UtmpIdentifier",
1032
                              "UtmpMode",
1033
                              "PAMName",
1034
                              "TTYPath",
1035
                              "WorkingDirectory",
1036
                              "RootDirectory",
1037
                              "SyslogIdentifier",
1038
                              "ProtectSystem",
1039
                              "ProtectHome",
1040
                              "PrivateTmpEx",
1041
                              "PrivateUsersEx",
1042
                              "ProtectControlGroupsEx",
1043
                              "SELinuxContext",
1044
                              "RootImage",
1045
                              "RootVerity",
1046
                              "RuntimeDirectoryPreserve",
1047
                              "Personality",
1048
                              "KeyringMode",
1049
                              "ProtectProc",
1050
                              "ProcSubset",
1051
                              "NetworkNamespacePath",
1052
                              "IPCNamespacePath",
1053
                              "LogNamespace",
1054
                              "RootImagePolicy",
1055
                              "MountImagePolicy",
1056
                              "ExtensionImagePolicy",
1057
                              "PrivatePIDs"))
1058
                return bus_append_string(m, field, eq);
435✔
1059

1060
        if (STR_IN_SET(field, "IgnoreSIGPIPE",
2,091✔
1061
                              "TTYVHangup",
1062
                              "TTYReset",
1063
                              "TTYVTDisallocate",
1064
                              "PrivateTmp",
1065
                              "PrivateDevices",
1066
                              "PrivateNetwork",
1067
                              "PrivateUsers",
1068
                              "PrivateMounts",
1069
                              "PrivateIPC",
1070
                              "NoNewPrivileges",
1071
                              "SyslogLevelPrefix",
1072
                              "MemoryDenyWriteExecute",
1073
                              "RestrictRealtime",
1074
                              "DynamicUser",
1075
                              "RemoveIPC",
1076
                              "ProtectKernelTunables",
1077
                              "ProtectKernelModules",
1078
                              "ProtectKernelLogs",
1079
                              "ProtectClock",
1080
                              "ProtectControlGroups",
1081
                              "MountAPIVFS",
1082
                              "BindLogSockets",
1083
                              "CPUSchedulingResetOnFork",
1084
                              "LockPersonality",
1085
                              "ProtectHostname",
1086
                              "MemoryKSM",
1087
                              "RestrictSUIDSGID",
1088
                              "RootEphemeral",
1089
                              "SetLoginEnvironment"))
1090
                return bus_append_parse_boolean(m, field, eq);
224✔
1091

1092
        if (STR_IN_SET(field, "ReadWriteDirectories",
1,867✔
1093
                              "ReadOnlyDirectories",
1094
                              "InaccessibleDirectories",
1095
                              "ReadWritePaths",
1096
                              "ReadOnlyPaths",
1097
                              "InaccessiblePaths",
1098
                              "ExecPaths",
1099
                              "NoExecPaths",
1100
                              "ExecSearchPath",
1101
                              "ExtensionDirectories",
1102
                              "ConfigurationDirectory",
1103
                              "SupplementaryGroups",
1104
                              "SystemCallArchitectures"))
1105
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
30✔
1106

1107
        if (STR_IN_SET(field, "SyslogLevel",
1,837✔
1108
                              "LogLevelMax"))
1109
                return bus_append_log_level_from_string(m, field, eq);
1✔
1110

1111
        if (streq(field, "SyslogFacility"))
1,836✔
1112
                return bus_append_log_facility_unshifted_from_string(m, field, eq);
×
1113

1114
        if (streq(field, "SecureBits"))
1,836✔
1115
                return bus_append_secure_bits_from_string(m, field, eq);
×
1116

1117
        if (streq(field, "CPUSchedulingPolicy"))
1,836✔
1118
                return bus_append_sched_policy_from_string(m, field, eq);
×
1119

1120
        if (STR_IN_SET(field, "CPUSchedulingPriority",
1,836✔
1121
                              "OOMScoreAdjust"))
1122
                return bus_append_safe_atoi(m, field, eq);
1✔
1123

1124
        if (streq(field, "CoredumpFilter"))
1,835✔
1125
                return bus_append_coredump_filter_mask_from_string(m, field, eq);
2✔
1126

1127
        if (streq(field, "Nice"))
1,833✔
1128
                return bus_append_parse_nice(m, field, eq);
×
1129

1130
        if (streq(field, "SystemCallErrorNumber"))
1,833✔
1131
                return bus_append_seccomp_parse_errno_or_action(m, field, eq);
×
1132

1133
        if (streq(field, "IOSchedulingClass"))
1,833✔
1134
                return bus_append_ioprio_class_from_string(m, field, eq);
×
1135

1136
        if (streq(field, "IOSchedulingPriority"))
1,833✔
1137
                return bus_append_ioprio_parse_priority(m, field, eq);
×
1138

1139
        if (STR_IN_SET(field, "RuntimeDirectoryMode",
1,833✔
1140
                              "StateDirectoryMode",
1141
                              "CacheDirectoryMode",
1142
                              "LogsDirectoryMode",
1143
                              "ConfigurationDirectoryMode",
1144
                              "UMask"))
1145
                return bus_append_parse_mode(m, field, eq);
20✔
1146

1147
        if (streq(field, "TimerSlackNSec"))
1,813✔
1148
                return bus_append_parse_nsec(m, field, eq);
×
1149

1150
        if (streq(field, "LogRateLimitIntervalSec"))
1,813✔
1151
                return bus_append_parse_sec_rename(m, field, eq);
×
1152

1153
        if (STR_IN_SET(field, "LogRateLimitBurst",
1,813✔
1154
                              "TTYRows",
1155
                              "TTYColumns"))
1156
                return bus_append_safe_atou(m, field, eq);
×
1157

1158
        if (streq(field, "MountFlags"))
1,813✔
1159
                return bus_append_mount_propagation_flag_from_string(m, field, eq);
1✔
1160

1161
        if (STR_IN_SET(field, "Environment",
1,812✔
1162
                              "UnsetEnvironment",
1163
                              "PassEnvironment"))
1164
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE|EXTRACT_CUNESCAPE);
350✔
1165

1166
        if (streq(field, "EnvironmentFile")) {
1,462✔
1167
                if (isempty(eq))
339✔
1168
                        r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 0);
×
1169
                else
1170
                        r = sd_bus_message_append(m, "(sv)", "EnvironmentFiles", "a(sb)", 1,
339✔
1171
                                                  eq[0] == '-' ? eq + 1 : eq,
1172
                                                  eq[0] == '-');
1173
                if (r < 0)
339✔
1174
                        return bus_log_create_error(r);
×
1175

1176
                return 1;
1177
        }
1178

1179
        if (STR_IN_SET(field, "SetCredential", "SetCredentialEncrypted")) {
1,123✔
1180
                r = sd_bus_message_open_container(m, 'r', "sv");
80✔
1181
                if (r < 0)
80✔
1182
                        return bus_log_create_error(r);
80✔
1183

1184
                r = sd_bus_message_append_basic(m, 's', field);
80✔
1185
                if (r < 0)
80✔
1186
                        return bus_log_create_error(r);
×
1187

1188
                r = sd_bus_message_open_container(m, 'v', "a(say)");
80✔
1189
                if (r < 0)
80✔
1190
                        return bus_log_create_error(r);
×
1191

1192
                if (isempty(eq))
80✔
1193
                        r = sd_bus_message_append(m, "a(say)", 0);
×
1194
                else {
1195
                        _cleanup_free_ char *word = NULL;
80✔
1196
                        const char *p = eq;
80✔
1197

1198
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
80✔
1199
                        if (r == -ENOMEM)
80✔
1200
                                return log_oom();
×
1201
                        if (r < 0)
80✔
1202
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1203
                        if (r == 0 || !p)
80✔
1204
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1205

1206
                        r = sd_bus_message_open_container(m, 'a', "(say)");
80✔
1207
                        if (r < 0)
80✔
1208
                                return bus_log_create_error(r);
×
1209

1210
                        r = sd_bus_message_open_container(m, 'r', "say");
80✔
1211
                        if (r < 0)
80✔
1212
                                return bus_log_create_error(r);
×
1213

1214
                        r = sd_bus_message_append(m, "s", word);
80✔
1215
                        if (r < 0)
80✔
1216
                                return bus_log_create_error(r);
×
1217

1218
                        if (streq(field, "SetCredentialEncrypted")) {
80✔
1219
                                _cleanup_free_ void *decoded = NULL;
2✔
1220
                                size_t decoded_size;
2✔
1221

1222
                                r = unbase64mem(p, &decoded, &decoded_size);
2✔
1223
                                if (r < 0)
2✔
1224
                                        return log_error_errno(r, "Failed to base64 decode encrypted credential: %m");
×
1225

1226
                                r = sd_bus_message_append_array(m, 'y', decoded, decoded_size);
2✔
1227
                        } else {
1228
                                _cleanup_free_ char *unescaped = NULL;
78✔
1229
                                ssize_t l;
78✔
1230

1231
                                l = cunescape(p, UNESCAPE_ACCEPT_NUL, &unescaped);
78✔
1232
                                if (l < 0)
78✔
1233
                                        return log_error_errno(l, "Failed to unescape %s= value: %s", field, p);
×
1234

1235
                                r = sd_bus_message_append_array(m, 'y', unescaped, l);
78✔
1236
                        }
1237
                        if (r < 0)
80✔
1238
                                return bus_log_create_error(r);
×
1239

1240
                        r = sd_bus_message_close_container(m);
80✔
1241
                        if (r < 0)
80✔
1242
                                return bus_log_create_error(r);
×
1243

1244
                        r = sd_bus_message_close_container(m);
80✔
1245
                }
1246
                if (r < 0)
80✔
1247
                        return bus_log_create_error(r);
×
1248

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

1253
                r = sd_bus_message_close_container(m);
80✔
1254
                if (r < 0)
80✔
1255
                        return bus_log_create_error(r);
×
1256

1257
                return 1;
1258
        }
1259

1260
        if (STR_IN_SET(field, "LoadCredential", "LoadCredentialEncrypted")) {
1,043✔
1261
                r = sd_bus_message_open_container(m, 'r', "sv");
18✔
1262
                if (r < 0)
18✔
1263
                        return bus_log_create_error(r);
18✔
1264

1265
                r = sd_bus_message_append_basic(m, 's', field);
18✔
1266
                if (r < 0)
18✔
1267
                        return bus_log_create_error(r);
×
1268

1269
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
18✔
1270
                if (r < 0)
18✔
1271
                        return bus_log_create_error(r);
×
1272

1273
                if (isempty(eq))
18✔
1274
                        r = sd_bus_message_append(m, "a(ss)", 0);
×
1275
                else {
1276
                        _cleanup_free_ char *word = NULL;
18✔
1277
                        const char *p = eq;
18✔
1278

1279
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
18✔
1280
                        if (r == -ENOMEM)
18✔
1281
                                return log_oom();
×
1282
                        if (r < 0)
18✔
1283
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1284
                        if (r == 0)
18✔
1285
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1286

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

1290
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
18✔
1291
                }
1292
                if (r < 0)
18✔
1293
                        return bus_log_create_error(r);
×
1294

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

1299
                r = sd_bus_message_close_container(m);
18✔
1300
                if (r < 0)
18✔
1301
                        return bus_log_create_error(r);
×
1302

1303
                return 1;
1304
        }
1305

1306
        if (streq(field, "ImportCredential")) {
1,025✔
1307
                if (isempty(eq))
3✔
1308
                        r = sd_bus_message_append(m, "(sv)", field, "as", 0);
×
1309
                else
1310
                        r = sd_bus_message_append(m, "(sv)", field, "as", 1, eq);
3✔
1311
                if (r < 0)
3✔
1312
                        return bus_log_create_error(r);
×
1313

1314
                return 1;
1315
        }
1316

1317
        if (streq(field, "ImportCredentialEx")) {
1,022✔
1318
                r = sd_bus_message_open_container(m, 'r', "sv");
9✔
1319
                if (r < 0)
9✔
1320
                        return bus_log_create_error(r);
×
1321

1322
                r = sd_bus_message_append_basic(m, 's', field);
9✔
1323
                if (r < 0)
9✔
1324
                        return bus_log_create_error(r);
×
1325

1326
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
9✔
1327
                if (r < 0)
9✔
1328
                        return bus_log_create_error(r);
×
1329

1330
                if (isempty(eq))
9✔
1331
                        r = sd_bus_message_append(m, "a(ss)", 0);
×
1332
                else {
1333
                         _cleanup_free_ char *word = NULL;
9✔
1334
                        const char *p = eq;
9✔
1335

1336
                        r = extract_first_word(&p, &word, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
9✔
1337
                        if (r == -ENOMEM)
9✔
1338
                                return log_oom();
×
1339
                        if (r < 0)
9✔
1340
                                return log_error_errno(r, "Failed to parse %s= parameter: %s", field, eq);
×
1341
                        if (r == 0)
9✔
1342
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Missing argument to %s=.", field);
×
1343

1344
                        r = sd_bus_message_append(m, "a(ss)", 1, word, p);
9✔
1345
                }
1346
                if (r < 0)
9✔
1347
                        return bus_log_create_error(r);
×
1348

1349
                r = sd_bus_message_close_container(m);
9✔
1350
                if (r < 0)
9✔
1351
                        return bus_log_create_error(r);
×
1352

1353
                r = sd_bus_message_close_container(m);
9✔
1354
                if (r < 0)
9✔
1355
                        return bus_log_create_error(r);
×
1356

1357
                return 1;
1358
        }
1359

1360
        if (streq(field, "LogExtraFields")) {
1,013✔
1361
                r = sd_bus_message_open_container(m, 'r', "sv");
408✔
1362
                if (r < 0)
408✔
1363
                        return bus_log_create_error(r);
×
1364

1365
                r = sd_bus_message_append_basic(m, 's', "LogExtraFields");
408✔
1366
                if (r < 0)
408✔
1367
                        return bus_log_create_error(r);
×
1368

1369
                r = sd_bus_message_open_container(m, 'v', "aay");
408✔
1370
                if (r < 0)
408✔
1371
                        return bus_log_create_error(r);
×
1372

1373
                r = sd_bus_message_open_container(m, 'a', "ay");
408✔
1374
                if (r < 0)
408✔
1375
                        return bus_log_create_error(r);
×
1376

1377
                r = sd_bus_message_append_array(m, 'y', eq, strlen(eq));
408✔
1378
                if (r < 0)
408✔
1379
                        return bus_log_create_error(r);
×
1380

1381
                r = sd_bus_message_close_container(m);
408✔
1382
                if (r < 0)
408✔
1383
                        return bus_log_create_error(r);
×
1384

1385
                r = sd_bus_message_close_container(m);
408✔
1386
                if (r < 0)
408✔
1387
                        return bus_log_create_error(r);
×
1388

1389
                r = sd_bus_message_close_container(m);
408✔
1390
                if (r < 0)
408✔
1391
                        return bus_log_create_error(r);
×
1392

1393
                return 1;
1394
        }
1395

1396
        if (streq(field, "LogFilterPatterns")) {
605✔
1397
                r = sd_bus_message_append(m, "(sv)", "LogFilterPatterns", "a(bs)", 1,
×
1398
                                          eq[0] != '~',
1399
                                          eq[0] != '~' ? eq : eq + 1);
×
1400
                if (r < 0)
×
1401
                        return bus_log_create_error(r);
×
1402

1403
                return 1;
1404
        }
1405

1406
        if (STR_IN_SET(field, "StandardInput",
605✔
1407
                              "StandardOutput",
1408
                              "StandardError")) {
1409
                const char *n, *appended;
46✔
1410

1411
                if ((n = startswith(eq, "fd:"))) {
46✔
1412
                        appended = strjoina(field, "FileDescriptorName");
×
1413
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
×
1414
                } else if ((n = startswith(eq, "file:"))) {
46✔
1415
                        appended = strjoina(field, "File");
20✔
1416
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
4✔
1417
                } else if ((n = startswith(eq, "append:"))) {
42✔
1418
                        appended = strjoina(field, "FileToAppend");
10✔
1419
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
2✔
1420
                } else if ((n = startswith(eq, "truncate:"))) {
40✔
1421
                        appended = strjoina(field, "FileToTruncate");
15✔
1422
                        r = sd_bus_message_append(m, "(sv)", appended, "s", n);
3✔
1423
                } else
1424
                        r = sd_bus_message_append(m, "(sv)", field, "s", eq);
37✔
1425
                if (r < 0)
46✔
1426
                        return bus_log_create_error(r);
46✔
1427

1428
                return 1;
1429
        }
1430

1431
        if (streq(field, "StandardInputText")) {
559✔
1432
                _cleanup_free_ char *unescaped = NULL;
×
1433
                ssize_t l;
×
1434

1435
                l = cunescape(eq, 0, &unescaped);
×
1436
                if (l < 0)
×
1437
                        return log_error_errno(l, "Failed to unescape text '%s': %m", eq);
×
1438

1439
                if (!strextend(&unescaped, "\n"))
×
1440
                        return log_oom();
×
1441

1442
                /* Note that we don't expand specifiers here, but that should be OK, as this is a
1443
                 * programmatic interface anyway */
1444

1445
                return bus_append_byte_array(m, field, unescaped, l + 1);
×
1446
        }
1447

1448
        if (streq(field, "StandardInputData")) {
559✔
1449
                _cleanup_free_ void *decoded = NULL;
1✔
1450
                size_t sz;
1✔
1451

1452
                r = unbase64mem(eq, &decoded, &sz);
1✔
1453
                if (r < 0)
1✔
1454
                        return log_error_errno(r, "Failed to decode base64 data '%s': %m", eq);
×
1455

1456
                return bus_append_byte_array(m, field, decoded, sz);
1✔
1457
        }
1458

1459
        if ((suffix = startswith(field, "Limit"))) {
558✔
1460
                int rl;
24✔
1461

1462
                rl = rlimit_from_string(suffix);
24✔
1463
                if (rl >= 0) {
24✔
1464
                        const char *sn;
24✔
1465
                        struct rlimit l;
24✔
1466

1467
                        r = rlimit_parse(rl, eq, &l);
24✔
1468
                        if (r < 0)
24✔
1469
                                return log_error_errno(r, "Failed to parse resource limit: %s", eq);
24✔
1470

1471
                        r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) l.rlim_max);
24✔
1472
                        if (r < 0)
24✔
1473
                                return bus_log_create_error(r);
×
1474

1475
                        sn = strjoina(field, "Soft");
120✔
1476
                        r = sd_bus_message_append(m, "(sv)", sn, "t", (uint64_t) l.rlim_cur);
24✔
1477
                        if (r < 0)
24✔
1478
                                return bus_log_create_error(r);
×
1479

1480
                        return 1;
1481
                }
1482
        }
1483

1484
        if (STR_IN_SET(field, "AppArmorProfile",
534✔
1485
                              "SmackProcessLabel")) {
1486
                int ignore = 0;
×
1487
                const char *s = eq;
×
1488

1489
                if (eq[0] == '-') {
×
1490
                        ignore = 1;
×
1491
                        s = eq + 1;
×
1492
                }
1493

1494
                r = sd_bus_message_append(m, "(sv)", field, "(bs)", ignore, s);
×
1495
                if (r < 0)
×
1496
                        return bus_log_create_error(r);
×
1497

1498
                return 1;
1499
        }
1500

1501
        if (STR_IN_SET(field, "CapabilityBoundingSet",
534✔
1502
                              "AmbientCapabilities")) {
1503
                uint64_t sum = 0;
5✔
1504
                bool invert = false;
5✔
1505
                const char *p = eq;
5✔
1506

1507
                if (*p == '~') {
5✔
1508
                        invert = true;
2✔
1509
                        p++;
2✔
1510
                }
1511

1512
                r = capability_set_from_string(p, &sum);
5✔
1513
                if (r < 0)
5✔
1514
                        return log_error_errno(r, "Failed to parse %s value %s: %m", field, eq);
5✔
1515

1516
                sum = invert ? ~sum : sum;
5✔
1517

1518
                r = sd_bus_message_append(m, "(sv)", field, "t", sum);
5✔
1519
                if (r < 0)
5✔
1520
                        return bus_log_create_error(r);
×
1521

1522
                return 1;
1523
        }
1524

1525
        if (streq(field, "CPUAffinity")) {
529✔
1526
                _cleanup_(cpu_set_reset) CPUSet cpuset = {};
×
1527
                _cleanup_free_ uint8_t *array = NULL;
1✔
1528
                size_t allocated;
1✔
1529

1530
                if (eq && streq(eq, "numa")) {
1✔
1531
                        r = sd_bus_message_append(m, "(sv)", "CPUAffinityFromNUMA", "b", true);
1✔
1532
                        if (r < 0)
1✔
1533
                                return bus_log_create_error(r);
×
1534
                        return r;
1535
                }
1536

1537
                r = parse_cpu_set(eq, &cpuset);
×
1538
                if (r < 0)
×
1539
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1540

1541
                r = cpu_set_to_dbus(&cpuset, &array, &allocated);
×
1542
                if (r < 0)
×
1543
                        return log_error_errno(r, "Failed to serialize CPUAffinity: %m");
×
1544

1545
                return bus_append_byte_array(m, field, array, allocated);
×
1546
        }
1547

1548
        if (streq(field, "NUMAPolicy")) {
528✔
1549
                r = mpol_from_string(eq);
8✔
1550
                if (r < 0)
8✔
1551
                        return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1552

1553
                r = sd_bus_message_append(m, "(sv)", field, "i", (int32_t) r);
8✔
1554
                if (r < 0)
8✔
1555
                        return bus_log_create_error(r);
×
1556

1557
                return 1;
1558
        }
1559

1560
        if (streq(field, "NUMAMask")) {
520✔
1561
                _cleanup_(cpu_set_reset) CPUSet nodes = {};
×
1562
                _cleanup_free_ uint8_t *array = NULL;
6✔
1563
                size_t allocated;
6✔
1564

1565
                if (eq && streq(eq, "all")) {
6✔
1566
                        r = numa_mask_add_all(&nodes);
×
1567
                        if (r < 0)
×
1568
                                return log_error_errno(r, "Failed to create NUMA mask representing \"all\" NUMA nodes: %m");
×
1569
                } else {
1570
                        r = parse_cpu_set(eq, &nodes);
6✔
1571
                        if (r < 0)
6✔
1572
                                return log_error_errno(r, "Failed to parse %s value: %s", field, eq);
×
1573
                }
1574

1575
                r = cpu_set_to_dbus(&nodes, &array, &allocated);
6✔
1576
                if (r < 0)
6✔
1577
                        return log_error_errno(r, "Failed to serialize NUMAMask: %m");
×
1578

1579
                return bus_append_byte_array(m, field, array, allocated);
6✔
1580
        }
1581

1582
        if (STR_IN_SET(field, "RestrictAddressFamilies",
514✔
1583
                              "RestrictFileSystems",
1584
                              "SystemCallFilter",
1585
                              "SystemCallLog",
1586
                              "RestrictNetworkInterfaces")) {
1587
                int allow_list = 1;
7✔
1588
                const char *p = eq;
7✔
1589

1590
                if (*p == '~') {
7✔
1591
                        allow_list = 0;
3✔
1592
                        p++;
3✔
1593
                }
1594

1595
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
7✔
1596
                if (r < 0)
7✔
1597
                        return bus_log_create_error(r);
7✔
1598

1599
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
7✔
1600
                if (r < 0)
7✔
1601
                        return bus_log_create_error(r);
×
1602

1603
                r = sd_bus_message_open_container(m, 'v', "(bas)");
7✔
1604
                if (r < 0)
7✔
1605
                        return bus_log_create_error(r);
×
1606

1607
                r = sd_bus_message_open_container(m, 'r', "bas");
7✔
1608
                if (r < 0)
7✔
1609
                        return bus_log_create_error(r);
×
1610

1611
                r = sd_bus_message_append_basic(m, 'b', &allow_list);
7✔
1612
                if (r < 0)
7✔
1613
                        return bus_log_create_error(r);
×
1614

1615
                r = sd_bus_message_open_container(m, 'a', "s");
7✔
1616
                if (r < 0)
7✔
1617
                        return bus_log_create_error(r);
×
1618

1619
                for (;;) {
25✔
1620
                        _cleanup_free_ char *word = NULL;
9✔
1621

1622
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
16✔
1623
                        if (r == 0)
16✔
1624
                                break;
1625
                        if (r == -ENOMEM)
9✔
1626
                                return log_oom();
×
1627
                        if (r < 0)
9✔
1628
                                return log_error_errno(r, "Invalid syntax: %s", eq);
×
1629

1630
                        r = sd_bus_message_append_basic(m, 's', word);
9✔
1631
                        if (r < 0)
9✔
1632
                                return bus_log_create_error(r);
×
1633
                }
1634

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

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

1643
                r = sd_bus_message_close_container(m);
7✔
1644
                if (r < 0)
7✔
1645
                        return bus_log_create_error(r);
×
1646

1647
                r = sd_bus_message_close_container(m);
7✔
1648
                if (r < 0)
7✔
1649
                        return bus_log_create_error(r);
×
1650

1651
                return 1;
1652
        }
1653

1654
        if (STR_IN_SET(field, "RestrictNamespaces",
507✔
1655
                              "DelegateNamespaces")) {
1656
                bool invert = false;
10✔
1657
                unsigned long all = UPDATE_FLAG(NAMESPACE_FLAGS_ALL, CLONE_NEWUSER, !streq(field, "DelegateNamespaces"));
10✔
1658
                unsigned long flags;
10✔
1659

1660
                r = parse_boolean(eq);
10✔
1661
                if (r > 0)
10✔
1662
                        /* RestrictNamespaces= value gets stored into a field with reverse semantics (the
1663
                         * namespaces which are retained), so RestrictNamespaces=true means we retain no
1664
                         * access to any namespaces and vice-versa. */
1665
                        flags = streq(field, "RestrictNamespaces") ? 0 : all;
1✔
1666
                else if (r == 0)
9✔
1667
                        flags = streq(field, "RestrictNamespaces") ? all : 0;
2✔
1668
                else {
1669
                        if (eq[0] == '~') {
7✔
1670
                                invert = true;
1✔
1671
                                eq++;
1✔
1672
                        }
1673

1674
                        r = namespace_flags_from_string(eq, &flags);
7✔
1675
                        if (r < 0)
7✔
1676
                                return log_error_errno(r, "Failed to parse %s value %s.", field, eq);
10✔
1677
                }
1678

1679
                if (invert)
10✔
1680
                        flags = (~flags) & all;
1✔
1681

1682
                r = sd_bus_message_append(m, "(sv)", field, "t", (uint64_t) flags);
10✔
1683
                if (r < 0)
10✔
1684
                        return bus_log_create_error(r);
×
1685

1686
                return 1;
1687
        }
1688

1689
        if (STR_IN_SET(field, "BindPaths",
497✔
1690
                              "BindReadOnlyPaths")) {
1691
                const char *p = eq;
9✔
1692

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

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

1701
                r = sd_bus_message_open_container(m, 'v', "a(ssbt)");
9✔
1702
                if (r < 0)
9✔
1703
                        return bus_log_create_error(r);
×
1704

1705
                r = sd_bus_message_open_container(m, 'a', "(ssbt)");
9✔
1706
                if (r < 0)
9✔
1707
                        return bus_log_create_error(r);
×
1708

1709
                for (;;) {
43✔
1710
                        _cleanup_free_ char *source = NULL, *destination = NULL;
17✔
1711
                        char *s = NULL, *d = NULL;
26✔
1712
                        bool ignore_enoent = false;
26✔
1713
                        uint64_t flags = MS_REC;
26✔
1714

1715
                        r = extract_first_word(&p, &source, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
26✔
1716
                        if (r < 0)
26✔
1717
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1718
                        if (r == 0)
26✔
1719
                                break;
1720

1721
                        s = source;
17✔
1722
                        if (s[0] == '-') {
17✔
1723
                                ignore_enoent = true;
2✔
1724
                                s++;
2✔
1725
                        }
1726

1727
                        if (p && p[-1] == ':') {
17✔
1728
                                r = extract_first_word(&p, &destination, ":" WHITESPACE, EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS);
9✔
1729
                                if (r < 0)
9✔
1730
                                        return log_error_errno(r, "Failed to parse argument: %m");
×
1731
                                if (r == 0)
9✔
1732
                                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1733
                                                               "Missing argument after ':': %s",
1734
                                                               eq);
1735

1736
                                d = destination;
9✔
1737

1738
                                if (p && p[-1] == ':') {
9✔
1739
                                        _cleanup_free_ char *options = NULL;
6✔
1740

1741
                                        r = extract_first_word(&p, &options, NULL, EXTRACT_UNQUOTE);
6✔
1742
                                        if (r < 0)
6✔
1743
                                                return log_error_errno(r, "Failed to parse argument: %m");
×
1744

1745
                                        if (isempty(options) || streq(options, "rbind"))
16✔
1746
                                                flags = MS_REC;
1747
                                        else if (streq(options, "norbind"))
4✔
1748
                                                flags = 0;
1749
                                        else
1750
                                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1751
                                                                       "Unknown options: %s",
1752
                                                                       eq);
1753
                                }
1754
                        } else
1755
                                d = s;
1756

1757
                        r = sd_bus_message_append(m, "(ssbt)", s, d, ignore_enoent, flags);
17✔
1758
                        if (r < 0)
17✔
1759
                                return bus_log_create_error(r);
×
1760
                }
1761

1762
                r = sd_bus_message_close_container(m);
9✔
1763
                if (r < 0)
9✔
1764
                        return bus_log_create_error(r);
×
1765

1766
                r = sd_bus_message_close_container(m);
9✔
1767
                if (r < 0)
9✔
1768
                        return bus_log_create_error(r);
×
1769

1770
                r = sd_bus_message_close_container(m);
9✔
1771
                if (r < 0)
9✔
1772
                        return bus_log_create_error(r);
×
1773

1774
                return 1;
1775
        }
1776

1777
        if (streq(field, "TemporaryFileSystem")) {
488✔
1778
                const char *p = eq;
48✔
1779

1780
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
48✔
1781
                if (r < 0)
48✔
1782
                        return bus_log_create_error(r);
48✔
1783

1784
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
48✔
1785
                if (r < 0)
48✔
1786
                        return bus_log_create_error(r);
×
1787

1788
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
48✔
1789
                if (r < 0)
48✔
1790
                        return bus_log_create_error(r);
×
1791

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

1796
                for (;;) {
144✔
1797
                        _cleanup_free_ char *word = NULL, *path = NULL;
48✔
1798
                        const char *w;
96✔
1799

1800
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
96✔
1801
                        if (r < 0)
96✔
1802
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1803
                        if (r == 0)
96✔
1804
                                break;
1805

1806
                        w = word;
48✔
1807
                        r = extract_first_word(&w, &path, ":", EXTRACT_DONT_COALESCE_SEPARATORS);
48✔
1808
                        if (r < 0)
48✔
1809
                                return log_error_errno(r, "Failed to parse argument: %m");
×
1810
                        if (r == 0)
48✔
1811
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1812
                                                       "Failed to parse argument: %s",
1813
                                                       p);
1814

1815
                        r = sd_bus_message_append(m, "(ss)", path, w);
48✔
1816
                        if (r < 0)
48✔
1817
                                return bus_log_create_error(r);
×
1818
                }
1819

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

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

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

1832
                return 1;
1833
        }
1834

1835
        if (streq(field, "RootHash")) {
440✔
1836
                _cleanup_free_ void *roothash_decoded = NULL;
12✔
1837
                size_t roothash_decoded_size = 0;
12✔
1838

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

1843
                /* We have a roothash to decode, eg: RootHash=012345789abcdef */
1844
                r = unhexmem(eq, &roothash_decoded, &roothash_decoded_size);
11✔
1845
                if (r < 0)
11✔
1846
                        return log_error_errno(r, "Failed to decode RootHash= '%s': %m", eq);
×
1847
                if (roothash_decoded_size < sizeof(sd_id128_t))
11✔
1848
                        return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "RootHash= '%s' is too short.", eq);
×
1849

1850
                return bus_append_byte_array(m, field, roothash_decoded, roothash_decoded_size);
11✔
1851
        }
1852

1853
        if (streq(field, "RootHashSignature")) {
428✔
1854
                _cleanup_free_ void *roothash_sig_decoded = NULL;
×
1855
                char *value;
×
1856
                size_t roothash_sig_decoded_size = 0;
×
1857

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

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

1865
                /* We have a roothash signature to decode, eg: RootHashSignature=base64:012345789abcdef */
1866
                r = unbase64mem(value, &roothash_sig_decoded, &roothash_sig_decoded_size);
×
1867
                if (r < 0)
×
1868
                        return log_error_errno(r, "Failed to decode RootHashSignature= '%s': %m", eq);
×
1869

1870
                return bus_append_byte_array(m, field, roothash_sig_decoded, roothash_sig_decoded_size);
×
1871
        }
1872

1873
        if (streq(field, "RootImageOptions")) {
428✔
1874
                _cleanup_strv_free_ char **l = NULL;
2✔
1875
                const char *p = eq;
2✔
1876

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

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

1885
                r = sd_bus_message_open_container(m, 'v', "a(ss)");
2✔
1886
                if (r < 0)
2✔
1887
                        return bus_log_create_error(r);
×
1888

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

1893
                r = strv_split_colon_pairs(&l, p);
2✔
1894
                if (r < 0)
2✔
1895
                        return log_error_errno(r, "Failed to parse argument: %m");
×
1896

1897
                STRV_FOREACH_PAIR(first, second, l) {
7✔
1898
                        r = sd_bus_message_append(m, "(ss)",
15✔
1899
                                                  !isempty(*second) ? *first : "root",
5✔
1900
                                                  !isempty(*second) ? *second : *first);
5✔
1901
                        if (r < 0)
5✔
1902
                                return bus_log_create_error(r);
×
1903
                }
1904

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

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

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

1917
                return 1;
1918
        }
1919

1920
        if (streq(field, "MountImages")) {
426✔
1921
                const char *p = eq;
11✔
1922

1923
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
11✔
1924
                if (r < 0)
11✔
1925
                        return bus_log_create_error(r);
11✔
1926

1927
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
11✔
1928
                if (r < 0)
11✔
1929
                        return bus_log_create_error(r);
×
1930

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

1935
                r = sd_bus_message_open_container(m, 'a', "(ssba(ss))");
11✔
1936
                if (r < 0)
11✔
1937
                        return bus_log_create_error(r);
×
1938

1939
                for (;;) {
29✔
1940
                        _cleanup_free_ char *first = NULL, *second = NULL, *tuple = NULL;
18✔
1941
                        const char *q = NULL, *source = NULL;
29✔
1942
                        bool permissive = false;
29✔
1943

1944
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
29✔
1945
                        if (r < 0)
29✔
1946
                                return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1947
                        if (r == 0)
29✔
1948
                                break;
1949

1950
                        q = tuple;
18✔
1951
                        r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &first, &second);
18✔
1952
                        if (r < 0)
18✔
1953
                                return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1954
                        if (r == 0)
18✔
1955
                                continue;
×
1956

1957
                        source = first;
18✔
1958
                        if (source[0] == '-') {
18✔
1959
                                permissive = true;
×
1960
                                source++;
×
1961
                        }
1962

1963
                        if (isempty(second))
18✔
1964
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
×
1965
                                                        "Missing argument after ':': %s",
1966
                                                        eq);
1967

1968
                        r = sd_bus_message_open_container(m, 'r', "ssba(ss)");
18✔
1969
                        if (r < 0)
18✔
1970
                                return bus_log_create_error(r);
×
1971

1972
                        r = sd_bus_message_append(m, "ssb", source, second, permissive);
18✔
1973
                        if (r < 0)
18✔
1974
                                return bus_log_create_error(r);
×
1975

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

1980
                        for (;;) {
22✔
1981
                                _cleanup_free_ char *partition = NULL, *mount_options = NULL;
2✔
1982

1983
                                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
20✔
1984
                                if (r < 0)
20✔
1985
                                        return log_error_errno(r, "Failed to parse MountImages= property: %s", eq);
×
1986
                                if (r == 0)
20✔
1987
                                        break;
1988
                                /* Single set of options, applying to the root partition/single filesystem */
1989
                                if (r == 1) {
5✔
1990
                                        r = sd_bus_message_append(m, "(ss)", "root", partition);
3✔
1991
                                        if (r < 0)
3✔
1992
                                                return bus_log_create_error(r);
×
1993

1994
                                        break;
1995
                                }
1996

1997
                                r = sd_bus_message_append(m, "(ss)", partition, mount_options);
2✔
1998
                                if (r < 0)
2✔
1999
                                        return bus_log_create_error(r);
×
2000
                        }
2001

2002
                        r = sd_bus_message_close_container(m);
18✔
2003
                        if (r < 0)
18✔
2004
                                return bus_log_create_error(r);
×
2005

2006
                        r = sd_bus_message_close_container(m);
18✔
2007
                        if (r < 0)
18✔
2008
                                return bus_log_create_error(r);
×
2009
                }
2010

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

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

2019
                r = sd_bus_message_close_container(m);
11✔
2020
                if (r < 0)
11✔
2021
                        return bus_log_create_error(r);
×
2022

2023
                return 1;
2024
        }
2025

2026
        if (streq(field, "ExtensionImages")) {
415✔
2027
                const char *p = eq;
20✔
2028

2029
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
20✔
2030
                if (r < 0)
20✔
2031
                        return bus_log_create_error(r);
20✔
2032

2033
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
20✔
2034
                if (r < 0)
20✔
2035
                        return bus_log_create_error(r);
×
2036

2037
                r = sd_bus_message_open_container(m, 'v', "a(sba(ss))");
20✔
2038
                if (r < 0)
20✔
2039
                        return bus_log_create_error(r);
×
2040

2041
                r = sd_bus_message_open_container(m, 'a', "(sba(ss))");
20✔
2042
                if (r < 0)
20✔
2043
                        return bus_log_create_error(r);
×
2044

2045
                for (;;) {
48✔
2046
                        _cleanup_free_ char *source = NULL, *tuple = NULL;
28✔
2047
                        const char *q = NULL, *s = NULL;
48✔
2048
                        bool permissive = false;
48✔
2049

2050
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE|EXTRACT_RETAIN_ESCAPE);
48✔
2051
                        if (r < 0)
48✔
2052
                                return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2053
                        if (r == 0)
48✔
2054
                                break;
2055

2056
                        q = tuple;
28✔
2057
                        r = extract_first_word(&q, &source, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS);
28✔
2058
                        if (r < 0)
28✔
2059
                                return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2060
                        if (r == 0)
28✔
2061
                                continue;
×
2062

2063
                        s = source;
28✔
2064
                        if (s[0] == '-') {
28✔
2065
                                permissive = true;
2✔
2066
                                s++;
2✔
2067
                        }
2068

2069
                        r = sd_bus_message_open_container(m, 'r', "sba(ss)");
28✔
2070
                        if (r < 0)
28✔
2071
                                return bus_log_create_error(r);
×
2072

2073
                        r = sd_bus_message_append(m, "sb", s, permissive);
28✔
2074
                        if (r < 0)
28✔
2075
                                return bus_log_create_error(r);
×
2076

2077
                        r = sd_bus_message_open_container(m, 'a', "(ss)");
28✔
2078
                        if (r < 0)
28✔
2079
                                return bus_log_create_error(r);
×
2080

2081
                        for (;;) {
28✔
2082
                                _cleanup_free_ char *partition = NULL, *mount_options = NULL;
×
2083

2084
                                r = extract_many_words(&q, ":", EXTRACT_CUNESCAPE|EXTRACT_UNESCAPE_SEPARATORS, &partition, &mount_options);
28✔
2085
                                if (r < 0)
28✔
2086
                                        return log_error_errno(r, "Failed to parse ExtensionImages= property: %s", eq);
×
2087
                                if (r == 0)
28✔
2088
                                        break;
2089
                                /* Single set of options, applying to the root partition/single filesystem */
2090
                                if (r == 1) {
×
2091
                                        r = sd_bus_message_append(m, "(ss)", "root", partition);
×
2092
                                        if (r < 0)
×
2093
                                                return bus_log_create_error(r);
×
2094

2095
                                        break;
2096
                                }
2097

2098
                                r = sd_bus_message_append(m, "(ss)", partition, mount_options);
×
2099
                                if (r < 0)
×
2100
                                        return bus_log_create_error(r);
×
2101
                        }
2102

2103
                        r = sd_bus_message_close_container(m);
28✔
2104
                        if (r < 0)
28✔
2105
                                return bus_log_create_error(r);
×
2106

2107
                        r = sd_bus_message_close_container(m);
28✔
2108
                        if (r < 0)
28✔
2109
                                return bus_log_create_error(r);
×
2110
                }
2111

2112
                r = sd_bus_message_close_container(m);
20✔
2113
                if (r < 0)
20✔
2114
                        return bus_log_create_error(r);
×
2115

2116
                r = sd_bus_message_close_container(m);
20✔
2117
                if (r < 0)
20✔
2118
                        return bus_log_create_error(r);
×
2119

2120
                r = sd_bus_message_close_container(m);
20✔
2121
                if (r < 0)
20✔
2122
                        return bus_log_create_error(r);
×
2123

2124
                return 1;
2125
        }
2126

2127
        if (STR_IN_SET(field, "StateDirectory", "RuntimeDirectory", "CacheDirectory", "LogsDirectory")) {
395✔
2128
                _cleanup_strv_free_ char **symlinks = NULL, **symlinks_ro = NULL, **sources = NULL, **sources_ro = NULL;
183✔
2129
                const char *p = eq;
183✔
2130

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

2135
                for (;;) {
665✔
2136
                        _cleanup_free_ char *tuple = NULL, *source = NULL, *dest = NULL, *flags = NULL;
241✔
2137

2138
                        r = extract_first_word(&p, &tuple, NULL, EXTRACT_UNQUOTE);
424✔
2139
                        if (r < 0)
424✔
2140
                                return log_error_errno(r, "Failed to parse argument: %m");
×
2141
                        if (r == 0)
424✔
2142
                                break;
2143

2144
                        const char *t = tuple;
241✔
2145
                        r = extract_many_words(&t, ":", EXTRACT_UNQUOTE|EXTRACT_DONT_COALESCE_SEPARATORS, &source, &dest, &flags);
241✔
2146
                        if (r <= 0)
241✔
2147
                                return log_error_errno(r ?: SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %m");
×
2148

2149
                        path_simplify(source);
241✔
2150

2151
                        if (isempty(dest) && isempty(flags)) {
278✔
2152
                                r = strv_consume(&sources, TAKE_PTR(source));
110✔
2153
                                if (r < 0)
110✔
2154
                                        return bus_log_create_error(r);
×
2155
                        } else if (isempty(flags)) {
131✔
2156
                                path_simplify(dest);
57✔
2157
                                r = strv_consume_pair(&symlinks, TAKE_PTR(source), TAKE_PTR(dest));
57✔
2158
                                if (r < 0)
57✔
2159
                                        return log_oom();
×
2160
                        } else {
2161
                                ExecDirectoryFlags exec_directory_flags = exec_directory_flags_from_string(flags);
74✔
2162
                                if (exec_directory_flags < 0 || (exec_directory_flags & ~_EXEC_DIRECTORY_FLAGS_PUBLIC) != 0)
74✔
2163
                                        return log_error_errno(r, "Failed to parse flags: %s", flags);
×
2164

2165
                                if (!isempty(dest)) {
74✔
2166
                                        path_simplify(dest);
37✔
2167
                                        r = strv_consume_pair(&symlinks_ro, TAKE_PTR(source), TAKE_PTR(dest));
37✔
2168
                                } else
2169
                                        r = strv_consume(&sources_ro, TAKE_PTR(source));
37✔
2170
                                if (r < 0)
74✔
2171
                                        return log_oom();
×
2172
                        }
2173
                }
2174

2175
                if (!strv_isempty(sources)) {
183✔
2176
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
95✔
2177
                        if (r < 0)
95✔
2178
                                return bus_log_create_error(r);
×
2179

2180
                        r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
95✔
2181
                        if (r < 0)
95✔
2182
                                return bus_log_create_error(r);
×
2183

2184
                        r = sd_bus_message_open_container(m, 'v', "as");
95✔
2185
                        if (r < 0)
95✔
2186
                                return bus_log_create_error(r);
×
2187

2188
                        r = sd_bus_message_append_strv(m, sources);
95✔
2189
                        if (r < 0)
95✔
2190
                                return bus_log_create_error(r);
×
2191

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

2196
                        r = sd_bus_message_close_container(m);
95✔
2197
                        if (r < 0)
95✔
2198
                                return bus_log_create_error(r);
×
2199
                }
2200

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

2207
                        r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
83✔
2208
                        if (r < 0)
83✔
2209
                                return bus_log_create_error(r);
×
2210

2211
                        if (streq(field, "StateDirectory"))
83✔
2212
                                symlink_field = "StateDirectorySymlink";
2213
                        else if (streq(field, "RuntimeDirectory"))
62✔
2214
                                symlink_field = "RuntimeDirectorySymlink";
2215
                        else if (streq(field, "CacheDirectory"))
38✔
2216
                                symlink_field = "CacheDirectorySymlink";
2217
                        else if (streq(field, "LogsDirectory"))
19✔
2218
                                symlink_field = "LogsDirectorySymlink";
2219
                        else
2220
                                assert_not_reached();
×
2221

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

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

2230
                        r = sd_bus_message_open_container(m, 'a', "(sst)");
83✔
2231
                        if (r < 0)
83✔
2232
                                return bus_log_create_error(r);
×
2233

2234
                        STRV_FOREACH_PAIR(source, destination, symlinks) {
140✔
2235
                                r = sd_bus_message_append(m, "(sst)", *source, *destination, UINT64_C(0));
57✔
2236
                                if (r < 0)
57✔
2237
                                        return bus_log_create_error(r);
×
2238
                        }
2239

2240
                        STRV_FOREACH_PAIR(source, destination, symlinks_ro) {
120✔
2241
                                r = sd_bus_message_append(m, "(sst)", *source, *destination, (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2242
                                if (r < 0)
37✔
2243
                                        return bus_log_create_error(r);
×
2244
                        }
2245

2246
                        STRV_FOREACH(source, sources_ro) {
120✔
2247
                                r = sd_bus_message_append(m, "(sst)", *source, "", (uint64_t) EXEC_DIRECTORY_READ_ONLY);
37✔
2248
                                if (r < 0)
37✔
2249
                                        return bus_log_create_error(r);
×
2250
                        }
2251

2252
                        r = sd_bus_message_close_container(m);
83✔
2253
                        if (r < 0)
83✔
2254
                                return bus_log_create_error(r);
×
2255

2256
                        r = sd_bus_message_close_container(m);
83✔
2257
                        if (r < 0)
83✔
2258
                                return bus_log_create_error(r);
×
2259

2260
                        r = sd_bus_message_close_container(m);
83✔
2261
                        if (r < 0)
83✔
2262
                                return bus_log_create_error(r);
×
2263
                }
2264

2265
                return 1;
183✔
2266
        }
2267

2268
        if (streq(field, "ProtectHostnameEx")) {
212✔
2269
                const char *colon = strchr(eq, ':');
15✔
2270
                if (colon) {
15✔
2271
                        if (isempty(colon + 1))
11✔
2272
                                return log_error_errno(SYNTHETIC_ERRNO(EINVAL), "Failed to parse argument: %s=%s", field, eq);
2,526✔
2273

2274
                        _cleanup_free_ char *p = strndup(eq, colon - eq);
9✔
2275
                        if (!p)
9✔
2276
                                return -ENOMEM;
×
2277

2278
                        r = sd_bus_message_append(m, "(sv)", field, "(ss)", p, colon + 1);
9✔
2279
                } else
2280
                        r = sd_bus_message_append(m, "(sv)", field, "(ss)", eq, NULL);
4✔
2281
                if (r < 0)
13✔
2282
                        return bus_log_create_error(r);
×
2283

2284
                return 1;
2285
        }
2286
        return 0;
2287
}
2288

2289
static int bus_append_kill_property(sd_bus_message *m, const char *field, const char *eq) {
205✔
2290
        if (streq(field, "KillMode"))
205✔
2291
                return bus_append_string(m, field, eq);
1✔
2292

2293
        if (STR_IN_SET(field, "SendSIGHUP",
204✔
2294
                              "SendSIGKILL"))
2295
                return bus_append_parse_boolean(m, field, eq);
×
2296

2297
        if (STR_IN_SET(field, "KillSignal",
204✔
2298
                              "RestartKillSignal",
2299
                              "FinalKillSignal",
2300
                              "WatchdogSignal",
2301
                              "ReloadSignal"))
2302
                return bus_append_signal_from_string(m, field, eq);
2✔
2303

2304
        return 0;
202✔
2305
}
2306

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

2309
        if (STR_IN_SET(field, "What",
1✔
2310
                              "Where",
2311
                              "Options",
2312
                              "Type"))
2313
                return bus_append_string(m, field, eq);
×
2314

2315
        if (streq(field, "TimeoutSec"))
1✔
2316
                return bus_append_parse_sec_rename(m, field, eq);
×
2317

2318
        if (streq(field, "DirectoryMode"))
1✔
2319
                return bus_append_parse_mode(m, field, eq);
×
2320

2321
        if (STR_IN_SET(field, "SloppyOptions",
1✔
2322
                              "LazyUnmount",
2323
                              "ForceUnmount",
2324
                              "ReadwriteOnly"))
2325
                return bus_append_parse_boolean(m, field, eq);
×
2326

2327
        return 0;
1✔
2328
}
2329

2330
static int bus_append_path_property(sd_bus_message *m, const char *field, const char *eq) {
3✔
2331
        int r;
3✔
2332

2333
        if (streq(field, "MakeDirectory"))
3✔
2334
                return bus_append_parse_boolean(m, field, eq);
×
2335

2336
        if (streq(field, "DirectoryMode"))
3✔
2337
                return bus_append_parse_mode(m, field, eq);
×
2338

2339
        if (STR_IN_SET(field, "PathExists",
3✔
2340
                              "PathExistsGlob",
2341
                              "PathChanged",
2342
                              "PathModified",
2343
                              "DirectoryNotEmpty")) {
2344
                if (isempty(eq))
3✔
2345
                        r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 0);
×
2346
                else
2347
                        r = sd_bus_message_append(m, "(sv)", "Paths", "a(ss)", 1, field, eq);
3✔
2348
                if (r < 0)
3✔
2349
                        return bus_log_create_error(r);
3✔
2350

2351
                return 1;
2352
        }
2353

2354
        if (STR_IN_SET(field, "TriggerLimitBurst", "PollLimitBurst"))
×
2355
                return bus_append_safe_atou(m, field, eq);
×
2356

2357
        if (STR_IN_SET(field, "TriggerLimitIntervalSec", "PollLimitIntervalSec"))
×
2358
                return bus_append_parse_sec_rename(m, field, eq);
×
2359

2360
        return 0;
×
2361
}
2362

2363
static int bus_append_scope_property(sd_bus_message *m, const char *field, const char *eq) {
8✔
2364
        if (streq(field, "RuntimeMaxSec"))
8✔
2365
                return bus_append_parse_sec_rename(m, field, eq);
4✔
2366

2367
        if (streq(field, "RuntimeRandomizedExtraSec"))
4✔
2368
                return bus_append_parse_sec_rename(m, field, eq);
×
2369

2370
        if (streq(field, "TimeoutStopSec"))
4✔
2371
                return bus_append_parse_sec_rename(m, field, eq);
×
2372

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

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

2381
        return 0;
2382
}
2383

2384
static int bus_append_service_property(sd_bus_message *m, const char *field, const char *eq) {
189✔
2385
        int r;
189✔
2386

2387
        if (STR_IN_SET(field, "PIDFile",
189✔
2388
                              "Type",
2389
                              "ExitType",
2390
                              "Restart",
2391
                              "RestartMode",
2392
                              "BusName",
2393
                              "NotifyAccess",
2394
                              "USBFunctionDescriptors",
2395
                              "USBFunctionStrings",
2396
                              "OOMPolicy",
2397
                              "TimeoutStartFailureMode",
2398
                              "TimeoutStopFailureMode",
2399
                              "FileDescriptorStorePreserve"))
2400
                return bus_append_string(m, field, eq);
116✔
2401

2402
        if (STR_IN_SET(field, "PermissionsStartOnly",
73✔
2403
                              "RootDirectoryStartOnly",
2404
                              "RemainAfterExit",
2405
                              "GuessMainPID"))
2406
                return bus_append_parse_boolean(m, field, eq);
1✔
2407

2408
        if (STR_IN_SET(field, "RestartSec",
72✔
2409
                              "RestartMaxDelaySec",
2410
                              "TimeoutStartSec",
2411
                              "TimeoutStopSec",
2412
                              "TimeoutAbortSec",
2413
                              "RuntimeMaxSec",
2414
                              "RuntimeRandomizedExtraSec",
2415
                              "WatchdogSec"))
2416
                return bus_append_parse_sec_rename(m, field, eq);
2✔
2417

2418
        if (streq(field, "TimeoutSec")) {
70✔
2419
                r = bus_append_parse_sec_rename(m, "TimeoutStartSec", eq);
×
2420
                if (r < 0)
×
2421
                        return r;
2422

2423
                return bus_append_parse_sec_rename(m, "TimeoutStopSec", eq);
×
2424
        }
2425

2426
        if (STR_IN_SET(field, "FileDescriptorStoreMax",
70✔
2427
                              "RestartSteps"))
2428
                return bus_append_safe_atou(m, field, eq);
1✔
2429

2430
        if (STR_IN_SET(field, "ExecCondition",
69✔
2431
                              "ExecStartPre",
2432
                              "ExecStart",
2433
                              "ExecStartPost",
2434
                              "ExecConditionEx",
2435
                              "ExecStartPreEx",
2436
                              "ExecStartEx",
2437
                              "ExecStartPostEx",
2438
                              "ExecReload",
2439
                              "ExecStop",
2440
                              "ExecStopPost",
2441
                              "ExecReloadEx",
2442
                              "ExecStopEx",
2443
                              "ExecStopPostEx"))
2444
                return bus_append_exec_command(m, field, eq);
41✔
2445

2446
        if (STR_IN_SET(field, "RestartPreventExitStatus",
28✔
2447
                              "RestartForceExitStatus",
2448
                              "SuccessExitStatus")) {
2449
                _cleanup_free_ int *status = NULL, *signal = NULL;
×
2450
                size_t n_status = 0, n_signal = 0;
×
2451
                const char *p;
×
2452

2453
                for (p = eq;;) {
×
2454
                        _cleanup_free_ char *word = NULL;
×
2455

2456
                        r = extract_first_word(&p, &word, NULL, EXTRACT_UNQUOTE);
×
2457
                        if (r == 0)
×
2458
                                break;
2459
                        if (r == -ENOMEM)
×
2460
                                return log_oom();
×
2461
                        if (r < 0)
×
2462
                                return log_error_errno(r, "Invalid syntax in %s: %s", field, eq);
×
2463

2464
                        /* We need to call exit_status_from_string() first, because we want
2465
                         * to parse numbers as exit statuses, not signals. */
2466

2467
                        r = exit_status_from_string(word);
×
2468
                        if (r >= 0) {
×
2469
                                assert(r >= 0 && r < 256);
×
2470

2471
                                if (!GREEDY_REALLOC(status, n_status + 1))
×
2472
                                        return log_oom();
×
2473

2474
                                status[n_status++] = r;
×
2475

2476
                        } else if ((r = signal_from_string(word)) >= 0) {
×
2477
                                if (!GREEDY_REALLOC(signal, n_signal + 1))
×
2478
                                        return log_oom();
×
2479

2480
                                signal[n_signal++] = r;
×
2481

2482
                        } else
2483
                                /* original r from exit_status_to_string() */
2484
                                return log_error_errno(r, "Invalid status or signal %s in %s: %m",
×
2485
                                                       word, field);
2486
                }
2487

2488
                r = sd_bus_message_open_container(m, SD_BUS_TYPE_STRUCT, "sv");
×
2489
                if (r < 0)
×
2490
                        return bus_log_create_error(r);
×
2491

2492
                r = sd_bus_message_append_basic(m, SD_BUS_TYPE_STRING, field);
×
2493
                if (r < 0)
×
2494
                        return bus_log_create_error(r);
×
2495

2496
                r = sd_bus_message_open_container(m, 'v', "(aiai)");
×
2497
                if (r < 0)
×
2498
                        return bus_log_create_error(r);
×
2499

2500
                r = sd_bus_message_open_container(m, 'r', "aiai");
×
2501
                if (r < 0)
×
2502
                        return bus_log_create_error(r);
×
2503

2504
                r = sd_bus_message_append_array(m, 'i', status, n_status * sizeof(int));
×
2505
                if (r < 0)
×
2506
                        return bus_log_create_error(r);
×
2507

2508
                r = sd_bus_message_append_array(m, 'i', signal, n_signal * sizeof(int));
×
2509
                if (r < 0)
×
2510
                        return bus_log_create_error(r);
×
2511

2512
                r = sd_bus_message_close_container(m);
×
2513
                if (r < 0)
×
2514
                        return bus_log_create_error(r);
×
2515

2516
                r = sd_bus_message_close_container(m);
×
2517
                if (r < 0)
×
2518
                        return bus_log_create_error(r);
×
2519

2520
                r = sd_bus_message_close_container(m);
×
2521
                if (r < 0)
×
2522
                        return bus_log_create_error(r);
×
2523

2524
                return 1;
2525
        }
2526

2527
        if (streq(field, "OpenFile"))
28✔
2528
                return bus_append_open_file(m, field, eq);
5✔
2529

2530
        return 0;
2531
}
2532

2533
static int bus_append_socket_property(sd_bus_message *m, const char *field, const char *eq) {
4✔
2534
        int r;
4✔
2535

2536
        if (STR_IN_SET(field, "Accept",
4✔
2537
                              "FlushPending",
2538
                              "Writable",
2539
                              "KeepAlive",
2540
                              "NoDelay",
2541
                              "FreeBind",
2542
                              "Transparent",
2543
                              "Broadcast",
2544
                              "PassCredentials",
2545
                              "PassFileDescriptorsToExec",
2546
                              "PassSecurity",
2547
                              "PassPacketInfo",
2548
                              "ReusePort",
2549
                              "RemoveOnStop",
2550
                              "SELinuxContextFromNet"))
2551
                return bus_append_parse_boolean(m, field, eq);
×
2552

2553
        if (STR_IN_SET(field, "Priority",
4✔
2554
                              "IPTTL",
2555
                              "Mark"))
2556
                return bus_append_safe_atoi(m, field, eq);
×
2557

2558
        if (streq(field, "IPTOS"))
4✔
2559
                return bus_append_ip_tos_from_string(m, field, eq);
×
2560

2561
        if (STR_IN_SET(field, "Backlog",
4✔
2562
                              "MaxConnections",
2563
                              "MaxConnectionsPerSource",
2564
                              "KeepAliveProbes",
2565
                              "TriggerLimitBurst",
2566
                              "PollLimitBurst"))
2567
                return bus_append_safe_atou(m, field, eq);
×
2568

2569
        if (STR_IN_SET(field, "SocketMode",
4✔
2570
                              "DirectoryMode"))
2571
                return bus_append_parse_mode(m, field, eq);
2✔
2572

2573
        if (STR_IN_SET(field, "MessageQueueMaxMessages",
2✔
2574
                              "MessageQueueMessageSize"))
2575
                return bus_append_safe_atoi64(m, field, eq);
×
2576

2577
        if (STR_IN_SET(field, "TimeoutSec",
2✔
2578
                              "KeepAliveTimeSec",
2579
                              "KeepAliveIntervalSec",
2580
                              "DeferAcceptSec",
2581
                              "TriggerLimitIntervalSec",
2582
                              "PollLimitIntervalSec"))
2583
                return bus_append_parse_sec_rename(m, field, eq);
×
2584

2585
        if (STR_IN_SET(field, "ReceiveBuffer",
2✔
2586
                              "SendBuffer",
2587
                              "PipeSize"))
2588
                return bus_append_parse_size(m, field, eq, 1024);
×
2589

2590
        if (STR_IN_SET(field, "ExecStartPre",
2✔
2591
                              "ExecStartPost",
2592
                              "ExecReload",
2593
                              "ExecStopPost"))
2594
                return bus_append_exec_command(m, field, eq);
×
2595

2596
        if (STR_IN_SET(field, "SmackLabel",
2✔
2597
                              "SmackLabelIPIn",
2598
                              "SmackLabelIPOut",
2599
                              "TCPCongestion",
2600
                              "BindToDevice",
2601
                              "BindIPv6Only",
2602
                              "FileDescriptorName",
2603
                              "SocketUser",
2604
                              "SocketGroup",
2605
                              "Timestamping"))
2606
                return bus_append_string(m, field, eq);
×
2607

2608
        if (streq(field, "Symlinks"))
2✔
2609
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
×
2610

2611
        if (streq(field, "SocketProtocol"))
2✔
2612
                return bus_append_parse_ip_protocol(m, field, eq);
×
2613

2614
        if (STR_IN_SET(field, "ListenStream",
2✔
2615
                              "ListenDatagram",
2616
                              "ListenSequentialPacket",
2617
                              "ListenNetlink",
2618
                              "ListenSpecial",
2619
                              "ListenMessageQueue",
2620
                              "ListenFIFO",
2621
                              "ListenUSBFunction")) {
2622
                if (isempty(eq))
2✔
2623
                        r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 0);
×
2624
                else
2625
                        r = sd_bus_message_append(m, "(sv)", "Listen", "a(ss)", 1, field + STRLEN("Listen"), eq);
2✔
2626
                if (r < 0)
2✔
2627
                        return bus_log_create_error(r);
2✔
2628

2629
                return 1;
2630
        }
2631

2632
        return 0;
×
2633
}
2634
static int bus_append_timer_property(sd_bus_message *m, const char *field, const char *eq) {
25✔
2635
        int r;
25✔
2636

2637
        if (STR_IN_SET(field, "WakeSystem",
25✔
2638
                              "RemainAfterElapse",
2639
                              "Persistent",
2640
                              "OnTimezoneChange",
2641
                              "OnClockChange",
2642
                              "FixedRandomDelay",
2643
                              "DeferReactivation"))
2644
                return bus_append_parse_boolean(m, field, eq);
5✔
2645

2646
        if (STR_IN_SET(field, "AccuracySec",
20✔
2647
                              "RandomizedDelaySec"))
2648
                return bus_append_parse_sec_rename(m, field, eq);
×
2649

2650
        if (STR_IN_SET(field, "OnActiveSec",
20✔
2651
                              "OnBootSec",
2652
                              "OnStartupSec",
2653
                              "OnUnitActiveSec",
2654
                              "OnUnitInactiveSec")) {
2655
                if (isempty(eq))
17✔
2656
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 0);
5✔
2657
                else {
2658
                        usec_t t;
12✔
2659
                        r = parse_sec(eq, &t);
12✔
2660
                        if (r < 0)
12✔
2661
                                return log_error_errno(r, "Failed to parse %s=%s: %m", field, eq);
5✔
2662

2663
                        r = sd_bus_message_append(m, "(sv)", "TimersMonotonic", "a(st)", 1, field, t);
7✔
2664
                }
2665
                if (r < 0)
12✔
2666
                        return bus_log_create_error(r);
×
2667

2668
                return 1;
2669
        }
2670

2671
        if (streq(field, "OnCalendar")) {
3✔
2672
                if (isempty(eq))
2✔
2673
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 0);
×
2674
                else
2675
                        r = sd_bus_message_append(m, "(sv)", "TimersCalendar", "a(ss)", 1, field, eq);
2✔
2676
                if (r < 0)
2✔
2677
                        return bus_log_create_error(r);
×
2678

2679
                return 1;
2680
        }
2681

2682
        return 0;
2683
}
2684

2685
static int bus_append_unit_property(sd_bus_message *m, const char *field, const char *eq) {
29✔
2686
        ConditionType t = _CONDITION_TYPE_INVALID;
29✔
2687
        bool is_condition = false;
29✔
2688
        int r;
29✔
2689

2690
        if (STR_IN_SET(field, "Description",
29✔
2691
                              "SourcePath",
2692
                              "OnFailureJobMode",
2693
                              "JobTimeoutAction",
2694
                              "JobTimeoutRebootArgument",
2695
                              "StartLimitAction",
2696
                              "FailureAction",
2697
                              "SuccessAction",
2698
                              "RebootArgument",
2699
                              "CollectMode"))
2700
                return bus_append_string(m, field, eq);
12✔
2701

2702
        if (STR_IN_SET(field, "StopWhenUnneeded",
17✔
2703
                              "RefuseManualStart",
2704
                              "RefuseManualStop",
2705
                              "AllowIsolate",
2706
                              "IgnoreOnIsolate",
2707
                              "SurviveFinalKillSignal",
2708
                              "DefaultDependencies"))
2709
                return bus_append_parse_boolean(m, field, eq);
2✔
2710

2711
        if (STR_IN_SET(field, "JobTimeoutSec",
15✔
2712
                              "JobRunningTimeoutSec",
2713
                              "StartLimitIntervalSec"))
2714
                return bus_append_parse_sec_rename(m, field, eq);
1✔
2715

2716
        if (streq(field, "StartLimitBurst"))
14✔
2717
                return bus_append_safe_atou(m, field, eq);
1✔
2718

2719
        if (STR_IN_SET(field, "SuccessActionExitStatus",
13✔
2720
                              "FailureActionExitStatus")) {
2721
                if (isempty(eq))
×
2722
                        r = sd_bus_message_append(m, "(sv)", field, "i", -1);
×
2723
                else {
2724
                        uint8_t u;
×
2725

2726
                        r = safe_atou8(eq, &u);
×
2727
                        if (r < 0)
×
2728
                                return log_error_errno(r, "Failed to parse %s=%s", field, eq);
×
2729

2730
                        r = sd_bus_message_append(m, "(sv)", field, "i", (int) u);
×
2731
                }
2732
                if (r < 0)
×
2733
                        return bus_log_create_error(r);
×
2734

2735
                return 1;
2736
        }
2737

2738
        if (unit_dependency_from_string(field) >= 0 ||
16✔
2739
            STR_IN_SET(field, "Documentation",
3✔
2740
                              "RequiresMountsFor",
2741
                              "WantsMountsFor",
2742
                              "Markers"))
2743
                return bus_append_strv(m, field, eq, /* separator= */ NULL, EXTRACT_UNQUOTE);
11✔
2744

2745
        t = condition_type_from_string(field);
2✔
2746
        if (t >= 0)
2✔
2747
                is_condition = true;
2748
        else
2749
                t = assert_type_from_string(field);
2✔
2750
        if (t >= 0) {
2✔
2751
                if (isempty(eq))
2✔
2752
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 0);
×
2753
                else {
2754
                        const char *p = eq;
2✔
2755
                        int trigger, negate;
2✔
2756

2757
                        trigger = *p == '|';
2✔
2758
                        if (trigger)
2✔
2759
                                p++;
×
2760

2761
                        negate = *p == '!';
2✔
2762
                        if (negate)
2✔
2763
                                p++;
×
2764

2765
                        r = sd_bus_message_append(m, "(sv)", is_condition ? "Conditions" : "Asserts", "a(sbbs)", 1,
4✔
2766
                                                  field, trigger, negate, p);
2767
                }
2768
                if (r < 0)
2✔
2769
                        return bus_log_create_error(r);
×
2770

2771
                return 1;
2772
        }
2773

2774
        return 0;
2775
}
2776

2777
int bus_append_unit_property_assignment(sd_bus_message *m, UnitType t, const char *assignment) {
2,955✔
2778
        const char *eq, *field;
2,955✔
2779
        int r;
2,955✔
2780

2781
        assert(m);
2,955✔
2782
        assert(assignment);
2,955✔
2783

2784
        eq = strchr(assignment, '=');
2,955✔
2785
        if (!eq)
2,955✔
2786
                return log_error_errno(SYNTHETIC_ERRNO(EINVAL),
2✔
2787
                                       "Not an assignment: %s", assignment);
2788

2789
        field = strndupa_safe(assignment, eq - assignment);
2,953✔
2790
        eq++;
2,953✔
2791

2792
        switch (t) {
2,953✔
2793
        case UNIT_SERVICE:
2,904✔
2794
                r = bus_append_cgroup_property(m, field, eq);
2,904✔
2795
                if (r != 0)
2,904✔
2796
                        return r;
2797

2798
                r = bus_append_execute_property(m, field, eq);
2,519✔
2799
                if (r != 0)
2,519✔
2800
                        return r;
2801

2802
                r = bus_append_kill_property(m, field, eq);
192✔
2803
                if (r != 0)
192✔
2804
                        return r;
2805

2806
                r = bus_append_service_property(m, field, eq);
189✔
2807
                if (r != 0)
189✔
2808
                        return r;
2809
                break;
2810

2811
        case UNIT_SOCKET:
4✔
2812
                r = bus_append_cgroup_property(m, field, eq);
4✔
2813
                if (r != 0)
4✔
2814
                        return r;
2815

2816
                r = bus_append_execute_property(m, field, eq);
4✔
2817
                if (r != 0)
4✔
2818
                        return r;
2819

2820
                r = bus_append_kill_property(m, field, eq);
4✔
2821
                if (r != 0)
4✔
2822
                        return r;
2823

2824
                r = bus_append_socket_property(m, field, eq);
4✔
2825
                if (r != 0)
4✔
2826
                        return r;
2827
                break;
2828

2829
        case UNIT_TIMER:
25✔
2830
                r = bus_append_timer_property(m, field, eq);
25✔
2831
                if (r != 0)
25✔
2832
                        return r;
2833
                break;
2834

2835
        case UNIT_PATH:
3✔
2836
                r = bus_append_path_property(m, field, eq);
3✔
2837
                if (r != 0)
3✔
2838
                        return r;
2839
                break;
2840

2841
        case UNIT_SLICE:
3✔
2842
                r = bus_append_cgroup_property(m, field, eq);
3✔
2843
                if (r != 0)
3✔
2844
                        return r;
2845
                break;
2846

2847
        case UNIT_SCOPE:
10✔
2848
                r = bus_append_cgroup_property(m, field, eq);
10✔
2849
                if (r != 0)
10✔
2850
                        return r;
2851

2852
                r = bus_append_kill_property(m, field, eq);
8✔
2853
                if (r != 0)
8✔
2854
                        return r;
2855

2856
                r = bus_append_scope_property(m, field, eq);
8✔
2857
                if (r != 0)
8✔
2858
                        return r;
2859
                break;
2860

2861
        case UNIT_MOUNT:
3✔
2862
                r = bus_append_cgroup_property(m, field, eq);
3✔
2863
                if (r != 0)
3✔
2864
                        return r;
2865

2866
                r = bus_append_execute_property(m, field, eq);
3✔
2867
                if (r != 0)
3✔
2868
                        return r;
2869

2870
                r = bus_append_kill_property(m, field, eq);
1✔
2871
                if (r != 0)
1✔
2872
                        return r;
2873

2874
                r = bus_append_mount_property(m, field, eq);
1✔
2875
                if (r != 0)
1✔
2876
                        return r;
2877

2878
                break;
2879

2880
        case UNIT_AUTOMOUNT:
1✔
2881
                r = bus_append_automount_property(m, field, eq);
1✔
2882
                if (r != 0)
1✔
2883
                        return r;
2884

2885
                break;
2886

2887
        case UNIT_TARGET:
2888
        case UNIT_DEVICE:
2889
        case UNIT_SWAP:
2890
                break;
2891

2892
        default:
×
2893
                assert_not_reached();
×
2894
        }
2895

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

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

2904
int bus_append_unit_property_assignment_many(sd_bus_message *m, UnitType t, char **l) {
1,306✔
2905
        int r;
1,306✔
2906

2907
        assert(m);
1,306✔
2908

2909
        STRV_FOREACH(i, l) {
4,252✔
2910
                r = bus_append_unit_property_assignment(m, t, *i);
2,955✔
2911
                if (r < 0)
2,955✔
2912
                        return r;
2913
        }
2914

2915
        return 0;
2916
}
2917

2918
int bus_append_scope_pidref(sd_bus_message *m, const PidRef *pidref, bool allow_pidfd) {
403✔
2919
        assert(m);
403✔
2920

2921
        if (!pidref_is_set(pidref))
403✔
2922
                return -ESRCH;
2923

2924
        if (pidref->fd >= 0 && allow_pidfd)
403✔
2925
                return sd_bus_message_append(
403✔
2926
                                m, "(sv)",
2927
                                "PIDFDs", "ah", 1, pidref->fd);
2928

2929
        return sd_bus_message_append(
×
2930
                        m, "(sv)",
2931
                        "PIDs", "au", 1, pidref->pid);
2932
}
2933

2934
int bus_deserialize_and_dump_unit_file_changes(sd_bus_message *m, bool quiet) {
58✔
2935
        const char *type, *path, *source;
58✔
2936
        InstallChange *changes = NULL;
58✔
2937
        size_t n_changes = 0;
58✔
2938
        int r;
58✔
2939

2940
        CLEANUP_ARRAY(changes, n_changes, install_changes_free);
58✔
2941

2942
        r = sd_bus_message_enter_container(m, SD_BUS_TYPE_ARRAY, "(sss)");
58✔
2943
        if (r < 0)
58✔
2944
                return bus_log_parse_error(r);
×
2945

2946
        while ((r = sd_bus_message_read(m, "(sss)", &type, &path, &source)) > 0) {
114✔
2947
                InstallChangeType t;
56✔
2948

2949
                /* We expect only "success" changes to be sent over the bus. Hence, reject anything
2950
                 * negative. */
2951
                t = install_change_type_from_string(type);
56✔
2952
                if (t < 0) {
56✔
2953
                        log_notice_errno(t, "Manager reported unknown change type \"%s\" for path \"%s\", ignoring.",
×
2954
                                         type, path);
2955
                        continue;
×
2956
                }
2957

2958
                r = install_changes_add(&changes, &n_changes, t, path, source);
56✔
2959
                if (r < 0)
56✔
2960
                        return r;
2961
        }
2962
        if (r < 0)
58✔
2963
                return bus_log_parse_error(r);
×
2964

2965
        r = sd_bus_message_exit_container(m);
58✔
2966
        if (r < 0)
58✔
2967
                return bus_log_parse_error(r);
×
2968

2969
        install_changes_dump(0, NULL, changes, n_changes, quiet);
58✔
2970

2971
        return 0;
2972
}
2973

2974
int unit_load_state(sd_bus *bus, const char *name, char **load_state) {
3,465✔
2975
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
2976
        _cleanup_free_ char *path = NULL;
3,465✔
2977
        int r;
3,465✔
2978

2979
        path = unit_dbus_path_from_name(name);
3,465✔
2980
        if (!path)
3,465✔
2981
                return log_oom();
×
2982

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

2986
        r = sd_bus_get_property_string(
3,465✔
2987
                        bus,
2988
                        "org.freedesktop.systemd1",
2989
                        path,
2990
                        "org.freedesktop.systemd1.Unit",
2991
                        "LoadState",
2992
                        &error,
2993
                        load_state);
2994
        if (r < 0)
3,465✔
2995
                return log_error_errno(r, "Failed to get load state of %s: %s", name, bus_error_message(&error, r));
×
2996

2997
        return 0;
2998
}
2999

3000
int unit_info_compare(const UnitInfo *a, const UnitInfo *b) {
31,162✔
3001
        int r;
31,162✔
3002

3003
        /* First, order by machine */
3004
        r = strcasecmp_ptr(a->machine, b->machine);
31,162✔
3005
        if (r != 0)
31,162✔
3006
                return r;
3007

3008
        /* Second, order by unit type */
3009
        r = strcasecmp_ptr(strrchr(a->id, '.'), strrchr(b->id, '.'));
31,162✔
3010
        if (r != 0)
31,162✔
3011
                return r;
3012

3013
        /* Third, order by name */
3014
        return strcasecmp(a->id, b->id);
28,918✔
3015
}
3016

3017
int bus_service_manager_reload(sd_bus *bus) {
62✔
3018
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3019
        _cleanup_(sd_bus_message_unrefp) sd_bus_message *m = NULL;
62✔
3020
        int r;
62✔
3021

3022
        assert(bus);
62✔
3023

3024
        r = bus_message_new_method_call(bus, &m, bus_systemd_mgr, "Reload");
62✔
3025
        if (r < 0)
62✔
3026
                return bus_log_create_error(r);
×
3027

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

3033
        return 0;
3034
}
3035

3036
typedef struct UnitFreezer {
3037
        char *name;
3038
        sd_bus *bus;
3039
} UnitFreezer;
3040

3041
/* Wait for 60 seconds at maximum for freezer operation */
3042
#define FREEZE_BUS_CALL_TIMEOUT (60 * USEC_PER_SEC)
3043

3044
UnitFreezer* unit_freezer_free(UnitFreezer *f) {
×
3045
        if (!f)
×
3046
                return NULL;
3047

3048
        free(f->name);
×
3049
        sd_bus_flush_close_unref(f->bus);
×
3050

3051
        return mfree(f);
×
3052
}
3053

3054
int unit_freezer_new(const char *name, UnitFreezer **ret) {
×
3055
        _cleanup_(unit_freezer_freep) UnitFreezer *f = NULL;
×
3056
        int r;
×
3057

3058
        assert(name);
×
3059
        assert(ret);
×
3060

3061
        f = new(UnitFreezer, 1);
×
3062
        if (!f)
×
3063
                return log_oom();
×
3064

3065
        *f = (UnitFreezer) {
×
3066
                .name = strdup(name),
×
3067
        };
3068
        if (!f->name)
×
3069
                return log_oom();
×
3070

3071
        r = bus_connect_system_systemd(&f->bus);
×
3072
        if (r < 0)
×
3073
                return log_error_errno(r, "Failed to open connection to systemd: %m");
×
3074

3075
        (void) sd_bus_set_method_call_timeout(f->bus, FREEZE_BUS_CALL_TIMEOUT);
×
3076

3077
        *ret = TAKE_PTR(f);
×
3078
        return 0;
×
3079
}
3080

3081
static int unit_freezer_action(UnitFreezer *f, bool freeze) {
×
3082
        _cleanup_(sd_bus_error_free) sd_bus_error error = SD_BUS_ERROR_NULL;
×
3083
        int r;
×
3084

3085
        assert(f);
×
3086
        assert(f->name);
×
3087
        assert(f->bus);
×
3088

3089
        r = bus_call_method(f->bus, bus_systemd_mgr,
×
3090
                            freeze ? "FreezeUnit" : "ThawUnit",
3091
                            &error,
3092
                            /* reply = */ NULL,
3093
                            "s",
3094
                            f->name);
3095
        if (r < 0) {
×
3096
                if (sd_bus_error_has_names(&error,
×
3097
                                           BUS_ERROR_NO_SUCH_UNIT,
3098
                                           BUS_ERROR_UNIT_INACTIVE,
3099
                                           SD_BUS_ERROR_NOT_SUPPORTED)) {
3100

3101
                        log_debug_errno(r, "Skipping freezer for '%s': %s", f->name, bus_error_message(&error, r));
×
3102
                        return 0;
×
3103
                }
3104

3105
                return log_error_errno(r, "Failed to %s unit '%s': %s",
×
3106
                                       freeze ? "freeze" : "thaw", f->name, bus_error_message(&error, r));
3107
        }
3108

3109
        log_info("Successfully %s unit '%s'.", freeze ? "froze" : "thawed", f->name);
×
3110
        return 1;
3111
}
3112

3113
int unit_freezer_freeze(UnitFreezer *f) {
×
3114
        return unit_freezer_action(f, true);
×
3115
}
3116

3117
int unit_freezer_thaw(UnitFreezer *f) {
×
3118
        return unit_freezer_action(f, false);
×
3119
}
3120

3121
ExecDirectoryFlags exec_directory_flags_from_string(const char *s) {
1,800✔
3122
        if (isempty(s))
1,800✔
3123
                return 0;
3124

3125
        if (streq(s, "ro"))
74✔
3126
                return EXEC_DIRECTORY_READ_ONLY;
74✔
3127

3128
        return _EXEC_DIRECTORY_FLAGS_INVALID;
3129
}
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