1129470Spjd/*- 2213074Spjd * Copyright (c) 2004-2010 Pawel Jakub Dawidek <pjd@FreeBSD.org> 3129470Spjd * All rights reserved. 4129470Spjd * 5129470Spjd * Redistribution and use in source and binary forms, with or without 6129470Spjd * modification, are permitted provided that the following conditions 7129470Spjd * are met: 8129470Spjd * 1. Redistributions of source code must retain the above copyright 9129470Spjd * notice, this list of conditions and the following disclaimer. 10129470Spjd * 2. Redistributions in binary form must reproduce the above copyright 11129470Spjd * notice, this list of conditions and the following disclaimer in the 12129470Spjd * documentation and/or other materials provided with the distribution. 13155175Spjd * 14129470Spjd * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 15129470Spjd * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16129470Spjd * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17129470Spjd * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 18129470Spjd * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19129470Spjd * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20129470Spjd * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21129470Spjd * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22129470Spjd * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23129470Spjd * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24129470Spjd * SUCH DAMAGE. 25129470Spjd */ 26129470Spjd 27129470Spjd#include <sys/cdefs.h> 28129470Spjd__FBSDID("$FreeBSD: releng/11.0/sbin/geom/misc/subr.c 226718 2011-10-25 07:34:35Z pjd $"); 29129470Spjd 30129470Spjd#include <sys/param.h> 31129470Spjd#include <sys/disk.h> 32129470Spjd#include <sys/endian.h> 33129470Spjd#include <sys/uio.h> 34129470Spjd#include <errno.h> 35129470Spjd#include <fcntl.h> 36129470Spjd#include <paths.h> 37129470Spjd#include <stdio.h> 38129470Spjd#include <stdlib.h> 39209388Sae#include <limits.h> 40209388Sae#include <inttypes.h> 41129470Spjd#include <stdarg.h> 42129470Spjd#include <string.h> 43129470Spjd#include <strings.h> 44129470Spjd#include <unistd.h> 45129470Spjd#include <assert.h> 46129470Spjd#include <libgeom.h> 47129470Spjd 48129470Spjd#include "misc/subr.h" 49129470Spjd 50129470Spjd 51129470Spjdstruct std_metadata { 52129470Spjd char md_magic[16]; 53129470Spjd uint32_t md_version; 54129470Spjd}; 55129470Spjd 56129470Spjdstatic void 57213074Spjdstd_metadata_decode(const unsigned char *data, struct std_metadata *md) 58129470Spjd{ 59129470Spjd 60129470Spjd bcopy(data, md->md_magic, sizeof(md->md_magic)); 61129470Spjd md->md_version = le32dec(data + 16); 62129470Spjd} 63129470Spjd 64130591Spjd/* 65130591Spjd * Greatest Common Divisor. 66130591Spjd */ 67213074Spjdstatic unsigned int 68213074Spjdgcd(unsigned int a, unsigned int b) 69130591Spjd{ 70213074Spjd unsigned int c; 71130591Spjd 72130591Spjd while (b != 0) { 73130591Spjd c = a; 74130591Spjd a = b; 75130591Spjd b = (c % b); 76130591Spjd } 77130591Spjd return (a); 78130591Spjd} 79130591Spjd 80130591Spjd/* 81130591Spjd * Least Common Multiple. 82130591Spjd */ 83213074Spjdunsigned int 84213074Spjdg_lcm(unsigned int a, unsigned int b) 85130591Spjd{ 86130591Spjd 87130591Spjd return ((a * b) / gcd(a, b)); 88130591Spjd} 89130591Spjd 90149302Spjduint32_t 91149302Spjdbitcount32(uint32_t x) 92149302Spjd{ 93149302Spjd 94149302Spjd x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 95149302Spjd x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 96149302Spjd x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 97149302Spjd x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 98149302Spjd x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 99149302Spjd return (x); 100149302Spjd} 101149302Spjd 102209388Sae/* 103209388Sae * The size of a sector is context specific (i.e. determined by the 104209388Sae * media). But when users enter a value with a SI unit, they really 105209388Sae * mean the byte-size or byte-offset and not the size or offset in 106209388Sae * sectors. We should map the byte-oriented value into a sector-oriented 107209388Sae * value when we already know the sector size in bytes. At this time 108209388Sae * we can use g_parse_lba() function. It converts user specified 109209388Sae * value into sectors with following conditions: 110209388Sae * o Sectors size taken as argument from caller. 111209388Sae * o When no SI unit is specified the value is in sectors. 112209388Sae * o With an SI unit the value is in bytes. 113209388Sae * o The 'b' suffix forces byte interpretation and the 's' 114209388Sae * suffix forces sector interpretation. 115209388Sae * 116209388Sae * Thus: 117209388Sae * o 2 and 2s mean 2 sectors, and 2b means 2 bytes. 118209388Sae * o 4k and 4kb mean 4096 bytes, and 4ks means 4096 sectors. 119209388Sae * 120209388Sae */ 121209388Saeint 122213074Spjdg_parse_lba(const char *lbastr, unsigned int sectorsize, off_t *sectors) 123209388Sae{ 124209388Sae off_t number, mult, unit; 125209388Sae char *s; 126209388Sae 127209388Sae assert(lbastr != NULL); 128209388Sae assert(sectorsize > 0); 129209388Sae assert(sectors != NULL); 130209388Sae 131209388Sae number = (off_t)strtoimax(lbastr, &s, 0); 132209392Sae if (s == lbastr || number < 0) 133209388Sae return (EINVAL); 134209388Sae 135209388Sae mult = 1; 136209388Sae unit = sectorsize; 137209388Sae if (*s == '\0') 138209388Sae goto done; 139209388Sae switch (*s) { 140209388Sae case 'e': case 'E': 141209388Sae mult *= 1024; 142209388Sae /* FALLTHROUGH */ 143209388Sae case 'p': case 'P': 144209388Sae mult *= 1024; 145209388Sae /* FALLTHROUGH */ 146209388Sae case 't': case 'T': 147209388Sae mult *= 1024; 148209388Sae /* FALLTHROUGH */ 149209388Sae case 'g': case 'G': 150209388Sae mult *= 1024; 151209388Sae /* FALLTHROUGH */ 152209388Sae case 'm': case 'M': 153209388Sae mult *= 1024; 154209388Sae /* FALLTHROUGH */ 155209388Sae case 'k': case 'K': 156209388Sae mult *= 1024; 157209388Sae break; 158209388Sae default: 159209388Sae goto sfx; 160209388Sae } 161209388Sae unit = 1; /* bytes */ 162209388Sae s++; 163209388Sae if (*s == '\0') 164209388Sae goto done; 165209388Saesfx: 166209388Sae switch (*s) { 167209388Sae case 's': case 'S': 168209388Sae unit = sectorsize; /* sector */ 169209388Sae break; 170209388Sae case 'b': case 'B': 171209388Sae unit = 1; /* bytes */ 172209388Sae break; 173209388Sae default: 174209388Sae return (EINVAL); 175209388Sae } 176209388Sae s++; 177209388Sae if (*s != '\0') 178209388Sae return (EINVAL); 179209388Saedone: 180209392Sae if ((OFF_MAX / unit) < mult || (OFF_MAX / mult / unit) < number) 181209388Sae return (ERANGE); 182209388Sae number *= mult * unit; 183209388Sae if (number % sectorsize) 184209388Sae return (EINVAL); 185209388Sae number /= sectorsize; 186209388Sae *sectors = number; 187209388Sae return (0); 188209388Sae} 189209388Sae 190130591Spjdoff_t 191130591Spjdg_get_mediasize(const char *name) 192130591Spjd{ 193130591Spjd off_t mediasize; 194130591Spjd int fd; 195130591Spjd 196213074Spjd fd = g_open(name, 0); 197130591Spjd if (fd == -1) 198130591Spjd return (0); 199213074Spjd mediasize = g_mediasize(fd); 200213074Spjd if (mediasize == -1) 201213074Spjd mediasize = 0; 202213074Spjd (void)g_close(fd); 203130591Spjd return (mediasize); 204130591Spjd} 205130591Spjd 206213074Spjdunsigned int 207130591Spjdg_get_sectorsize(const char *name) 208130591Spjd{ 209213074Spjd ssize_t sectorsize; 210130591Spjd int fd; 211130591Spjd 212213074Spjd fd = g_open(name, 0); 213130591Spjd if (fd == -1) 214130591Spjd return (0); 215213074Spjd sectorsize = g_sectorsize(fd); 216213074Spjd if (sectorsize == -1) 217213074Spjd sectorsize = 0; 218213074Spjd (void)g_close(fd); 219213074Spjd return ((unsigned int)sectorsize); 220130591Spjd} 221130591Spjd 222129470Spjdint 223213074Spjdg_metadata_read(const char *name, unsigned char *md, size_t size, 224213074Spjd const char *magic) 225131603Spjd{ 226131603Spjd struct std_metadata stdmd; 227213074Spjd unsigned char *sector; 228213074Spjd ssize_t sectorsize; 229131603Spjd off_t mediasize; 230131603Spjd int error, fd; 231131603Spjd 232131603Spjd sector = NULL; 233131603Spjd error = 0; 234131603Spjd 235213074Spjd fd = g_open(name, 0); 236131603Spjd if (fd == -1) 237131603Spjd return (errno); 238213074Spjd mediasize = g_mediasize(fd); 239213074Spjd if (mediasize == -1) { 240131603Spjd error = errno; 241131603Spjd goto out; 242131603Spjd } 243213074Spjd sectorsize = g_sectorsize(fd); 244213074Spjd if (sectorsize == -1) { 245131603Spjd error = errno; 246131603Spjd goto out; 247131603Spjd } 248213074Spjd assert(sectorsize >= (ssize_t)size); 249131603Spjd sector = malloc(sectorsize); 250131603Spjd if (sector == NULL) { 251131603Spjd error = ENOMEM; 252131603Spjd goto out; 253131603Spjd } 254131603Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 255213074Spjd sectorsize) { 256131603Spjd error = errno; 257131603Spjd goto out; 258131603Spjd } 259131603Spjd if (magic != NULL) { 260131603Spjd std_metadata_decode(sector, &stdmd); 261131603Spjd if (strcmp(stdmd.md_magic, magic) != 0) { 262131603Spjd error = EINVAL; 263131603Spjd goto out; 264131603Spjd } 265131603Spjd } 266131603Spjd bcopy(sector, md, size); 267131603Spjdout: 268131603Spjd if (sector != NULL) 269131603Spjd free(sector); 270213074Spjd g_close(fd); 271131603Spjd return (error); 272131603Spjd} 273131603Spjd 274131603Spjdint 275213074Spjdg_metadata_store(const char *name, const unsigned char *md, size_t size) 276129470Spjd{ 277213074Spjd unsigned char *sector; 278213074Spjd ssize_t sectorsize; 279129470Spjd off_t mediasize; 280129470Spjd int error, fd; 281129470Spjd 282129470Spjd sector = NULL; 283129470Spjd error = 0; 284129470Spjd 285213074Spjd fd = g_open(name, 1); 286129470Spjd if (fd == -1) 287129470Spjd return (errno); 288213074Spjd mediasize = g_mediasize(fd); 289213074Spjd if (mediasize == -1) { 290129470Spjd error = errno; 291129470Spjd goto out; 292129470Spjd } 293213074Spjd sectorsize = g_sectorsize(fd); 294213074Spjd if (sectorsize == -1) { 295129470Spjd error = errno; 296129470Spjd goto out; 297129470Spjd } 298213074Spjd assert(sectorsize >= (ssize_t)size); 299129470Spjd sector = malloc(sectorsize); 300129470Spjd if (sector == NULL) { 301129470Spjd error = ENOMEM; 302129470Spjd goto out; 303129470Spjd } 304129470Spjd bcopy(md, sector, size); 305129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 306213074Spjd sectorsize) { 307129470Spjd error = errno; 308129470Spjd goto out; 309129470Spjd } 310213074Spjd (void)g_flush(fd); 311129470Spjdout: 312129470Spjd if (sector != NULL) 313129470Spjd free(sector); 314213074Spjd (void)g_close(fd); 315129470Spjd return (error); 316129470Spjd} 317129470Spjd 318129470Spjdint 319129470Spjdg_metadata_clear(const char *name, const char *magic) 320129470Spjd{ 321129470Spjd struct std_metadata md; 322213074Spjd unsigned char *sector; 323213074Spjd ssize_t sectorsize; 324129470Spjd off_t mediasize; 325129470Spjd int error, fd; 326129470Spjd 327129470Spjd sector = NULL; 328129470Spjd error = 0; 329129470Spjd 330213074Spjd fd = g_open(name, 1); 331129470Spjd if (fd == -1) 332129470Spjd return (errno); 333213074Spjd mediasize = g_mediasize(fd); 334130591Spjd if (mediasize == 0) { 335129470Spjd error = errno; 336129470Spjd goto out; 337129470Spjd } 338213074Spjd sectorsize = g_sectorsize(fd); 339130591Spjd if (sectorsize == 0) { 340129470Spjd error = errno; 341129470Spjd goto out; 342129470Spjd } 343129470Spjd sector = malloc(sectorsize); 344129470Spjd if (sector == NULL) { 345129470Spjd error = ENOMEM; 346129470Spjd goto out; 347129470Spjd } 348129470Spjd if (magic != NULL) { 349129470Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 350213074Spjd sectorsize) { 351129470Spjd error = errno; 352129470Spjd goto out; 353129470Spjd } 354129470Spjd std_metadata_decode(sector, &md); 355129470Spjd if (strcmp(md.md_magic, magic) != 0) { 356129470Spjd error = EINVAL; 357129470Spjd goto out; 358129470Spjd } 359129470Spjd } 360129470Spjd bzero(sector, sectorsize); 361129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 362213074Spjd sectorsize) { 363129470Spjd error = errno; 364129470Spjd goto out; 365129470Spjd } 366213074Spjd (void)g_flush(fd); 367129470Spjdout: 368129470Spjd if (sector != NULL) 369129470Spjd free(sector); 370213074Spjd g_close(fd); 371129470Spjd return (error); 372129470Spjd} 373129470Spjd 374129470Spjd/* 375129470Spjd * Set an error message, if one does not already exist. 376129470Spjd */ 377129470Spjdvoid 378129470Spjdgctl_error(struct gctl_req *req, const char *error, ...) 379129470Spjd{ 380129470Spjd va_list ap; 381129470Spjd 382226718Spjd if (req != NULL && req->error != NULL) 383129470Spjd return; 384129470Spjd va_start(ap, error); 385226718Spjd if (req != NULL) { 386226718Spjd vasprintf(&req->error, error, ap); 387226718Spjd } else { 388226718Spjd vfprintf(stderr, error, ap); 389226718Spjd fprintf(stderr, "\n"); 390226718Spjd } 391129470Spjd va_end(ap); 392129470Spjd} 393129470Spjd 394153190Spjdstatic void * 395153190Spjdgctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 396129470Spjd{ 397153190Spjd struct gctl_req_arg *argp; 398153190Spjd char param[256]; 399213074Spjd unsigned int i; 400153190Spjd void *p; 401129470Spjd 402153190Spjd vsnprintf(param, sizeof(param), pfmt, ap); 403129470Spjd for (i = 0; i < req->narg; i++) { 404153190Spjd argp = &req->arg[i]; 405153190Spjd if (strcmp(param, argp->name)) 406129470Spjd continue; 407153190Spjd if (!(argp->flag & GCTL_PARAM_RD)) 408129470Spjd continue; 409153190Spjd p = argp->value; 410153190Spjd if (len == 0) { 411153190Spjd /* We are looking for a string. */ 412153190Spjd if (argp->len < 1) { 413153190Spjd fprintf(stderr, "No length argument (%s).\n", 414153190Spjd param); 415153190Spjd abort(); 416153190Spjd } 417153190Spjd if (((char *)p)[argp->len - 1] != '\0') { 418153190Spjd fprintf(stderr, "Unterminated argument (%s).\n", 419153190Spjd param); 420153190Spjd abort(); 421153190Spjd } 422153190Spjd } else if ((int)len != argp->len) { 423153190Spjd fprintf(stderr, "Wrong length %s argument.\n", param); 424153190Spjd abort(); 425153190Spjd } 426129470Spjd return (p); 427129470Spjd } 428153190Spjd fprintf(stderr, "No such argument (%s).\n", param); 429153190Spjd abort(); 430129470Spjd} 431129470Spjd 432153190Spjdint 433153190Spjdgctl_get_int(struct gctl_req *req, const char *pfmt, ...) 434129470Spjd{ 435153190Spjd int *p; 436153190Spjd va_list ap; 437129470Spjd 438153190Spjd va_start(ap, pfmt); 439153190Spjd p = gctl_get_param(req, sizeof(int), pfmt, ap); 440153190Spjd va_end(ap); 441153190Spjd return (*p); 442129470Spjd} 443129470Spjd 444153190Spjdintmax_t 445153190Spjdgctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 446129470Spjd{ 447153190Spjd intmax_t *p; 448153190Spjd va_list ap; 449129470Spjd 450153190Spjd va_start(ap, pfmt); 451153190Spjd p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 452153190Spjd va_end(ap); 453153190Spjd return (*p); 454153190Spjd} 455153190Spjd 456153190Spjdconst char * 457153190Spjdgctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 458153190Spjd{ 459153190Spjd const char *p; 460153190Spjd va_list ap; 461153190Spjd 462153190Spjd va_start(ap, pfmt); 463153190Spjd p = gctl_get_param(req, 0, pfmt, ap); 464153190Spjd va_end(ap); 465129470Spjd return (p); 466129470Spjd} 467166215Spjd 468166215Spjdint 469166215Spjdgctl_change_param(struct gctl_req *req, const char *name, int len, 470166215Spjd const void *value) 471166215Spjd{ 472166215Spjd struct gctl_req_arg *ap; 473213074Spjd unsigned int i; 474166215Spjd 475166215Spjd if (req == NULL || req->error != NULL) 476166215Spjd return (EDOOFUS); 477166215Spjd for (i = 0; i < req->narg; i++) { 478166215Spjd ap = &req->arg[i]; 479166215Spjd if (strcmp(ap->name, name) != 0) 480166215Spjd continue; 481166215Spjd ap->value = __DECONST(void *, value); 482166215Spjd if (len >= 0) { 483166215Spjd ap->flag &= ~GCTL_PARAM_ASCII; 484166215Spjd ap->len = len; 485166215Spjd } else if (len < 0) { 486166215Spjd ap->flag |= GCTL_PARAM_ASCII; 487166215Spjd ap->len = strlen(value) + 1; 488166215Spjd } 489166215Spjd return (0); 490166215Spjd } 491166215Spjd return (ENOENT); 492166215Spjd} 493179628Smarcel 494179628Smarcelint 495179628Smarcelgctl_delete_param(struct gctl_req *req, const char *name) 496179628Smarcel{ 497179628Smarcel struct gctl_req_arg *ap; 498179628Smarcel unsigned int i; 499179628Smarcel 500179628Smarcel if (req == NULL || req->error != NULL) 501179628Smarcel return (EDOOFUS); 502179628Smarcel 503179628Smarcel i = 0; 504179628Smarcel while (i < req->narg) { 505179628Smarcel ap = &req->arg[i]; 506179628Smarcel if (strcmp(ap->name, name) == 0) 507179628Smarcel break; 508179628Smarcel i++; 509179628Smarcel } 510179628Smarcel if (i == req->narg) 511179628Smarcel return (ENOENT); 512179628Smarcel 513208886Sae free(ap->name); 514179628Smarcel req->narg--; 515179628Smarcel while (i < req->narg) { 516179628Smarcel req->arg[i] = req->arg[i + 1]; 517179628Smarcel i++; 518179628Smarcel } 519179628Smarcel return (0); 520179628Smarcel} 521179628Smarcel 522179628Smarcelint 523179628Smarcelgctl_has_param(struct gctl_req *req, const char *name) 524179628Smarcel{ 525179628Smarcel struct gctl_req_arg *ap; 526179628Smarcel unsigned int i; 527179628Smarcel 528179628Smarcel if (req == NULL || req->error != NULL) 529179628Smarcel return (0); 530179628Smarcel 531179628Smarcel for (i = 0; i < req->narg; i++) { 532179628Smarcel ap = &req->arg[i]; 533179628Smarcel if (strcmp(ap->name, name) == 0) 534179628Smarcel return (1); 535179628Smarcel } 536179628Smarcel return (0); 537179628Smarcel} 538