subr.c revision 208886
1129470Spjd/*- 2129470Spjd * Copyright (c) 2004 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: head/sbin/geom/misc/subr.c 208886 2010-06-07 07:41:41Z ae $"); 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> 39129470Spjd#include <stdarg.h> 40129470Spjd#include <string.h> 41129470Spjd#include <strings.h> 42129470Spjd#include <unistd.h> 43129470Spjd#include <assert.h> 44129470Spjd#include <libgeom.h> 45129470Spjd 46129470Spjd#include "misc/subr.h" 47129470Spjd 48129470Spjd 49129470Spjdstruct std_metadata { 50129470Spjd char md_magic[16]; 51129470Spjd uint32_t md_version; 52129470Spjd}; 53129470Spjd 54129470Spjdstatic void 55129470Spjdstd_metadata_decode(const u_char *data, struct std_metadata *md) 56129470Spjd{ 57129470Spjd 58129470Spjd bcopy(data, md->md_magic, sizeof(md->md_magic)); 59129470Spjd md->md_version = le32dec(data + 16); 60129470Spjd} 61129470Spjd 62129470Spjdstatic void 63129470Spjdpathgen(const char *name, char *path, size_t size) 64129470Spjd{ 65129470Spjd 66129470Spjd if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 67129470Spjd snprintf(path, size, "%s%s", _PATH_DEV, name); 68129470Spjd else 69129470Spjd strlcpy(path, name, size); 70129470Spjd} 71129470Spjd 72130591Spjd/* 73130591Spjd * Greatest Common Divisor. 74130591Spjd */ 75130591Spjdstatic unsigned 76130591Spjdgcd(unsigned a, unsigned b) 77130591Spjd{ 78130591Spjd u_int c; 79130591Spjd 80130591Spjd while (b != 0) { 81130591Spjd c = a; 82130591Spjd a = b; 83130591Spjd b = (c % b); 84130591Spjd } 85130591Spjd return (a); 86130591Spjd} 87130591Spjd 88130591Spjd/* 89130591Spjd * Least Common Multiple. 90130591Spjd */ 91130591Spjdunsigned 92130591Spjdg_lcm(unsigned a, unsigned b) 93130591Spjd{ 94130591Spjd 95130591Spjd return ((a * b) / gcd(a, b)); 96130591Spjd} 97130591Spjd 98149302Spjduint32_t 99149302Spjdbitcount32(uint32_t x) 100149302Spjd{ 101149302Spjd 102149302Spjd x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 103149302Spjd x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 104149302Spjd x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 105149302Spjd x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 106149302Spjd x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 107149302Spjd return (x); 108149302Spjd} 109149302Spjd 110130591Spjdoff_t 111130591Spjdg_get_mediasize(const char *name) 112130591Spjd{ 113130591Spjd char path[MAXPATHLEN]; 114130591Spjd off_t mediasize; 115130591Spjd int fd; 116130591Spjd 117130591Spjd pathgen(name, path, sizeof(path)); 118130591Spjd fd = open(path, O_RDONLY); 119130591Spjd if (fd == -1) 120130591Spjd return (0); 121130591Spjd if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 122130591Spjd close(fd); 123130591Spjd return (0); 124130591Spjd } 125130591Spjd close(fd); 126130591Spjd return (mediasize); 127130591Spjd} 128130591Spjd 129130591Spjdunsigned 130130591Spjdg_get_sectorsize(const char *name) 131130591Spjd{ 132130591Spjd char path[MAXPATHLEN]; 133130591Spjd unsigned sectorsize; 134130591Spjd int fd; 135130591Spjd 136130591Spjd pathgen(name, path, sizeof(path)); 137130591Spjd fd = open(path, O_RDONLY); 138130591Spjd if (fd == -1) 139130591Spjd return (0); 140130591Spjd if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 141130591Spjd close(fd); 142130591Spjd return (0); 143130591Spjd } 144130591Spjd close(fd); 145130591Spjd return (sectorsize); 146130591Spjd} 147130591Spjd 148129470Spjdint 149131603Spjdg_metadata_read(const char *name, u_char *md, size_t size, const char *magic) 150131603Spjd{ 151131603Spjd struct std_metadata stdmd; 152131603Spjd char path[MAXPATHLEN]; 153131603Spjd unsigned sectorsize; 154131603Spjd off_t mediasize; 155131603Spjd u_char *sector; 156131603Spjd int error, fd; 157131603Spjd 158131603Spjd pathgen(name, path, sizeof(path)); 159131603Spjd sector = NULL; 160131603Spjd error = 0; 161131603Spjd 162131603Spjd fd = open(path, O_RDONLY); 163131603Spjd if (fd == -1) 164131603Spjd return (errno); 165131603Spjd mediasize = g_get_mediasize(name); 166131603Spjd if (mediasize == 0) { 167131603Spjd error = errno; 168131603Spjd goto out; 169131603Spjd } 170131603Spjd sectorsize = g_get_sectorsize(name); 171131603Spjd if (sectorsize == 0) { 172131603Spjd error = errno; 173131603Spjd goto out; 174131603Spjd } 175131603Spjd assert(sectorsize >= size); 176131603Spjd sector = malloc(sectorsize); 177131603Spjd if (sector == NULL) { 178131603Spjd error = ENOMEM; 179131603Spjd goto out; 180131603Spjd } 181131603Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 182131603Spjd (ssize_t)sectorsize) { 183131603Spjd error = errno; 184131603Spjd goto out; 185131603Spjd } 186131603Spjd if (magic != NULL) { 187131603Spjd std_metadata_decode(sector, &stdmd); 188131603Spjd if (strcmp(stdmd.md_magic, magic) != 0) { 189131603Spjd error = EINVAL; 190131603Spjd goto out; 191131603Spjd } 192131603Spjd } 193131603Spjd bcopy(sector, md, size); 194131603Spjdout: 195131603Spjd if (sector != NULL) 196131603Spjd free(sector); 197131603Spjd close(fd); 198131603Spjd return (error); 199131603Spjd} 200131603Spjd 201131603Spjdint 202129470Spjdg_metadata_store(const char *name, u_char *md, size_t size) 203129470Spjd{ 204129470Spjd char path[MAXPATHLEN]; 205129470Spjd unsigned sectorsize; 206129470Spjd off_t mediasize; 207129470Spjd u_char *sector; 208129470Spjd int error, fd; 209129470Spjd 210129470Spjd pathgen(name, path, sizeof(path)); 211129470Spjd sector = NULL; 212129470Spjd error = 0; 213129470Spjd 214186516Slulf fd = open(path, O_WRONLY); 215129470Spjd if (fd == -1) 216129470Spjd return (errno); 217130591Spjd mediasize = g_get_mediasize(name); 218130591Spjd if (mediasize == 0) { 219129470Spjd error = errno; 220129470Spjd goto out; 221129470Spjd } 222130591Spjd sectorsize = g_get_sectorsize(name); 223130591Spjd if (sectorsize == 0) { 224129470Spjd error = errno; 225129470Spjd goto out; 226129470Spjd } 227129470Spjd assert(sectorsize >= size); 228129470Spjd sector = malloc(sectorsize); 229129470Spjd if (sector == NULL) { 230129470Spjd error = ENOMEM; 231129470Spjd goto out; 232129470Spjd } 233129470Spjd bcopy(md, sector, size); 234129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 235129470Spjd (ssize_t)sectorsize) { 236129470Spjd error = errno; 237129470Spjd goto out; 238129470Spjd } 239206666Spjd (void)ioctl(fd, DIOCGFLUSH, NULL); 240129470Spjdout: 241129470Spjd if (sector != NULL) 242129470Spjd free(sector); 243129470Spjd close(fd); 244129470Spjd return (error); 245129470Spjd} 246129470Spjd 247129470Spjdint 248129470Spjdg_metadata_clear(const char *name, const char *magic) 249129470Spjd{ 250129470Spjd struct std_metadata md; 251129470Spjd char path[MAXPATHLEN]; 252129470Spjd unsigned sectorsize; 253129470Spjd off_t mediasize; 254129470Spjd u_char *sector; 255129470Spjd int error, fd; 256129470Spjd 257129470Spjd pathgen(name, path, sizeof(path)); 258129470Spjd sector = NULL; 259129470Spjd error = 0; 260129470Spjd 261129470Spjd fd = open(path, O_RDWR); 262129470Spjd if (fd == -1) 263129470Spjd return (errno); 264130591Spjd mediasize = g_get_mediasize(name); 265130591Spjd if (mediasize == 0) { 266129470Spjd error = errno; 267129470Spjd goto out; 268129470Spjd } 269130591Spjd sectorsize = g_get_sectorsize(name); 270130591Spjd if (sectorsize == 0) { 271129470Spjd error = errno; 272129470Spjd goto out; 273129470Spjd } 274129470Spjd sector = malloc(sectorsize); 275129470Spjd if (sector == NULL) { 276129470Spjd error = ENOMEM; 277129470Spjd goto out; 278129470Spjd } 279129470Spjd if (magic != NULL) { 280129470Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 281129470Spjd (ssize_t)sectorsize) { 282129470Spjd error = errno; 283129470Spjd goto out; 284129470Spjd } 285129470Spjd std_metadata_decode(sector, &md); 286129470Spjd if (strcmp(md.md_magic, magic) != 0) { 287129470Spjd error = EINVAL; 288129470Spjd goto out; 289129470Spjd } 290129470Spjd } 291129470Spjd bzero(sector, sectorsize); 292129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 293129470Spjd (ssize_t)sectorsize) { 294129470Spjd error = errno; 295129470Spjd goto out; 296129470Spjd } 297206666Spjd (void)ioctl(fd, DIOCGFLUSH, NULL); 298129470Spjdout: 299129470Spjd if (sector != NULL) 300129470Spjd free(sector); 301129470Spjd close(fd); 302129470Spjd return (error); 303129470Spjd} 304129470Spjd 305129470Spjd/* 306129470Spjd * Set an error message, if one does not already exist. 307129470Spjd */ 308129470Spjdvoid 309129470Spjdgctl_error(struct gctl_req *req, const char *error, ...) 310129470Spjd{ 311129470Spjd va_list ap; 312129470Spjd 313129470Spjd if (req->error != NULL) 314129470Spjd return; 315129470Spjd va_start(ap, error); 316129470Spjd vasprintf(&req->error, error, ap); 317129470Spjd va_end(ap); 318129470Spjd} 319129470Spjd 320153190Spjdstatic void * 321153190Spjdgctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 322129470Spjd{ 323153190Spjd struct gctl_req_arg *argp; 324153190Spjd char param[256]; 325153190Spjd void *p; 326129470Spjd unsigned i; 327129470Spjd 328153190Spjd vsnprintf(param, sizeof(param), pfmt, ap); 329129470Spjd for (i = 0; i < req->narg; i++) { 330153190Spjd argp = &req->arg[i]; 331153190Spjd if (strcmp(param, argp->name)) 332129470Spjd continue; 333153190Spjd if (!(argp->flag & GCTL_PARAM_RD)) 334129470Spjd continue; 335153190Spjd p = argp->value; 336153190Spjd if (len == 0) { 337153190Spjd /* We are looking for a string. */ 338153190Spjd if (argp->len < 1) { 339153190Spjd fprintf(stderr, "No length argument (%s).\n", 340153190Spjd param); 341153190Spjd abort(); 342153190Spjd } 343153190Spjd if (((char *)p)[argp->len - 1] != '\0') { 344153190Spjd fprintf(stderr, "Unterminated argument (%s).\n", 345153190Spjd param); 346153190Spjd abort(); 347153190Spjd } 348153190Spjd } else if ((int)len != argp->len) { 349153190Spjd fprintf(stderr, "Wrong length %s argument.\n", param); 350153190Spjd abort(); 351153190Spjd } 352129470Spjd return (p); 353129470Spjd } 354153190Spjd fprintf(stderr, "No such argument (%s).\n", param); 355153190Spjd abort(); 356129470Spjd} 357129470Spjd 358153190Spjdint 359153190Spjdgctl_get_int(struct gctl_req *req, const char *pfmt, ...) 360129470Spjd{ 361153190Spjd int *p; 362153190Spjd va_list ap; 363129470Spjd 364153190Spjd va_start(ap, pfmt); 365153190Spjd p = gctl_get_param(req, sizeof(int), pfmt, ap); 366153190Spjd va_end(ap); 367153190Spjd return (*p); 368129470Spjd} 369129470Spjd 370153190Spjdintmax_t 371153190Spjdgctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 372129470Spjd{ 373153190Spjd intmax_t *p; 374153190Spjd va_list ap; 375129470Spjd 376153190Spjd va_start(ap, pfmt); 377153190Spjd p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 378153190Spjd va_end(ap); 379153190Spjd return (*p); 380153190Spjd} 381153190Spjd 382153190Spjdconst char * 383153190Spjdgctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 384153190Spjd{ 385153190Spjd const char *p; 386153190Spjd va_list ap; 387153190Spjd 388153190Spjd va_start(ap, pfmt); 389153190Spjd p = gctl_get_param(req, 0, pfmt, ap); 390153190Spjd va_end(ap); 391129470Spjd return (p); 392129470Spjd} 393166215Spjd 394166215Spjdint 395166215Spjdgctl_change_param(struct gctl_req *req, const char *name, int len, 396166215Spjd const void *value) 397166215Spjd{ 398166215Spjd struct gctl_req_arg *ap; 399166215Spjd unsigned i; 400166215Spjd 401166215Spjd if (req == NULL || req->error != NULL) 402166215Spjd return (EDOOFUS); 403166215Spjd for (i = 0; i < req->narg; i++) { 404166215Spjd ap = &req->arg[i]; 405166215Spjd if (strcmp(ap->name, name) != 0) 406166215Spjd continue; 407166215Spjd ap->value = __DECONST(void *, value); 408166215Spjd if (len >= 0) { 409166215Spjd ap->flag &= ~GCTL_PARAM_ASCII; 410166215Spjd ap->len = len; 411166215Spjd } else if (len < 0) { 412166215Spjd ap->flag |= GCTL_PARAM_ASCII; 413166215Spjd ap->len = strlen(value) + 1; 414166215Spjd } 415166215Spjd return (0); 416166215Spjd } 417166215Spjd return (ENOENT); 418166215Spjd} 419179628Smarcel 420179628Smarcelint 421179628Smarcelgctl_delete_param(struct gctl_req *req, const char *name) 422179628Smarcel{ 423179628Smarcel struct gctl_req_arg *ap; 424179628Smarcel unsigned int i; 425179628Smarcel 426179628Smarcel if (req == NULL || req->error != NULL) 427179628Smarcel return (EDOOFUS); 428179628Smarcel 429179628Smarcel i = 0; 430179628Smarcel while (i < req->narg) { 431179628Smarcel ap = &req->arg[i]; 432179628Smarcel if (strcmp(ap->name, name) == 0) 433179628Smarcel break; 434179628Smarcel i++; 435179628Smarcel } 436179628Smarcel if (i == req->narg) 437179628Smarcel return (ENOENT); 438179628Smarcel 439208886Sae free(ap->name); 440179628Smarcel req->narg--; 441179628Smarcel while (i < req->narg) { 442179628Smarcel req->arg[i] = req->arg[i + 1]; 443179628Smarcel i++; 444179628Smarcel } 445179628Smarcel return (0); 446179628Smarcel} 447179628Smarcel 448179628Smarcelint 449179628Smarcelgctl_has_param(struct gctl_req *req, const char *name) 450179628Smarcel{ 451179628Smarcel struct gctl_req_arg *ap; 452179628Smarcel unsigned int i; 453179628Smarcel 454179628Smarcel if (req == NULL || req->error != NULL) 455179628Smarcel return (0); 456179628Smarcel 457179628Smarcel for (i = 0; i < req->narg; i++) { 458179628Smarcel ap = &req->arg[i]; 459179628Smarcel if (strcmp(ap->name, name) == 0) 460179628Smarcel return (1); 461179628Smarcel } 462179628Smarcel return (0); 463179628Smarcel} 464