Changes in uspace/lib/c/generic/cap.c [8d2dd7f2:05b59393] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/c/generic/cap.c
r8d2dd7f2 r05b59393 1 1 /* 2 * Copyright (c) 20 06 Jakub Jermar2 * Copyright (c) 2015 Jiri Svoboda 3 3 * All rights reserved. 4 4 * … … 31 31 */ 32 32 /** 33 * @file cap.c 34 * @brief Functions to grant/revoke capabilities to/from a task. 33 * @file Storage capacity specification. 35 34 */ 36 35 37 36 #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 */ 43 enum { 44 /** Simplified capacity maximum integer digits */ 45 scap_max_idig = 3, 46 /** Simplified capacity maximum significant digits */ 47 scap_max_sdig = 4 48 }; 49 50 static 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 62 void 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 */ 83 int 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 */ 140 void 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 177 int 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 209 static 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 229 int 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; 276 found: 277 cap->cunit = i; 278 } 279 280 cap->m = m; 281 cap->dp = dp; 282 return EOK; 80 283 } 81 284
Note:
See TracChangeset
for help on using the changeset viewer.