1 /*- 2 * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <sys/param.h> 31 #include <sys/disk.h> 32 #include <sys/endian.h> 33 #include <sys/uio.h> 34 #include <errno.h> 35 #include <fcntl.h> 36 #include <paths.h> 37 #include <stdio.h> 38 #include <stdlib.h> 39 #include <limits.h> 40 #include <inttypes.h> 41 #include <stdarg.h> 42 #include <string.h> 43 #include <strings.h> 44 #include <unistd.h> 45 #include <assert.h> 46 #include <libgeom.h> 47 48 #include "misc/subr.h" 49 50 51 struct std_metadata { 52 char md_magic[16]; 53 uint32_t md_version; 54 }; 55 56 static void 57 std_metadata_decode(const unsigned char *data, struct std_metadata *md) 58 { 59 60 bcopy(data, md->md_magic, sizeof(md->md_magic)); 61 md->md_version = le32dec(data + 16); 62 } 63 64 /* 65 * Greatest Common Divisor. 66 */ 67 static unsigned int 68 gcd(unsigned int a, unsigned int b) 69 { 70 unsigned int c; 71 72 while (b != 0) { 73 c = a; 74 a = b; 75 b = (c % b); 76 } 77 return (a); 78 } 79 80 /* 81 * Least Common Multiple. 82 */ 83 unsigned int 84 g_lcm(unsigned int a, unsigned int b) 85 { 86 87 return ((a * b) / gcd(a, b)); 88 } 89 90 uint32_t 91 bitcount32(uint32_t x) 92 { 93 94 x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 95 x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 96 x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 97 x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 98 x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 99 return (x); 100 } 101 102 /* 103 * The size of a sector is context specific (i.e. determined by the 104 * media). But when users enter a value with a SI unit, they really 105 * mean the byte-size or byte-offset and not the size or offset in 106 * sectors. We should map the byte-oriented value into a sector-oriented 107 * value when we already know the sector size in bytes. At this time 108 * we can use g_parse_lba() function. It converts user specified 109 * value into sectors with following conditions: 110 * o Sectors size taken as argument from caller. 111 * o When no SI unit is specified the value is in sectors. 112 * o With an SI unit the value is in bytes. 113 * o The 'b' suffix forces byte interpretation and the 's' 114 * suffix forces sector interpretation. 115 * 116 * Thus: 117 * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 118 * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 119 * 120 */ 121 int 122 g_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors) 123 { 124 off_t number, mult, unit; 125 char *s; 126 127 assert(lbastr != NULL); 128 assert(sectorsize > 0); 129 assert(sectors != NULL); 130 131 number = (off_t)strtoimax(lbastr, &s, 0); 132 if (s == lbastr || number < 0) 133 return (EINVAL); 134 135 mult = 1; 136 unit = sectorsize; 137 if (*s == '\0') 138 goto done; 139 switch (*s) { 140 case 'e': case 'E': 141 mult *= 1024; 142 /* FALLTHROUGH */ 143 case 'p': case 'P': 144 mult *= 1024; 145 /* FALLTHROUGH */ 146 case 't': case 'T': 147 mult *= 1024; 148 /* FALLTHROUGH */ 149 case 'g': case 'G': 150 mult *= 1024; 151 /* FALLTHROUGH */ 152 case 'm': case 'M': 153 mult *= 1024; 154 /* FALLTHROUGH */ 155 case 'k': case 'K': 156 mult *= 1024; 157 break; 158 default: 159 goto sfx; 160 } 161 unit = 1; /* bytes */ 162 s++; 163 if (*s == '\0') 164 goto done; 165 sfx: 166 switch (*s) { 167 case 's': case 'S': 168 unit = sectorsize; /* sector */ 169 break; 170 case 'b': case 'B': 171 unit = 1; /* bytes */ 172 break; 173 default: 174 return (EINVAL); 175 } 176 s++; 177 if (*s != '\0') 178 return (EINVAL); 179 done: 180 if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number) 181 return (ERANGE); 182 number *= mult * unit; 183 if (number % sectorsize) 184 return (EINVAL); 185 number /= sectorsize; 186 *sectors = number; 187 return (0); 188 } 189 190 off_t 191 g_get_mediasize(const char *name) 192 { 193 off_t mediasize; 194 int fd; 195 196 fd = g_open(name, 0); 197 if (fd == -1) 198 return (0); 199 mediasize = g_mediasize(fd); 200 if (mediasize == -1) 201 mediasize = 0; 202 (void)g_close(fd); 203 return (mediasize); 204 } 205 206 unsigned int 207 g_get_sectorsize(const char *name) 208 { 209 ssize_t sectorsize; 210 int fd; 211 212 fd = g_open(name, 0); 213 if (fd == -1) 214 return (0); 215 sectorsize = g_sectorsize(fd); 216 if (sectorsize == -1) 217 sectorsize = 0; 218 (void)g_close(fd); 219 return ((unsigned int)sectorsize); 220 } 221 222 int 223 g_metadata_read(const char *name, unsigned char *md, size_t size, 224 const char *magic) 225 { 226 struct std_metadata stdmd; 227 unsigned char *sector; 228 ssize_t sectorsize; 229 off_t mediasize; 230 int error, fd; 231 232 sector = NULL; 233 error = 0; 234 235 fd = g_open(name, 0); 236 if (fd == -1) 237 return (errno); 238 mediasize = g_mediasize(fd); 239 if (mediasize == -1) { 240 error = errno; 241 goto out; 242 } 243 sectorsize = g_sectorsize(fd); 244 if (sectorsize == -1) { 245 error = errno; 246 goto out; 247 } 248 assert(sectorsize >= (ssize_t)size); 249 sector = malloc(sectorsize); 250 if (sector == NULL) { 251 error = ENOMEM; 252 goto out; 253 } 254 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 255 sectorsize) { 256 error = errno; 257 goto out; 258 } 259 if (magic != NULL) { 260 std_metadata_decode(sector, &stdmd); 261 if (strcmp(stdmd.md_magic, magic) != 0) { 262 error = EINVAL; 263 goto out; 264 } 265 } 266 bcopy(sector, md, size); 267 out: 268 if (sector != NULL) 269 free(sector); 270 g_close(fd); 271 return (error); 272 } 273 274 int 275 g_metadata_store(const char *name, const unsigned char *md, size_t size) 276 { 277 unsigned char *sector; 278 ssize_t sectorsize; 279 off_t mediasize; 280 int error, fd; 281 282 sector = NULL; 283 error = 0; 284 285 fd = g_open(name, 1); 286 if (fd == -1) 287 return (errno); 288 mediasize = g_mediasize(fd); 289 if (mediasize == -1) { 290 error = errno; 291 goto out; 292 } 293 sectorsize = g_sectorsize(fd); 294 if (sectorsize == -1) { 295 error = errno; 296 goto out; 297 } 298 assert(sectorsize >= (ssize_t)size); 299 sector = malloc(sectorsize); 300 if (sector == NULL) { 301 error = ENOMEM; 302 goto out; 303 } 304 bcopy(md, sector, size); 305 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 306 sectorsize) { 307 error = errno; 308 goto out; 309 } 310 (void)g_flush(fd); 311 out: 312 if (sector != NULL) 313 free(sector); 314 (void)g_close(fd); 315 return (error); 316 } 317 318 int 319 g_metadata_clear(const char *name, const char *magic) 320 { 321 struct std_metadata md; 322 unsigned char *sector; 323 ssize_t sectorsize; 324 off_t mediasize; 325 int error, fd; 326 327 sector = NULL; 328 error = 0; 329 330 fd = g_open(name, 1); 331 if (fd == -1) 332 return (errno); 333 mediasize = g_mediasize(fd); 334 if (mediasize == 0) { 335 error = errno; 336 goto out; 337 } 338 sectorsize = g_sectorsize(fd); 339 if (sectorsize == 0) { 340 error = errno; 341 goto out; 342 } 343 sector = malloc(sectorsize); 344 if (sector == NULL) { 345 error = ENOMEM; 346 goto out; 347 } 348 if (magic != NULL) { 349 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 350 sectorsize) { 351 error = errno; 352 goto out; 353 } 354 std_metadata_decode(sector, &md); 355 if (strcmp(md.md_magic, magic) != 0) { 356 error = EINVAL; 357 goto out; 358 } 359 } 360 bzero(sector, sectorsize); 361 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 362 sectorsize) { 363 error = errno; 364 goto out; 365 } 366 (void)g_flush(fd); 367 out: 368 if (sector != NULL) 369 free(sector); 370 g_close(fd); 371 return (error); 372 } 373 374 /* 375 * Set an error message, if one does not already exist. 376 */ 377 void 378 gctl_error(struct gctl_req *req, const char *error, ...) 379 { 380 va_list ap; 381 382 if (req != NULL && req->error != NULL) 383 return; 384 va_start(ap, error); 385 if (req != NULL) { 386 vasprintf(&req->error, error, ap); 387 } else { 388 vfprintf(stderr, error, ap); 389 fprintf(stderr, "\n"); 390 } 391 va_end(ap); 392 } 393 394 static void * 395 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 396 { 397 struct gctl_req_arg *argp; 398 char param[256]; 399 unsigned int i; 400 void *p; 401 402 vsnprintf(param, sizeof(param), pfmt, ap); 403 for (i = 0; i < req->narg; i++) { 404 argp = &req->arg[i]; 405 if (strcmp(param, argp->name)) 406 continue; 407 if (!(argp->flag & GCTL_PARAM_RD)) 408 continue; 409 p = argp->value; 410 if (len == 0) { 411 /* We are looking for a string. */ 412 if (argp->len < 1) { 413 fprintf(stderr, "No length argument (%s).\n", 414 param); 415 abort(); 416 } 417 if (((char *)p)[argp->len - 1] != '\0') { 418 fprintf(stderr, "Unterminated argument (%s).\n", 419 param); 420 abort(); 421 } 422 } else if ((int)len != argp->len) { 423 fprintf(stderr, "Wrong length %s argument.\n", param); 424 abort(); 425 } 426 return (p); 427 } 428 fprintf(stderr, "No such argument (%s).\n", param); 429 abort(); 430 } 431 432 int 433 gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 434 { 435 int *p; 436 va_list ap; 437 438 va_start(ap, pfmt); 439 p = gctl_get_param(req, sizeof(int), pfmt, ap); 440 va_end(ap); 441 return (*p); 442 } 443 444 intmax_t 445 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 446 { 447 intmax_t *p; 448 va_list ap; 449 450 va_start(ap, pfmt); 451 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 452 va_end(ap); 453 return (*p); 454 } 455 456 const char * 457 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 458 { 459 const char *p; 460 va_list ap; 461 462 va_start(ap, pfmt); 463 p = gctl_get_param(req, 0, pfmt, ap); 464 va_end(ap); 465 return (p); 466 } 467 468 int 469 gctl_change_param(struct gctl_req *req, const char *name, int len, 470 const void *value) 471 { 472 struct gctl_req_arg *ap; 473 unsigned int i; 474 475 if (req == NULL || req->error != NULL) 476 return (EDOOFUS); 477 for (i = 0; i < req->narg; i++) { 478 ap = &req->arg[i]; 479 if (strcmp(ap->name, name) != 0) 480 continue; 481 ap->value = __DECONST(void *, value); 482 if (len >= 0) { 483 ap->flag &= ~GCTL_PARAM_ASCII; 484 ap->len = len; 485 } else if (len < 0) { 486 ap->flag |= GCTL_PARAM_ASCII; 487 ap->len = strlen(value) + 1; 488 } 489 return (0); 490 } 491 return (ENOENT); 492 } 493 494 int 495 gctl_delete_param(struct gctl_req *req, const char *name) 496 { 497 struct gctl_req_arg *ap; 498 unsigned int i; 499 500 if (req == NULL || req->error != NULL) 501 return (EDOOFUS); 502 503 i = 0; 504 while (i < req->narg) { 505 ap = &req->arg[i]; 506 if (strcmp(ap->name, name) == 0) 507 break; 508 i++; 509 } 510 if (i == req->narg) 511 return (ENOENT); 512 513 free(ap->name); 514 req->narg--; 515 while (i < req->narg) { 516 req->arg[i] = req->arg[i + 1]; 517 i++; 518 } 519 return (0); 520 } 521 522 int 523 gctl_has_param(struct gctl_req *req, const char *name) 524 { 525 struct gctl_req_arg *ap; 526 unsigned int i; 527 528 if (req == NULL || req->error != NULL) 529 return (0); 530 531 for (i = 0; i < req->narg; i++) { 532 ap = &req->arg[i]; 533 if (strcmp(ap->name, name) == 0) 534 return (1); 535 } 536 return (0); 537 } 538