subr.c revision 155175
118334Speter/*- 252284Sobrien * Copyright (c) 2004 Pawel Jakub Dawidek <pjd@FreeBSD.org> 318334Speter * All rights reserved. 418334Speter * 518334Speter * Redistribution and use in source and binary forms, with or without 618334Speter * modification, are permitted provided that the following conditions 718334Speter * are met: 818334Speter * 1. Redistributions of source code must retain the above copyright 918334Speter * notice, this list of conditions and the following disclaimer. 1018334Speter * 2. Redistributions in binary form must reproduce the above copyright 1118334Speter * notice, this list of conditions and the following disclaimer in the 1218334Speter * documentation and/or other materials provided with the distribution. 1318334Speter * 1418334Speter * THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND 1518334Speter * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 1618334Speter * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 1718334Speter * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHORS OR CONTRIBUTORS BE LIABLE 1818334Speter * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 1918334Speter * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 2018334Speter * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 2118334Speter * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 2218334Speter * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 2318334Speter * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 2418334Speter * SUCH DAMAGE. 2518334Speter */ 2618334Speter 2718334Speter#include <sys/cdefs.h> 2818334Speter__FBSDID("$FreeBSD: head/sbin/geom/misc/subr.c 155175 2006-02-01 12:11:37Z pjd $"); 2918334Speter 3018334Speter#include <sys/param.h> 3118334Speter#include <sys/disk.h> 3218334Speter#include <sys/endian.h> 3318334Speter#include <sys/uio.h> 3418334Speter#include <errno.h> 3518334Speter#include <fcntl.h> 3618334Speter#include <paths.h> 3718334Speter#include <stdio.h> 3818334Speter#include <stdlib.h> 3918334Speter#include <stdarg.h> 4018334Speter#include <string.h> 4118334Speter#include <strings.h> 4218334Speter#include <unistd.h> 4318334Speter#include <assert.h> 4418334Speter#include <libgeom.h> 4518334Speter 4618334Speter#include "misc/subr.h" 4718334Speter 4818334Speter 4918334Speterstruct std_metadata { 5018334Speter char md_magic[16]; 5118334Speter uint32_t md_version; 5218334Speter}; 5318334Speter 5418334Speterstatic void 5518334Speterstd_metadata_decode(const u_char *data, struct std_metadata *md) 5618334Speter{ 5718334Speter 5818334Speter bcopy(data, md->md_magic, sizeof(md->md_magic)); 5918334Speter md->md_version = le32dec(data + 16); 6018334Speter} 6118334Speter 6218334Speterstatic void 6318334Speterpathgen(const char *name, char *path, size_t size) 6418334Speter{ 6518334Speter 6618334Speter if (strncmp(name, _PATH_DEV, strlen(_PATH_DEV)) != 0) 6718334Speter snprintf(path, size, "%s%s", _PATH_DEV, name); 6818334Speter else 6918334Speter strlcpy(path, name, size); 7018334Speter} 7118334Speter 7218334Speter/* 7318334Speter * Greatest Common Divisor. 7418334Speter */ 7518334Speterstatic unsigned 7618334Spetergcd(unsigned a, unsigned b) 7718334Speter{ 7818334Speter u_int c; 7918334Speter 8018334Speter while (b != 0) { 8118334Speter c = a; 8218334Speter a = b; 8318334Speter b = (c % b); 8418334Speter } 8518334Speter return (a); 8618334Speter} 8718334Speter 8818334Speter/* 8918334Speter * Least Common Multiple. 9018334Speter */ 9118334Speterunsigned 9218334Speterg_lcm(unsigned a, unsigned b) 9318334Speter{ 9418334Speter 9518334Speter return ((a * b) / gcd(a, b)); 9618334Speter} 9718334Speter 9818334Speteruint32_t 9918334Speterbitcount32(uint32_t x) 10018334Speter{ 10118334Speter 10218334Speter x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); 10318334Speter x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); 10418334Speter x = (x & 0x0f0f0f0f) + ((x & 0xf0f0f0f0) >> 4); 10518334Speter x = (x & 0x00ff00ff) + ((x & 0xff00ff00) >> 8); 10618334Speter x = (x & 0x0000ffff) + ((x & 0xffff0000) >> 16); 10718334Speter return (x); 10818334Speter} 10918334Speter 11018334Speteroff_t 11118334Speterg_get_mediasize(const char *name) 11218334Speter{ 11318334Speter char path[MAXPATHLEN]; 11418334Speter off_t mediasize; 11518334Speter int fd; 11618334Speter 11718334Speter pathgen(name, path, sizeof(path)); 11818334Speter fd = open(path, O_RDONLY); 11918334Speter if (fd == -1) 12018334Speter return (0); 12118334Speter if (ioctl(fd, DIOCGMEDIASIZE, &mediasize) < 0) { 12218334Speter close(fd); 12318334Speter return (0); 12418334Speter } 12518334Speter close(fd); 12618334Speter return (mediasize); 12718334Speter} 12818334Speter 12918334Speterunsigned 13018334Speterg_get_sectorsize(const char *name) 13118334Speter{ 13218334Speter char path[MAXPATHLEN]; 13318334Speter unsigned sectorsize; 13418334Speter int fd; 13518334Speter 13618334Speter pathgen(name, path, sizeof(path)); 13718334Speter fd = open(path, O_RDONLY); 13818334Speter if (fd == -1) 13918334Speter return (0); 14018334Speter if (ioctl(fd, DIOCGSECTORSIZE, §orsize) < 0) { 14118334Speter close(fd); 14218334Speter return (0); 14318334Speter } 14418334Speter close(fd); 14518334Speter return (sectorsize); 14618334Speter} 14718334Speter 14818334Speterint 14918334Speterg_metadata_read(const char *name, u_char *md, size_t size, const char *magic) 15018334Speter{ 15118334Speter struct std_metadata stdmd; 15218334Speter char path[MAXPATHLEN]; 15318334Speter unsigned sectorsize; 15450397Sobrien off_t mediasize; 15518334Speter u_char *sector; 15618334Speter int error, fd; 15718334Speter 15818334Speter pathgen(name, path, sizeof(path)); 15918334Speter sector = NULL; 16018334Speter error = 0; 16150397Sobrien 16252284Sobrien fd = open(path, O_RDONLY); 16350397Sobrien if (fd == -1) 16452284Sobrien return (errno); 16518334Speter mediasize = g_get_mediasize(name); 16618334Speter if (mediasize == 0) { 16718334Speter error = errno; 16818334Speter goto out; 16918334Speter } 17018334Speter sectorsize = g_get_sectorsize(name); 17118334Speter if (sectorsize == 0) { 17218334Speter error = errno; 17318334Speter goto out; 17418334Speter } 17518334Speter assert(sectorsize >= size); 17618334Speter sector = malloc(sectorsize); 17718334Speter if (sector == NULL) { 17818334Speter error = ENOMEM; 17918334Speter goto out; 18018334Speter } 18118334Speter if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 18218334Speter (ssize_t)sectorsize) { 18318334Speter error = errno; 18418334Speter goto out; 18518334Speter } 18618334Speter if (magic != NULL) { 18718334Speter std_metadata_decode(sector, &stdmd); 18818334Speter if (strcmp(stdmd.md_magic, magic) != 0) { 18918334Speter error = EINVAL; 19018334Speter goto out; 19118334Speter } 19218334Speter } 19318334Speter bcopy(sector, md, size); 19418334Speterout: 19518334Speter if (sector != NULL) 19618334Speter free(sector); 19718334Speter close(fd); 19818334Speter return (error); 19918334Speter} 20018334Speter 20118334Speterint 20218334Speterg_metadata_store(const char *name, u_char *md, size_t size) 20318334Speter{ 20418334Speter char path[MAXPATHLEN]; 20518334Speter unsigned sectorsize; 20618334Speter off_t mediasize; 20718334Speter u_char *sector; 20818334Speter int error, fd; 20918334Speter 21018334Speter pathgen(name, path, sizeof(path)); 21118334Speter sector = NULL; 21218334Speter error = 0; 21350397Sobrien 21418334Speter fd = open(path, O_WRONLY); 21518334Speter if (fd == -1) 21652284Sobrien return (errno); 21752284Sobrien mediasize = g_get_mediasize(name); 21852284Sobrien if (mediasize == 0) { 21952284Sobrien error = errno; 22052284Sobrien goto out; 22152284Sobrien } 22252284Sobrien sectorsize = g_get_sectorsize(name); 22352284Sobrien if (sectorsize == 0) { 22418334Speter error = errno; 22518334Speter goto out; 22618334Speter } 22718334Speter assert(sectorsize >= size); 22818334Speter sector = malloc(sectorsize); 22918334Speter if (sector == NULL) { 23018334Speter error = ENOMEM; 23118334Speter goto out; 23250397Sobrien } 23318334Speter bcopy(md, sector, size); 23452284Sobrien if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 23518334Speter (ssize_t)sectorsize) { 23652284Sobrien error = errno; 23752284Sobrien goto out; 23852284Sobrien } 23952284Sobrienout: 24052284Sobrien if (sector != NULL) 24152284Sobrien free(sector); 24252284Sobrien close(fd); 24352284Sobrien return (error); 24452284Sobrien} 24552284Sobrien 24652284Sobrienint 24752284Sobrieng_metadata_clear(const char *name, const char *magic) 24852284Sobrien{ 24952284Sobrien struct std_metadata md; 25052284Sobrien char path[MAXPATHLEN]; 25152284Sobrien unsigned sectorsize; 25218334Speter off_t mediasize; 25318334Speter u_char *sector; 25418334Speter int error, fd; 25518334Speter 25650397Sobrien pathgen(name, path, sizeof(path)); 25750397Sobrien sector = NULL; 25850397Sobrien error = 0; 25950397Sobrien 26050397Sobrien fd = open(path, O_RDWR); 26150397Sobrien if (fd == -1) 26252284Sobrien return (errno); 26350397Sobrien mediasize = g_get_mediasize(name); 26450397Sobrien if (mediasize == 0) { 26552284Sobrien error = errno; 26650397Sobrien goto out; 26750397Sobrien } 26850397Sobrien sectorsize = g_get_sectorsize(name); 26950397Sobrien if (sectorsize == 0) { 27050397Sobrien error = errno; 27150397Sobrien goto out; 27250397Sobrien } 27350397Sobrien sector = malloc(sectorsize); 27450397Sobrien if (sector == NULL) { 27550397Sobrien error = ENOMEM; 27650397Sobrien goto out; 27750397Sobrien } 27850397Sobrien if (magic != NULL) { 27950397Sobrien if (pread(fd, sector, sectorsize, mediasize - sectorsize) != 28052284Sobrien (ssize_t)sectorsize) { 28150397Sobrien error = errno; 28250397Sobrien goto out; 28350397Sobrien } 28450397Sobrien std_metadata_decode(sector, &md); 28550397Sobrien if (strcmp(md.md_magic, magic) != 0) { 28650397Sobrien error = EINVAL; 28750397Sobrien goto out; 28852284Sobrien } 28918334Speter } 29052284Sobrien bzero(sector, sectorsize); 29152284Sobrien if (pwrite(fd, sector, sectorsize, mediasize - sectorsize) != 29252284Sobrien (ssize_t)sectorsize) { 29352284Sobrien error = errno; 29452284Sobrien goto out; 29552284Sobrien } 29652284Sobrienout: 29752284Sobrien if (sector != NULL) 29852284Sobrien free(sector); 29952284Sobrien close(fd); 30052284Sobrien return (error); 30152284Sobrien} 30252284Sobrien 30352284Sobrien/* 30452284Sobrien * Set an error message, if one does not already exist. 30552284Sobrien */ 30652284Sobrienvoid 30752284Sobriengctl_error(struct gctl_req *req, const char *error, ...) 30852284Sobrien{ 30952284Sobrien va_list ap; 31052284Sobrien 31152284Sobrien if (req->error != NULL) 31252284Sobrien return; 31352284Sobrien va_start(ap, error); 31452284Sobrien vasprintf(&req->error, error, ap); 31552284Sobrien va_end(ap); 31652284Sobrien} 31752284Sobrien 31852284Sobrienstatic void * 31952284Sobriengctl_get_param(struct gctl_req *req, size_t len, const char *pfmt, va_list ap) 32052284Sobrien{ 32152284Sobrien struct gctl_req_arg *argp; 32252284Sobrien char param[256]; 32352284Sobrien void *p; 32452284Sobrien unsigned i; 32552284Sobrien 32652284Sobrien vsnprintf(param, sizeof(param), pfmt, ap); 32752284Sobrien for (i = 0; i < req->narg; i++) { 32852284Sobrien argp = &req->arg[i]; 32952284Sobrien if (strcmp(param, argp->name)) 33018334Speter continue; 33118334Speter if (!(argp->flag & GCTL_PARAM_RD)) 33218334Speter continue; 33318334Speter p = argp->value; 33418334Speter if (len == 0) { 33518334Speter /* We are looking for a string. */ 33618334Speter if (argp->len < 1) { 33718334Speter fprintf(stderr, "No length argument (%s).\n", 33818334Speter param); 33918334Speter abort(); 34018334Speter } 34118334Speter if (((char *)p)[argp->len - 1] != '\0') { 34218334Speter fprintf(stderr, "Unterminated argument (%s).\n", 34318334Speter param); 34418334Speter abort(); 34518334Speter } 34618334Speter } else if ((int)len != argp->len) { 34718334Speter fprintf(stderr, "Wrong length %s argument.\n", param); 34818334Speter abort(); 34918334Speter } 35018334Speter return (p); 35118334Speter } 35218334Speter fprintf(stderr, "No such argument (%s).\n", param); 35318334Speter abort(); 35418334Speter} 35518334Speter 35618334Speterint 35718334Spetergctl_get_int(struct gctl_req *req, const char *pfmt, ...) 35818334Speter{ 35918334Speter int *p; 36018334Speter va_list ap; 36118334Speter 36218334Speter va_start(ap, pfmt); 36318334Speter p = gctl_get_param(req, sizeof(int), pfmt, ap); 36418334Speter va_end(ap); 36518334Speter return (*p); 36650397Sobrien} 36750397Sobrien 36850397Sobrienintmax_t 36950397Sobriengctl_get_intmax(struct gctl_req *req, const char *pfmt, ...) 37050397Sobrien{ 37150397Sobrien intmax_t *p; 37250397Sobrien va_list ap; 37318334Speter 37418334Speter va_start(ap, pfmt); 37518334Speter p = gctl_get_param(req, sizeof(intmax_t), pfmt, ap); 37618334Speter va_end(ap); 37718334Speter return (*p); 37818334Speter} 37918334Speter 38050397Sobrienconst char * 38150397Sobriengctl_get_ascii(struct gctl_req *req, const char *pfmt, ...) 38250397Sobrien{ 38350397Sobrien const char *p; 38450397Sobrien va_list ap; 38550397Sobrien 38650397Sobrien va_start(ap, pfmt); 38750397Sobrien p = gctl_get_param(req, 0, pfmt, ap); 38850397Sobrien va_end(ap); 38950397Sobrien return (p); 39050397Sobrien} 39150397Sobrien