LCOV - code coverage report
Current view: top level - shared - uid-range.c (source / functions) Hit Total Coverage
Test: systemd test coverage Lines: 91 102 89.2 %
Date: 2015-07-29 18:47:03 Functions: 7 7 100.0 %

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

Generated by: LCOV version 1.11