1 /*- 2 * Copyright (c) 2004 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 u_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 static void 65 pathgen(const char *name, char *path, size_t size) 66 { 67 68 if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 69 snprintf(path, size, "%s%s", _PATH_DEV, name); 70 else 71 strlcpy(path, name, size); 72 } 73 74 /* 75 * Greatest Common Divisor. 76 */ 77 static unsigned 78 gcd(unsigned a, unsigned b) 79 { 80 u_int c; 81 82 while (b != 0) { 83 c = a; 84 a = b; 85 b = (c % b); 86 } 87 return (a); 88 } 89 90 /* 91 * Least Common Multiple. 92 */ 93 unsigned 94 g_lcm(unsigned a, unsigned b) 95 { 96 97 return ((a * b) / gcd(a, b)); 98 } 99 100 uint32_t 101 bitcount32(uint32_t x) 102 { 103 104 x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 105 x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 106 x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 107 x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 108 x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 109 return (x); 110 } 111 112 /* 113 * The size of a sector is context specific (i.e. determined by the 114 * media). But when users enter a value with a SI unit, they really 115 * mean the byte-size or byte-offset and not the size or offset in 116 * sectors. We should map the byte-oriented value into a sector-oriented 117 * value when we already know the sector size in bytes. At this time 118 * we can use g_parse_lba() function. It converts user specified 119 * value into sectors with following conditions: 120 * o Sectors size taken as argument from caller. 121 * o When no SI unit is specified the value is in sectors. 122 * o With an SI unit the value is in bytes. 123 * o The 'b' suffix forces byte interpretation and the 's' 124 * suffix forces sector interpretation. 125 * 126 * Thus: 127 * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 128 * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 129 * 130 */ 131 int 132 g_parse_lba(const char *lbastr, unsigned sectorsize, off_t *sectors) 133 { 134 off_t number, mult, unit; 135 char *s; 136 137 assert(lbastr != NULL); 138 assert(sectorsize > 0); 139 assert(sectors != NULL); 140 141 number = (off_t)strtoimax(lbastr, &s, 0); 142 if (s == lbastr || number < 0) 143 return (EINVAL); 144 145 mult = 1; 146 unit = sectorsize; 147 if (*s == '\0') 148 goto done; 149 switch (*s) { 150 case 'e': case 'E': 151 mult *= 1024; 152 /* FALLTHROUGH */ 153 case 'p': case 'P': 154 mult *= 1024; 155 /* FALLTHROUGH */ 156 case 't': case 'T': 157 mult *= 1024; 158 /* FALLTHROUGH */ 159 case 'g': case 'G': 160 mult *= 1024; 161 /* FALLTHROUGH */ 162 case 'm': case 'M': 163 mult *= 1024; 164 /* FALLTHROUGH */ 165 case 'k': case 'K': 166 mult *= 1024; 167 break; 168 default: 169 goto sfx; 170 } 171 unit = 1; /* bytes */ 172 s++; 173 if (*s == '\0') 174 goto done; 175 sfx: 176 switch (*s) { 177 case 's': case 'S': 178 unit = sectorsize; /* sector */ 179 break; 180 case 'b': case 'B': 181 unit = 1; /* bytes */ 182 break; 183 default: 184 return (EINVAL); 185 } 186 s++; 187 if (*s != '\0') 188 return (EINVAL); 189 done: 190 if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number) 191 return (ERANGE); 192 number *= mult * unit; 193 if (number % sectorsize) 194 return (EINVAL); 195 number /= sectorsize; 196 *sectors = number; 197 return (0); 198 } 199 200 off_t 201 g_get_mediasize(const char *name) 202 { 203 char path[MAXPATHLEN]; 204 off_t mediasize; 205 int fd; 206 207 pathgen(name, path, sizeof(path)); 208 fd = open(path, O_RDONLY); 209 if (fd == -1) 210 return (0); 211 if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 212 close(fd); 213 return (0); 214 } 215 close(fd); 216 return (mediasize); 217 } 218 219 unsigned 220 g_get_sectorsize(const char *name) 221 { 222 char path[MAXPATHLEN]; 223 unsigned sectorsize; 224 int fd; 225 226 pathgen(name, path, sizeof(path)); 227 fd = open(path, O_RDONLY); 228 if (fd == -1) 229 return (0); 230 if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 231 close(fd); 232 return (0); 233 } 234 close(fd); 235 return (sectorsize); 236 } 237 238 int 239 g_metadata_read(const char *name, u_char *md, size_t size, const char *magic) 240 { 241 struct std_metadata stdmd; 242 char path[MAXPATHLEN]; 243 unsigned sectorsize; 244 off_t mediasize; 245 u_char *sector; 246 int error, fd; 247 248 pathgen(name, path, sizeof(path)); 249 sector = NULL; 250 error = 0; 251 252 fd = open(path, O_RDONLY); 253 if (fd == -1) 254 return (errno); 255 mediasize = g_get_mediasize(name); 256 if (mediasize == 0) { 257 error = errno; 258 goto out; 259 } 260 sectorsize = g_get_sectorsize(name); 261 if (sectorsize == 0) { 262 error = errno; 263 goto out; 264 } 265 assert(sectorsize >= size); 266 sector = malloc(sectorsize); 267 if (sector == NULL) { 268 error = ENOMEM; 269 goto out; 270 } 271 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 272 (ssize_t)sectorsize) { 273 error = errno; 274 goto out; 275 } 276 if (magic != NULL) { 277 std_metadata_decode(sector, &stdmd); 278 if (strcmp(stdmd.md_magic, magic) != 0) { 279 error = EINVAL; 280 goto out; 281 } 282 } 283 bcopy(sector, md, size); 284 out: 285 if (sector != NULL) 286 free(sector); 287 close(fd); 288 return (error); 289 } 290 291 int 292 g_metadata_store(const char *name, u_char *md, size_t size) 293 { 294 char path[MAXPATHLEN]; 295 unsigned sectorsize; 296 off_t mediasize; 297 u_char *sector; 298 int error, fd; 299 300 pathgen(name, path, sizeof(path)); 301 sector = NULL; 302 error = 0; 303 304 fd = open(path, O_WRONLY); 305 if (fd == -1) 306 return (errno); 307 mediasize = g_get_mediasize(name); 308 if (mediasize == 0) { 309 error = errno; 310 goto out; 311 } 312 sectorsize = g_get_sectorsize(name); 313 if (sectorsize == 0) { 314 error = errno; 315 goto out; 316 } 317 assert(sectorsize >= size); 318 sector = malloc(sectorsize); 319 if (sector == NULL) { 320 error = ENOMEM; 321 goto out; 322 } 323 bcopy(md, sector, size); 324 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 325 (ssize_t)sectorsize) { 326 error = errno; 327 goto out; 328 } 329 (void)ioctl(fd, DIOCGFLUSH, NULL); 330 out: 331 if (sector != NULL) 332 free(sector); 333 close(fd); 334 return (error); 335 } 336 337 int 338 g_metadata_clear(const char *name, const char *magic) 339 { 340 struct std_metadata md; 341 char path[MAXPATHLEN]; 342 unsigned sectorsize; 343 off_t mediasize; 344 u_char *sector; 345 int error, fd; 346 347 pathgen(name, path, sizeof(path)); 348 sector = NULL; 349 error = 0; 350 351 fd = open(path, O_RDWR); 352 if (fd == -1) 353 return (errno); 354 mediasize = g_get_mediasize(name); 355 if (mediasize == 0) { 356 error = errno; 357 goto out; 358 } 359 sectorsize = g_get_sectorsize(name); 360 if (sectorsize == 0) { 361 error = errno; 362 goto out; 363 } 364 sector = malloc(sectorsize); 365 if (sector == NULL) { 366 error = ENOMEM; 367 goto out; 368 } 369 if (magic != NULL) { 370 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 371 (ssize_t)sectorsize) { 372 error = errno; 373 goto out; 374 } 375 std_metadata_decode(sector, &md); 376 if (strcmp(md.md_magic, magic) != 0) { 377 error = EINVAL; 378 goto out; 379 } 380 } 381 bzero(sector, sectorsize); 382 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 383 (ssize_t)sectorsize) { 384 error = errno; 385 goto out; 386 } 387 (void)ioctl(fd, DIOCGFLUSH, NULL); 388 out: 389 if (sector != NULL) 390 free(sector); 391 close(fd); 392 return (error); 393 } 394 395 /* 396 * Set an error message, if one does not already exist. 397 */ 398 void 399 gctl_error(struct gctl_req *req, const char *error, ...) 400 { 401 va_list ap; 402 403 if (req->error != NULL) 404 return; 405 va_start(ap, error); 406 vasprintf(&req->error, error, ap); 407 va_end(ap); 408 } 409 410 static void * 411 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 412 { 413 struct gctl_req_arg *argp; 414 char param[256]; 415 void *p; 416 unsigned i; 417 418 vsnprintf(param, sizeof(param), pfmt, ap); 419 for (i = 0; i < req->narg; i++) { 420 argp = &req->arg[i]; 421 if (strcmp(param, argp->name)) 422 continue; 423 if (!(argp->flag & GCTL_PARAM_RD)) 424 continue; 425 p = argp->value; 426 if (len == 0) { 427 /* We are looking for a string. */ 428 if (argp->len < 1) { 429 fprintf(stderr, "No length argument (%s).\n", 430 param); 431 abort(); 432 } 433 if (((char *)p)[argp->len - 1] != '\0') { 434 fprintf(stderr, "Unterminated argument (%s).\n", 435 param); 436 abort(); 437 } 438 } else if ((int)len != argp->len) { 439 fprintf(stderr, "Wrong length %s argument.\n", param); 440 abort(); 441 } 442 return (p); 443 } 444 fprintf(stderr, "No such argument (%s).\n", param); 445 abort(); 446 } 447 448 int 449 gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 450 { 451 int *p; 452 va_list ap; 453 454 va_start(ap, pfmt); 455 p = gctl_get_param(req, sizeof(int), pfmt, ap); 456 va_end(ap); 457 return (*p); 458 } 459 460 intmax_t 461 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 462 { 463 intmax_t *p; 464 va_list ap; 465 466 va_start(ap, pfmt); 467 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 468 va_end(ap); 469 return (*p); 470 } 471 472 const char * 473 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 474 { 475 const char *p; 476 va_list ap; 477 478 va_start(ap, pfmt); 479 p = gctl_get_param(req, 0, pfmt, ap); 480 va_end(ap); 481 return (p); 482 } 483 484 int 485 gctl_change_param(struct gctl_req *req, const char *name, int len, 486 const void *value) 487 { 488 struct gctl_req_arg *ap; 489 unsigned i; 490 491 if (req == NULL || req->error != NULL) 492 return (EDOOFUS); 493 for (i = 0; i < req->narg; i++) { 494 ap = &req->arg[i]; 495 if (strcmp(ap->name, name) != 0) 496 continue; 497 ap->value = __DECONST(void *, value); 498 if (len >= 0) { 499 ap->flag &= ~GCTL_PARAM_ASCII; 500 ap->len = len; 501 } else if (len < 0) { 502 ap->flag |= GCTL_PARAM_ASCII; 503 ap->len = strlen(value) + 1; 504 } 505 return (0); 506 } 507 return (ENOENT); 508 } 509 510 int 511 gctl_delete_param(struct gctl_req *req, const char *name) 512 { 513 struct gctl_req_arg *ap; 514 unsigned int i; 515 516 if (req == NULL || req->error != NULL) 517 return (EDOOFUS); 518 519 i = 0; 520 while (i < req->narg) { 521 ap = &req->arg[i]; 522 if (strcmp(ap->name, name) == 0) 523 break; 524 i++; 525 } 526 if (i == req->narg) 527 return (ENOENT); 528 529 free(ap->name); 530 req->narg--; 531 while (i < req->narg) { 532 req->arg[i] = req->arg[i + 1]; 533 i++; 534 } 535 return (0); 536 } 537 538 int 539 gctl_has_param(struct gctl_req *req, const char *name) 540 { 541 struct gctl_req_arg *ap; 542 unsigned int i; 543 544 if (req == NULL || req->error != NULL) 545 return (0); 546 547 for (i = 0; i < req->narg; i++) { 548 ap = &req->arg[i]; 549 if (strcmp(ap->name, name) == 0) 550 return (1); 551 } 552 return (0); 553 } 554