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 /* 277 * Actually write the GEOM label to the provider 278 * 279 * @param name GEOM provider's name (ie "ada0") 280 * @param md Pointer to the label data to write 281 * @param size Size of the data pointed to by md 282 */ 283 int 284 g_metadata_store(const char *name, const unsigned char *md, size_t size) 285 { 286 unsigned char *sector; 287 ssize_t sectorsize; 288 off_t mediasize; 289 int error, fd; 290 291 sector = NULL; 292 error = 0; 293 294 fd = g_open(name, 1); 295 if (fd == -1) 296 return (errno); 297 mediasize = g_mediasize(fd); 298 if (mediasize == -1) { 299 error = errno; 300 goto out; 301 } 302 sectorsize = g_sectorsize(fd); 303 if (sectorsize == -1) { 304 error = errno; 305 goto out; 306 } 307 assert(sectorsize >= (ssize_t)size); 308 sector = malloc(sectorsize); 309 if (sector == NULL) { 310 error = ENOMEM; 311 goto out; 312 } 313 bcopy(md, sector, size); 314 bzero(sector + size, sectorsize - size); 315 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 316 sectorsize) { 317 error = errno; 318 goto out; 319 } 320 (void)g_flush(fd); 321 out: 322 if (sector != NULL) 323 free(sector); 324 (void)g_close(fd); 325 return (error); 326 } 327 328 int 329 g_metadata_clear(const char *name, const char *magic) 330 { 331 struct std_metadata md; 332 unsigned char *sector; 333 ssize_t sectorsize; 334 off_t mediasize; 335 int error, fd; 336 337 sector = NULL; 338 error = 0; 339 340 fd = g_open(name, 1); 341 if (fd == -1) 342 return (errno); 343 mediasize = g_mediasize(fd); 344 if (mediasize == 0) { 345 error = errno; 346 goto out; 347 } 348 sectorsize = g_sectorsize(fd); 349 if (sectorsize <= 0) { 350 error = errno; 351 goto out; 352 } 353 sector = malloc(sectorsize); 354 if (sector == NULL) { 355 error = ENOMEM; 356 goto out; 357 } 358 if (magic != NULL) { 359 if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 360 sectorsize) { 361 error = errno; 362 goto out; 363 } 364 std_metadata_decode(sector, &md); 365 if (strcmp(md.md_magic, magic) != 0) { 366 error = EINVAL; 367 goto out; 368 } 369 } 370 bzero(sector, sectorsize); 371 if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 372 sectorsize) { 373 error = errno; 374 goto out; 375 } 376 (void)g_flush(fd); 377 out: 378 free(sector); 379 g_close(fd); 380 return (error); 381 } 382 383 /* 384 * Set an error message, if one does not already exist. 385 */ 386 void 387 gctl_error(struct gctl_req *req, const char *error, ...) 388 { 389 va_list ap; 390 391 if (req != NULL && req->error != NULL) 392 return; 393 va_start(ap, error); 394 if (req != NULL) { 395 vasprintf(&req->error, error, ap); 396 } else { 397 vfprintf(stderr, error, ap); 398 fprintf(stderr, "\n"); 399 } 400 va_end(ap); 401 if (req != NULL && req->nerror == 0) 402 req->nerror = EINVAL; 403 } 404 405 static void * 406 gctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 407 { 408 struct gctl_req_arg *argp; 409 char param[256]; 410 unsigned int i; 411 void *p; 412 413 vsnprintf(param, sizeof(param), pfmt, ap); 414 for (i = 0; i < req->narg; i++) { 415 argp = &req->arg[i]; 416 if (strcmp(param, argp->name)) 417 continue; 418 if (!(argp->flag & GCTL_PARAM_RD)) 419 continue; 420 p = argp->value; 421 if (len == 0) { 422 /* We are looking for a string. */ 423 if (argp->len < 1) { 424 fprintf(stderr, "No length argument (%s).\n", 425 param); 426 abort(); 427 } 428 if (((char *)p)[argp->len - 1] != '\0') { 429 fprintf(stderr, "Unterminated argument (%s).\n", 430 param); 431 abort(); 432 } 433 } else if ((int)len != argp->len) { 434 fprintf(stderr, "Wrong length %s argument.\n", param); 435 abort(); 436 } 437 return (p); 438 } 439 fprintf(stderr, "No such argument (%s).\n", param); 440 abort(); 441 } 442 443 int 444 gctl_get_int(struct gctl_req *req, const char *pfmt, ...) 445 { 446 int *p; 447 va_list ap; 448 449 va_start(ap, pfmt); 450 p = gctl_get_param(req, sizeof(int), pfmt, ap); 451 va_end(ap); 452 return (*p); 453 } 454 455 intmax_t 456 gctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 457 { 458 intmax_t *p; 459 va_list ap; 460 461 va_start(ap, pfmt); 462 p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 463 va_end(ap); 464 return (*p); 465 } 466 467 const char * 468 gctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 469 { 470 const char *p; 471 va_list ap; 472 473 va_start(ap, pfmt); 474 p = gctl_get_param(req, 0, pfmt, ap); 475 va_end(ap); 476 return (p); 477 } 478 479 int 480 gctl_change_param(struct gctl_req *req, const char *name, int len, 481 const void *value) 482 { 483 struct gctl_req_arg *ap; 484 unsigned int i; 485 486 if (req == NULL || req->error != NULL) 487 return (EDOOFUS); 488 for (i = 0; i < req->narg; i++) { 489 ap = &req->arg[i]; 490 if (strcmp(ap->name, name) != 0) 491 continue; 492 ap->value = __DECONST(void *, value); 493 if (len >= 0) { 494 ap->flag &= ~GCTL_PARAM_ASCII; 495 ap->len = len; 496 } else if (len < 0) { 497 ap->flag |= GCTL_PARAM_ASCII; 498 ap->len = strlen(value) + 1; 499 } 500 return (0); 501 } 502 return (ENOENT); 503 } 504 505 int 506 gctl_delete_param(struct gctl_req *req, const char *name) 507 { 508 struct gctl_req_arg *ap; 509 unsigned int i; 510 511 if (req == NULL || req->error != NULL) 512 return (EDOOFUS); 513 514 i = 0; 515 while (i < req->narg) { 516 ap = &req->arg[i]; 517 if (strcmp(ap->name, name) == 0) 518 break; 519 i++; 520 } 521 if (i == req->narg) 522 return (ENOENT); 523 524 free(ap->name); 525 req->narg--; 526 while (i < req->narg) { 527 req->arg[i] = req->arg[i + 1]; 528 i++; 529 } 530 return (0); 531 } 532 533 int 534 gctl_has_param(struct gctl_req *req, const char *name) 535 { 536 struct gctl_req_arg *ap; 537 unsigned int i; 538 539 if (req == NULL || req->error != NULL) 540 return (0); 541 542 for (i = 0; i < req->narg; i++) { 543 ap = &req->arg[i]; 544 if (strcmp(ap->name, name) == 0) 545 return (1); 546 } 547 return (0); 548 } 549