subr.c revision 179628
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 179628 2008-06-06 22:44:03Z marcel $"); 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 214129470Spjd 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 } 239129470Spjdout: 240129470Spjd if (sector != NULL) 241129470Spjd free(sector); 242129470Spjd close(fd); 243129470Spjd return (error); 244129470Spjd} 245129470Spjd 246129470Spjdint 247129470Spjdg_metadata_clear(const char *name, const char *magic) 248129470Spjd{ 249129470Spjd struct std_metadata md; 250129470Spjd char path[MAXPATHLEN]; 251129470Spjd unsigned sectorsize; 252129470Spjd off_t mediasize; 253129470Spjd u_char *sector; 254129470Spjd int error, fd; 255129470Spjd 256129470Spjd pathgen(name, path, sizeof(path)); 257129470Spjd sector = NULL; 258129470Spjd error = 0; 259129470Spjd 260129470Spjd fd = open(path, O_RDWR); 261129470Spjd if (fd == -1) 262129470Spjd return (errno); 263130591Spjd mediasize = g_get_mediasize(name); 264130591Spjd if (mediasize == 0) { 265129470Spjd error = errno; 266129470Spjd goto out; 267129470Spjd } 268130591Spjd sectorsize = g_get_sectorsize(name); 269130591Spjd if (sectorsize == 0) { 270129470Spjd error = errno; 271129470Spjd goto out; 272129470Spjd } 273129470Spjd sector = malloc(sectorsize); 274129470Spjd if (sector == NULL) { 275129470Spjd error = ENOMEM; 276129470Spjd goto out; 277129470Spjd } 278129470Spjd if (magic != NULL) { 279129470Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 280129470Spjd (ssize_t)sectorsize) { 281129470Spjd error = errno; 282129470Spjd goto out; 283129470Spjd } 284129470Spjd std_metadata_decode(sector, &md); 285129470Spjd if (strcmp(md.md_magic, magic) != 0) { 286129470Spjd error = EINVAL; 287129470Spjd goto out; 288129470Spjd } 289129470Spjd } 290129470Spjd bzero(sector, sectorsize); 291129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 292129470Spjd (ssize_t)sectorsize) { 293129470Spjd error = errno; 294129470Spjd goto out; 295129470Spjd } 296129470Spjdout: 297129470Spjd if (sector != NULL) 298129470Spjd free(sector); 299129470Spjd close(fd); 300129470Spjd return (error); 301129470Spjd} 302129470Spjd 303129470Spjd/* 304129470Spjd * Set an error message, if one does not already exist. 305129470Spjd */ 306129470Spjdvoid 307129470Spjdgctl_error(struct gctl_req *req, const char *error, ...) 308129470Spjd{ 309129470Spjd va_list ap; 310129470Spjd 311129470Spjd if (req->error != NULL) 312129470Spjd return; 313129470Spjd va_start(ap, error); 314129470Spjd vasprintf(&req->error, error, ap); 315129470Spjd va_end(ap); 316129470Spjd} 317129470Spjd 318153190Spjdstatic void * 319153190Spjdgctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 320129470Spjd{ 321153190Spjd struct gctl_req_arg *argp; 322153190Spjd char param[256]; 323153190Spjd void *p; 324129470Spjd unsigned i; 325129470Spjd 326153190Spjd vsnprintf(param, sizeof(param), pfmt, ap); 327129470Spjd for (i = 0; i < req->narg; i++) { 328153190Spjd argp = &req->arg[i]; 329153190Spjd if (strcmp(param, argp->name)) 330129470Spjd continue; 331153190Spjd if (!(argp->flag & GCTL_PARAM_RD)) 332129470Spjd continue; 333153190Spjd p = argp->value; 334153190Spjd if (len == 0) { 335153190Spjd /* We are looking for a string. */ 336153190Spjd if (argp->len < 1) { 337153190Spjd fprintf(stderr, "No length argument (%s).\n", 338153190Spjd param); 339153190Spjd abort(); 340153190Spjd } 341153190Spjd if (((char *)p)[argp->len - 1] != '\0') { 342153190Spjd fprintf(stderr, "Unterminated argument (%s).\n", 343153190Spjd param); 344153190Spjd abort(); 345153190Spjd } 346153190Spjd } else if ((int)len != argp->len) { 347153190Spjd fprintf(stderr, "Wrong length %s argument.\n", param); 348153190Spjd abort(); 349153190Spjd } 350129470Spjd return (p); 351129470Spjd } 352153190Spjd fprintf(stderr, "No such argument (%s).\n", param); 353153190Spjd abort(); 354129470Spjd} 355129470Spjd 356153190Spjdint 357153190Spjdgctl_get_int(struct gctl_req *req, const char *pfmt, ...) 358129470Spjd{ 359153190Spjd int *p; 360153190Spjd va_list ap; 361129470Spjd 362153190Spjd va_start(ap, pfmt); 363153190Spjd p = gctl_get_param(req, sizeof(int), pfmt, ap); 364153190Spjd va_end(ap); 365153190Spjd return (*p); 366129470Spjd} 367129470Spjd 368153190Spjdintmax_t 369153190Spjdgctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 370129470Spjd{ 371153190Spjd intmax_t *p; 372153190Spjd va_list ap; 373129470Spjd 374153190Spjd va_start(ap, pfmt); 375153190Spjd p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 376153190Spjd va_end(ap); 377153190Spjd return (*p); 378153190Spjd} 379153190Spjd 380153190Spjdconst char * 381153190Spjdgctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 382153190Spjd{ 383153190Spjd const char *p; 384153190Spjd va_list ap; 385153190Spjd 386153190Spjd va_start(ap, pfmt); 387153190Spjd p = gctl_get_param(req, 0, pfmt, ap); 388153190Spjd va_end(ap); 389129470Spjd return (p); 390129470Spjd} 391166215Spjd 392166215Spjdint 393166215Spjdgctl_change_param(struct gctl_req *req, const char *name, int len, 394166215Spjd const void *value) 395166215Spjd{ 396166215Spjd struct gctl_req_arg *ap; 397166215Spjd unsigned i; 398166215Spjd 399166215Spjd if (req == NULL || req->error != NULL) 400166215Spjd return (EDOOFUS); 401166215Spjd for (i = 0; i < req->narg; i++) { 402166215Spjd ap = &req->arg[i]; 403166215Spjd if (strcmp(ap->name, name) != 0) 404166215Spjd continue; 405166215Spjd ap->value = __DECONST(void *, value); 406166215Spjd if (len >= 0) { 407166215Spjd ap->flag &= ~GCTL_PARAM_ASCII; 408166215Spjd ap->len = len; 409166215Spjd } else if (len < 0) { 410166215Spjd ap->flag |= GCTL_PARAM_ASCII; 411166215Spjd ap->len = strlen(value) + 1; 412166215Spjd } 413166215Spjd return (0); 414166215Spjd } 415166215Spjd return (ENOENT); 416166215Spjd} 417179628Smarcel 418179628Smarcelint 419179628Smarcelgctl_delete_param(struct gctl_req *req, const char *name) 420179628Smarcel{ 421179628Smarcel struct gctl_req_arg *ap; 422179628Smarcel unsigned int i; 423179628Smarcel 424179628Smarcel if (req == NULL || req->error != NULL) 425179628Smarcel return (EDOOFUS); 426179628Smarcel 427179628Smarcel i = 0; 428179628Smarcel while (i < req->narg) { 429179628Smarcel ap = &req->arg[i]; 430179628Smarcel if (strcmp(ap->name, name) == 0) 431179628Smarcel break; 432179628Smarcel i++; 433179628Smarcel } 434179628Smarcel if (i == req->narg) 435179628Smarcel return (ENOENT); 436179628Smarcel 437179628Smarcel req->narg--; 438179628Smarcel while (i < req->narg) { 439179628Smarcel req->arg[i] = req->arg[i + 1]; 440179628Smarcel i++; 441179628Smarcel } 442179628Smarcel return (0); 443179628Smarcel} 444179628Smarcel 445179628Smarcelint 446179628Smarcelgctl_has_param(struct gctl_req *req, const char *name) 447179628Smarcel{ 448179628Smarcel struct gctl_req_arg *ap; 449179628Smarcel unsigned int i; 450179628Smarcel 451179628Smarcel if (req == NULL || req->error != NULL) 452179628Smarcel return (0); 453179628Smarcel 454179628Smarcel for (i = 0; i < req->narg; i++) { 455179628Smarcel ap = &req->arg[i]; 456179628Smarcel if (strcmp(ap->name, name) == 0) 457179628Smarcel return (1); 458179628Smarcel } 459179628Smarcel return (0); 460179628Smarcel} 461