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

systemd / systemd / 15263807472

26 May 2025 08:53PM UTC coverage: 72.046% (-0.002%) from 72.048%
15263807472

push

github

yuwata
src/core/manager.c: log preset activity on first boot

This gives us a little more information about what units were enabled
or disabled on that first boot and will be useful for OS developers
tracking down the source of unit state.

An example with this enabled looks like:

```
NET: Registered PF_VSOCK protocol family
systemd[1]: Applying preset policy.
systemd[1]: Unit /etc/systemd/system/dnsmasq.service is masked, ignoring.
systemd[1]: Unit /etc/systemd/system/systemd-repart.service is masked, ignoring.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket'.
systemd[1]: Removed '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir.mount' → '/etc/systemd/system/var-mnt-workdir.mount'.
systemd[1]: Created symlink '/etc/systemd/system/multi-user.target.wants/var-mnt-workdir\x2dtmp.mount' → '/etc/systemd/system/var-mnt-workdir\x2dtmp.mount'.
systemd[1]: Created symlink '/etc/systemd/system/afterburn-sshkeys.target.requires/afterburn-sshkeys@core.service' → '/usr/lib/systemd/system/afterburn-sshkeys@.service'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-varlink.socket' → '/usr/lib/systemd/system/systemd-resolved-varlink.socket'.
systemd[1]: Created symlink '/etc/systemd/system/sockets.target.wants/systemd-resolved-monitor.socket' → '/usr/lib/systemd/system/systemd-resolved-monitor.socket'.
systemd[1]: Populated /etc with preset unit settings.
```

Considering it only happens on first boot and not on every boot I think
the extra information is worth the extra verbosity in the logs just for
that boot.

5 of 6 new or added lines in 1 file covered. (83.33%)

5463 existing lines in 165 files now uncovered.

299151 of 415222 relevant lines covered (72.05%)

702386.45 hits per line

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

93.51
/src/basic/uid-range.c
1
/* SPDX-License-Identifier: LGPL-2.1-or-later */
2

3
#include <string.h>
4

5
#include "alloc-util.h"
6
#include "errno-util.h"
7
#include "fd-util.h"
8
#include "format-util.h"
9
#include "namespace-util.h"
10
#include "path-util.h"
11
#include "process-util.h"
12
#include "sort-util.h"
13
#include "stat-util.h"
14
#include "uid-range.h"
15
#include "user-util.h"
16

17
UIDRange *uid_range_free(UIDRange *range) {
2,853✔
18
        if (!range)
2,853✔
19
                return NULL;
20

21
        free(range->entries);
282✔
22
        return mfree(range);
282✔
23
}
24

25
static bool uid_range_entry_intersect(const UIDRangeEntry *a, const UIDRangeEntry *b) {
94✔
26
        assert(a);
94✔
27
        assert(b);
94✔
28

29
        return a->start <= b->start + b->nr && a->start + a->nr >= b->start;
94✔
30
}
31

32
static int uid_range_entry_compare(const UIDRangeEntry *a, const UIDRangeEntry *b) {
282✔
33
        int r;
282✔
34

35
        assert(a);
282✔
36
        assert(b);
282✔
37

38
        r = CMP(a->start, b->start);
282✔
39
        if (r != 0)
138✔
40
                return r;
262✔
41

42
        return CMP(a->nr, b->nr);
20✔
43
}
44

