]> git.ipfire.org Git - thirdparty/systemd.git/blame - src/shared/uid-range.c
Add SPDX license identifiers to source files under the LGPL
[thirdparty/systemd.git] / src / shared / uid-range.c
CommitLineData
53e1b683 1/* SPDX-License-Identifier: LGPL-2.1+ */
8530dc44
LP
2/***
3 This file is part of systemd.
4
5 Copyright 2014 Lennart Poettering
6
7 systemd is free software; you can redistribute it and/or modify it
8 under the terms of the GNU Lesser General Public License as published by
9 the Free Software Foundation; either version 2.1 of the License, or
10 (at your option) any later version.
11
12 systemd is distributed in the hope that it will be useful, but
13 WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Lesser General Public License for more details.
16
17 You should have received a copy of the GNU Lesser General Public License
18 along with systemd; If not, see <http://www.gnu.org/licenses/>.
19***/
20
a8fbdf54
TA
21#include <errno.h>
22#include <stdlib.h>
23#include <string.h>
24
25#include "macro.h"
8530dc44 26#include "uid-range.h"
b1d4f8e1 27#include "user-util.h"
8530dc44
LP
28
29static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
30 assert(range);
31
32 return range->start <= start + nr &&
33 range->start + range->nr >= start;
34}
35
36static void uid_range_coalesce(UidRange **p, unsigned *n) {
37 unsigned i, j;
38
39 assert(p);
40 assert(n);
41
42 for (i = 0; i < *n; i++) {
43 for (j = i + 1; j < *n; j++) {
44 UidRange *x = (*p)+i, *y = (*p)+j;
45
46 if (uid_range_intersect(x, y->start, y->nr)) {
47 uid_t begin, end;
48
49 begin = MIN(x->start, y->start);
50 end = MAX(x->start + x->nr, y->start + y->nr);
51
52 x->start = begin;
53 x->nr = end - begin;
54
55 if (*n > j+1)
56 memmove(y, y+1, sizeof(UidRange) * (*n - j -1));
57
313cefa1 58 (*n)--;
8530dc44
LP
59 j--;
60 }
61 }
62 }
63
64}
65
66static int uid_range_compare(const void *a, const void *b) {
67 const UidRange *x = a, *y = b;
68
69 if (x->start < y->start)
70 return -1;
71 if (x->start > y->start)
72 return 1;
73
74 if (x->nr < y->nr)
75 return -1;
76 if (x->nr > y->nr)
77 return 1;
78
79 return 0;
80}
81
82int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
83 bool found = false;
84 UidRange *x;
85 unsigned i;
86
87 assert(p);
88 assert(n);
89
90 if (nr <= 0)
91 return 0;
92
93 for (i = 0; i < *n; i++) {
94 x = (*p) + i;
95 if (uid_range_intersect(x, start, nr)) {
96 found = true;
97 break;
98 }
99 }
100
101 if (found) {
102 uid_t begin, end;
103
104 begin = MIN(x->start, start);
105 end = MAX(x->start + x->nr, start + nr);
106
107 x->start = begin;
108 x->nr = end - begin;
109 } else {
110 UidRange *t;
111
112 t = realloc(*p, sizeof(UidRange) * (*n + 1));
113 if (!t)
114 return -ENOMEM;
115
116 *p = t;
117 x = t + ((*n) ++);
118
119 x->start = start;
120 x->nr = nr;
121 }
122
123 qsort(*p, *n, sizeof(UidRange), uid_range_compare);
124 uid_range_coalesce(p, n);
125
126 return *n;
127}
128
129int uid_range_add_str(UidRange **p, unsigned *n, const char *s) {
130 uid_t start, nr;
131 const char *t;
132 int r;
133
134 assert(p);
135 assert(n);
136 assert(s);
137
138 t = strchr(s, '-');
139 if (t) {
140 char *b;
141 uid_t end;
142
143 b = strndupa(s, t - s);
144 r = parse_uid(b, &start);
145 if (r < 0)
146 return r;
147
148 r = parse_uid(t+1, &end);
149 if (r < 0)
150 return r;
151
152 if (end < start)
153 return -EINVAL;
154
155 nr = end - start + 1;
156 } else {
157 r = parse_uid(s, &start);
158 if (r < 0)
159 return r;
160
161 nr = 1;
162 }
163
164 return uid_range_add(p, n, start, nr);
165}
166
167int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
fed1e721 168 uid_t closest = UID_INVALID, candidate;
8530dc44
LP
169 unsigned i;
170
171 assert(p);
172 assert(uid);
173
174 candidate = *uid - 1;
175
176 for (i = 0; i < n; i++) {
177 uid_t begin, end;
178
179 begin = p[i].start;
180 end = p[i].start + p[i].nr - 1;
181
182 if (candidate >= begin && candidate <= end) {
183 *uid = candidate;
184 return 1;
185 }
186
187 if (end < candidate)
188 closest = end;
189 }
190
fed1e721 191 if (closest == UID_INVALID)
8530dc44
LP
192 return -EBUSY;
193
194 *uid = closest;
195 return 1;
196}
197
198bool uid_range_contains(const UidRange *p, unsigned n, uid_t uid) {
199 unsigned i;
200
201 assert(p);
202 assert(uid);
203
204 for (i = 0; i < n; i++)
205 if (uid >= p[i].start && uid < p[i].start + p[i].nr)
206 return true;
207
208 return false;
209}