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

systemd / systemd / 22246189288

20 Feb 2026 07:59PM UTC coverage: 72.238% (-0.2%) from 72.47%
22246189288

push

github

bluca
Add BNCF NewBook 11 ACCEL_MOUNT_MATRIX  to 60-sensor.hwdb

Corrects DE autorotation

Device description: https://www.bncfai.com/product/773/

313540 of 434040 relevant lines covered (72.24%)

1346131.39 hits per line

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

93.3
/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 "pidref.h"
12
#include "process-util.h"
13
#include "sort-util.h"
14
#include "stat-util.h"
15
#include "uid-range.h"
16
#include "user-util.h"
17

18
UIDRange *uid_range_free(UIDRange *range) {
3,441✔
19
        if (!range)
3,441✔
20
                return NULL;
21

22
        free(range->entries);
703✔
23
        return mfree(range);
703✔
24
}
25

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

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

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

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

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

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

46
static void uid_range_coalesce(UIDRange *range) {
711✔
47
        assert(range);
711✔
48

49
        if (range->n_entries <= 0)
711✔
50
                return;
51

52
        typesafe_qsort(range->entries, range->n_entries, uid_range_entry_compare);
373✔
53

54
        for (size_t i = 0; i < range->n_entries; i++) {
752✔
55
                UIDRangeEntry *x = range->entries + i;
379✔
56

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

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

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

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

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

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

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

83
        assert(range);
454✔
84

85
        if (nr <= 0)
454✔
86
                return 0;
87

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

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

98
                p = range_new;
99
        }
100

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

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

109
        if (coalesce)
454✔
110
                uid_range_coalesce(p);
127✔
111

112
        TAKE_PTR(range_new);
454✔
113
        *range = p;
454✔
114

115
        return 0;
454✔
116
}
117

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

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

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

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

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

135
        assert(range);
229✔
136
        assert(uid);
229✔
137

138
        if (*uid == 0)
229✔
139
                return -EBUSY;
140

141
        candidate = *uid - 1;
229✔
142

143
        for (size_t i = 0; i < range->n_entries; i++) {
276✔
144
                uid_t begin, end;
229✔
145

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

149
                if (candidate >= begin && candidate <= end) {
229✔
150
                        *uid = candidate;
182✔
151
                        return 1;
182✔
152
                }
153

154
                if (end < candidate)
47✔
155
                        closest = end;
46✔
156
        }
157

158
        if (closest == UID_INVALID)
47✔
159
                return -EBUSY;
160

161
        *uid = closest;
46✔
162
        return 1;
46✔
163
}
164

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

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

172
        if (!range)
318✔
173
                return false;
174

175
        FOREACH_ARRAY(i, range->entries, range->n_entries)
334✔
176
                if (start >= i->start &&
322✔
177
                    start + nr <= i->start + i->nr)
316✔
178
                        return true;
179

180
        return false;
181
}
182

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

187
        assert(f);
1,081✔
188

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

199
        if (ret_base)
426✔
200
                *ret_base = uid_base;
426✔
201
        if (ret_shift)
426✔
202
                *ret_shift = uid_shift;
426✔
203
        if (ret_range)
426✔
204
                *ret_range = uid_range;
364✔
205

206
        return 0;
207
}
208

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

213
        unsigned n = 0;
6✔
214

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

218
        return n;
219
}
220

221
bool uid_range_is_empty(const UIDRange *range) {
350✔
222

223
        if (!range)
350✔
224
                return true;
225

226
        FOREACH_ARRAY(e, range->entries, range->n_entries)
349✔
227
                if (e->nr > 0)
11✔
228
                        return false;
229

230
        return true;
231
}
232

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

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

244
        assert(mode >= 0);
584✔
245
        assert(mode < _UID_RANGE_USERNS_MODE_MAX);
584✔
246
        assert(ret);
584✔
247

248
        if (!path)
584✔
249
                path = IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "/proc/self/uid_map" : "/proc/self/gid_map";
237✔
250

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

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

258
                return r;
259
        }
260

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

265
        for (;;) {
247✔
266
                uid_t uid_base, uid_shift, uid_range;
831✔
267

268
                r = uid_map_read_one(f, &uid_base, &uid_shift, &uid_range);
831✔
269
                if (r == -ENOMSG)
831✔
270
                        break;
271
                if (r < 0)
247✔
272
                        return r;
×
273

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

283
        uid_range_coalesce(range);
584✔
284

285
        *ret = TAKE_PTR(range);
584✔
286
        return 0;
584✔
287
}
288