45
static void uid_range_coalesce(UIDRange *range) {
290✔
46
        assert(range);
290✔
47

48
        if (range->n_entries <= 0)
290✔
49
                return;
50

51
        typesafe_qsort(range->entries, range->n_entries, uid_range_entry_compare);
272✔
52

53
        for (size_t i = 0; i < range->n_entries; i++) {
550✔
54
                UIDRangeEntry *x = range->entries + i;
278✔
55

56
                for (size_t j = i + 1; j < range->n_entries; j++) {
366✔
57
                        UIDRangeEntry *y = range->entries + j;
94✔
58
                        uid_t begin, end;
94✔
59

60
                        if (!uid_range_entry_intersect(x, y))
94✔
61
                                break;
62

63
                        begin = MIN(x->start, y->start);
88✔
64
                        end = MAX(x->start + x->nr, y->start + y->nr);
88✔
65

66
                        x->start = begin;
88✔
67
                        x->nr = end - begin;
88✔
68

69
                        if (range->n_entries > j + 1)
88✔
70
                                memmove(y, y + 1, sizeof(UIDRangeEntry) * (range->n_entries - j - 1));
81✔
71

72
                        range->n_entries--;
88✔
73
                        j--;
88✔
74
                }
75
        }
76
}
77

78
int uid_range_add_internal(UIDRange **range, uid_t start, uid_t nr, bool coalesce) {
353✔
79
        _cleanup_(uid_range_freep) UIDRange *range_new = NULL;
353✔
80
        UIDRange *p;
353✔
81

82
        assert(range);
353✔
83

84
        if (nr <= 0)
353✔
85
                return 0;
86

87
        if (start > UINT32_MAX - nr) /* overflow check */
353✔
88
                return -ERANGE;
89

90
        if (*range)
353✔
91
                p = *range;
92
        else {
93
                range_new = new0(UIDRange, 1);
118✔
94
                if (!range_new)
118✔
95
                        return -ENOMEM;
96

97
                p = range_new;
98
        }
99

100
        if (!GREEDY_REALLOC(p->entries, p->n_entries + 1))
353✔
101
                return -ENOMEM;
102

103
        p->entries[p->n_entries++] = (UIDRangeEntry) {
353✔
104
                .start = start,
105
                .nr = nr,
106
        };
107

108
        if (coalesce)
353✔
109
                uid_range_coalesce(p);
126✔
110

111
        TAKE_PTR(range_new);
353✔
112
        *range = p;
353✔
113

114
        return 0;
353✔
115
}
116

117
int uid_range_add_str(UIDRange **range, const char *s) {
10✔
118
        uid_t start, end;
10✔
119
        int r;
10✔
120

121
        assert(range);
10✔
122
        assert(s);
10✔
123

124
        r = parse_uid_range(s, &start, &end);
10✔
125
        if (r < 0)
10✔
126
                return r;
10✔
127

128
        return uid_range_add_internal(range, start, end - start + 1, /* coalesce = */ true);
10✔
129
}
130

131
int uid_range_next_lower(const UIDRange *range, uid_t *uid) {
187✔
132
        uid_t closest = UID_INVALID, candidate;
187✔
133

134
        assert(range);
187✔
135
        assert(uid);
187✔
136

137
        if (*uid == 0)
187✔
138
                return -EBUSY;
139

140
        candidate = *uid - 1;
187✔
141

142
        for (size_t i = 0; i < range->n_entries; i++) {
233✔
143
                uid_t begin, end;
187✔
144

145
                begin = range->entries[i].start;
187✔
146
                end = range->entries[i].start + range->entries[i].nr - 1;
187✔
147

148
                if (candidate >= begin && candidate <= end) {
187✔
149
                        *uid = candidate;
141✔
150
                        return 1;
141✔
151
                }
152

153
                if (end < candidate)
46✔
154
                        closest = end;
45✔
155
        }
156

157
        if (closest == UID_INVALID)
46✔
158
                return -EBUSY;
159

160
        *uid = closest;
45✔
161
        return 1;
45✔
162
}
163

164
bool uid_range_covers(const UIDRange *range, uid_t start, uid_t nr) {
218✔
165
        if (nr == 0) /* empty range? always covered... */
218✔
166
                return true;
167

168
        if (start > UINT32_MAX - nr) /* range overflows? definitely not covered... */
217✔
169
                return false;
170

171
        if (!range)
214✔
172
                return false;
173

174
        FOREACH_ARRAY(i, range->entries, range->n_entries)
230✔
175
                if (start >= i->start &&
218✔
176
                    start + nr <= i->start + i->nr)
212✔
177
                        return true;
178

179
        return false;
180
}
181

