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 free(sector); 369 g_close(fd); 370 return (error); 371 } 372 373 /* 374 * Set an error message, if one does not already exist. 375 */ 376 void 377 gctl_error(struct gctl_req *req, const char *error, ...) 378 { 379 va_list ap; 380 381 if (req != NULL && req->error != NULL) 382 return; 383 va_start(ap, error); 384 if (req != NULL) { 385 vasprintf(&req->error, error, ap); 386 } else { 387 vfprintf(stderr, error, ap); 388 fprintf(stderr, "\n"); 389 } 390 va_end(ap); 391 } 392 393 static void * 394 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 395 { 396 struct gctl_req_arg *argp; 397 char param[256]; 398 unsigned int i; 399 void *p; 400 401 vsnprintf(param, sizeof(param), pfmt, ap); 402 for (i = 0; i < req->narg; i++) { 403 argp = &req->arg[i]; 404 if (strcmp(param, argp->name)) 405 continue; 406 if (!(argp->flag & GCTL_PARAM_RD)) 407 continue; 408 p = argp->value; 409 if (len == 0) { 410 /* We are looking for a string. */ 411 if (argp->len < 1) { 412 fprintf(stderr, "No length argument (%s).\n", 413 param); 414 abort(); 415 } 416 if (((char *)p)[argp->len - 1] != '\0') { 417 fprintf(stderr, "Unterminated argument (%s).\n", 418 param); 419 abort(); 420 } 421 } else if ((int)len != argp->len) { 422 fprintf(stderr, "Wrong length %s argument.\n", param); 423 abort(); 424 } 425 return (p); 426 } 427 fprintf(stderr, "No such argument (%s).\n", param); 428 abort(); 429 } 430 431 int 432 gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 433 { 434 int *p; 435 va_list ap; 436 437 va_start(ap, pfmt); 438 p = gctl_get_param(req, sizeof(int), pfmt, ap); 439 va_end(ap); 440 return (*p); 441 } 442 443 intmax_t 444 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 445 { 446 intmax_t *p; 447 va_list ap; 448 449 va_start(ap, pfmt); 450 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 451 va_end(ap); 452 return (*p); 453 } 454 455 const char * 456 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 457 { 458 const char *p; 459 va_list ap; 460 461 va_start(ap, pfmt); 462 p = gctl_get_param(req, 0, pfmt, ap); 463 va_end(ap); 464 return (p); 465 } 466 467 int 468 gctl_change_param(struct gctl_req *req, const char *name, int len, 469 const void *value) 470 { 471 struct gctl_req_arg *ap; 472 unsigned int i; 473 474 if (req == NULL || req->error != NULL) 475 return (EDOOFUS); 476 for (i = 0; i < req->narg; i++) { 477 ap = &req->arg[i]; 478 if (strcmp(ap->name, name) != 0) 479 continue; 480 ap->value = __DECONST(void *, value); 481 if (len >= 0) { 482 ap->flag &= ~GCTL_PARAM_ASCII; 483 ap->len = len; 484 } else if (len < 0) { 485 ap->flag |= GCTL_PARAM_ASCII; 486 ap->len = strlen(value) + 1; 487 } 488 return (0); 489 } 490 return (ENOENT); 491 } 492 493 int 494 gctl_delete_param(struct gctl_req *req, const char *name) 495 { 496 struct gctl_req_arg *ap; 497 unsigned int i; 498 499 if (req == NULL || req->error != NULL) 500 return (EDOOFUS); 501 502 i = 0; 503 while (i < req->narg) { 504 ap = &req->arg[i]; 505 if (strcmp(ap->name, name) == 0) 506 break; 507 i++; 508 } 509 if (i == req->narg) 510 return (ENOENT); 511 512 free(ap->name); 513 req->narg--; 514 while (i < req->narg) { 515 req->arg[i] = req->arg[i + 1]; 516 i++; 517 } 518 return (0); 519 } 520 521 int 522 gctl_has_param(struct gctl_req *req, const char *name) 523 { 524 struct gctl_req_arg *ap; 525 unsigned int i; 526 527 if (req == NULL || req->error != NULL) 528 return (0); 529 530 for (i = 0; i < req->narg; i++) { 531 ap = &req->arg[i]; 532 if (strcmp(ap->name, name) == 0) 533 return (1); 534 } 535 return (0); 536 } 537