Systemd/src/shared/uid-range.c
Lennart Poettering 0c69794138 tree-wide: remove Lennart's copyright lines
These lines are generally out-of-date, incomplete and unnecessary. With
SPDX and git repository much more accurate and fine grained information
about licensing and authorship is available, hence let's drop the
per-file copyright notice. Of course, removing copyright lines of others
is problematic, hence this commit only removes my own lines and leaves
all others untouched. It might be nicer if sooner or later those could
go away too, making git the only and accurate source of authorship
information.
2018-06-14 10:20:20 +02:00

192 lines
4.5 KiB
C

/* SPDX-License-Identifier: LGPL-2.1+ */
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#include "alloc-util.h"
#include "macro.h"
#include "uid-range.h"
#include "user-util.h"
static bool uid_range_intersect(UidRange *range, uid_t start, uid_t nr) {
assert(range);
return range->start <= start + nr &&
range->start + range->nr >= start;
}
static void uid_range_coalesce(UidRange **p, unsigned *n) {
unsigned i, j;
assert(p);
assert(n);
for (i = 0; i < *n; i++) {
for (j = i + 1; j < *n; j++) {
UidRange *x = (*p)+i, *y = (*p)+j;
if (uid_range_intersect(x, y->start, y->nr)) {
uid_t begin, end;
begin = MIN(x->start, y->start);
end = MAX(x->start + x->nr, y->start + y->nr);
x->start = begin;
x->nr = end - begin;
if (*n > j+1)
memmove(y, y+1, sizeof(UidRange) * (*n - j -1));
(*n)--;
j--;
}
}
}
}
static int uid_range_compare(const void *a, const void *b) {
const UidRange *x = a, *y = b;
if (x->start < y->start)
return -1;
if (x->start > y->start)
return 1;
if (x->nr < y->nr)
return -1;
if (x->nr > y->nr)
return 1;
return 0;
}
int uid_range_add(UidRange **p, unsigned *n, uid_t start, uid_t nr) {
bool found = false;
UidRange *x;
unsigned i;
assert(p);
assert(n);
if (nr <= 0)
return 0;
for (i = 0; i < *n; i++) {
x = (*p) + i;
if (uid_range_intersect(x, start, nr)) {
found = true;
break;
}
}
if (found) {
uid_t begin, end;
begin = MIN(x->start, start);
end = MAX(x->start + x->nr, start + nr);
x->start = begin;
x->nr = end - begin;
} else {
UidRange *t;
t = reallocarray(*p, *n + 1, sizeof(UidRange));
if (!t)
return -ENOMEM;
*p = t;
x = t + ((*n) ++);
x->start = start;
x->nr = nr;
}
qsort(*p, *n, sizeof(UidRange), uid_range_compare);
uid_range_coalesce(p, n);
return *n;
}
int uid_range_add_str(UidRange **p, unsigned *n, const char *s) {
uid_t start, nr;
const char *t;
int r;
assert(p);
assert(n);
assert(s);
t = strchr(s, '-');
if (t) {
char *b;
uid_t end;
b = strndupa(s, t - s);
r = parse_uid(b, &start);
if (r < 0)
return r;
r = parse_uid(t+1, &end);
if (r < 0)
return r;
if (end < start)
return -EINVAL;
nr = end - start + 1;
} else {
r = parse_uid(s, &start);
if (r < 0)
return r;
nr = 1;
}
return uid_range_add(p, n, start, nr);
}
int uid_range_next_lower(const UidRange *p, unsigned n, uid_t *uid) {
uid_t closest = UID_INVALID, candidate;
unsigned i;
assert(p);
assert(uid);
candidate = *uid - 1;
for (i = 0; i < n; i++) {
uid_t begin, end;
begin = p[i].start;
end = p[i].start + p[i].nr - 1;
if (candidate >= begin && candidate <= end) {
*uid = candidate;
return 1;
}
if (end < candidate)
closest = end;
}
if (closest == UID_INVALID)
return -EBUSY;
*uid = closest;
return 1;
}
bool uid_range_contains(const UidRange *p, unsigned n, uid_t uid) {
unsigned i;
assert(p);
assert(uid);
for (i = 0; i < n; i++)
if (uid >= p[i].start && uid < p[i].start + p[i].nr)
return true;
return false;
}