182
int uid_map_read_one(FILE *f, uid_t *ret_base, uid_t *ret_shift, uid_t *ret_range) {
464✔
183
        uid_t uid_base, uid_shift, uid_range;
464✔
184
        int r;
464✔
185

186
        assert(f);
464✔
187

188
        errno = 0;
464✔
189
        r = fscanf(f, UID_FMT " " UID_FMT " " UID_FMT "\n", &uid_base, &uid_shift, &uid_range);
464✔
190
        if (r == EOF)
464✔
191
                return errno_or_else(ENOMSG);
199✔
192
        assert(r >= 0);
265✔
193
        if (r != 3)
265✔
194
                return -EBADMSG;
195
        if (uid_range <= 0)
265✔
196
                return -EBADMSG;
197

198
        if (ret_base)
265✔
199
                *ret_base = uid_base;
265✔
200
        if (ret_shift)
265✔
201
                *ret_shift = uid_shift;
265✔
202
        if (ret_range)
265✔
203
                *ret_range = uid_range;
223✔
204

205
        return 0;
206
}
207

208
unsigned uid_range_size(const UIDRange *range) {
7✔
209
        if (!range)
7✔
210
                return 0;
211

212
        unsigned n = 0;
6✔
213

214
        FOREACH_ARRAY(e, range->entries, range->n_entries)
16✔
215
                n += e->nr;
10✔
216

217
        return n;
218
}
219

220
bool uid_range_is_empty(const UIDRange *range) {
22✔
221

222
        if (!range)
22✔
223
                return true;
224

225
        FOREACH_ARRAY(e, range->entries, range->n_entries)
21✔
226
                if (e->nr > 0)
3✔
227
                        return false;
228

229
        return true;
230
}
231

232
int uid_range_load_userns(const char *path, UIDRangeUsernsMode mode, UIDRange **ret) {
164✔
UNCOV
233
        _cleanup_(uid_range_freep) UIDRange *range = NULL;
×
234
        _cleanup_fclose_ FILE *f = NULL;
164✔
235
        int r;
164✔
236

237
        /* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
238
         * the specified file (which can be either uid_map or gid_map, in case caller needs to deal with GID
239
         * maps).
240
         *
241
         * To simplify things this will modify the passed array in case of later failure. */
242

243
        assert(mode >= 0);
164✔
244
        assert(mode < _UID_RANGE_USERNS_MODE_MAX);
164✔
245
        assert(ret);
164✔
246

247
        if (!path)
164✔
248
                path = IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "/proc/self/uid_map" : "/proc/self/gid_map";
145✔
249

250
        f = fopen(path, "re");
164✔
251
        if (!f) {
164✔
UNCOV
252
                r = -errno;
×
253

UNCOV
254
                if (r == -ENOENT && path_startswith(path, "/proc/"))
×
UNCOV
255
                        return proc_mounted() > 0 ? -EOPNOTSUPP : -ENOSYS;
×
256

257
                return r;
258
        }
259

260
        range = new0(UIDRange, 1);
164✔
261
        if (!range)
164✔
262
                return -ENOMEM;
263

264
        for (;;) {
147✔
265
                uid_t uid_base, uid_shift, uid_range;
311✔
266

267
                r = uid_map_read_one(f, &uid_base, &uid_shift, &uid_range);
311✔
268
                if (r == -ENOMSG)
311✔
269
                        break;
270
                if (r < 0)
147✔
UNCOV
271
                        return r;
×
272

273
                r = uid_range_add_internal(
147✔
274
                                &range,
275
                                IN_SET(mode, UID_RANGE_USERNS_INSIDE, GID_RANGE_USERNS_INSIDE) ? uid_base : uid_shift,
147✔
276
                                uid_range,
277
                                /* coalesce = */ false);
278
                if (r < 0)
147✔
279
                        return r;
280
        }
281

282
        uid_range_coalesce(range);
164✔
283

284
        *ret = TAKE_PTR(range);
164✔
285
        return 0;
164✔
286
}
287

