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