]> git.ipfire.org Git - thirdparty/systemd.git/commitdiff
uid-range: tie up number and array of uid range entries
authorYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 16 Sep 2022 01:52:00 +0000 (10:52 +0900)
committerYu Watanabe <watanabe.yu+github@gmail.com>
Fri, 16 Sep 2022 11:56:58 +0000 (20:56 +0900)
This renames UidRange -> UidRangeEntry, and reintroduces UidRange which
contains the array of UidRangeEntry and its size.
No fucntional changes, just refactoring.

src/basic/uid-range.c
src/basic/uid-range.h
src/core/manager.c
src/libsystemd/sd-device/device-monitor.c
src/sysusers/sysusers.c
src/test/test-uid-range.c
src/userdb/userdbctl.c

index fbc764673c4ebce0fd9746974f44e76272d88d75..846359927612a22532f9435dedc902b4b2ddada0 100644 (file)
 #include "uid-range.h"
 #include "user-util.h"
 
-static bool uid_range_intersect(const UidRange *a, const UidRange *b) {
+UidRange *uid_range_free(UidRange *range) {
+        if (!range)
+                return NULL;
+
+        free(range->entries);
+        return mfree(range);
+}
+
+static bool uid_range_entry_intersect(const UidRangeEntry *a, const UidRangeEntry *b) {
         assert(a);
         assert(b);
 
         return a->start <= b->start + b->nr && a->start + a->nr >= b->start;
 }
 
-static int uid_range_compare(const UidRange *a, const UidRange *b) {
+static int uid_range_entry_compare(const UidRangeEntry *a, const UidRangeEntry *b) {
         int r;
 
         assert(a);
@@ -35,23 +43,22 @@ static int uid_range_compare(const UidRange *a, const UidRange *b) {
         return CMP(a->nr, b->nr);
 }
 
-static void uid_range_coalesce(UidRange **p, size_t *n) {
-        assert(p);
-        assert(n);
+static void uid_range_coalesce(UidRange *range) {
+        assert(range);
 
-        if (*n <= 1)
+        if (range->n_entries <= 0)
                 return;
 
-        typesafe_qsort(*p, *n, uid_range_compare);
+        typesafe_qsort(range->entries, range->n_entries, uid_range_entry_compare);
 
-        for (size_t i = 0; i < *n; i++) {
-                UidRange *x = (*p) + i;
+        for (size_t i = 0; i < range->n_entries; i++) {
+                UidRangeEntry *x = range->entries + i;
 
-                for (size_t j = i + 1; j < *n; j++) {
-                        UidRange *y = (*p)+j;
+                for (size_t j = i + 1; j < range->n_entries; j++) {
+                        UidRangeEntry *y = range->entries + j;
                         uid_t begin, end;
 
-                        if (!uid_range_intersect(x, y))
+                        if (!uid_range_entry_intersect(x, y))
                                 break;
 
                         begin = MIN(x->start, y->start);
@@ -60,18 +67,20 @@ static void uid_range_coalesce(UidRange **p, size_t *n) {
                         x->start = begin;
                         x->nr = end - begin;
 
-                        if (*n > j+1)
-                                memmove(y, y+1, sizeof(UidRange) * (*n - j -1));
+                        if (range->n_entries > j + 1)
+                                memmove(y, y + 1, sizeof(UidRangeEntry) * (range->n_entries - j - 1));
 
-                        (*n)--;
+                        range->n_entries--;
                         j--;
                 }
         }
 }
 
-int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce) {
-        assert(p);
-        assert(n);
+int uid_range_add_internal(UidRange **range, uid_t start, uid_t nr, bool coalesce) {
+        _cleanup_(uid_range_freep) UidRange *range_new = NULL;
+        UidRange *p;
+
+        assert(range);
 
         if (nr <= 0)
                 return 0;
@@ -79,39 +88,51 @@ int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool
         if (start > UINT32_MAX - nr) /* overflow check */
                 return -ERANGE;
 
-        if (!GREEDY_REALLOC(*p, *n + 1))
+        if (*range)
+                p = *range;
+        else {
+                range_new = new0(UidRange, 1);
+                if (!range_new)
+                        return -ENOMEM;
+
+                p = range_new;
+        }
+
+        if (!GREEDY_REALLOC(p->entries, p->n_entries + 1))
                 return -ENOMEM;
 
-        (*p)[(*n)++] = (UidRange) {
+        p->entries[p->n_entries++] = (UidRangeEntry) {
                 .start = start,
                 .nr = nr,
         };
 
         if (coalesce)
-                uid_range_coalesce(p, n);
+                uid_range_coalesce(p);
+
+        TAKE_PTR(range_new);
+        *range = p;
 
-        return *n;
+        return 0;
 }
 
-int uid_range_add_str(UidRange **p, size_t *n, const char *s) {
+int uid_range_add_str(UidRange **range, const char *s) {
         uid_t start, end;
         int r;
 
-        assert(p);
-        assert(n);
+        assert(range);
         assert(s);
 
         r = parse_uid_range(s, &start, &end);
         if (r < 0)
                 return r;
 
-        return uid_range_add(p, n, start, end - start + 1);
+        return uid_range_add_internal(range, start, end - start + 1, /* coalesce = */ true);
 }
 
-int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
+int uid_range_next_lower(const UidRange *range, uid_t *uid) {
         uid_t closest = UID_INVALID, candidate;
 
-        assert(p);
+        assert(range);
         assert(uid);
 
         if (*uid == 0)
@@ -119,11 +140,11 @@ int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
 
         candidate = *uid - 1;
 
-        for (size_t i = 0; i < n; i++) {
+        for (size_t i = 0; i < range->n_entries; i++) {
                 uid_t begin, end;
 
-                begin = p[i].start;
-                end = p[i].start + p[i].nr - 1;
+                begin = range->entries[i].start;
+                end = range->entries[i].start + range->entries[i].nr - 1;
 
                 if (candidate >= begin && candidate <= end) {
                         *uid = candidate;
@@ -141,26 +162,27 @@ int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid) {
         return 1;
 }
 
-bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr) {
-        assert(p || n == 0);
-
+bool uid_range_covers(const UidRange *range, uid_t start, uid_t nr) {
         if (nr == 0) /* empty range? always covered... */
                 return true;
 
         if (start > UINT32_MAX - nr) /* range overflows? definitely not covered... */
                 return false;
 
-        for (size_t i = 0; i < n; i++)
-                if (start >= p[i].start && start + nr <= p[i].start + p[i].nr)
+        if (!range)
+                return false;
+
+        for (size_t i = 0; i < range->n_entries; i++)
+                if (start >= range->entries[i].start &&
+                    start + nr <= range->entries[i].start + range->entries[i].nr)
                         return true;
 
         return false;
 }
 
-int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
-        _cleanup_free_ UidRange *q = NULL;
+int uid_range_load_userns(UidRange **ret, const char *path) {
+        _cleanup_(uid_range_freep) UidRange *range = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        size_t m = 0;
         int r;
 
         /* If 'path' is NULL loads the UID range of the userns namespace we run. Otherwise load the data from
@@ -169,8 +191,7 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
          *
          * To simplify things this will modify the passed array in case of later failure. */
 
-        assert(p);
-        assert(n);
+        assert(ret);
 
         if (!path)
                 path = "/proc/self/uid_map";
@@ -185,6 +206,10 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
                 return r;
         }
 
+        range = new0(UidRange, 1);
+        if (!range)
+                return -ENOMEM;
+
         for (;;) {
                 uid_t uid_base, uid_shift, uid_range;
                 int k;
@@ -200,15 +225,13 @@ int uid_range_load_userns(UidRange **p, size_t *n, const char *path) {
                 if (k != 3)
                         return -EBADMSG;
 
-                r = uid_range_add_internal(&q, &m, uid_base, uid_range, /* coalesce = */ false);
+                r = uid_range_add_internal(&range, uid_base, uid_range, /* coalesce = */ false);
                 if (r < 0)
                         return r;
         }
 
-        uid_range_coalesce(&q, &m);
-
-        *p = TAKE_PTR(q);
-        *n = m;
+        uid_range_coalesce(range);
 
+        *ret = TAKE_PTR(range);
         return 0;
 }
index 7e238409d11fb5ad9a96cf12c8dd179a945816b3..461a5117373bbe2c12c4d2c78122af7d9b81a8a9 100644 (file)
@@ -4,21 +4,31 @@
 #include <stdbool.h>
 #include <sys/types.h>
 
-typedef struct UidRange {
+#include "macro.h"
+
+typedef struct UidRangeEntry {
         uid_t start, nr;
+} UidRangeEntry;
+
+typedef struct UidRange {
+        UidRangeEntry *entries;
+        size_t n_entries;
 } UidRange;
 
-int uid_range_add_internal(UidRange **p, size_t *n, uid_t start, uid_t nr, bool coalesce);
-static inline int uid_range_add(UidRange **p, size_t *n, uid_t start, uid_t nr) {
-        return uid_range_add_internal(p, n, start, nr, true);
+UidRange *uid_range_free(UidRange *range);
+DEFINE_TRIVIAL_CLEANUP_FUNC(UidRange*, uid_range_free);
+
+int uid_range_add_internal(UidRange **range, uid_t start, uid_t nr, bool coalesce);
+static inline int uid_range_add(UidRange **range, uid_t start, uid_t nr) {
+        return uid_range_add_internal(range, start, nr, true);
 }
-int uid_range_add_str(UidRange **p, size_t *n, const char *s);
+int uid_range_add_str(UidRange **range, const char *s);
 
-int uid_range_next_lower(const UidRange *p, size_t n, uid_t *uid);
-bool uid_range_covers(const UidRange *p, size_t n, uid_t start, uid_t nr);
+int uid_range_next_lower(const UidRange *range, uid_t *uid);
 
-static inline bool uid_range_contains(const UidRange *p, size_t n, uid_t uid) {
-        return uid_range_covers(p, n, uid, 1);
+bool uid_range_covers(const UidRange *range, uid_t start, uid_t nr);
+static inline bool uid_range_contains(const UidRange *range, uid_t uid) {
+        return uid_range_covers(range, uid, 1);
 }
 
-int uid_range_load_userns(UidRange **p, size_t *n, const char *path);
+int uid_range_load_userns(UidRange **ret, const char *path);
index cc89ae3f9c082949db8b7941081b428a03880acb..90e126840a79bb53634b729ecdd44c0ce38652fb 100644 (file)
@@ -4457,8 +4457,7 @@ int manager_dispatch_user_lookup_fd(sd_event_source *source, int fd, uint32_t re
 }
 
 static int short_uid_range(const char *path) {
-        _cleanup_free_ UidRange *p = NULL;
-        size_t n = 0;
+        _cleanup_(uid_range_freep) UidRange *p = NULL;
         int r;
 
         assert(path);
@@ -4466,13 +4465,14 @@ static int short_uid_range(const char *path) {
         /* Taint systemd if we the UID range assigned to this environment doesn't at least cover 0…65534,
          * i.e. from root to nobody. */
 
-        r = uid_range_load_userns(&p, &n, path);
-        if (ERRNO_IS_NOT_SUPPORTED(r))
-                return false;
-        if (r < 0)
+        r = uid_range_load_userns(&p, path);
+        if (r < 0) {
+                if (ERRNO_IS_NOT_SUPPORTED(r))
+                        return false;
                 return log_debug_errno(r, "Failed to load %s: %m", path);
+        }
 
-        return !uid_range_covers(p, n, 0, 65535);
+        return !uid_range_covers(p, 0, 65535);
 }
 
 char* manager_taint_string(const Manager *m) {
index 072c6b94d3589cbaa3511c596802317760f19a3e..48f425396acd5fe1a2bc5e3b4c956046e8e4d99c 100644 (file)
@@ -48,7 +48,6 @@ struct sd_device_monitor {
         bool bound;
 
         UidRange *mapped_userns_uid_range;
-        size_t n_uid_range;
 
         Hashmap *subsystem_filter;
         Set *tag_filter;
@@ -174,7 +173,6 @@ int device_monitor_new_full(sd_device_monitor **ret, MonitorNetlinkGroup group,
                 .bound = fd >= 0,
                 .snl.nl.nl_family = AF_NETLINK,
                 .snl.nl.nl_groups = group,
-                .n_uid_range = SIZE_MAX,
         };
 
         if (fd >= 0) {
@@ -376,7 +374,7 @@ static sd_device_monitor *device_monitor_free(sd_device_monitor *m) {
 
         (void) sd_device_monitor_detach_event(m);
 
-        free(m->mapped_userns_uid_range);
+        uid_range_free(m->mapped_userns_uid_range);
         free(m->description);
         hashmap_free(m->subsystem_filter);
         set_free(m->tag_filter);
@@ -468,15 +466,14 @@ static bool check_sender_uid(sd_device_monitor *m, uid_t uid) {
         if (uid == getuid() || uid == geteuid())
                 return true;
 
-        if (m->n_uid_range == SIZE_MAX) {
-                m->n_uid_range = 0;
-                r = uid_range_load_userns(&m->mapped_userns_uid_range, &m->n_uid_range, NULL);
+        if (!m->mapped_userns_uid_range) {
+                r = uid_range_load_userns(&m->mapped_userns_uid_range, NULL);
                 if (r < 0)
                         log_monitor_errno(m, r, "Failed to load UID ranges mapped to the current user namespace, ignoring: %m");
         }
 
         /* Trust messages come from outside of the current user namespace. */
-        if (m->n_uid_range != SIZE_MAX && !uid_range_contains(m->mapped_userns_uid_range, m->n_uid_range, uid))
+        if (!uid_range_contains(m->mapped_userns_uid_range, uid))
                 return true;
 
         /* Otherwise, refuse messages. */
index 491e4a0ea284d6a16b69a370bbc92a30969c1b2b..6f66f087cbe808226933b405d82b09f8aec6e354 100644 (file)
@@ -107,7 +107,6 @@ static Set *database_users = NULL, *database_groups = NULL;
 
 static uid_t search_uid = UID_INVALID;
 static UidRange *uid_range = NULL;
-static size_t n_uid_range = 0;
 
 static UGIDAllocationRange login_defs = {};
 static bool login_defs_need_warning = false;
@@ -123,7 +122,7 @@ STATIC_DESTRUCTOR_REGISTER(database_users, set_free_freep);
 STATIC_DESTRUCTOR_REGISTER(database_by_gid, hashmap_freep);
 STATIC_DESTRUCTOR_REGISTER(database_by_groupname, hashmap_freep);
 STATIC_DESTRUCTOR_REGISTER(database_groups, set_free_freep);
-STATIC_DESTRUCTOR_REGISTER(uid_range, freep);
+STATIC_DESTRUCTOR_REGISTER(uid_range, uid_range_freep);
 STATIC_DESTRUCTOR_REGISTER(arg_root, freep);
 STATIC_DESTRUCTOR_REGISTER(arg_image, freep);
 
@@ -1113,7 +1112,7 @@ static int add_user(Item *i) {
 
                 if (read_id_from_file(i, &c, NULL) > 0) {
 
-                        if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
+                        if (c <= 0 || !uid_range_contains(uid_range, c))
                                 log_debug("User ID " UID_FMT " of file not suitable for %s.", c, i->name);
                         else {
                                 r = uid_is_ok(c, i->name, true);
@@ -1144,7 +1143,7 @@ static int add_user(Item *i) {
                 maybe_emit_login_defs_warning();
 
                 for (;;) {
-                        r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
+                        r = uid_range_next_lower(uid_range, &search_uid);
                         if (r < 0)
                                 return log_error_errno(r, "No free user ID available for %s.", i->name);
 
@@ -1297,7 +1296,7 @@ static int add_group(Item *i) {
 
                 if (read_id_from_file(i, NULL, &c) > 0) {
 
-                        if (c <= 0 || !uid_range_contains(uid_range, n_uid_range, c))
+                        if (c <= 0 || !uid_range_contains(uid_range, c))
                                 log_debug("Group ID " GID_FMT " of file not suitable for %s.", c, i->name);
                         else {
                                 r = gid_is_ok(c, true);
@@ -1318,7 +1317,7 @@ static int add_group(Item *i) {
 
                 for (;;) {
                         /* We look for new GIDs in the UID pool! */
-                        r = uid_range_next_lower(uid_range, n_uid_range, &search_uid);
+                        r = uid_range_next_lower(uid_range, &search_uid);
                         if (r < 0)
                                 return log_error_errno(r, "No free group ID available for %s.", i->name);
 
@@ -1668,7 +1667,7 @@ static int parse_line(const char *fname, unsigned line, const char *buffer) {
                                           action[0],
                                           description ? "GECOS" : home ? "home directory" : "login shell");
 
-                r = uid_range_add_str(&uid_range, &n_uid_range, resolved_id);
+                r = uid_range_add_str(&uid_range, resolved_id);
                 if (r < 0)
                         return log_syntax(NULL, LOG_ERR, fname, line, SYNTHETIC_ERRNO(EINVAL),
                                           "Invalid UID range %s.", resolved_id);
@@ -2169,7 +2168,7 @@ static int run(int argc, char *argv[]) {
                 uid_t begin = login_defs.system_alloc_uid_min,
                       end = MIN3((uid_t) SYSTEM_UID_MAX, login_defs.system_uid_max, login_defs.system_gid_max);
                 if (begin < end) {
-                        r = uid_range_add(&uid_range, &n_uid_range, begin, end - begin + 1);
+                        r = uid_range_add(&uid_range, begin, end - begin + 1);
                         if (r < 0)
                                 return log_oom();
                 }
index be8530bdd857a55626884c8e5e600aead4c39864..2ed557dd1320ddc72fd7861838ee4fab21e9b86d 100644 (file)
 #include "virt.h"
 
 TEST(uid_range) {
-        _cleanup_free_ UidRange *p = NULL;
-        size_t n = 0;
+        _cleanup_(uid_range_freep) UidRange *p = NULL;
         uid_t search;
 
-        assert_se(uid_range_covers(p, n, 0, 0));
-        assert_se(!uid_range_covers(p, n, 0, 1));
-        assert_se(!uid_range_covers(p, n, 100, UINT32_MAX));
-
-        assert_se(uid_range_add_str(&p, &n, "500-999") >= 0);
-        assert_se(n == 1);
-        assert_se(p[0].start == 500);
-        assert_se(p[0].nr == 500);
-
-        assert_se(!uid_range_contains(p, n, 499));
-        assert_se(uid_range_contains(p, n, 500));
-        assert_se(uid_range_contains(p, n, 999));
-        assert_se(!uid_range_contains(p, n, 1000));
-
-        assert_se(!uid_range_covers(p, n, 100, 150));
-        assert_se(!uid_range_covers(p, n, 400, 200));
-        assert_se(!uid_range_covers(p, n, 499, 1));
-        assert_se(uid_range_covers(p, n, 500, 1));
-        assert_se(uid_range_covers(p, n, 501, 10));
-        assert_se(uid_range_covers(p, n, 999, 1));
-        assert_se(!uid_range_covers(p, n, 999, 2));
-        assert_se(!uid_range_covers(p, n, 1000, 1));
-        assert_se(!uid_range_covers(p, n, 1000, 100));
-        assert_se(!uid_range_covers(p, n, 1001, 100));
+        assert_se(uid_range_covers(p, 0, 0));
+        assert_se(!uid_range_covers(p, 0, 1));
+        assert_se(!uid_range_covers(p, 100, UINT32_MAX));
+
+        assert_se(uid_range_add_str(&p, "500-999") >= 0);
+        assert_se(p);
+        assert_se(p->n_entries == 1);
+        assert_se(p->entries[0].start == 500);
+        assert_se(p->entries[0].nr == 500);
+
+        assert_se(!uid_range_contains(p, 499));
+        assert_se(uid_range_contains(p, 500));
+        assert_se(uid_range_contains(p, 999));
+        assert_se(!uid_range_contains(p, 1000));
+
+        assert_se(!uid_range_covers(p, 100, 150));
+        assert_se(!uid_range_covers(p, 400, 200));
+        assert_se(!uid_range_covers(p, 499, 1));
+        assert_se(uid_range_covers(p, 500, 1));
+        assert_se(uid_range_covers(p, 501, 10));
+        assert_se(uid_range_covers(p, 999, 1));
+        assert_se(!uid_range_covers(p, 999, 2));
+        assert_se(!uid_range_covers(p, 1000, 1));
+        assert_se(!uid_range_covers(p, 1000, 100));
+        assert_se(!uid_range_covers(p, 1001, 100));
 
         search = UID_INVALID;
-        assert_se(uid_range_next_lower(p, n, &search));
+        assert_se(uid_range_next_lower(p, &search));
         assert_se(search == 999);
-        assert_se(uid_range_next_lower(p, n, &search));
+        assert_se(uid_range_next_lower(p, &search));
         assert_se(search == 998);
         search = 501;
-        assert_se(uid_range_next_lower(p, n, &search));
+        assert_se(uid_range_next_lower(p, &search));
         assert_se(search == 500);
-        assert_se(uid_range_next_lower(p, n, &search) == -EBUSY);
-
-        assert_se(uid_range_add_str(&p, &n, "1000") >= 0);
-        assert_se(n == 1);
-        assert_se(p[0].start == 500);
-        assert_se(p[0].nr == 501);
-
-        assert_se(uid_range_add_str(&p, &n, "30-40") >= 0);
-        assert_se(n == 2);
-        assert_se(p[0].start == 30);
-        assert_se(p[0].nr == 11);
-        assert_se(p[1].start == 500);
-        assert_se(p[1].nr == 501);
-
-        assert_se(uid_range_add_str(&p, &n, "60-70") >= 0);
-        assert_se(n == 3);
-        assert_se(p[0].start == 30);
-        assert_se(p[0].nr == 11);
-        assert_se(p[1].start == 60);
-        assert_se(p[1].nr == 11);
-        assert_se(p[2].start == 500);
-        assert_se(p[2].nr == 501);
-
-        assert_se(uid_range_add_str(&p, &n, "20-2000") >= 0);
-        assert_se(n == 1);
-        assert_se(p[0].start == 20);
-        assert_se(p[0].nr == 1981);
-
-        assert_se(uid_range_add_str(&p, &n, "2002") >= 0);
-        assert_se(n == 2);
-        assert_se(p[0].start == 20);
-        assert_se(p[0].nr == 1981);
-        assert_se(p[1].start == 2002);
-        assert_se(p[1].nr == 1);
-
-        assert_se(uid_range_add_str(&p, &n, "2001") >= 0);
-        assert_se(n == 1);
-        assert_se(p[0].start == 20);
-        assert_se(p[0].nr == 1983);
+        assert_se(uid_range_next_lower(p, &search) == -EBUSY);
+
+        assert_se(uid_range_add_str(&p, "1000") >= 0);
+        assert_se(p->n_entries == 1);
+        assert_se(p->entries[0].start == 500);
+        assert_se(p->entries[0].nr == 501);
+
+        assert_se(uid_range_add_str(&p, "30-40") >= 0);
+        assert_se(p->n_entries == 2);
+        assert_se(p->entries[0].start == 30);
+        assert_se(p->entries[0].nr == 11);
+        assert_se(p->entries[1].start == 500);
+        assert_se(p->entries[1].nr == 501);
+
+        assert_se(uid_range_add_str(&p, "60-70") >= 0);
+        assert_se(p->n_entries == 3);
+        assert_se(p->entries[0].start == 30);
+        assert_se(p->entries[0].nr == 11);
+        assert_se(p->entries[1].start == 60);
+        assert_se(p->entries[1].nr == 11);
+        assert_se(p->entries[2].start == 500);
+        assert_se(p->entries[2].nr == 501);
+
+        assert_se(uid_range_add_str(&p, "20-2000") >= 0);
+        assert_se(p->n_entries == 1);
+        assert_se(p->entries[0].start == 20);
+        assert_se(p->entries[0].nr == 1981);
+
+        assert_se(uid_range_add_str(&p, "2002") >= 0);
+        assert_se(p->n_entries == 2);
+        assert_se(p->entries[0].start == 20);
+        assert_se(p->entries[0].nr == 1981);
+        assert_se(p->entries[1].start == 2002);
+        assert_se(p->entries[1].nr == 1);
+
+        assert_se(uid_range_add_str(&p, "2001") >= 0);
+        assert_se(p->n_entries == 1);
+        assert_se(p->entries[0].start == 20);
+        assert_se(p->entries[0].nr == 1983);
 }
 
 TEST(load_userns) {
+        _cleanup_(uid_range_freep) UidRange *p = NULL;
         _cleanup_(unlink_and_freep) char *fn = NULL;
-        _cleanup_free_ UidRange *p = NULL;
         _cleanup_fclose_ FILE *f = NULL;
-        size_t n = 0;
         int r;
 
-        r = uid_range_load_userns(&p, &n, NULL);
-        if (ERRNO_IS_NOT_SUPPORTED(r))
+        r = uid_range_load_userns(&p, NULL);
+        if (r < 0 && ERRNO_IS_NOT_SUPPORTED(r))
                 return;
 
         assert_se(r >= 0);
-        assert_se(uid_range_contains(p, n, getuid()));
+        assert_se(uid_range_contains(p, getuid()));
 
         r = running_in_userns();
         if (r == 0) {
-                assert_se(n == 1);
-                assert_se(p[0].start == 0);
-                assert_se(p[0].nr == UINT32_MAX);
+                assert_se(p->n_entries == 1);
+                assert_se(p->entries[0].start == 0);
+                assert_se(p->entries[0].nr == UINT32_MAX);
 
-                assert_se(uid_range_covers(p, n, 0, UINT32_MAX));
+                assert_se(uid_range_covers(p, 0, UINT32_MAX));
         }
 
         assert_se(fopen_temporary(NULL, &f, &fn) >= 0);
@@ -121,19 +120,18 @@ TEST(load_userns) {
               "100 0 20\n", f);
         assert_se(fflush_and_check(f) >= 0);
 
-        p = mfree(p);
-        n = 0;
+        p = uid_range_free(p);
 
-        assert_se(uid_range_load_userns(&p, &n, fn) >= 0);
+        assert_se(uid_range_load_userns(&p, fn) >= 0);
 
-        assert_se(uid_range_contains(p, n, 0));
-        assert_se(uid_range_contains(p, n, 19));
-        assert_se(!uid_range_contains(p, n, 20));
+        assert_se(uid_range_contains(p, 0));
+        assert_se(uid_range_contains(p, 19));
+        assert_se(!uid_range_contains(p, 20));
 
-        assert_se(!uid_range_contains(p, n, 99));
-        assert_se(uid_range_contains(p, n, 100));
-        assert_se(uid_range_contains(p, n, 119));
-        assert_se(!uid_range_contains(p, n, 120));
+        assert_se(!uid_range_contains(p, 99));
+        assert_se(uid_range_contains(p, 100));
+        assert_se(uid_range_contains(p, 119));
+        assert_se(!uid_range_contains(p, 120));
 }
 
 DEFINE_TEST_MAIN(LOG_DEBUG);
index 362c29585fbe2c7bc2b2564d5690a10a818dc3bd..5e9bce3bae35321f6a2f8a3ad42f95dc001f680e 100644 (file)
@@ -168,19 +168,15 @@ static const struct {
         },
 };
 
-static int table_add_uid_boundaries(
-                Table *table,
-                const UidRange *p,
-                size_t n) {
+static int table_add_uid_boundaries(Table *table, const UidRange *p) {
         int r;
 
         assert(table);
-        assert(p || n == 0);
 
         for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
                 _cleanup_free_ char *name = NULL, *comment = NULL;
 
-                if (!uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1))
+                if (!uid_range_covers(p, uid_range_table[i].first, uid_range_table[i].last - uid_range_table[i].first + 1))
                         continue;
 
                 name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
@@ -305,31 +301,31 @@ static int add_unavailable_uid(Table *table, uid_t start, uid_t end) {
 static int table_add_uid_map(
                 Table *table,
                 const UidRange *p,
-                size_t n,
                 int (*add_unavailable)(Table *t, uid_t start, uid_t end)) {
 
         uid_t focus = 0;
         int n_added = 0, r;
 
         assert(table);
-        assert(p || n == 0);
         assert(add_unavailable);
 
-        for (size_t i = 0; i < n; i++) {
-                if (focus < p[i].start) {
-                        r = add_unavailable(table, focus, p[i].start-1);
+        for (size_t i = 0; p && i < p->n_entries; i++) {
+                UidRangeEntry *x = p->entries + i;
+
+                if (focus < x->start) {
+                        r = add_unavailable(table, focus, x->start-1);
                         if (r < 0)
                                 return r;
 
                         n_added += r;
                 }
 
-                if (p[i].start > UINT32_MAX - p[i].nr) { /* overflow check */
+                if (x->start > UINT32_MAX - x->nr) { /* overflow check */
                         focus = UINT32_MAX;
                         break;
                 }
 
-                focus = p[i].start + p[i].nr;
+                focus = x->start + x->nr;
         }
 
         if (focus < UINT32_MAX-1) {
@@ -428,19 +424,18 @@ static int display_user(int argc, char *argv[], void *userdata) {
         }
 
         if (table) {
-                _cleanup_free_ UidRange *uid_range = NULL;
+                _cleanup_(uid_range_freep) UidRange *uid_range = NULL;
                 int boundary_lines, uid_map_lines;
-                size_t n_uid_range = 0;
 
-                r = uid_range_load_userns(&uid_range, &n_uid_range, "/proc/self/uid_map");
+                r = uid_range_load_userns(&uid_range, "/proc/self/uid_map");
                 if (r < 0)
                         log_debug_errno(r, "Failed to load /proc/self/uid_map, ignoring: %m");
 
-                boundary_lines = table_add_uid_boundaries(table, uid_range, n_uid_range);
+                boundary_lines = table_add_uid_boundaries(table, uid_range);
                 if (boundary_lines < 0)
                         return boundary_lines;
 
-                uid_map_lines = table_add_uid_map(table, uid_range, n_uid_range, add_unavailable_uid);
+                uid_map_lines = table_add_uid_map(table, uid_range, add_unavailable_uid);
                 if (uid_map_lines < 0)
                         return uid_map_lines;
 
@@ -530,19 +525,15 @@ static int show_group(GroupRecord *gr, Table *table) {
         return 0;
 }
 
-static int table_add_gid_boundaries(
-                Table *table,
-                const UidRange *p,
-                size_t n) {
+static int table_add_gid_boundaries(Table *table, const UidRange *p) {
         int r;
 
         assert(table);
-        assert(p || n == 0);
 
         for (size_t i = 0; i < ELEMENTSOF(uid_range_table); i++) {
                 _cleanup_free_ char *name = NULL, *comment = NULL;
 
-                if (!uid_range_covers(p, n, uid_range_table[i].first, uid_range_table[i].last))
+                if (!uid_range_covers(p, uid_range_table[i].first, uid_range_table[i].last))
                         continue;
 
                 name = strjoin(special_glyph(SPECIAL_GLYPH_ARROW_DOWN),
@@ -736,19 +727,18 @@ static int display_group(int argc, char *argv[], void *userdata) {
         }
 
         if (table) {
-                _cleanup_free_ UidRange *gid_range = NULL;
+                _cleanup_(uid_range_freep) UidRange *gid_range = NULL;
                 int boundary_lines, gid_map_lines;
-                size_t n_gid_range = 0;
 
-                r = uid_range_load_userns(&gid_range, &n_gid_range, "/proc/self/gid_map");
+                r = uid_range_load_userns(&gid_range, "/proc/self/gid_map");
                 if (r < 0)
                         log_debug_errno(r, "Failed to load /proc/self/gid_map, ignoring: %m");
 
-                boundary_lines = table_add_gid_boundaries(table, gid_range, n_gid_range);
+                boundary_lines = table_add_gid_boundaries(table, gid_range);
                 if (boundary_lines < 0)
                         return boundary_lines;
 
-                gid_map_lines = table_add_uid_map(table, gid_range, n_gid_range, add_unavailable_gid);
+                gid_map_lines = table_add_uid_map(table, gid_range, add_unavailable_gid);
                 if (gid_map_lines < 0)
                         return gid_map_lines;