1129470Spjd/*- 2330449Seadler * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3330449Seadler * 4213074Spjd * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 5129470Spjd * All rights reserved. 6129470Spjd * 7129470Spjd * Redistribution and use in source and binary forms, with or without 8129470Spjd * modification, are permitted provided that the following conditions 9129470Spjd * are met: 10129470Spjd * 1. Redistributions of source code must retain the above copyright 11129470Spjd * notice, this list of conditions and the following disclaimer. 12129470Spjd * 2. Redistributions in binary form must reproduce the above copyright 13129470Spjd * notice, this list of conditions and the following disclaimer in the 14129470Spjd * documentation and/or other materials provided with the distribution. 15155175Spjd * 16129470Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 17129470Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18129470Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19129470Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 20129470Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21129470Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22129470Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23129470Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24129470Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25129470Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26129470Spjd * SUCH DAMAGE. 27129470Spjd */ 28129470Spjd 29129470Spjd#include <sys/cdefs.h> 30129470Spjd__FBSDID("$FreeBSD: stable/11/sbin/geom/misc/subr.c 330726 2018-03-10 02:15:45Z asomers $"); 31129470Spjd 32129470Spjd#include <sys/param.h> 33129470Spjd#include <sys/disk.h> 34129470Spjd#include <sys/endian.h> 35129470Spjd#include <sys/uio.h> 36129470Spjd#include <errno.h> 37129470Spjd#include <fcntl.h> 38129470Spjd#include <paths.h> 39129470Spjd#include <stdio.h> 40129470Spjd#include <stdlib.h> 41209388Sae#include <limits.h> 42209388Sae#include <inttypes.h> 43129470Spjd#include <stdarg.h> 44129470Spjd#include <string.h> 45129470Spjd#include <strings.h> 46129470Spjd#include <unistd.h> 47129470Spjd#include <assert.h> 48129470Spjd#include <libgeom.h> 49129470Spjd 50129470Spjd#include "misc/subr.h" 51129470Spjd 52129470Spjd 53129470Spjdstruct std_metadata { 54129470Spjd char md_magic[16]; 55129470Spjd uint32_t md_version; 56129470Spjd}; 57129470Spjd 58129470Spjdstatic void 59213074Spjdstd_metadata_decode(const unsigned char *data, struct std_metadata *md) 60129470Spjd{ 61129470Spjd 62129470Spjd bcopy(data, md->md_magic, sizeof(md->md_magic)); 63129470Spjd md->md_version = le32dec(data + 16); 64129470Spjd} 65129470Spjd 66130591Spjd/* 67130591Spjd * Greatest Common Divisor. 68130591Spjd */ 69213074Spjdstatic unsigned int 70213074Spjdgcd(unsigned int a, unsigned int b) 71130591Spjd{ 72213074Spjd unsigned int c; 73130591Spjd 74130591Spjd while (b != 0) { 75130591Spjd c = a; 76130591Spjd a = b; 77130591Spjd b = (c % b); 78130591Spjd } 79130591Spjd return (a); 80130591Spjd} 81130591Spjd 82130591Spjd/* 83130591Spjd * Least Common Multiple. 84130591Spjd */ 85213074Spjdunsigned int 86213074Spjdg_lcm(unsigned int a, unsigned int b) 87130591Spjd{ 88130591Spjd 89130591Spjd return ((a * b) / gcd(a, b)); 90130591Spjd} 91130591Spjd 92149302Spjduint32_t 93149302Spjdbitcount32(uint32_t x) 94149302Spjd{ 95149302Spjd 96149302Spjd x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 97149302Spjd x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 98149302Spjd x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 99149302Spjd x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 100149302Spjd x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 101149302Spjd return (x); 102149302Spjd} 103149302Spjd 104209388Sae/* 105209388Sae * The size of a sector is context specific (i.e. determined by the 106209388Sae * media). But when users enter a value with a SI unit, they really 107209388Sae * mean the byte-size or byte-offset and not the size or offset in 108209388Sae * sectors. We should map the byte-oriented value into a sector-oriented 109209388Sae * value when we already know the sector size in bytes. At this time 110209388Sae * we can use g_parse_lba() function. It converts user specified 111209388Sae * value into sectors with following conditions: 112209388Sae * o Sectors size taken as argument from caller. 113209388Sae * o When no SI unit is specified the value is in sectors. 114209388Sae * o With an SI unit the value is in bytes. 115209388Sae * o The 'b' suffix forces byte interpretation and the 's' 116209388Sae * suffix forces sector interpretation. 117209388Sae * 118209388Sae * Thus: 119209388Sae * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 120209388Sae * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 121209388Sae * 122209388Sae */ 123209388Saeint 124213074Spjdg_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors) 125209388Sae{ 126209388Sae off_t number, mult, unit; 127209388Sae char *s; 128209388Sae 129209388Sae assert(lbastr != NULL); 130209388Sae assert(sectorsize > 0); 131209388Sae assert(sectors != NULL); 132209388Sae 133209388Sae number = (off_t)strtoimax(lbastr, &s, 0); 134209392Sae if (s == lbastr || number < 0) 135209388Sae return (EINVAL); 136209388Sae 137209388Sae mult = 1; 138209388Sae unit = sectorsize; 139209388Sae if (*s == '\0') 140209388Sae goto done; 141209388Sae switch (*s) { 142209388Sae case 'e': case 'E': 143209388Sae mult *= 1024; 144209388Sae /* FALLTHROUGH */ 145209388Sae case 'p': case 'P': 146209388Sae mult *= 1024; 147209388Sae /* FALLTHROUGH */ 148209388Sae case 't': case 'T': 149209388Sae mult *= 1024; 150209388Sae /* FALLTHROUGH */ 151209388Sae case 'g': case 'G': 152209388Sae mult *= 1024; 153209388Sae /* FALLTHROUGH */ 154209388Sae case 'm': case 'M': 155209388Sae mult *= 1024; 156209388Sae /* FALLTHROUGH */ 157209388Sae case 'k': case 'K': 158209388Sae mult *= 1024; 159209388Sae break; 160209388Sae default: 161209388Sae goto sfx; 162209388Sae } 163209388Sae unit = 1; /* bytes */ 164209388Sae s++; 165209388Sae if (*s == '\0') 166209388Sae goto done; 167209388Saesfx: 168209388Sae switch (*s) { 169209388Sae case 's': case 'S': 170209388Sae unit = sectorsize; /* sector */ 171209388Sae break; 172209388Sae case 'b': case 'B': 173209388Sae unit = 1; /* bytes */ 174209388Sae break; 175209388Sae default: 176209388Sae return (EINVAL); 177209388Sae } 178209388Sae s++; 179209388Sae if (*s != '\0') 180209388Sae return (EINVAL); 181209388Saedone: 182209392Sae if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number) 183209388Sae return (ERANGE); 184209388Sae number *= mult * unit; 185209388Sae if (number % sectorsize) 186209388Sae return (EINVAL); 187209388Sae number /= sectorsize; 188209388Sae *sectors = number; 189209388Sae return (0); 190209388Sae} 191209388Sae 192130591Spjdoff_t 193130591Spjdg_get_mediasize(const char *name) 194130591Spjd{ 195130591Spjd off_t mediasize; 196130591Spjd int fd; 197130591Spjd 198213074Spjd fd = g_open(name, 0); 199130591Spjd if (fd == -1) 200130591Spjd return (0); 201213074Spjd mediasize = g_mediasize(fd); 202213074Spjd if (mediasize == -1) 203213074Spjd mediasize = 0; 204213074Spjd (void)g_close(fd); 205130591Spjd return (mediasize); 206130591Spjd} 207130591Spjd 208213074Spjdunsigned int 209130591Spjdg_get_sectorsize(const char *name) 210130591Spjd{ 211213074Spjd ssize_t sectorsize; 212130591Spjd int fd; 213130591Spjd 214213074Spjd fd = g_open(name, 0); 215130591Spjd if (fd == -1) 216130591Spjd return (0); 217213074Spjd sectorsize = g_sectorsize(fd); 218213074Spjd if (sectorsize == -1) 219213074Spjd sectorsize = 0; 220213074Spjd (void)g_close(fd); 221213074Spjd return ((unsigned int)sectorsize); 222130591Spjd} 223130591Spjd 224129470Spjdint 225213074Spjdg_metadata_read(const char *name, unsigned char *md, size_t size, 226213074Spjd const char *magic) 227131603Spjd{ 228131603Spjd struct std_metadata stdmd; 229213074Spjd unsigned char *sector; 230213074Spjd ssize_t sectorsize; 231131603Spjd off_t mediasize; 232131603Spjd int error, fd; 233131603Spjd 234131603Spjd sector = NULL; 235131603Spjd error = 0; 236131603Spjd 237213074Spjd fd = g_open(name, 0); 238131603Spjd if (fd == -1) 239131603Spjd return (errno); 240213074Spjd mediasize = g_mediasize(fd); 241213074Spjd if (mediasize == -1) { 242131603Spjd error = errno; 243131603Spjd goto out; 244131603Spjd } 245213074Spjd sectorsize = g_sectorsize(fd); 246213074Spjd if (sectorsize == -1) { 247131603Spjd error = errno; 248131603Spjd goto out; 249131603Spjd } 250213074Spjd assert(sectorsize >= (ssize_t)size); 251131603Spjd sector = malloc(sectorsize); 252131603Spjd if (sector == NULL) { 253131603Spjd error = ENOMEM; 254131603Spjd goto out; 255131603Spjd } 256131603Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 257213074Spjd sectorsize) { 258131603Spjd error = errno; 259131603Spjd goto out; 260131603Spjd } 261131603Spjd if (magic != NULL) { 262131603Spjd std_metadata_decode(sector, &stdmd); 263131603Spjd if (strcmp(stdmd.md_magic, magic) != 0) { 264131603Spjd error = EINVAL; 265131603Spjd goto out; 266131603Spjd } 267131603Spjd } 268131603Spjd bcopy(sector, md, size); 269131603Spjdout: 270131603Spjd if (sector != NULL) 271131603Spjd free(sector); 272213074Spjd g_close(fd); 273131603Spjd return (error); 274131603Spjd} 275131603Spjd 276330726Sasomers/* 277330726Sasomers * Actually write the GEOM label to the provider 278330726Sasomers * 279330726Sasomers * @param name GEOM provider's name (ie "ada0") 280330726Sasomers * @param md Pointer to the label data to write 281330726Sasomers * @param size Size of the data pointed to by md 282330726Sasomers */ 283131603Spjdint 284213074Spjdg_metadata_store(const char *name, const unsigned char *md, size_t size) 285129470Spjd{ 286213074Spjd unsigned char *sector; 287213074Spjd ssize_t sectorsize; 288129470Spjd off_t mediasize; 289129470Spjd int error, fd; 290129470Spjd 291129470Spjd sector = NULL; 292129470Spjd error = 0; 293129470Spjd 294213074Spjd fd = g_open(name, 1); 295129470Spjd if (fd == -1) 296129470Spjd return (errno); 297213074Spjd mediasize = g_mediasize(fd); 298213074Spjd if (mediasize == -1) { 299129470Spjd error = errno; 300129470Spjd goto out; 301129470Spjd } 302213074Spjd sectorsize = g_sectorsize(fd); 303213074Spjd if (sectorsize == -1) { 304129470Spjd error = errno; 305129470Spjd goto out; 306129470Spjd } 307213074Spjd assert(sectorsize >= (ssize_t)size); 308129470Spjd sector = malloc(sectorsize); 309129470Spjd if (sector == NULL) { 310129470Spjd error = ENOMEM; 311129470Spjd goto out; 312129470Spjd } 313129470Spjd bcopy(md, sector, size); 314330726Sasomers bzero(sector + size, sectorsize - size); 315129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 316213074Spjd sectorsize) { 317129470Spjd error = errno; 318129470Spjd goto out; 319129470Spjd } 320213074Spjd (void)g_flush(fd); 321129470Spjdout: 322129470Spjd if (sector != NULL) 323129470Spjd free(sector); 324213074Spjd (void)g_close(fd); 325129470Spjd return (error); 326129470Spjd} 327129470Spjd 328129470Spjdint 329129470Spjdg_metadata_clear(const char *name, const char *magic) 330129470Spjd{ 331129470Spjd struct std_metadata md; 332213074Spjd unsigned char *sector; 333213074Spjd ssize_t sectorsize; 334129470Spjd off_t mediasize; 335129470Spjd int error, fd; 336129470Spjd 337129470Spjd sector = NULL; 338129470Spjd error = 0; 339129470Spjd 340213074Spjd fd = g_open(name, 1); 341129470Spjd if (fd == -1) 342129470Spjd return (errno); 343213074Spjd mediasize = g_mediasize(fd); 344130591Spjd if (mediasize == 0) { 345129470Spjd error = errno; 346129470Spjd goto out; 347129470Spjd } 348213074Spjd sectorsize = g_sectorsize(fd); 349317440Sasomers if (sectorsize <= 0) { 350129470Spjd error = errno; 351129470Spjd goto out; 352129470Spjd } 353129470Spjd sector = malloc(sectorsize); 354129470Spjd if (sector == NULL) { 355129470Spjd error = ENOMEM; 356129470Spjd goto out; 357129470Spjd } 358129470Spjd if (magic != NULL) { 359129470Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 360213074Spjd sectorsize) { 361129470Spjd error = errno; 362129470Spjd goto out; 363129470Spjd } 364129470Spjd std_metadata_decode(sector, &md); 365129470Spjd if (strcmp(md.md_magic, magic) != 0) { 366129470Spjd error = EINVAL; 367129470Spjd goto out; 368129470Spjd } 369129470Spjd } 370129470Spjd bzero(sector, sectorsize); 371129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 372213074Spjd sectorsize) { 373129470Spjd error = errno; 374129470Spjd goto out; 375129470Spjd } 376213074Spjd (void)g_flush(fd); 377129470Spjdout: 378317440Sasomers free(sector); 379213074Spjd g_close(fd); 380129470Spjd return (error); 381129470Spjd} 382129470Spjd 383129470Spjd/* 384129470Spjd * Set an error message, if one does not already exist. 385129470Spjd */ 386129470Spjdvoid 387129470Spjdgctl_error(struct gctl_req *req, const char *error, ...) 388129470Spjd{ 389129470Spjd va_list ap; 390129470Spjd 391226718Spjd if (req != NULL && req->error != NULL) 392129470Spjd return; 393129470Spjd va_start(ap, error); 394226718Spjd if (req != NULL) { 395226718Spjd vasprintf(&req->error, error, ap); 396226718Spjd } else { 397226718Spjd vfprintf(stderr, error, ap); 398226718Spjd fprintf(stderr, "\n"); 399226718Spjd } 400129470Spjd va_end(ap); 401129470Spjd} 402129470Spjd 403153190Spjdstatic void * 404153190Spjdgctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 405129470Spjd{ 406153190Spjd struct gctl_req_arg *argp; 407153190Spjd char param[256]; 408213074Spjd unsigned int i; 409153190Spjd void *p; 410129470Spjd 411153190Spjd vsnprintf(param, sizeof(param), pfmt, ap); 412129470Spjd for (i = 0; i < req->narg; i++) { 413153190Spjd argp = &req->arg[i]; 414153190Spjd if (strcmp(param, argp->name)) 415129470Spjd continue; 416153190Spjd if (!(argp->flag & GCTL_PARAM_RD)) 417129470Spjd continue; 418153190Spjd p = argp->value; 419153190Spjd if (len == 0) { 420153190Spjd /* We are looking for a string. */ 421153190Spjd if (argp->len < 1) { 422153190Spjd fprintf(stderr, "No length argument (%s).\n", 423153190Spjd param); 424153190Spjd abort(); 425153190Spjd } 426153190Spjd if (((char *)p)[argp->len - 1] != '\0') { 427153190Spjd fprintf(stderr, "Unterminated argument (%s).\n", 428153190Spjd param); 429153190Spjd abort(); 430153190Spjd } 431153190Spjd } else if ((int)len != argp->len) { 432153190Spjd fprintf(stderr, "Wrong length %s argument.\n", param); 433153190Spjd abort(); 434153190Spjd } 435129470Spjd return (p); 436129470Spjd } 437153190Spjd fprintf(stderr, "No such argument (%s).\n", param); 438153190Spjd abort(); 439129470Spjd} 440129470Spjd 441153190Spjdint 442153190Spjdgctl_get_int(struct gctl_req *req, const char *pfmt, ...) 443129470Spjd{ 444153190Spjd int *p; 445153190Spjd va_list ap; 446129470Spjd 447153190Spjd va_start(ap, pfmt); 448153190Spjd p = gctl_get_param(req, sizeof(int), pfmt, ap); 449153190Spjd va_end(ap); 450153190Spjd return (*p); 451129470Spjd} 452129470Spjd 453153190Spjdintmax_t 454153190Spjdgctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 455129470Spjd{ 456153190Spjd intmax_t *p; 457153190Spjd va_list ap; 458129470Spjd 459153190Spjd va_start(ap, pfmt); 460153190Spjd p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 461153190Spjd va_end(ap); 462153190Spjd return (*p); 463153190Spjd} 464153190Spjd 465153190Spjdconst char * 466153190Spjdgctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 467153190Spjd{ 468153190Spjd const char *p; 469153190Spjd va_list ap; 470153190Spjd 471153190Spjd va_start(ap, pfmt); 472153190Spjd p = gctl_get_param(req, 0, pfmt, ap); 473153190Spjd va_end(ap); 474129470Spjd return (p); 475129470Spjd} 476166215Spjd 477166215Spjdint 478166215Spjdgctl_change_param(struct gctl_req *req, const char *name, int len, 479166215Spjd const void *value) 480166215Spjd{ 481166215Spjd struct gctl_req_arg *ap; 482213074Spjd unsigned int i; 483166215Spjd 484166215Spjd if (req == NULL || req->error != NULL) 485166215Spjd return (EDOOFUS); 486166215Spjd for (i = 0; i < req->narg; i++) { 487166215Spjd ap = &req->arg[i]; 488166215Spjd if (strcmp(ap->name, name) != 0) 489166215Spjd continue; 490166215Spjd ap->value = __DECONST(void *, value); 491166215Spjd if (len >= 0) { 492166215Spjd ap->flag &= ~GCTL_PARAM_ASCII; 493166215Spjd ap->len = len; 494166215Spjd } else if (len < 0) { 495166215Spjd ap->flag |= GCTL_PARAM_ASCII; 496166215Spjd ap->len = strlen(value) + 1; 497166215Spjd } 498166215Spjd return (0); 499166215Spjd } 500166215Spjd return (ENOENT); 501166215Spjd} 502179628Smarcel 503179628Smarcelint 504179628Smarcelgctl_delete_param(struct gctl_req *req, const char *name) 505179628Smarcel{ 506179628Smarcel struct gctl_req_arg *ap; 507179628Smarcel unsigned int i; 508179628Smarcel 509179628Smarcel if (req == NULL || req->error != NULL) 510179628Smarcel return (EDOOFUS); 511179628Smarcel 512179628Smarcel i = 0; 513179628Smarcel while (i < req->narg) { 514179628Smarcel ap = &req->arg[i]; 515179628Smarcel if (strcmp(ap->name, name) == 0) 516179628Smarcel break; 517179628Smarcel i++; 518179628Smarcel } 519179628Smarcel if (i == req->narg) 520179628Smarcel return (ENOENT); 521179628Smarcel 522208886Sae free(ap->name); 523179628Smarcel req->narg--; 524179628Smarcel while (i < req->narg) { 525179628Smarcel req->arg[i] = req->arg[i + 1]; 526179628Smarcel i++; 527179628Smarcel } 528179628Smarcel return (0); 529179628Smarcel} 530179628Smarcel 531179628Smarcelint 532179628Smarcelgctl_has_param(struct gctl_req *req, const char *name) 533179628Smarcel{ 534179628Smarcel struct gctl_req_arg *ap; 535179628Smarcel unsigned int i; 536179628Smarcel 537179628Smarcel if (req == NULL || req->error != NULL) 538179628Smarcel return (0); 539179628Smarcel 540179628Smarcel for (i = 0; i < req->narg; i++) { 541179628Smarcel ap = &req->arg[i]; 542179628Smarcel if (strcmp(ap->name, name) == 0) 543179628Smarcel return (1); 544179628Smarcel } 545179628Smarcel return (0); 546179628Smarcel} 547