subr.c revision 130591
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. 13129470Spjd * 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 130591 2004-06-16 10:44:26Z 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> 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 98130591Spjdoff_t 99130591Spjdg_get_mediasize(const char *name) 100130591Spjd{ 101130591Spjd char path[MAXPATHLEN]; 102130591Spjd off_t mediasize; 103130591Spjd int fd; 104130591Spjd 105130591Spjd pathgen(name, path, sizeof(path)); 106130591Spjd fd = open(path, O_RDONLY); 107130591Spjd if (fd == -1) 108130591Spjd return (0); 109130591Spjd if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 110130591Spjd close(fd); 111130591Spjd return (0); 112130591Spjd } 113130591Spjd close(fd); 114130591Spjd return (mediasize); 115130591Spjd} 116130591Spjd 117130591Spjdunsigned 118130591Spjdg_get_sectorsize(const char *name) 119130591Spjd{ 120130591Spjd char path[MAXPATHLEN]; 121130591Spjd unsigned sectorsize; 122130591Spjd int fd; 123130591Spjd 124130591Spjd pathgen(name, path, sizeof(path)); 125130591Spjd fd = open(path, O_RDONLY); 126130591Spjd if (fd == -1) 127130591Spjd return (0); 128130591Spjd if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 129130591Spjd close(fd); 130130591Spjd return (0); 131130591Spjd } 132130591Spjd close(fd); 133130591Spjd return (sectorsize); 134130591Spjd} 135130591Spjd 136129470Spjdint 137129470Spjdg_metadata_store(const char *name, u_char *md, size_t size) 138129470Spjd{ 139129470Spjd char path[MAXPATHLEN]; 140129470Spjd unsigned sectorsize; 141129470Spjd off_t mediasize; 142129470Spjd u_char *sector; 143129470Spjd int error, fd; 144129470Spjd 145129470Spjd pathgen(name, path, sizeof(path)); 146129470Spjd sector = NULL; 147129470Spjd error = 0; 148129470Spjd 149129470Spjd fd = open(path, O_WRONLY); 150129470Spjd if (fd == -1) 151129470Spjd return (errno); 152130591Spjd mediasize = g_get_mediasize(name); 153130591Spjd if (mediasize == 0) { 154129470Spjd error = errno; 155129470Spjd goto out; 156129470Spjd } 157130591Spjd sectorsize = g_get_sectorsize(name); 158130591Spjd if (sectorsize == 0) { 159129470Spjd error = errno; 160129470Spjd goto out; 161129470Spjd } 162129470Spjd assert(sectorsize >= size); 163129470Spjd sector = malloc(sectorsize); 164129470Spjd if (sector == NULL) { 165129470Spjd error = ENOMEM; 166129470Spjd goto out; 167129470Spjd } 168129470Spjd bcopy(md, sector, size); 169129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 170129470Spjd (ssize_t)sectorsize) { 171129470Spjd error = errno; 172129470Spjd goto out; 173129470Spjd } 174129470Spjdout: 175129470Spjd if (sector != NULL) 176129470Spjd free(sector); 177129470Spjd close(fd); 178129470Spjd return (error); 179129470Spjd} 180129470Spjd 181129470Spjdint 182129470Spjdg_metadata_clear(const char *name, const char *magic) 183129470Spjd{ 184129470Spjd struct std_metadata md; 185129470Spjd char path[MAXPATHLEN]; 186129470Spjd unsigned sectorsize; 187129470Spjd off_t mediasize; 188129470Spjd u_char *sector; 189129470Spjd int error, fd; 190129470Spjd 191129470Spjd pathgen(name, path, sizeof(path)); 192129470Spjd sector = NULL; 193129470Spjd error = 0; 194129470Spjd 195129470Spjd fd = open(path, O_RDWR); 196129470Spjd if (fd == -1) 197129470Spjd return (errno); 198130591Spjd mediasize = g_get_mediasize(name); 199130591Spjd if (mediasize == 0) { 200129470Spjd error = errno; 201129470Spjd goto out; 202129470Spjd } 203130591Spjd sectorsize = g_get_sectorsize(name); 204130591Spjd if (sectorsize == 0) { 205129470Spjd error = errno; 206129470Spjd goto out; 207129470Spjd } 208129470Spjd sector = malloc(sectorsize); 209129470Spjd if (sector == NULL) { 210129470Spjd error = ENOMEM; 211129470Spjd goto out; 212129470Spjd } 213129470Spjd if (magic != NULL) { 214129470Spjd if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 215129470Spjd (ssize_t)sectorsize) { 216129470Spjd error = errno; 217129470Spjd goto out; 218129470Spjd } 219129470Spjd std_metadata_decode(sector, &md); 220129470Spjd if (strcmp(md.md_magic, magic) != 0) { 221129470Spjd error = EINVAL; 222129470Spjd goto out; 223129470Spjd } 224129470Spjd } 225129470Spjd bzero(sector, sectorsize); 226129470Spjd if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 227129470Spjd (ssize_t)sectorsize) { 228129470Spjd error = errno; 229129470Spjd goto out; 230129470Spjd } 231129470Spjdout: 232129470Spjd if (sector != NULL) 233129470Spjd free(sector); 234129470Spjd close(fd); 235129470Spjd return (error); 236129470Spjd} 237129470Spjd 238129470Spjd/* 239129470Spjd * Set an error message, if one does not already exist. 240129470Spjd */ 241129470Spjdvoid 242129470Spjdgctl_error(struct gctl_req *req, const char *error, ...) 243129470Spjd{ 244129470Spjd va_list ap; 245129470Spjd 246129470Spjd if (req->error != NULL) 247129470Spjd return; 248129470Spjd va_start(ap, error); 249129470Spjd vasprintf(&req->error, error, ap); 250129470Spjd va_end(ap); 251129470Spjd} 252129470Spjd 253129470Spjdvoid * 254129470Spjdgctl_get_param(struct gctl_req *req, const char *param, int *len) 255129470Spjd{ 256129470Spjd unsigned i; 257129470Spjd void *p; 258129470Spjd struct gctl_req_arg *ap; 259129470Spjd 260129470Spjd for (i = 0; i < req->narg; i++) { 261129470Spjd ap = &req->arg[i]; 262129470Spjd if (strcmp(param, ap->name)) 263129470Spjd continue; 264129470Spjd if (!(ap->flag & GCTL_PARAM_RD)) 265129470Spjd continue; 266129470Spjd p = ap->value; 267129470Spjd if (len != NULL) 268129470Spjd *len = ap->len; 269129470Spjd return (p); 270129470Spjd } 271129470Spjd return (NULL); 272129470Spjd} 273129470Spjd 274129470Spjdchar const * 275129470Spjdgctl_get_asciiparam(struct gctl_req *req, const char *param) 276129470Spjd{ 277129470Spjd unsigned i; 278129470Spjd char const *p; 279129470Spjd struct gctl_req_arg *ap; 280129470Spjd 281129470Spjd for (i = 0; i < req->narg; i++) { 282129470Spjd ap = &req->arg[i]; 283129470Spjd if (strcmp(param, ap->name)) 284129470Spjd continue; 285129470Spjd if (!(ap->flag & GCTL_PARAM_RD)) 286129470Spjd continue; 287129470Spjd p = ap->value; 288129470Spjd if (ap->len < 1) { 289129470Spjd gctl_error(req, "No length argument (%s)", param); 290129470Spjd return (NULL); 291129470Spjd } 292129470Spjd if (p[ap->len - 1] != '\0') { 293129470Spjd gctl_error(req, "Unterminated argument (%s)", param); 294129470Spjd return (NULL); 295129470Spjd } 296129470Spjd return (p); 297129470Spjd } 298129470Spjd return (NULL); 299129470Spjd} 300129470Spjd 301129470Spjdvoid * 302129470Spjdgctl_get_paraml(struct gctl_req *req, const char *param, int len) 303129470Spjd{ 304129470Spjd int i; 305129470Spjd void *p; 306129470Spjd 307129470Spjd p = gctl_get_param(req, param, &i); 308129470Spjd if (p == NULL) 309129470Spjd gctl_error(req, "Missing %s argument", param); 310129470Spjd else if (i != len) { 311129470Spjd p = NULL; 312129470Spjd gctl_error(req, "Wrong length %s argument", param); 313129470Spjd } 314129470Spjd return (p); 315129470Spjd} 316