Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/c/generic/cap.c

    r8d2dd7f2 r05b59393  
    11/*
    2  * Copyright (c) 2006 Jakub Jermar
     2 * Copyright (c) 2015 Jiri Svoboda
    33 * All rights reserved.
    44 *
     
    3131 */
    3232/**
    33  * @file  cap.c
    34  * @brief Functions to grant/revoke capabilities to/from a task.
     33 * @file Storage capacity specification.
    3534 */
    3635
    3736#include <cap.h>
    38 #include <task.h>
    39 #include <libc.h>
    40 #include <libarch/types.h>
    41 
    42 /** Grant capabilities to a task.
    43  *
    44  * @param id   Destination task ID.
    45  * @param caps Capabilities to grant.
    46  *
    47  * @return Zero on success or a value from @ref errno.h on failure.
    48  *
    49  */
    50 int cap_grant(task_id_t id, unsigned int caps)
    51 {
    52 #ifdef __32_BITS__
    53         sysarg64_t arg = (sysarg64_t) id;
    54         return __SYSCALL2(SYS_CAP_GRANT, (sysarg_t) &arg, (sysarg_t) caps);
    55 #endif
    56        
    57 #ifdef __64_BITS__
    58         return __SYSCALL2(SYS_CAP_GRANT, (sysarg_t) id, (sysarg_t) caps);
    59 #endif
    60 }
    61 
    62 /** Revoke capabilities from a task.
    63  *
    64  * @param id   Destination task ID.
    65  * @param caps Capabilities to revoke.
    66  *
    67  * @return Zero on success or a value from @ref errno.h on failure.
    68  *
    69  */
    70 int cap_revoke(task_id_t id, unsigned int caps)
    71 {
    72 #ifdef __32_BITS__
    73         sysarg64_t arg = (sysarg64_t) id;
    74         return __SYSCALL2(SYS_CAP_REVOKE, (sysarg_t) &arg, (sysarg_t) caps);
    75 #endif
    76        
    77 #ifdef __64_BITS__
    78         return __SYSCALL2(SYS_CAP_REVOKE, (sysarg_t) id, (sysarg_t) caps);
    79 #endif
     37#include <errno.h>
     38#include <imath.h>
     39#include <stdio.h>
     40#include <str.h>
     41
     42/** Simplified capacity parameters */
     43enum {
     44        /** Simplified capacity maximum integer digits */
     45        scap_max_idig = 3,
     46        /** Simplified capacity maximum significant digits */
     47        scap_max_sdig = 4
     48};
     49
     50static const char *cu_str[] = {
     51        [cu_byte] = "B",
     52        [cu_kbyte] = "kB",
     53        [cu_mbyte] = "MB",
     54        [cu_gbyte] = "GB",
     55        [cu_tbyte] = "TB",
     56        [cu_pbyte] = "PB",
     57        [cu_ebyte] = "EB",
     58        [cu_zbyte] = "ZB",
     59        [cu_ybyte] = "YB"
     60};
     61
     62void cap_from_blocks(uint64_t nblocks, size_t block_size, cap_spec_t *cap)
     63{
     64        uint64_t tsize;
     65
     66        tsize = nblocks * block_size;
     67        cap->m = tsize;
     68        cap->dp = 0;
     69        cap->cunit = cu_byte;
     70}
     71
     72/** Convert capacity to blocks.
     73 *
     74 * If the value of bytes is not integer, it is properly rounded. If the number
     75 * of bytes is not divisible by the number of blocks, it is rounded
     76 * up to an integer number of blocks.
     77 *
     78 * A capacity value entails precision, i.e. it corresponds to a range
     79 * of values. @a cvsel selects the value to return. @c cv_nom gives
     80 * the nominal (middle) value, @c cv_min gives the minimum value
     81 * and @c cv_max gives the maximum value.
     82 */
     83int cap_to_blocks(cap_spec_t *cap, cap_vsel_t cvsel, size_t block_size,
     84    uint64_t *rblocks)
     85{
     86        int exp;
     87        uint64_t bytes;
     88        uint64_t f;
     89        uint64_t adj;
     90        uint64_t blocks;
     91        uint64_t rem;
     92        int rc;
     93
     94        exp = cap->cunit * 3 - cap->dp;
     95        if (exp < 0) {
     96                rc = ipow10_u64(-exp, &f);
     97                if (rc != EOK)
     98                        return ERANGE;
     99                bytes = (cap->m + (f / 2)) / f;
     100                if (bytes * f - (f / 2) != cap->m)
     101                        return ERANGE;
     102        } else {
     103                rc = ipow10_u64(exp, &f);
     104                if (rc != EOK)
     105                        return ERANGE;
     106
     107                adj = 0;
     108                switch (cvsel) {
     109                case cv_nom:
     110                        adj = 0;
     111                        break;
     112                case cv_min:
     113                        adj = -(f / 2);
     114                        break;
     115                case cv_max:
     116                        adj = f / 2 - 1;
     117                        break;
     118                }
     119
     120                bytes = cap->m * f + adj;
     121                if ((bytes - adj) / f != cap->m)
     122                        return ERANGE;
     123        }
     124
     125        rem = bytes % block_size;
     126        if ((bytes + rem) < bytes)
     127                return ERANGE;
     128
     129        blocks = (bytes + rem) / block_size;
     130
     131        *rblocks = blocks;
     132        return EOK;
     133}
     134
     135/** Simplify and round capacity to a human-friendly form.
     136 *
     137 * Change unit and round the number so that we have at most three integer
     138 * digits and at most two fractional digits, e.g abc.xy <unit>.
     139 */
     140void cap_simplify(cap_spec_t *cap)
     141{
     142        uint64_t div;
     143        uint64_t maxv;
     144        unsigned sdig;
     145        unsigned rdig;
     146        int rc;
     147
     148        /* Change units so that we have at most @c scap_max_idig integer digits */
     149        rc = ipow10_u64(scap_max_idig, &maxv);
     150        assert(rc == EOK);
     151
     152        rc = ipow10_u64(cap->dp, &div);
     153        assert(rc == EOK);
     154
     155        while (cap->m / div >= maxv) {
     156                ++cap->cunit;
     157                cap->dp += 3;
     158                div = div * 1000;
     159        }
     160
     161        /* Round the number so that we have at most @c scap_max_sdig significant digits */
     162        sdig = 1 + ilog10_u64(cap->m); /* number of significant digits */
     163        if (sdig > scap_max_sdig) {
     164                /* Number of digits to remove */
     165                rdig = sdig - scap_max_sdig;
     166                if (rdig > cap->dp)
     167                        rdig = cap->dp;
     168
     169                rc = ipow10_u64(rdig, &div);
     170                assert(rc == EOK);
     171
     172                cap->m = (cap->m + (div / 2)) / div;
     173                cap->dp -= rdig;
     174        }
     175}
     176
     177int cap_format(cap_spec_t *cap, char **rstr)
     178{
     179        int rc;
     180        const char *sunit;
     181        uint64_t ipart;
     182        uint64_t fpart;
     183        uint64_t div;
     184
     185        sunit = NULL;
     186
     187        assert(cap->cunit < CU_LIMIT);
     188
     189        rc = ipow10_u64(cap->dp, &div);
     190        if (rc != EOK)
     191                return rc;
     192
     193        ipart = cap->m / div;
     194        fpart = cap->m % div;
     195
     196        sunit = cu_str[cap->cunit];
     197        if (cap->dp > 0) {
     198                rc = asprintf(rstr, "%" PRIu64 ".%0*" PRIu64 " %s", ipart,
     199                    (int)cap->dp, fpart, sunit);
     200        } else {
     201                rc = asprintf(rstr, "%" PRIu64 " %s", ipart, sunit);
     202        }
     203        if (rc < 0)
     204                return ENOMEM;
     205
     206        return EOK;
     207}
     208
     209static int cap_digit_val(char c, int *val)
     210{
     211        switch (c) {
     212        case '0': *val = 0; break;
     213        case '1': *val = 1; break;
     214        case '2': *val = 2; break;
     215        case '3': *val = 3; break;
     216        case '4': *val = 4; break;
     217        case '5': *val = 5; break;
     218        case '6': *val = 6; break;
     219        case '7': *val = 7; break;
     220        case '8': *val = 8; break;
     221        case '9': *val = 9; break;
     222        default:
     223                return EINVAL;
     224        }
     225
     226        return EOK;
     227}
     228
     229int cap_parse(const char *str, cap_spec_t *cap)
     230{
     231        const char *eptr;
     232        const char *p;
     233        int d;
     234        int dp;
     235        unsigned long m;
     236        int i;
     237
     238        m = 0;
     239
     240        eptr = str;
     241        while (cap_digit_val(*eptr, &d) == EOK) {
     242                m = m * 10 + d;
     243                ++eptr;
     244        }
     245
     246        if (*eptr == '.') {
     247                ++eptr;
     248                dp = 0;
     249                while (cap_digit_val(*eptr, &d) == EOK) {
     250                        m = m * 10 + d;
     251                        ++dp;
     252                        ++eptr;
     253                }
     254        } else {
     255                dp = 0;
     256        }
     257
     258        while (*eptr == ' ')
     259                ++eptr;
     260
     261        if (*eptr == '\0') {
     262                cap->cunit = cu_byte;
     263        } else {
     264                for (i = 0; i < CU_LIMIT; i++) {
     265                        if (str_lcasecmp(eptr, cu_str[i],
     266                            str_length(cu_str[i])) == 0) {
     267                                p = eptr + str_size(cu_str[i]);
     268                                while (*p == ' ')
     269                                        ++p;
     270                                if (*p == '\0')
     271                                        goto found;
     272                        }
     273                }
     274
     275                return EINVAL;
     276found:
     277                cap->cunit = i;
     278        }
     279
     280        cap->m = m;
     281        cap->dp = dp;
     282        return EOK;
    80283}
    81284
Note: See TracChangeset for help on using the changeset viewer.