289
int uid_range_load_userns_by_fd(int userns_fd, UIDRangeUsernsMode mode, UIDRange **ret) {
346✔
290
        _cleanup_(pidref_done_sigkill_wait) PidRef pidref = PIDREF_NULL;
346✔
291
        int r;
346✔
292

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

298
        r = is_our_namespace(userns_fd, NAMESPACE_USER);
346✔
299
        if (r < 0)
346✔
300
                return r;
301
        if (r > 0)
346✔
302
                return uid_range_load_userns(/* path= */ NULL, mode, ret);
×
303

304
        r = userns_enter_and_pin(userns_fd, &pidref);
346✔
305
        if (r < 0)
346✔
306
                return r;
307

308
        const char *p = procfs_file_alloca(
346✔
309
                        pidref.pid,
310
                        IN_SET(mode, UID_RANGE_USERNS_INSIDE, UID_RANGE_USERNS_OUTSIDE) ? "uid_map" : "gid_map");
311

312
        return uid_range_load_userns(p, mode, ret);
346✔
313
}
314

315
bool uid_range_overlaps(const UIDRange *range, uid_t start, uid_t nr) {
85✔
316

317
        if (!range)
85✔
318
                return false;
319

320
        /* Avoid overflow */
321
        if (start > UINT32_MAX - nr)
85✔
322
                nr = UINT32_MAX - start;
×
323

324
        if (nr == 0)
85✔
325
                return false;
326

327
        FOREACH_ARRAY(entry, range->entries, range->n_entries)
85✔
328
                if (start < entry->start + entry->nr &&
85✔
329
                    start + nr >= entry->start)
85✔
330
                        return true;
331

332
        return false;
333
}
334

335
bool uid_range_equal(const UIDRange *a, const UIDRange *b) {
4✔
336
        if (a == b)
4✔
337
                return true;
338

339
        if (!a || !b)
4✔
340
                return false;
341

342
        if (a->n_entries != b->n_entries)
3✔
343
                return false;
344

345
        for (size_t i = 0; i < a->n_entries; i++) {
5✔
346
                if (a->entries[i].start != b->entries[i].start)
3✔
347
                        return false;
348
                if (a->entries[i].nr != b->entries[i].nr)
3✔
349
                        return false;
350
        }
351

352
        return true;
353
}
354

355
int uid_map_search_root(pid_t pid, UIDRangeUsernsMode mode, uid_t *ret) {
63✔
356
        int r;
63✔
357

358
        assert(pid_is_valid(pid));
63✔
359
        assert(IN_SET(mode, UID_RANGE_USERNS_OUTSIDE, GID_RANGE_USERNS_OUTSIDE));
63✔
360

361
        const char *p = procfs_file_alloca(pid, mode == UID_RANGE_USERNS_OUTSIDE ? "uid_map" : "gid_map");
63✔
362
        _cleanup_fclose_ FILE *f = fopen(p, "re");
126✔
363
        if (!f) {
63✔
364
                if (errno != ENOENT)
×
365
                        return -errno;
×
366

367
                r = proc_mounted();
×
368
                if (r < 0)
×
369
                        return -ENOENT; /* original error, if we can't determine /proc/ state */
370

371
                return r ? -ENOPKG : -ENOSYS;
×
372
        }
373

374
        for (;;) {
×
375
                uid_t uid_base = UID_INVALID, uid_shift = UID_INVALID;
63✔
376

377
                r = uid_map_read_one(f, &uid_base, &uid_shift, /* ret_range= */ NULL);
63✔
378
                if (r < 0)
63✔
379
                        return r;
63✔
380

381
                if (uid_base == 0) {
62✔
382
                        if (ret)
62✔
383
                                *ret = uid_shift;
62✔
384
                        return 0;
62✔
385
                }
386
        }
387
}
388

389
uid_t uid_range_base(const UIDRange *range) {
8✔
390

391
        /* Returns the lowest UID in the range (notw that elements are sorted, hence we just need to look at
392
         * the first one that is populated. */
393

394
        if (uid_range_is_empty(range))
8✔
395
                return UID_INVALID;
396

397
        FOREACH_ARRAY(e, range->entries, range->n_entries)
8✔
398
                if (e->nr > 0)
8✔
399
                        return e->start;
8✔
400

401
        return UID_INVALID;
402
}
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