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