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