288
int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret) {
18✔
289
        _cleanup_(sigkill_waitp) pid_t pid = 0;
18✔
290
        int r;
18✔
291

292
        assert(userns_fd >= 0);
18✔
293
        assert(mode >= 0);
18✔
294
        assert(mode < _UID_RANGE_USERNS_MODE_MAX);
18✔
295
        assert(ret);
18✔
296

297
        r = userns_enter_and_pin(userns_fd, &pid);
18✔
298
        if (r < 0)
18✔
299
                return r;
300

301
        const char *p = procfs_file_alloca(
18✔
302
                        pid,
303
                        IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "uid_map" : "gid_map");
304

305
        return uid_range_load_userns(p, mode, ret);
18✔
306
}
307

308
bool uid_range_overlaps(const UIDRange *range, uid_t start, uid_t nr) {
5✔
309

310
        if (!range)
5✔
311
                return false;
312

313
        /* Avoid overflow */
314
        if (start > UINT32_MAX - nr)
5✔
UNCOV
315
                nr = UINT32_MAX - start;
×
316

317
        if (nr == 0)
5✔
318
                return false;
319

320
        FOREACH_ARRAY(entry, range->entries, range->n_entries)
5✔
321
                if (start < entry->start + entry->nr &&
5✔
322
                    start + nr >= entry->start)
5✔
323
                        return true;
324

325
        return false;
326
}
327

328
bool uid_range_equal(const UIDRange *a, const UIDRange *b) {
4✔
329
        if (a == b)
4✔
330
                return true;
331

332
        if (!a || !b)
4✔
333
                return false;
334

335
        if (a->n_entries != b->n_entries)
3✔
336
                return false;
337

338
        for (size_t i = 0; i < a->n_entries; i++) {
5✔
339
                if (a->entries[i].start != b->entries[i].start)
3✔
340
                        return false;
341
                if (a->entries[i].nr != b->entries[i].nr)
3✔
342
                        return false;
343
        }
344

345
        return true;
346
}
347

348
int uid_map_search_root(pid_t pid, UIDRangeUsernsMode mode, uid_t *ret) {
45✔
349
        int r;
45✔
350

351
        assert(pid_is_valid(pid));
45✔
352
        assert(IN_SET(mode, UID_RANGE_USERNS_OUTSIDE, GID_RANGE_USERNS_OUTSIDE));
45✔
353

354
        const char *p = procfs_file_alloca(pid, mode == UID_RANGE_USERNS_OUTSIDE ? "uid_map" : "gid_map");
45✔
355
        _cleanup_fclose_ FILE *f = fopen(p, "re");
90✔
356
        if (!f) {
45✔
UNCOV
357
                if (errno != ENOENT)
×
UNCOV
358
                        return -errno;
×
359

UNCOV
360
                r = proc_mounted();
×
UNCOV
361
                if (r < 0)
×
362
                        return -ENOENT; /* original error, if we can't determine /proc/ state */
363

UNCOV
364
                return r ? -ENOPKG : -ENOSYS;
×
365
        }
366

UNCOV
367
        for (;;) {
×
368
                uid_t uid_base = UID_INVALID, uid_shift = UID_INVALID;
45✔
369

370
                r = uid_map_read_one(f, &uid_base, &uid_shift, /* ret_uid_range= */ NULL);
45✔
371
                if (r < 0)
45✔
372
                        return r;
45✔
373

374
                if (uid_base == 0) {
42✔
375
                        if (ret)
42✔
376
                                *ret = uid_shift;
42✔
377
                        return 0;
42✔
378
                }
379
        }
380
}
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